зеркало из https://github.com/mozilla/gecko-dev.git
Bug 759666 - Make :disabled apply on <option> when their parent <optgroup> has @disabled set. r=bz
This commit is contained in:
Родитель
efcd6ffbea
Коммит
1c3fc21ec0
|
@ -54,6 +54,9 @@ public:
|
|||
|
||||
virtual nsXPCClassInfo* GetClassInfo();
|
||||
|
||||
virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify);
|
||||
|
||||
virtual nsIDOMNode* AsDOMNode() { return this; }
|
||||
|
||||
virtual bool IsDisabled() const {
|
||||
|
@ -165,6 +168,26 @@ nsHTMLOptGroupElement::RemoveChildAt(PRUint32 aIndex, bool aNotify)
|
|||
nsGenericHTMLElement::RemoveChildAt(aIndex, aNotify);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLOptGroupElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify)
|
||||
{
|
||||
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::disabled) {
|
||||
// All our children <option> have their :disabled state depending on our
|
||||
// disabled attribute. We should make sure their state is updated.
|
||||
for (nsIContent* child = nsINode::GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
if (child->IsHTML(nsGkAtoms::option)) {
|
||||
// No need to call |IsElement()| because it's an HTML element.
|
||||
child->AsElement()->UpdateState(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
|
||||
aNotify);
|
||||
}
|
||||
|
||||
nsEventStates
|
||||
nsHTMLOptGroupElement::IntrinsicState() const
|
||||
{
|
||||
|
|
|
@ -277,6 +277,31 @@ nsHTMLOptionElement::SetText(const nsAString& aText)
|
|||
return nsContentUtils::SetNodeTextContent(this, aText, true);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLOptionElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Our new parent might change :disabled/:enabled state.
|
||||
UpdateState(false);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLOptionElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
|
||||
// Our previous parent could have been involved in :disabled/:enabled state.
|
||||
UpdateState(false);
|
||||
}
|
||||
|
||||
nsEventStates
|
||||
nsHTMLOptionElement::IntrinsicState() const
|
||||
{
|
||||
|
@ -288,12 +313,21 @@ nsHTMLOptionElement::IntrinsicState() const
|
|||
state |= NS_EVENT_STATE_DEFAULT;
|
||||
}
|
||||
|
||||
// An <option> is disabled if it has @disabled set or if it's <optgroup> has
|
||||
// @disabled set.
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
|
||||
state |= NS_EVENT_STATE_DISABLED;
|
||||
state &= ~NS_EVENT_STATE_ENABLED;
|
||||
} else {
|
||||
state &= ~NS_EVENT_STATE_DISABLED;
|
||||
state |= NS_EVENT_STATE_ENABLED;
|
||||
nsIContent* parent = GetParent();
|
||||
if (parent && parent->IsHTML(nsGkAtoms::optgroup) &&
|
||||
parent->HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
|
||||
state |= NS_EVENT_STATE_DISABLED;
|
||||
state &= ~NS_EVENT_STATE_ENABLED;
|
||||
} else {
|
||||
state &= ~NS_EVENT_STATE_DISABLED;
|
||||
state |= NS_EVENT_STATE_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
|
|
|
@ -62,6 +62,12 @@ public:
|
|||
|
||||
void SetSelectedInternal(bool aValue, bool aNotify);
|
||||
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers);
|
||||
virtual void UnbindFromTree(bool aDeep = true,
|
||||
bool aNullParent = true);
|
||||
|
||||
// nsIContent
|
||||
virtual nsEventStates IntrinsicState() const;
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ _TEST_FILES = \
|
|||
test_form_attribute-2.html \
|
||||
test_form_attribute-3.html \
|
||||
test_form_attribute-4.html \
|
||||
test_option_disabled.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=759666
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for HTMLOptionElement disabled attribute and pseudo-class</title>
|
||||
<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="https://bugzilla.mozilla.org/show_bug.cgi?id=759666">Mozilla Bug 759666</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for HTMLOptionElement disabled attribute and pseudo-class **/
|
||||
|
||||
var testCases = [
|
||||
// Static checks.
|
||||
{ html: "<option></option>",
|
||||
result: { attr: null, idl: false, pseudo: false } },
|
||||
{ html: "<option disabled></option>",
|
||||
result: { attr: "", idl: true, pseudo: true } },
|
||||
{ html: "<optgroup><option></option></otpgroup>",
|
||||
result: { attr: null, idl: false, pseudo: false } },
|
||||
{ html: "<optgroup><option disabled></option></optgroup>",
|
||||
result: { attr: "", idl: true, pseudo: true } },
|
||||
{ html: "<optgroup disabled><option disabled></option></optgroup>",
|
||||
result: { attr: "", idl: true, pseudo: true } },
|
||||
{ html: "<optgroup disabled><option></option></optgroup>",
|
||||
result: { attr: null, idl: false, pseudo: true } },
|
||||
{ html: "<optgroup><optgroup disabled><option></option></optgroup></optgroup>",
|
||||
result: { attr: null, idl: false, pseudo: true } },
|
||||
{ html: "<optgroup disabled><optgroup><option></option></optgroup></optgroup>",
|
||||
result: { attr: null, idl: false, pseudo: false } },
|
||||
{ html: "<optgroup disabled><optgroup><option disabled></option></optgroup></optgroup>",
|
||||
result: { attr: "", idl: true, pseudo: true } },
|
||||
|
||||
// Dynamic checks: changing disable value.
|
||||
{ html: "<option></option>",
|
||||
modifier: function(c) { c.querySelector('option').disabled = true; },
|
||||
result: { attr: "", idl: true, pseudo: true } },
|
||||
{ html: "<option disabled></option>",
|
||||
modifier: function(c) { c.querySelector('option').disabled = false; },
|
||||
result: { attr: null, idl: false, pseudo: false } },
|
||||
{ html: "<optgroup><option></option></otpgroup>",
|
||||
modifier: function(c) { c.querySelector('optgroup').disabled = true; },
|
||||
result: { attr: null, idl: false, pseudo: true } },
|
||||
{ html: "<optgroup><option disabled></option></optgroup>",
|
||||
modifier: function(c) { c.querySelector('option').disabled = false; },
|
||||
result: { attr: null, idl: false, pseudo: false } },
|
||||
{ html: "<optgroup disabled><option disabled></option></optgroup>",
|
||||
modifier: function(c) { c.querySelector('optgroup').disabled = false; },
|
||||
result: { attr: "", idl: true, pseudo: true } },
|
||||
{ html: "<optgroup disabled><option disabled></option></optgroup>",
|
||||
modifier: function(c) { c.querySelector('option').disabled = false; },
|
||||
result: { attr: null, idl: false, pseudo: true } },
|
||||
{ html: "<optgroup disabled><option disabled></option></optgroup>",
|
||||
modifier: function(c) { c.querySelector('optgroup').disabled = c.querySelector('option').disabled = false; },
|
||||
result: { attr: null, idl: false, pseudo: false } },
|
||||
{ html: "<optgroup disabled><option></option></optgroup>",
|
||||
modifier: function(c) { c.querySelector('optgroup').disabled = false; },
|
||||
result: { attr: null, idl: false, pseudo: false } },
|
||||
{ html: "<optgroup><optgroup disabled><option></option></optgroup></optgroup>",
|
||||
modifier: function(c) { c.querySelector('optgroup[disabled]').disabled = false; },
|
||||
result: { attr: null, idl: false, pseudo: false } },
|
||||
{ html: "<optgroup disabled><optgroup><option></option></optgroup></optgroup>",
|
||||
modifier: function(c) { c.querySelector('optgroup[disabled]').disabled = false; },
|
||||
result: { attr: null, idl: false, pseudo: false } },
|
||||
{ html: "<optgroup disabled><optgroup><option disabled></option></optgroup></optgroup>",
|
||||
modifier: function(c) { c.querySelector('optgroup').disabled = false; },
|
||||
result: { attr: "", idl: true, pseudo: true } },
|
||||
{ html: "<optgroup disabled><optgroup><option disabled></option></optgroup></optgroup>",
|
||||
modifier: function(c) { c.querySelector('option').disabled = false; },
|
||||
result: { attr: null, idl: false, pseudo: false } },
|
||||
{ html: "<optgroup disabled><optgroup><option disabled></option></optgroup></optgroup>",
|
||||
modifier: function(c) { c.querySelector('option').disabled = c.querySelector('option').disabled = false; },
|
||||
result: { attr: null, idl: false, pseudo: false } },
|
||||
|
||||
// Dynamic checks: moving option element.
|
||||
{ html: "<optgroup id='a'><option></option></optgroup><optgroup id='b'></optgroup>",
|
||||
modifier: function(c) { c.querySelector('#b').appendChild(c.querySelector('option')); },
|
||||
result: { attr: null, idl: false, pseudo: false } },
|
||||
{ html: "<optgroup id='a'><option disabled></option></optgroup><optgroup id='b'></optgroup>",
|
||||
modifier: function(c) { c.querySelector('#b').appendChild(c.querySelector('option')); },
|
||||
result: { attr: "", idl: true, pseudo: true } },
|
||||
{ html: "<optgroup id='a'><option></option></optgroup><optgroup disabled id='b'></optgroup>",
|
||||
modifier: function(c) { c.querySelector('#b').appendChild(c.querySelector('option')); },
|
||||
result: { attr: null, idl: false, pseudo: true } },
|
||||
{ html: "<optgroup disabled id='a'><option></option></optgroup><optgroup id='b'></optgroup>",
|
||||
modifier: function(c) { c.querySelector('#b').appendChild(c.querySelector('option')); },
|
||||
result: { attr: null, idl: false, pseudo: false } },
|
||||
];
|
||||
|
||||
var content = document.getElementById('content');
|
||||
|
||||
testCases.forEach(function(testCase) {
|
||||
var result = testCase.result;
|
||||
|
||||
content.innerHTML = testCase.html;
|
||||
|
||||
if (testCase.modifier !== undefined) {
|
||||
testCase.modifier(content);
|
||||
}
|
||||
|
||||
var option = content.querySelector('option');
|
||||
is(option.getAttribute('disabled'), result.attr, "disabled content attribute value should be " + result.attr);
|
||||
is(option.disabled, result.idl, "disabled idl attribute value should be " + result.idl);
|
||||
is(option.mozMatchesSelector(":disabled"), result.pseudo, ":disabled state should be " + result.pseudo);
|
||||
is(option.mozMatchesSelector(":enabled"), !result.pseudo, ":enabled state should be " + !result.pseudo);
|
||||
|
||||
content.innerHTML = "";
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче