зеркало из https://github.com/mozilla/gecko-dev.git
Bug 501257 - Implement HTML 5's HTMLElement.classList property, p=sylvain.pasche@gmail.com, r=smaug, sr=sicking
--HG-- extra : rebase_source : cbbd5a5679af57f97122082213f44491431d87e3
This commit is contained in:
Родитель
630f98121a
Коммит
5575b12b86
|
@ -130,6 +130,7 @@ CPPSRCS = \
|
|||
nsDOMLists.cpp \
|
||||
nsDOMParser.cpp \
|
||||
nsDOMSerializer.cpp \
|
||||
nsDOMTokenList.cpp \
|
||||
nsDocument.cpp \
|
||||
nsDocumentEncoder.cpp \
|
||||
nsDocumentFragment.cpp \
|
||||
|
|
|
@ -0,0 +1,300 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Sylvain Pasche <sylvain.pasche@gmail.com>
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* Implementation of nsIDOMDOMTokenList specified by HTML5.
|
||||
*/
|
||||
|
||||
#include "nsDOMTokenList.h"
|
||||
|
||||
#include "nsAttrValue.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsGenericElement.h"
|
||||
#include "nsHashSets.h"
|
||||
|
||||
|
||||
nsDOMTokenList::nsDOMTokenList(nsGenericElement *aElement, nsIAtom* aAttrAtom)
|
||||
: mElement(aElement),
|
||||
mAttrAtom(aAttrAtom)
|
||||
{
|
||||
// We don't add a reference to our element. If it goes away,
|
||||
// we'll be told to drop our reference
|
||||
}
|
||||
|
||||
nsDOMTokenList::~nsDOMTokenList() { }
|
||||
|
||||
NS_INTERFACE_TABLE_HEAD(nsDOMTokenList)
|
||||
NS_INTERFACE_TABLE1(nsDOMTokenList,
|
||||
nsIDOMDOMTokenList)
|
||||
NS_INTERFACE_TABLE_TO_MAP_SEGUE
|
||||
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(DOMTokenList)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(nsDOMTokenList)
|
||||
NS_IMPL_RELEASE(nsDOMTokenList)
|
||||
|
||||
void
|
||||
nsDOMTokenList::DropReference()
|
||||
{
|
||||
mElement = nsnull;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMTokenList::GetLength(PRUint32 *aLength)
|
||||
{
|
||||
const nsAttrValue* attr = GetParsedAttr();
|
||||
if (!attr) {
|
||||
*aLength = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aLength = attr->GetAtomCount();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMTokenList::Item(PRUint32 aIndex, nsAString& aResult)
|
||||
{
|
||||
const nsAttrValue* attr = GetParsedAttr();
|
||||
|
||||
if (!attr || aIndex >= static_cast<PRUint32>(attr->GetAtomCount())) {
|
||||
SetDOMStringToNull(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
attr->AtomAt(aIndex)->ToString(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMTokenList::CheckToken(const nsAString& aStr)
|
||||
{
|
||||
if (aStr.IsEmpty()) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
||||
nsAString::const_iterator iter, end;
|
||||
aStr.BeginReading(iter);
|
||||
aStr.EndReading(end);
|
||||
|
||||
while (iter != end) {
|
||||
if (nsContentUtils::IsHTMLWhitespace(*iter))
|
||||
return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
|
||||
++iter;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsDOMTokenList::ContainsInternal(const nsAttrValue* aAttr,
|
||||
const nsAString& aToken)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aAttr, "Need an attribute");
|
||||
|
||||
nsCOMPtr<nsIAtom> atom = do_GetAtom(aToken);
|
||||
return aAttr->Contains(atom, eCaseMatters);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMTokenList::Contains(const nsAString& aToken, PRBool* aResult)
|
||||
{
|
||||
nsresult rv = CheckToken(aToken);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
const nsAttrValue* attr = GetParsedAttr();
|
||||
if (!attr) {
|
||||
*aResult = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aResult = ContainsInternal(attr, aToken);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMTokenList::AddInternal(const nsAttrValue* aAttr,
|
||||
const nsAString& aToken)
|
||||
{
|
||||
nsAutoString resultStr;
|
||||
|
||||
if (aAttr) {
|
||||
aAttr->ToString(resultStr);
|
||||
}
|
||||
|
||||
if (!resultStr.IsEmpty() &&
|
||||
!nsContentUtils::IsHTMLWhitespace(
|
||||
resultStr.CharAt(resultStr.Length() - 1))) {
|
||||
resultStr.Append(NS_LITERAL_STRING(" ") + aToken);
|
||||
} else {
|
||||
resultStr.Append(aToken);
|
||||
}
|
||||
mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, PR_TRUE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMTokenList::Add(const nsAString& aToken)
|
||||
{
|
||||
nsresult rv = CheckToken(aToken);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
const nsAttrValue* attr = GetParsedAttr();
|
||||
|
||||
if (attr && ContainsInternal(attr, aToken)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AddInternal(attr, aToken);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
|
||||
const nsAString& aToken)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aAttr, "Need an attribute");
|
||||
|
||||
nsAutoString input;
|
||||
aAttr->ToString(input);
|
||||
|
||||
nsAString::const_iterator copyStart, tokenStart, iter, end;
|
||||
input.BeginReading(iter);
|
||||
input.EndReading(end);
|
||||
copyStart = iter;
|
||||
|
||||
nsAutoString output;
|
||||
PRBool lastTokenRemoved = PR_FALSE;
|
||||
|
||||
while (iter != end) {
|
||||
// skip whitespace.
|
||||
while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
|
||||
++iter;
|
||||
}
|
||||
|
||||
if (iter == end) {
|
||||
// At this point we're sure the last seen token (if any) wasn't to be
|
||||
// removed. So the trailing spaces will need to be kept.
|
||||
NS_ABORT_IF_FALSE(!lastTokenRemoved, "How did this happen?");
|
||||
|
||||
output.Append(Substring(copyStart, end));
|
||||
break;
|
||||
}
|
||||
|
||||
tokenStart = iter;
|
||||
do {
|
||||
++iter;
|
||||
} while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter));
|
||||
|
||||
if (Substring(tokenStart, iter).Equals(aToken)) {
|
||||
|
||||
// Skip whitespace after the token, it will be collapsed.
|
||||
while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
|
||||
++iter;
|
||||
}
|
||||
copyStart = iter;
|
||||
lastTokenRemoved = PR_TRUE;
|
||||
|
||||
} else {
|
||||
|
||||
if (lastTokenRemoved && !output.IsEmpty()) {
|
||||
NS_ABORT_IF_FALSE(!nsContentUtils::IsHTMLWhitespace(
|
||||
output.CharAt(output.Length() - 1)), "Invalid last output token");
|
||||
output.Append(PRUnichar(' '));
|
||||
}
|
||||
lastTokenRemoved = PR_FALSE;
|
||||
output.Append(Substring(copyStart, iter));
|
||||
copyStart = iter;
|
||||
}
|
||||
}
|
||||
|
||||
mElement->SetAttr(kNameSpaceID_None, mAttrAtom, output, PR_TRUE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMTokenList::Remove(const nsAString& aToken)
|
||||
{
|
||||
nsresult rv = CheckToken(aToken);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
const nsAttrValue* attr = GetParsedAttr();
|
||||
if (!attr) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!ContainsInternal(attr, aToken)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RemoveInternal(attr, aToken);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMTokenList::Toggle(const nsAString& aToken, PRBool* aResult)
|
||||
{
|
||||
nsresult rv = CheckToken(aToken);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
const nsAttrValue* attr = GetParsedAttr();
|
||||
|
||||
if (attr && ContainsInternal(attr, aToken)) {
|
||||
RemoveInternal(attr, aToken);
|
||||
*aResult = PR_FALSE;
|
||||
} else {
|
||||
AddInternal(attr, aToken);
|
||||
*aResult = PR_TRUE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMTokenList::ToString(nsAString& aResult)
|
||||
{
|
||||
if (!mElement) {
|
||||
aResult.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mElement->GetAttr(kNameSpaceID_None, mAttrAtom, aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Sylvain Pasche <sylvain.pasche@gmail.com>
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* Implementation of nsIDOMDOMTokenList specified by HTML5.
|
||||
*/
|
||||
|
||||
#ifndef nsDOMTokenList_h___
|
||||
#define nsDOMTokenList_h___
|
||||
|
||||
#include "nsGenericElement.h"
|
||||
#include "nsIDOMDOMTokenList.h"
|
||||
|
||||
class nsAttrValue;
|
||||
|
||||
class nsDOMTokenList : public nsIDOMDOMTokenList
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMDOMTOKENLIST
|
||||
|
||||
nsDOMTokenList(nsGenericElement* aElement, nsIAtom* aAttrAtom);
|
||||
|
||||
void DropReference();
|
||||
|
||||
private:
|
||||
~nsDOMTokenList();
|
||||
|
||||
const nsAttrValue* GetParsedAttr() {
|
||||
if (!mElement) {
|
||||
return nsnull;
|
||||
}
|
||||
return mElement->GetParsedAttr(mAttrAtom);
|
||||
}
|
||||
|
||||
nsresult CheckToken(const nsAString& aStr);
|
||||
PRBool ContainsInternal(const nsAttrValue* aAttr, const nsAString& aToken);
|
||||
void AddInternal(const nsAttrValue* aAttr, const nsAString& aToken);
|
||||
void RemoveInternal(const nsAttrValue* aAttr, const nsAString& aToken);
|
||||
|
||||
nsGenericElement* mElement;
|
||||
nsCOMPtr<nsIAtom> mAttrAtom;
|
||||
};
|
||||
|
||||
#endif // nsDOMTokenList_h___
|
|
@ -74,6 +74,7 @@
|
|||
#include "nsDOMCSSDeclaration.h"
|
||||
#include "nsINameSpaceManager.h"
|
||||
#include "nsContentList.h"
|
||||
#include "nsDOMTokenList.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsDOMString.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
|
@ -1064,6 +1065,24 @@ nsNSElementTearoff::GetChildren(nsIDOMNodeList** aResult)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNSElementTearoff::GetClassList(nsIDOMDOMTokenList** aResult)
|
||||
{
|
||||
nsGenericElement::nsDOMSlots *slots = mContent->GetDOMSlots();
|
||||
NS_ENSURE_TRUE(slots, nsnull);
|
||||
|
||||
if (!slots->mClassList) {
|
||||
nsCOMPtr<nsIAtom> classAttr = mContent->GetClassAttributeName();
|
||||
NS_ENSURE_TRUE(classAttr, NS_OK);
|
||||
slots->mClassList = new nsDOMTokenList(mContent, classAttr);
|
||||
NS_ENSURE_TRUE(slots->mClassList, NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
NS_ADDREF(*aResult = slots->mClassList);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
|
||||
|
@ -1757,6 +1776,10 @@ nsGenericElement::nsDOMSlots::~nsDOMSlots()
|
|||
if (mAttributeMap) {
|
||||
mAttributeMap->DropReference();
|
||||
}
|
||||
|
||||
if (mClassList) {
|
||||
mClassList->DropReference();
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericElement::nsGenericElement(nsINodeInfo *aNodeInfo)
|
||||
|
|
|
@ -83,6 +83,7 @@ class nsIDOMNSFeatureFactory;
|
|||
class nsIEventListenerManager;
|
||||
class nsIScrollableView;
|
||||
class nsContentList;
|
||||
class nsDOMTokenList;
|
||||
struct nsRect;
|
||||
|
||||
typedef PRUptrdiff PtrBits;
|
||||
|
@ -110,7 +111,7 @@ public:
|
|||
// nsINodeList interface
|
||||
virtual nsIContent* GetNodeAt(PRUint32 aIndex);
|
||||
virtual PRInt32 IndexOf(nsIContent* aContent);
|
||||
|
||||
|
||||
void DropReference()
|
||||
{
|
||||
mNode = nsnull;
|
||||
|
@ -454,7 +455,7 @@ public:
|
|||
NS_IMETHOD SetInlineStyleRule(nsICSSStyleRule* aStyleRule, PRBool aNotify);
|
||||
NS_IMETHOD_(PRBool)
|
||||
IsAttributeMapped(const nsIAtom* aAttribute) const;
|
||||
virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||
virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||
PRInt32 aModType) const;
|
||||
/*
|
||||
* Attribute Mapping Helpers
|
||||
|
@ -462,7 +463,7 @@ public:
|
|||
struct MappedAttributeEntry {
|
||||
nsIAtom** attribute;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A common method where you can just pass in a list of maps to check
|
||||
* for attribute dependence. Most implementations of
|
||||
|
@ -540,7 +541,7 @@ public:
|
|||
|
||||
/**
|
||||
* Add a script event listener with the given event handler name
|
||||
* (like onclick) and with the value as JS
|
||||
* (like onclick) and with the value as JS
|
||||
* @param aEventName the event listener name
|
||||
* @param aValue the JS to attach
|
||||
* @param aDefer indicates if deferred execution is allowed
|
||||
|
@ -579,7 +580,7 @@ public:
|
|||
const nsAString& aFeature,
|
||||
const nsAString& aVersion,
|
||||
nsISupports** aReturn);
|
||||
|
||||
|
||||
static already_AddRefed<nsIDOMNSFeatureFactory>
|
||||
GetDOMFeatureFactory(const nsAString& aFeature, const nsAString& aVersion);
|
||||
|
||||
|
@ -684,7 +685,7 @@ public:
|
|||
nsIContent* aTarget,
|
||||
PRBool aFullDispatch,
|
||||
nsEventStatus* aStatus);
|
||||
|
||||
|
||||
/**
|
||||
* Method to dispatch aEvent to aTarget. If aFullDispatch is true, the event
|
||||
* will be dispatched through the full dispatching of the presshell of the
|
||||
|
@ -702,7 +703,7 @@ public:
|
|||
* Get the primary frame for this content without flushing (see
|
||||
* GetPrimaryFrameFor)
|
||||
*
|
||||
* @return the primary frame
|
||||
* @return the primary frame
|
||||
*/
|
||||
nsIFrame* GetPrimaryFrame();
|
||||
|
||||
|
@ -735,11 +736,16 @@ public:
|
|||
mName(aName), mValue(aValue) {}
|
||||
nsAttrInfo(const nsAttrInfo& aOther) :
|
||||
mName(aOther.mName), mValue(aOther.mValue) {}
|
||||
|
||||
|
||||
const nsAttrName* mName;
|
||||
const nsAttrValue* mValue;
|
||||
};
|
||||
|
||||
const nsAttrValue* GetParsedAttr(nsIAtom* aAttr) const
|
||||
{
|
||||
return mAttrsAndChildren.GetAttr(aAttr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the attribute map, if there is one.
|
||||
*
|
||||
|
@ -941,7 +947,7 @@ public:
|
|||
*/
|
||||
nsIControllers* mControllers; // [OWNER]
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Weak reference to this node
|
||||
*/
|
||||
|
@ -951,6 +957,11 @@ public:
|
|||
* An object implementing the .children property for this element.
|
||||
*/
|
||||
nsRefPtr<nsContentList> mChildrenList;
|
||||
|
||||
/**
|
||||
* An object implementing the .classList property for this element.
|
||||
*/
|
||||
nsRefPtr<nsDOMTokenList> mClassList;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
@ -1096,7 +1107,7 @@ public:
|
|||
nsNSElementTearoff(nsGenericElement *aContent) : mContent(aContent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
nsContentList* GetChildrenList();
|
||||
|
||||
|
|
|
@ -322,6 +322,7 @@ _TEST_FILES = test_bug5141.html \
|
|||
bug466409-page.html \
|
||||
bug466409-empty.css \
|
||||
test_bug466409.html \
|
||||
test_classList.html \
|
||||
$(NULL)
|
||||
# Disabled; see bug 492181
|
||||
# test_plugin_freezing.html
|
||||
|
|
|
@ -0,0 +1,351 @@
|
|||
<!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;
|
||||
// XUL returns an empty string when getting a non-existing class attribute.
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
try {
|
||||
e.classList = "foo";
|
||||
ok(false, "assigning to classList didn't throw");
|
||||
} catch (e) { }
|
||||
|
||||
// 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
|
||||
// WebIDL spec. They are returning an empty string at the moment.
|
||||
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");
|
||||
|
||||
// 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");
|
||||
|
||||
// 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", "");
|
||||
|
||||
// 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 ");
|
||||
}
|
||||
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>
|
|
@ -205,10 +205,6 @@ public:
|
|||
|
||||
// HTML element methods
|
||||
void Compact() { mAttrsAndChildren.Compact(); }
|
||||
const nsAttrValue* GetParsedAttr(nsIAtom* aAttr) const
|
||||
{
|
||||
return mAttrsAndChildren.GetAttr(aAttr);
|
||||
}
|
||||
|
||||
virtual void UpdateEditableState();
|
||||
|
||||
|
|
|
@ -123,6 +123,7 @@
|
|||
#include "nsIDOMNodeList.h"
|
||||
#include "nsIDOMNamedNodeMap.h"
|
||||
#include "nsIDOMDOMStringList.h"
|
||||
#include "nsIDOMDOMTokenList.h"
|
||||
#include "nsIDOMNameList.h"
|
||||
#include "nsIDOMNSElement.h"
|
||||
|
||||
|
@ -621,6 +622,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
|||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(DOMException, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(DOMTokenList, nsDOMTokenListSH,
|
||||
ARRAY_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(DocumentFragment, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(Element, nsElementSH,
|
||||
|
@ -2062,6 +2065,10 @@ nsDOMClassInfo::Init()
|
|||
DOM_CLASSINFO_MAP_ENTRY(nsIException)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(DOMTokenList, nsIDOMDOMTokenList)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMTokenList)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(DocumentFragment, nsIDOMDocumentFragment)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDocumentFragment)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)
|
||||
|
@ -7923,6 +7930,19 @@ nsStringListSH::GetStringAt(nsISupports *aNative, PRInt32 aIndex,
|
|||
}
|
||||
|
||||
|
||||
// DOMTokenList scriptable helper
|
||||
|
||||
nsresult
|
||||
nsDOMTokenListSH::GetStringAt(nsISupports *aNative, PRInt32 aIndex,
|
||||
nsAString& aResult)
|
||||
{
|
||||
nsCOMPtr<nsIDOMDOMTokenList> list(do_QueryInterface(aNative));
|
||||
NS_ENSURE_TRUE(list, NS_ERROR_UNEXPECTED);
|
||||
|
||||
return list->Item(aIndex, aResult);
|
||||
}
|
||||
|
||||
|
||||
// Named Array helper
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -1331,6 +1331,31 @@ public:
|
|||
};
|
||||
|
||||
|
||||
// DOMTokenList scriptable helper
|
||||
|
||||
class nsDOMTokenListSH : public nsStringArraySH
|
||||
{
|
||||
protected:
|
||||
nsDOMTokenListSH(nsDOMClassInfoData* aData) : nsStringArraySH(aData)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~nsDOMTokenListSH()
|
||||
{
|
||||
}
|
||||
|
||||
virtual nsresult GetStringAt(nsISupports *aNative, PRInt32 aIndex,
|
||||
nsAString& aResult);
|
||||
|
||||
public:
|
||||
|
||||
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
|
||||
{
|
||||
return new nsDOMTokenListSH(aData);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// MediaList helper
|
||||
|
||||
class nsMediaListSH : public nsStringArraySH
|
||||
|
|
|
@ -64,6 +64,7 @@ enum nsDOMClassInfoID {
|
|||
eDOMClassInfo_DocumentType_id,
|
||||
eDOMClassInfo_DOMImplementation_id,
|
||||
eDOMClassInfo_DOMException_id,
|
||||
eDOMClassInfo_DOMTokenList_id,
|
||||
eDOMClassInfo_DocumentFragment_id,
|
||||
eDOMClassInfo_Element_id,
|
||||
eDOMClassInfo_Attr_id,
|
||||
|
|
|
@ -62,6 +62,7 @@ interface nsIDOMNotation;
|
|||
interface nsIDOMProcessingInstruction;
|
||||
interface nsIDOMText;
|
||||
interface nsIDOMDOMStringList;
|
||||
interface nsIDOMDOMTokenList;
|
||||
interface nsIDOMNameList;
|
||||
interface nsIDOMClientRect;
|
||||
interface nsIDOMClientRectList;
|
||||
|
|
|
@ -80,7 +80,8 @@ XPIDLSRCS = \
|
|||
nsIDOMDOMConfiguration.idl \
|
||||
nsIDOMNSEditableElement.idl \
|
||||
nsIDOMNSElement.idl \
|
||||
nsIDOMNodeSelector.idl \
|
||||
nsIDOMNodeSelector.idl \
|
||||
nsIDOMDOMTokenList.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Sylvain Pasche <sylvain.pasche@gmail.com>
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "domstubs.idl"
|
||||
|
||||
/**
|
||||
* The DOMTokenList interface represents an interface to an underlying string
|
||||
* that consists of a set of space-separated tokens.
|
||||
*
|
||||
* For more information on this interface please see
|
||||
* http://www.w3.org/TR/html5/infrastructure.html#domtokenlist
|
||||
*
|
||||
*/
|
||||
[scriptable, uuid(c6f1e160-eeeb-404a-98b0-6f1246520b6e)]
|
||||
interface nsIDOMDOMTokenList : nsISupports
|
||||
{
|
||||
readonly attribute unsigned long length;
|
||||
|
||||
DOMString item(in unsigned long index);
|
||||
boolean contains(in DOMString token);
|
||||
void add(in DOMString token);
|
||||
void remove(in DOMString token);
|
||||
boolean toggle(in DOMString token);
|
||||
|
||||
DOMString toString();
|
||||
};
|
|
@ -39,9 +39,7 @@
|
|||
|
||||
#include "domstubs.idl"
|
||||
|
||||
interface nsIDOMNodeList;
|
||||
|
||||
[scriptable, uuid(f0aef489-18c5-4de6-99d5-58b3758b098c)]
|
||||
[scriptable, uuid(df86b1a8-02c3-47be-a76b-856620f925df)]
|
||||
interface nsIDOMNSElement : nsISupports
|
||||
{
|
||||
/*
|
||||
|
@ -149,4 +147,9 @@ interface nsIDOMNSElement : nsISupports
|
|||
* Returns a live nsIDOMNodeList of the current child elements.
|
||||
*/
|
||||
readonly attribute nsIDOMNodeList children;
|
||||
|
||||
/**
|
||||
* Returns a DOMTokenList object reflecting the class attribute.
|
||||
*/
|
||||
readonly attribute nsIDOMDOMTokenList classList;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<div style="color: green;">
|
||||
This should be green
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,7 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<body>
|
||||
<div style="color: green;">
|
||||
This should be green
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,18 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<style><![CDATA[
|
||||
.green { color: green; }
|
||||
.toremove { color: red !important; }
|
||||
]]></style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="foo toremove">
|
||||
This should be green
|
||||
</div>
|
||||
<script>
|
||||
var div = document.getElementsByTagName("div")[0];
|
||||
div.classList.toggle("toremove");
|
||||
div.classList.toggle("green");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.green { color: green; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
This should be green
|
||||
</div>
|
||||
<script>
|
||||
document.body.firstElementChild.classList.add("green");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body > div { color: green; }
|
||||
.toremove { color: red; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="toremove">
|
||||
This should be green
|
||||
</div>
|
||||
<script>
|
||||
document.body.firstElementChild.classList.remove("toremove");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1290,6 +1290,9 @@ fails-if(MOZ_WIDGET_TOOLKIT!="cocoa") == 488692-1.html 488692-1-ref.html # needs
|
|||
== 495385-5.html 495385-5-ref.html
|
||||
== 498228-1.xul 498228-1-ref.xul
|
||||
== 496032-1.html 496032-1-ref.html
|
||||
== 501257-1a.html 501257-1-ref.html
|
||||
== 501257-1b.html 501257-1-ref.html
|
||||
== 501257-1.xhtml 501257-1-ref.xhtml
|
||||
== 502288-1.html 502288-1-ref.html
|
||||
== 502942-1.html 502942-1-ref.html
|
||||
== 502447-1.html 502447-1-ref.html
|
||||
|
|
Загрузка…
Ссылка в новой задаче