2009-08-12 01:55:14 -07:00
|
|
|
<!DOCTYPE HTML>
|
|
|
|
<html>
|
|
|
|
<!--
|
|
|
|
https://bugzilla.mozilla.org/show_bug.cgi?id=501257
|
|
|
|
-->
|
|
|
|
<head>
|
|
|
|
<title>Test for the classList element attribute</title>
|
|
|
|
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
|
|
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
|
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<a target="_blank" href="http://www.whatwg.org/specs/web-apps/current-work/#dom-classlist">classList DOM attribute</a>
|
|
|
|
<p id="display"></p>
|
|
|
|
<div id="content" style="display: none">
|
|
|
|
</div>
|
|
|
|
<pre id="test">
|
|
|
|
<script type="application/javascript">
|
|
|
|
|
|
|
|
/** Test for Bug 501257 **/
|
|
|
|
|
|
|
|
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
|
|
|
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
|
|
const XHTML_NS = "http://www.w3.org/1999/xhtml"
|
|
|
|
const MATHML_NS = "http://www.w3.org/1998/Math/MathML";
|
|
|
|
|
|
|
|
var gMutationEvents = [];
|
|
|
|
|
|
|
|
function onAttrModified(event) {
|
|
|
|
is(event.attrName, "class", "mutation on unexpected attribute");
|
|
|
|
|
|
|
|
gMutationEvents.push({
|
|
|
|
attrChange: event.attrChange,
|
|
|
|
prevValue: event.prevValue,
|
|
|
|
newValue: event.newValue,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function checkModification(e, funcName, argument, expectedRes, before, after) {
|
|
|
|
var shouldThrow = typeof(after) === "number";
|
|
|
|
if (shouldThrow) {
|
|
|
|
var expectedException = after;
|
|
|
|
// If an exception is thrown, the class attribute shouldn't change.
|
|
|
|
after = before;
|
|
|
|
}
|
|
|
|
if (before === null)
|
|
|
|
e.removeAttribute("class");
|
|
|
|
else
|
|
|
|
e.setAttribute("class", before);
|
|
|
|
|
|
|
|
var contextMsg = "(checkModification: funcName=" + funcName + ",argument=" +
|
|
|
|
argument + ",expectedRes=" + expectedRes + ",before=" +
|
|
|
|
before + ",after=" + after + ")";
|
|
|
|
|
|
|
|
gMutationEvents = [];
|
|
|
|
e.addEventListener("DOMAttrModified", onAttrModified, false);
|
|
|
|
try {
|
|
|
|
var res = e.classList[funcName](argument);
|
|
|
|
if (shouldThrow)
|
|
|
|
ok(false, "classList modification didn't throw " + contextMsg);
|
|
|
|
} catch (e) {
|
|
|
|
if (!shouldThrow)
|
|
|
|
ok(false, "classList modification threw an exception " + contextMsg);
|
|
|
|
is(e.code, expectedException, "wrong exception thrown " + contextMsg);
|
|
|
|
}
|
|
|
|
e.removeEventListener("DOMAttrModified", onAttrModified, false);
|
|
|
|
if (expectedRes !== null)
|
|
|
|
is(res, expectedRes, "wrong return value from " + funcName +
|
|
|
|
" " + contextMsg);
|
|
|
|
|
|
|
|
var expectedAfter = after;
|
2010-05-23 12:26:15 -07:00
|
|
|
// XUL returns an empty string when getting a nonexistent class attribute.
|
2009-08-12 01:55:14 -07:00
|
|
|
if (e.namespaceURI == XUL_NS && expectedAfter === null)
|
|
|
|
expectedAfter = "";
|
|
|
|
|
|
|
|
is(e.getAttribute("class"), expectedAfter, "wrong class after modification " +
|
|
|
|
contextMsg);
|
|
|
|
var expectedMutation = before != after;
|
|
|
|
is(gMutationEvents.length, expectedMutation ? 1 : 0,
|
|
|
|
"unexpected mutation event count " + contextMsg);
|
|
|
|
if (expectedMutation && gMutationEvents.length) {
|
|
|
|
is(gMutationEvents[0].attrChange,
|
|
|
|
before == null ? MutationEvent.ADDITION : MutationEvent.MODIFICATION,
|
|
|
|
"wrong type of attribute change " + contextMsg);
|
|
|
|
// If there wasn't any previous attribute, prevValue will return an empty
|
|
|
|
// string.
|
|
|
|
var expectedPrevValue = before === null ? "" : before;
|
|
|
|
is(gMutationEvents[0].prevValue, expectedPrevValue,
|
|
|
|
"wrong previous value " + contextMsg);
|
|
|
|
is(gMutationEvents[0].newValue, after, "wrong new value " + contextMsg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-08 17:00:42 -08:00
|
|
|
function assignToClassListStrict(e) {
|
|
|
|
"use strict";
|
|
|
|
try {
|
|
|
|
e.classList = "foo";
|
|
|
|
ok(false, "assigning to classList didn't throw");
|
|
|
|
} catch (e) { }
|
|
|
|
}
|
|
|
|
|
|
|
|
function assignToClassList(e) {
|
|
|
|
try {
|
|
|
|
var expect = e.classList;
|
|
|
|
e.classList = "foo";
|
|
|
|
is(e.classList, expect, "classList should be unchanged after assignment");
|
|
|
|
} catch (e) {
|
|
|
|
ok(false, "assigning to classList threw");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-12 01:55:14 -07:00
|
|
|
function testClassList(e) {
|
|
|
|
|
|
|
|
// basic tests
|
|
|
|
|
|
|
|
isnot(e.classList, undefined, "no classList attribute");
|
|
|
|
is(typeof(e.classList.contains), "function",
|
|
|
|
"no classList.contains function");
|
|
|
|
is(typeof(e.classList.add), "function", "no classList.add function");
|
|
|
|
is(typeof(e.classList.remove), "function", "no classList.remove function");
|
|
|
|
is(typeof(e.classList.toggle), "function", "no classList.toggle function");
|
2009-12-08 17:00:42 -08:00
|
|
|
|
|
|
|
assignToClassListStrict(e);
|
|
|
|
assignToClassList(e);
|
2009-08-12 01:55:14 -07:00
|
|
|
|
|
|
|
// length attribute
|
|
|
|
|
|
|
|
is(e.classList.length, 0, "wrong classList.length value");
|
|
|
|
e.setAttribute("class", "");
|
|
|
|
is(e.classList.length, 0, "wrong classList.length value");
|
|
|
|
e.setAttribute("class", " \t \f");
|
|
|
|
is(e.classList.length, 0, "wrong classList.length value");
|
|
|
|
|
|
|
|
e.setAttribute("class", "a");
|
|
|
|
is(e.classList.length, 1, "wrong classList.length value");
|
|
|
|
e.setAttribute("class", "a A");
|
|
|
|
is(e.classList.length, 2, "wrong classList.length value");
|
|
|
|
e.setAttribute("class", "\r\na\t\f");
|
|
|
|
is(e.classList.length, 1, "wrong classList.length value");
|
|
|
|
|
|
|
|
e.setAttribute("class", "a a");
|
|
|
|
is(e.classList.length, 2, "wrong classList.length value");
|
|
|
|
|
|
|
|
e.setAttribute("class", "a a a a a a");
|
|
|
|
is(e.classList.length, 6, "wrong classList.length value");
|
|
|
|
|
|
|
|
e.setAttribute("class", "a a b b");
|
|
|
|
is(e.classList.length, 4, "wrong classList.length value");
|
|
|
|
|
|
|
|
e.setAttribute("class", "a A B b");
|
|
|
|
is(e.classList.length, 4, "wrong classList.length value");
|
|
|
|
|
|
|
|
e.setAttribute("class", "a b c c b a a b c c");
|
|
|
|
is(e.classList.length, 10, "wrong classList.length value");
|
|
|
|
|
|
|
|
// [Stringifies]
|
|
|
|
|
|
|
|
e.removeAttribute("class");
|
|
|
|
is(e.classList.toString(), "", "wrong classList.toString() value");
|
|
|
|
is(e.classList + "", "", "wrong classList string conversion value");
|
|
|
|
|
|
|
|
e.setAttribute("class", "foo");
|
|
|
|
is(e.classList.toString(), "foo", "wrong classList.toString() value");
|
|
|
|
is(e.classList + "", "foo", "wrong classList string conversion value");
|
|
|
|
|
|
|
|
// item() method
|
|
|
|
|
|
|
|
// TODO out of bounds array indexing should return undefined according to the
|
2009-12-30 15:29:40 -08:00
|
|
|
// WebIDL spec. They are returning an empty string at the moment. (bug 529328)
|
2009-08-12 01:55:14 -07:00
|
|
|
var OOB_VALUE = "";
|
|
|
|
todo_is(OOB_VALUE, undefined, "Wrong out of bounds value");
|
|
|
|
|
|
|
|
e.setAttribute("class", "a");
|
|
|
|
is(e.classList.item(-1), null, "wrong classList.item() result");
|
|
|
|
is(e.classList[-1], OOB_VALUE, "wrong classList[] result");
|
|
|
|
is(e.classList.item(0), "a", "wrong classList.item() result");
|
|
|
|
is(e.classList[0], "a", "wrong classList.item() result");
|
|
|
|
is(e.classList.item(1), null, "wrong classList.item() result");
|
|
|
|
is(e.classList[1], OOB_VALUE, "wrong classList.item() result");
|
|
|
|
|
|
|
|
e.setAttribute("class", "aa AA aa");
|
|
|
|
is(e.classList.item(-1), null, "wrong classList.item() result");
|
|
|
|
is(e.classList[-1], OOB_VALUE, "wrong classList[] result");
|
|
|
|
is(e.classList.item(0), "aa", "wrong classList.item() result");
|
|
|
|
is(e.classList[0], "aa", "wrong classList[] result");
|
|
|
|
is(e.classList.item(1), "AA", "wrong classList.item() result");
|
|
|
|
is(e.classList[1], "AA", "wrong classList[] result");
|
|
|
|
is(e.classList.item(2), "aa", "wrong classList.item() result");
|
|
|
|
is(e.classList[2], "aa", "wrong classList[] result");
|
|
|
|
is(e.classList.item(3), null, "wrong classList.item() result");
|
|
|
|
is(e.classList[3], OOB_VALUE, "wrong classList[] result");
|
|
|
|
is(e.classList.item(0xffffffff), null, "wrong classList.item() result");
|
|
|
|
// XXX returns undefined for index >= 0xffffffff
|
|
|
|
todo_is(e.classList[0xffffffff], OOB_VALUE, "wrong classList[] result");
|
|
|
|
is(e.classList.item(0xfffffffe), null, "wrong classList.item() result");
|
|
|
|
is(e.classList[0xffffffe], OOB_VALUE, "wrong classList[] result");
|
|
|
|
|
|
|
|
e.setAttribute("class", "a b");
|
|
|
|
is(e.classList.item(-1), null, "wrong classList.item() result");
|
|
|
|
is(e.classList[-1], OOB_VALUE, "wrong classList[] result");
|
|
|
|
is(e.classList.item(0), "a", "wrong classList.item() result");
|
|
|
|
is(e.classList[0], "a", "wrong classList[] result");
|
|
|
|
is(e.classList.item(1), "b", "wrong classList.item() result");
|
|
|
|
is(e.classList[1], "b", "wrong classList[] result");
|
|
|
|
is(e.classList.item(2), null, "wrong classList.item() result");
|
|
|
|
is(e.classList[2], OOB_VALUE, "wrong classList[] result");
|
|
|
|
|
|
|
|
// contains() method
|
|
|
|
|
|
|
|
e.removeAttribute("class");
|
|
|
|
is(e.classList.contains("a"), false, "wrong classList.contains() result");
|
|
|
|
try {
|
|
|
|
e.classList.contains("");
|
|
|
|
ok(false, "classList.contains() didn't throw");
|
|
|
|
} catch (e) {
|
|
|
|
is(e.code, DOMException.SYNTAX_ERR, "wrong exception thrown");
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
e.classList.contains(" ");
|
|
|
|
ok(false, "classList.contains() didn't throw");
|
|
|
|
} catch (e) {
|
|
|
|
is(e.code, DOMException.INVALID_CHARACTER_ERR, "wrong exception thrown");
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
e.classList.contains("aa ");
|
|
|
|
ok(false, "classList.contains() didn't throw");
|
|
|
|
} catch (e) {
|
|
|
|
is(e.code, DOMException.INVALID_CHARACTER_ERR, "wrong exception thrown");
|
|
|
|
}
|
|
|
|
|
|
|
|
e.setAttribute("class", "");
|
|
|
|
is(e.classList.contains("a"), false, "wrong classList.contains() result");
|
|
|
|
|
|
|
|
e.setAttribute("class", "a");
|
|
|
|
is(e.classList.contains("a"), true, "wrong classList.contains() result");
|
|
|
|
is(e.classList.contains("aa"), false, "wrong classList.contains() result");
|
|
|
|
is(e.classList.contains("b"), false, "wrong classList.contains() result");
|
|
|
|
|
|
|
|
e.setAttribute("class", "aa AA");
|
|
|
|
is(e.classList.contains("aa"), true, "wrong classList.contains() result");
|
|
|
|
is(e.classList.contains("AA"), true, "wrong classList.contains() result");
|
|
|
|
is(e.classList.contains("aA"), false, "wrong classList.contains() result");
|
|
|
|
|
|
|
|
e.setAttribute("class", "a a a");
|
|
|
|
is(e.classList.contains("a"), true, "wrong classList.contains() result");
|
|
|
|
is(e.classList.contains("aa"), false, "wrong classList.contains() result");
|
|
|
|
is(e.classList.contains("b"), false, "wrong classList.contains() result");
|
|
|
|
|
|
|
|
e.setAttribute("class", "a b c");
|
|
|
|
is(e.classList.contains("a"), true, "wrong classList.contains() result");
|
|
|
|
is(e.classList.contains("b"), true, "wrong classList.contains() result");
|
|
|
|
|
2009-12-30 15:29:40 -08:00
|
|
|
// Test for bug 530171
|
|
|
|
e.setAttribute("class", "null undefined");
|
|
|
|
is(e.classList.contains(null), true, "wrong classList.contains() result");
|
|
|
|
is(e.classList.contains(undefined), true, "wrong classList.contains() result");
|
|
|
|
|
2009-08-12 01:55:14 -07:00
|
|
|
// add() method
|
|
|
|
|
|
|
|
function checkAdd(before, argument, after) {
|
|
|
|
checkModification(e, "add", argument, null, before, after);
|
|
|
|
}
|
|
|
|
|
|
|
|
checkAdd(null, "", DOMException.SYNTAX_ERR);
|
|
|
|
checkAdd(null, " ", DOMException.INVALID_CHARACTER_ERR);
|
|
|
|
checkAdd(null, "aa ", DOMException.INVALID_CHARACTER_ERR);
|
|
|
|
|
|
|
|
checkAdd("a", "a", "a");
|
|
|
|
checkAdd("aa", "AA", "aa AA");
|
|
|
|
checkAdd("a b c", "a", "a b c");
|
|
|
|
checkAdd("a a a b", "a", "a a a b");
|
|
|
|
checkAdd(null, "a", "a");
|
|
|
|
checkAdd("", "a", "a");
|
|
|
|
checkAdd(" ", "a", " a");
|
|
|
|
checkAdd(" \f", "a", " \fa");
|
|
|
|
checkAdd("a", "b", "a b");
|
|
|
|
checkAdd("a b c", "d", "a b c d");
|
|
|
|
checkAdd("a b c ", "d", "a b c d");
|
|
|
|
|
2009-12-30 15:29:40 -08:00
|
|
|
// Test for bug 530171
|
|
|
|
checkAdd(null, null, "null");
|
|
|
|
checkAdd(null, undefined, "undefined");
|
|
|
|
|
2009-08-12 01:55:14 -07:00
|
|
|
// remove() method
|
|
|
|
|
|
|
|
function checkRemove(before, argument, after) {
|
|
|
|
checkModification(e, "remove", argument, null, before, after);
|
|
|
|
}
|
|
|
|
|
|
|
|
checkRemove(null, "", DOMException.SYNTAX_ERR);
|
|
|
|
checkRemove(null, " ", DOMException.INVALID_CHARACTER_ERR);
|
|
|
|
checkRemove(null, "aa ", DOMException.INVALID_CHARACTER_ERR);
|
|
|
|
|
|
|
|
checkRemove(null, "a", null);
|
|
|
|
checkRemove("", "a", "");
|
|
|
|
checkRemove("a b c", "d", "a b c");
|
|
|
|
checkRemove("a b c", "A", "a b c");
|
|
|
|
checkRemove(" a a a ", "a", "");
|
|
|
|
checkRemove("a b", "a", "b");
|
|
|
|
checkRemove("a b ", "a", "b ");
|
|
|
|
checkRemove("a a b", "a", "b");
|
|
|
|
checkRemove("aa aa bb", "aa", "bb");
|
|
|
|
checkRemove("a a b a a c a a", "a", "b c");
|
|
|
|
|
|
|
|
checkRemove("a b c", "b", "a c");
|
|
|
|
checkRemove("aaa bbb ccc", "bbb", "aaa ccc");
|
|
|
|
checkRemove(" a b c ", "b", " a c ");
|
|
|
|
checkRemove("a b b b c", "b", "a c");
|
|
|
|
|
|
|
|
checkRemove("a b c", "c", "a b");
|
|
|
|
checkRemove(" a b c ", "c", " a b");
|
|
|
|
checkRemove("a b c c c", "c", "a b");
|
|
|
|
|
|
|
|
checkRemove("a b a c a d a", "a", "b c d");
|
|
|
|
checkRemove("AA BB aa CC AA dd aa", "AA", "BB aa CC dd aa");
|
|
|
|
|
|
|
|
checkRemove("\ra\na\ta\f", "a", "");
|
|
|
|
|
2009-12-30 15:29:40 -08:00
|
|
|
// Test for bug 530171
|
|
|
|
checkRemove("null", null, "");
|
|
|
|
checkRemove("undefined", undefined, "");
|
|
|
|
|
2009-08-12 01:55:14 -07:00
|
|
|
// toggle() method
|
|
|
|
|
|
|
|
function checkToggle(before, argument, expectedRes, after) {
|
|
|
|
checkModification(e, "toggle", argument, expectedRes, before, after);
|
|
|
|
}
|
|
|
|
|
|
|
|
checkToggle(null, "", null, DOMException.SYNTAX_ERR);
|
|
|
|
checkToggle(null, "aa ", null, DOMException.INVALID_CHARACTER_ERR);
|
|
|
|
|
|
|
|
checkToggle(null, "a", true, "a");
|
|
|
|
checkToggle("", "a", true, "a");
|
|
|
|
checkToggle(" ", "a", true, " a");
|
|
|
|
checkToggle(" \f", "a", true, " \fa");
|
|
|
|
checkToggle("a", "b", true, "a b");
|
|
|
|
checkToggle("a", "A", true, "a A");
|
|
|
|
checkToggle("a b c", "d", true, "a b c d");
|
|
|
|
checkToggle("a b c", "d", true, "a b c d");
|
|
|
|
|
|
|
|
checkToggle("a", "a", false, "");
|
|
|
|
checkToggle(" a a a ", "a", false, "");
|
|
|
|
checkToggle(" A A A ", "a", true, " A A A a");
|
|
|
|
checkToggle(" a b c ", "b", false, " a c ");
|
|
|
|
checkToggle(" a b c b b", "b", false, " a c");
|
|
|
|
checkToggle(" a b c ", "c", false, " a b");
|
|
|
|
checkToggle(" a b c ", "a", false, "b c ");
|
2009-12-30 15:29:40 -08:00
|
|
|
|
|
|
|
// Test for bug 530171
|
|
|
|
checkToggle("null", null, false, "");
|
|
|
|
checkToggle("", null, true, "null");
|
|
|
|
checkToggle("undefined", undefined, false, "");
|
|
|
|
checkToggle("", undefined, true, "undefined");
|
2009-08-12 01:55:14 -07:00
|
|
|
}
|
|
|
|
var content = document.getElementById("content");
|
|
|
|
|
|
|
|
var htmlNode = document.createElement("div");
|
|
|
|
content.appendChild(htmlNode);
|
|
|
|
testClassList(htmlNode);
|
|
|
|
|
|
|
|
var xhtmlNode = document.createElementNS(XHTML_NS, "div");
|
|
|
|
content.appendChild(xhtmlNode);
|
|
|
|
testClassList(xhtmlNode);
|
|
|
|
|
|
|
|
var xulNode = document.createElementNS(XUL_NS, "box");
|
|
|
|
content.appendChild(xulNode);
|
|
|
|
testClassList(xulNode);
|
|
|
|
|
|
|
|
var mathMLNode = document.createElementNS(MATHML_NS, "math");
|
|
|
|
content.appendChild(mathMLNode);
|
|
|
|
testClassList(mathMLNode);
|
|
|
|
|
|
|
|
// Nodes not meant to be styled have a null classList property.
|
|
|
|
|
|
|
|
var xmlNode = document.createElementNS(null, "foo");
|
|
|
|
content.appendChild(xmlNode);
|
|
|
|
is(xmlNode.classList, null, "classList is not null for plain XML nodes");
|
|
|
|
|
|
|
|
var fooNode = document.createElementNS("http://example.org/foo", "foo");
|
|
|
|
content.appendChild(fooNode);
|
|
|
|
is(fooNode.classList, null, "classList is not null for nodes in " +
|
|
|
|
" http://example.org/foo namespace");
|
|
|
|
|
|
|
|
</script>
|
|
|
|
</pre>
|
|
|
|
</body>
|
|
|
|
</html>
|