closes #519: Element.toggleAttribute() + backbugs M1258205 M1276938

This commit is contained in:
Cameron Kaiser 2018-09-11 19:23:49 -07:00
parent 2c14dc434a
commit e5c93de89f
5 changed files with 76 additions and 36 deletions

View File

@ -1196,28 +1196,56 @@ Element::GetAttribute(const nsAString& aName, DOMString& aReturn)
}
}
bool
Element::ToggleAttribute(const nsAString& aName,
const Optional<bool>& aForce,
ErrorResult& aError)
{
aError = nsContentUtils::CheckQName(aName, false);
if (aError.Failed()) {
return false;
}
nsAutoString nameToUse;
const nsAttrName* name = InternalGetAttrNameFromQName(aName, &nameToUse);
if (!name) {
if (aForce.WasPassed() && !aForce.Value()) {
return false;
}
nsCOMPtr<nsIAtom> nameAtom = NS_AtomizeMainThread(nameToUse);
if (!nameAtom) {
aError.Throw(NS_ERROR_OUT_OF_MEMORY);
return false;
}
aError = SetAttr(kNameSpaceID_None, nameAtom, EmptyString(), true);
return true;
}
if (aForce.WasPassed() && aForce.Value()) {
return true;
}
// Hold a strong reference here so that the atom or nodeinfo doesn't go
// away during UnsetAttr. If it did UnsetAttr would be left with a
// dangling pointer as argument without knowing it.
nsAttrName tmp(*name);
aError = UnsetAttr(name->NamespaceID(), name->LocalName(), true);
return false;
}
void
Element::SetAttribute(const nsAString& aName,
const nsAString& aValue,
ErrorResult& aError)
{
const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
aError = nsContentUtils::CheckQName(aName, false);
if (aError.Failed()) {
return;
}
nsAutoString nameToUse;
const nsAttrName* name = InternalGetAttrNameFromQName(aName, &nameToUse);
if (!name) {
aError = nsContentUtils::CheckQName(aName, false);
if (aError.Failed()) {
return;
}
nsCOMPtr<nsIAtom> nameAtom;
if (IsHTMLElement() && IsInHTMLDocument()) {
nsAutoString lower;
nsContentUtils::ASCIIToLower(aName, lower);
nameAtom = NS_AtomizeMainThread(lower);
}
else {
nameAtom = NS_AtomizeMainThread(aName);
}
nsCOMPtr<nsIAtom> nameAtom = NS_AtomizeMainThread(nameToUse);
if (!nameAtom) {
aError.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
@ -1234,7 +1262,7 @@ Element::SetAttribute(const nsAString& aName,
void
Element::RemoveAttribute(const nsAString& aName, ErrorResult& aError)
{
const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
const nsAttrName* name = InternalGetAttrNameFromQName(aName);
if (!name) {
// If there is no canonical nsAttrName for this attribute name, then the
@ -2017,7 +2045,7 @@ Element::FindAttributeDependence(const nsIAtom* aAttribute,
already_AddRefed<mozilla::dom::NodeInfo>
Element::GetExistingAttrNameFromQName(const nsAString& aStr) const
{
const nsAttrName* name = InternalGetExistingAttrNameFromQName(aStr);
const nsAttrName* name = InternalGetAttrNameFromQName(aStr);
if (!name) {
return nullptr;
}
@ -2193,9 +2221,27 @@ Element::SetEventHandler(nsIAtom* aEventName,
//----------------------------------------------------------------------
const nsAttrName*
Element::InternalGetExistingAttrNameFromQName(const nsAString& aStr) const
Element::InternalGetAttrNameFromQName(const nsAString& aStr,
nsAutoString* aNameToUse) const
{
return mAttrsAndChildren.GetExistingAttrNameFromQName(aStr);
MOZ_ASSERT(!aNameToUse || aNameToUse->IsEmpty());
const nsAttrName* val = nullptr;
if (IsHTMLElement() && IsInHTMLDocument()) {
nsAutoString lower;
nsAutoString& outStr = aNameToUse ? *aNameToUse : lower;
nsContentUtils::ASCIIToLower(aStr, outStr);
val = mAttrsAndChildren.GetExistingAttrNameFromQName(outStr);
if (val) {
outStr.Truncate();
}
} else {
val = mAttrsAndChildren.GetExistingAttrNameFromQName(aStr);
if (!val && aNameToUse) {
*aNameToUse = aStr;
}
}
return val;
}
bool

View File

@ -675,6 +675,8 @@ public:
void GetAttributeNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName,
nsAString& aReturn);
bool ToggleAttribute(const nsAString& aName, const Optional<bool>& aForce,
ErrorResult& aError);
void SetAttribute(const nsAString& aName, const nsAString& aValue,
ErrorResult& aError);
void SetAttributeNS(const nsAString& aNamespaceURI,
@ -688,7 +690,7 @@ public:
ErrorResult& aError);
bool HasAttribute(const nsAString& aName) const
{
return InternalGetExistingAttrNameFromQName(aName) != nullptr;
return InternalGetAttrNameFromQName(aName) != nullptr;
}
bool HasAttributeNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName) const;
@ -1281,9 +1283,13 @@ protected:
GetEventListenerManagerForAttr(nsIAtom* aAttrName, bool* aDefer);
/**
* Internal hook for converting an attribute name-string to an atomized name
* Internal hook for converting an attribute name-string to nsAttrName in
* case there is such existing attribute. aNameToUse can be passed to get
* name which was used for looking for the attribute (lowercase in HTML).
*/
virtual const nsAttrName* InternalGetExistingAttrNameFromQName(const nsAString& aStr) const;
const nsAttrName*
InternalGetAttrNameFromQName(const nsAString& aStr,
nsAutoString* aNameToUse = nullptr) const;
nsIFrame* GetStyledFrame();

View File

@ -2857,18 +2857,6 @@ nsGenericHTMLElement::PerformAccesskey(bool aKeyCausesActivation,
return focused;
}
const nsAttrName*
nsGenericHTMLElement::InternalGetExistingAttrNameFromQName(const nsAString& aStr) const
{
if (IsInHTMLDocument()) {
nsAutoString lower;
nsContentUtils::ASCIIToLower(aStr, lower);
return mAttrsAndChildren.GetExistingAttrNameFromQName(lower);
}
return mAttrsAndChildren.GetExistingAttrNameFromQName(aStr);
}
nsresult
nsGenericHTMLElement::GetEditor(nsIEditor** aEditor)
{

View File

@ -1025,8 +1025,6 @@ protected:
GetEventListenerManagerForAttr(nsIAtom* aAttrName,
bool* aDefer) override;
virtual const nsAttrName* InternalGetExistingAttrNameFromQName(const nsAString& aStr) const override;
/**
* Create a URI for the given aURISpec string.
* Returns INVALID_STATE_ERR and nulls *aURI if aURISpec is empty

View File

@ -42,6 +42,8 @@ interface Element : Node {
[Pure]
DOMString? getAttributeNS(DOMString? namespace, DOMString localName);
[Throws]
boolean toggleAttribute(DOMString name, optional boolean force);
[Throws]
void setAttribute(DOMString name, DOMString value);
[Throws]
void setAttributeNS(DOMString? namespace, DOMString name, DOMString value);