Added: trunk/LayoutTests/fast/forms/fieldset/fieldset-disabled.html (0 => 112515)
--- trunk/LayoutTests/fast/forms/fieldset/fieldset-disabled.html (rev 0)
+++ trunk/LayoutTests/fast/forms/fieldset/fieldset-disabled.html 2012-03-29 10:14:32 UTC (rev 112515)
@@ -0,0 +1,300 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href=""
+<script src=""
+<style type="text/css">
+input {
+ background:rgb(255,255,100);
+}
+input:disabled {
+ background:rgb(255,0,0);
+}
+</style>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<form>
+<fieldset>
+<legend><input type="text" id="parserGeneratedInput1"></legend>
+<legend><input type="text" id="parserGeneratedInput2"></legend>
+<input type="text" id="parserGeneratedInput3">
+<input type="text" id="parserGeneratedInput4" disabled>
+</fieldset>
+<fieldset disabled>
+<legend><input type="text" id="parserGeneratedInput5"></legend>
+<legend><input type="text" id="parserGeneratedInput6"></legend>
+<input type="text" id="parserGeneratedInput7">
+<input type="text" id="parserGeneratedInput8" disabled>
+</fieldset>
+<fieldset disabled>
+<input type="text" id="parserGeneratedInput9">
+</fieldset>
+</form>
+
+<script>
+description('Tests for HTMLFieldSetElement.disabled behavior.');
+
+debug('\nVerifying parser generated fieldsets.');
+var parserGeneratedInput1 = document.getElementById("parserGeneratedInput1");
+var parserGeneratedInput2 = document.getElementById("parserGeneratedInput2");
+var parserGeneratedInput3 = document.getElementById("parserGeneratedInput3");
+var parserGeneratedInput4 = document.getElementById("parserGeneratedInput4");
+var parserGeneratedInput5 = document.getElementById("parserGeneratedInput5");
+var parserGeneratedInput6 = document.getElementById("parserGeneratedInput6");
+var parserGeneratedInput7 = document.getElementById("parserGeneratedInput7");
+var parserGeneratedInput8 = document.getElementById("parserGeneratedInput8");
+var parserGeneratedInput9 = document.getElementById("parserGeneratedInput9");
+
+parserGeneratedInput1.focus();
+document.execCommand('insertText', false, 'L');
+parserGeneratedInput2.focus();
+document.execCommand('insertText', false, 'M');
+parserGeneratedInput3.focus();
+document.execCommand('insertText', false, 'N');
+parserGeneratedInput4.focus();
+document.execCommand('insertText', false, 'O');
+parserGeneratedInput5.focus();
+document.execCommand('insertText', false, 'P');
+parserGeneratedInput6.focus();
+document.execCommand('insertText', false, 'Q');
+parserGeneratedInput7.focus();
+document.execCommand('insertText', false, 'R');
+parserGeneratedInput8.focus();
+document.execCommand('insertText', false, 'S');
+parserGeneratedInput9.focus();
+document.execCommand('insertText', false, 'T');
+
+shouldBe('parserGeneratedInput1.value', '"L"');
+shouldBe('parserGeneratedInput2.value', '"M"');
+shouldBe('parserGeneratedInput3.value', '"NO"');
+shouldBe('parserGeneratedInput4.value', '""');
+shouldBe('parserGeneratedInput5.value', '"P"');
+shouldBe('parserGeneratedInput6.value', '""');
+shouldBe('parserGeneratedInput7.value', '""');
+shouldBe('parserGeneratedInput8.value', '""');
+shouldBe('parserGeneratedInput9.value', '""');
+
+
+debug('\nTesting a single fieldset element.');
+var fieldSet = document.createElement('fieldset');
+document.body.appendChild(fieldSet);
+var textInput = document.createElement('input');
+textInput.type = "text";
+fieldSet.appendChild(textInput);
+
+debug('Verifying HTMLFormControl can be disabled regardless of enclosing fieldset.');
+textInput.disabled = true;
+shouldBeTrue('textInput.disabled');
+textInput.focus();
+document.execCommand('insertText', false, 'A');
+shouldBe('textInput.value', '""');
+shouldBeFalse('fieldSet.disabled');
+textInput.disabled = false;
+
+debug('Fieldset is enabled by default. A user can insertText into the text input field.');
+textInput.focus();
+document.execCommand('insertText', false, 'A');
+shouldBe('textInput.value', '"A"');
+
+debug('Disable fieldset.');
+fieldSet.disabled = true;
+shouldBeTrue('fieldSet.disabled');
+
+debug('Once the fieldset is disabled, text cannot be inserted.');
+textInput.focus();
+document.execCommand('insertText', false, 'B');
+shouldBe('textInput.value', '"A"');
+
+debug("Check if the style of the text element changed.");
+shouldBe("getComputedStyle(textInput).backgroundColor", "'rgb(255, 0, 0)'");
+
+debug('Enable fieldset.');
+fieldSet.disabled = false;
+shouldBeFalse('fieldSet.disabled');
+shouldBe("getComputedStyle(textInput).backgroundColor", "'rgb(255, 255, 100)'");
+
+textInput.focus();
+document.execCommand('insertText', false, 'B');
+shouldBe('textInput.value', '"AB"');
+
+debug('Move the textinput element out of the fieldset.');
+fieldSet.removeChild(textInput);
+document.body.appendChild(textInput);
+
+debug('Disable the fieldset.');
+fieldSet.disabled = true;
+shouldBeTrue('fieldSet.disabled');
+
+debug('Text can be inserted, because the textinput element is outside of the disabled fieldset.');
+textInput.focus();
+document.execCommand('insertText', false, 'C');
+shouldBe('textInput.value', '"ABC"');
+
+debug('Enable the fieldset.');
+fieldSet.disabled = false;
+shouldBeFalse('fieldSet.disabled');
+
+debug('Insert a table into the fieldset.');
+var table = document.createElement('table');
+fieldSet.appendChild(table);
+var tr = document.createElement('tr');
+table.appendChild(tr);
+var td = document.createElement('td');
+tr.appendChild(td);
+
+debug('Move the textinput field into the table.');
+document.body.removeChild(textInput);
+td.appendChild(textInput);
+
+textInput.focus();
+document.execCommand('insertText', false, 'D');
+shouldBe('textInput.value', '"ABCD"');
+
+debug('Disable the fieldset.');
+fieldSet.disabled = true;
+shouldBeTrue('fieldSet.disabled');
+
+debug('Inserting text should fail.')
+textInput.focus();
+document.execCommand('insertText', false, 'E');
+shouldBe('textInput.value', '"ABCD"');
+
+debug('Enable the fieldset.');
+fieldSet.disabled = false;
+shouldBeFalse('fieldSet.disabled');
+
+textInput.focus();
+document.execCommand('insertText', false, 'E');
+shouldBe('textInput.value', '"ABCDE"');
+
+
+debug('\nTesting nested fieldset elements.');
+var outerFieldSet = document.createElement('fieldset');
+document.body.appendChild(outerFieldSet);
+var innerFieldSet = document.createElement('fieldset');
+outerFieldSet.appendChild(innerFieldSet);
+var outerTextInput = document.createElement('input');
+outerTextInput.type = "text";
+outerFieldSet.appendChild(outerTextInput);
+var innerTextInput = document.createElement('input');
+innerTextInput.type = "text";
+innerFieldSet.appendChild(innerTextInput);
+
+debug('Verifying that subordinates of both fieldsets are enabled.');
+outerTextInput.focus();
+document.execCommand('insertText', false, 'F');
+innerTextInput.focus();
+document.execCommand('insertText', false, 'F');
+shouldBe('outerTextInput.value', '"F"');
+shouldBe('innerTextInput.value', '"F"');
+
+debug('Disabling the inner fieldset only.');
+innerFieldSet.disabled = true;
+shouldBeTrue('innerFieldSet.disabled');
+outerTextInput.focus();
+document.execCommand('insertText', false, 'G');
+innerTextInput.focus();
+document.execCommand('insertText', false, 'G');
+shouldBe('outerTextInput.value', '"FG"');
+shouldBe('innerTextInput.value', '"F"');
+
+debug('Enabling the inner and disabling the outer fieldset.');
+outerFieldSet.disabled = true;
+innerFieldSet.disabled = false;
+shouldBeTrue('outerFieldSet.disabled');
+shouldBeFalse('innerFieldSet.disabled');
+outerTextInput.focus();
+document.execCommand('insertText', false, 'H');
+innerTextInput.focus();
+document.execCommand('insertText', false, 'H');
+shouldBe('outerTextInput.value', '"FG"');
+shouldBe('innerTextInput.value', '"F"');
+
+debug('Disabling both fieldset elements.');
+outerFieldSet.disabled = true;
+innerFieldSet.disabled = true;
+shouldBeTrue('outerFieldSet.disabled');
+shouldBeTrue('innerFieldSet.disabled');
+outerTextInput.focus();
+document.execCommand('insertText', false, 'H');
+innerTextInput.focus();
+document.execCommand('insertText', false, 'H');
+shouldBe('outerTextInput.value', '"FG"');
+shouldBe('innerTextInput.value', '"F"');
+
+debug('Enabling both fieldset elements.');
+outerFieldSet.disabled = false;
+innerFieldSet.disabled = false;
+shouldBeFalse('outerFieldSet.disabled');
+shouldBeFalse('innerFieldSet.disabled');
+outerTextInput.focus();
+document.execCommand('insertText', false, 'H');
+innerTextInput.focus();
+document.execCommand('insertText', false, 'H');
+shouldBe('outerTextInput.value', '"FGH"');
+shouldBe('innerTextInput.value', '"FH"');
+
+
+debug('\nTest behavior of the first legend element in a fieldset elements.');
+var legendFieldSet = document.createElement('fieldset');
+document.body.appendChild(legendFieldSet);
+var firstLegend = document.createElement('legend');
+legendFieldSet.appendChild(firstLegend);
+var secondLegend = document.createElement('legend');
+legendFieldSet.appendChild(secondLegend);
+
+var firstLegendTextInput = document.createElement('input');
+firstLegendTextInput.type = "text";
+firstLegend.appendChild(firstLegendTextInput);
+
+var secondLegendTextInput = document.createElement('input');
+secondLegendTextInput.type = "text";
+secondLegend.appendChild(secondLegendTextInput);
+
+debug('Children of the first legend element in a fieldset should not get disabled with the fieldset.');
+legendFieldSet.disabled = true;
+shouldBeTrue('legendFieldSet.disabled');
+firstLegendTextInput.focus();
+document.execCommand('insertText', false, 'I');
+secondLegendTextInput.focus()
+document.execCommand('insertText', false, 'I');
+shouldBe('firstLegendTextInput.value', '"I"');
+shouldBe('secondLegendTextInput.value', '""');
+
+debug('Insert another legend element before the currently first one, and check again.');
+var insertedLegend = document.createElement('legend');
+legendFieldSet.insertBefore(insertedLegend, firstLegend);
+var insertedLegendTextInput = document.createElement('input');
+insertedLegend.appendChild(insertedLegendTextInput);
+
+insertedLegendTextInput.focus();
+document.execCommand('insertText', false, 'J');
+firstLegendTextInput.focus();
+document.execCommand('insertText', false, 'J');
+secondLegendTextInput.focus()
+document.execCommand('insertText', false, 'J');
+shouldBe('insertedLegendTextInput.value', '"J"');
+shouldBe('firstLegendTextInput.value', '"I"');
+shouldBe('secondLegendTextInput.value', '""');
+
+debug('Enable the fieldset again and check for sanity.');
+legendFieldSet.disabled = false;
+shouldBeFalse('legendFieldSet.disabled');
+insertedLegendTextInput.focus();
+document.execCommand('insertText', false, 'K');
+firstLegendTextInput.focus();
+document.execCommand('insertText', false, 'K');
+secondLegendTextInput.focus()
+document.execCommand('insertText', false, 'K');
+shouldBe('insertedLegendTextInput.value', '"JK"');
+shouldBe('firstLegendTextInput.value', '"IK"');
+shouldBe('secondLegendTextInput.value', '"K"');
+
+var successfullyParsed = true;
+</script>
+<script src=""
+
+</body>
+</html>
Modified: trunk/Source/WebCore/html/HTMLFormControlElement.cpp (112514 => 112515)
--- trunk/Source/WebCore/html/HTMLFormControlElement.cpp 2012-03-29 10:12:12 UTC (rev 112514)
+++ trunk/Source/WebCore/html/HTMLFormControlElement.cpp 2012-03-29 10:14:32 UTC (rev 112515)
@@ -30,8 +30,10 @@
#include "EventHandler.h"
#include "EventNames.h"
#include "Frame.h"
+#include "HTMLFieldSetElement.h"
#include "HTMLFormElement.h"
#include "HTMLInputElement.h"
+#include "HTMLLegendElement.h"
#include "RenderBox.h"
#include "RenderTheme.h"
#include "ScriptEventListener.h"
@@ -46,6 +48,9 @@
HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
: LabelableElement(tagName, document)
+ , m_fieldSetAncestor(0)
+ , m_legendAncestor(0)
+ , m_fieldSetAncestorValid(false)
, m_disabled(false)
, m_readOnly(false)
, m_required(false)
@@ -95,6 +100,21 @@
return fastHasAttribute(formnovalidateAttr);
}
+void HTMLFormControlElement::updateFieldSetAndLegendAncestor() const
+{
+ m_fieldSetAncestor = 0;
+ m_legendAncestor = 0;
+ for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
+ if (!m_legendAncestor && ancestor->hasTagName(legendTag))
+ m_legendAncestor = static_cast<HTMLLegendElement*>(ancestor);
+ if (ancestor->hasTagName(fieldsetTag)) {
+ m_fieldSetAncestor = static_cast<HTMLFieldSetElement*>(ancestor);
+ break;
+ }
+ }
+ m_fieldSetAncestorValid = true;
+}
+
void HTMLFormControlElement::parseAttribute(Attribute* attr)
{
if (attr->name() == formAttr)
@@ -102,11 +122,8 @@
else if (attr->name() == disabledAttr) {
bool oldDisabled = m_disabled;
m_disabled = !attr->isNull();
- if (oldDisabled != m_disabled) {
- setNeedsStyleRecalc();
- if (renderer() && renderer()->style()->hasAppearance())
- renderer()->theme()->stateChanged(renderer(), EnabledState);
- }
+ if (oldDisabled != m_disabled)
+ disabledAttributeChanged();
} else if (attr->name() == readonlyAttr) {
bool oldReadOnly = m_readOnly;
m_readOnly = !attr->isNull();
@@ -125,6 +142,13 @@
setNeedsWillValidateCheck();
}
+void HTMLFormControlElement::disabledAttributeChanged()
+{
+ setNeedsStyleRecalc();
+ if (renderer() && renderer()->style()->hasAppearance())
+ renderer()->theme()->stateChanged(renderer(), EnabledState);
+}
+
void HTMLFormControlElement::requiredAttributeChanged()
{
setNeedsValidityCheck();
@@ -205,6 +229,7 @@
void HTMLFormControlElement::removedFromTree(bool deep)
{
+ m_fieldSetAncestorValid = false;
FormAssociatedElement::removedFromTree();
HTMLElement::removedFromTree(deep);
}
@@ -254,6 +279,20 @@
HTMLElement::dispatchInputEvent();
}
+bool HTMLFormControlElement::disabled() const
+{
+ if (m_disabled)
+ return true;
+
+ if (!m_fieldSetAncestorValid)
+ updateFieldSetAndLegendAncestor();
+
+ // Form controls in the first legend element inside a fieldset are not affected by fieldset.disabled.
+ if (m_fieldSetAncestor && m_fieldSetAncestor->disabled())
+ return !(m_legendAncestor && m_legendAncestor == m_fieldSetAncestor->legend());
+ return false;
+}
+
void HTMLFormControlElement::setDisabled(bool b)
{
setAttribute(disabledAttr, b ? "" : 0);