Title: [121392] trunk
Revision
121392
Author
alexis.men...@openbossa.org
Date
2012-06-27 18:05:27 -0700 (Wed, 27 Jun 2012)

Log Message

Implement selectedOptions attribute of HTMLSelectElement.
https://bugs.webkit.org/show_bug.cgi?id=80631

Reviewed by Ryosuke Niwa.

Source/WebCore:

Add a new collection as a member of HTMLSelectElement which is
used to store the selected elements. Extend HTMLCollection to
support the new collection type needed by this feature. Make sure
that we invalidate the collection when the select state of an
option changes as the select state change does not trigger a dom
tree version change.

Reference : http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#dom-select-selectedoptions

Test: fast/dom/HTMLSelectElement/select-selectedOptions.html

* html/CollectionType.h:
* html/HTMLCollection.cpp:
(WebCore::shouldIncludeChildren):
(WebCore::HTMLCollection::clearCache):
(WebCore):
(WebCore::HTMLCollection::isAcceptableElement):
* html/HTMLCollection.h:
(HTMLCollection):
* html/HTMLOptionElement.cpp:
(WebCore::HTMLOptionElement::setSelectedState):
* html/HTMLSelectElement.cpp:
(WebCore::HTMLSelectElement::selectedOptions):
(WebCore):
(WebCore::HTMLSelectElement::invalidateSelectedItems):
(WebCore::HTMLSelectElement::setRecalcListItems):
* html/HTMLSelectElement.h:
(WebCore):
(HTMLSelectElement):
* html/HTMLSelectElement.idl:

LayoutTests:

New tests to cover the feature.

* fast/dom/HTMLSelectElement/select-selectedOptions-expected.txt: Added.
* fast/dom/HTMLSelectElement/select-selectedOptions.html: Added.
* fast/dom/htmlcollection-non-html-expected.txt:
* fast/dom/htmlcollection-non-html.html:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (121391 => 121392)


--- trunk/LayoutTests/ChangeLog	2012-06-28 00:49:55 UTC (rev 121391)
+++ trunk/LayoutTests/ChangeLog	2012-06-28 01:05:27 UTC (rev 121392)
@@ -1,3 +1,17 @@
+2012-06-27  Alexis Menard  <alexis.men...@openbossa.org>
+
+        Implement selectedOptions attribute of HTMLSelectElement.
+        https://bugs.webkit.org/show_bug.cgi?id=80631
+
+        Reviewed by Ryosuke Niwa.
+
+        New tests to cover the feature.
+
+        * fast/dom/HTMLSelectElement/select-selectedOptions-expected.txt: Added.
+        * fast/dom/HTMLSelectElement/select-selectedOptions.html: Added.
+        * fast/dom/htmlcollection-non-html-expected.txt:
+        * fast/dom/htmlcollection-non-html.html:
+
 2012-06-27  Filip Pizlo  <fpi...@apple.com>
 
         _javascript_ SHA-512 gives wrong hash on second and subsequent runs unless Web Inspector _javascript_ Debugging is on

Added: trunk/LayoutTests/fast/dom/HTMLSelectElement/select-selectedOptions-expected.txt (0 => 121392)


--- trunk/LayoutTests/fast/dom/HTMLSelectElement/select-selectedOptions-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/HTMLSelectElement/select-selectedOptions-expected.txt	2012-06-28 01:05:27 UTC (rev 121392)
@@ -0,0 +1,51 @@
+
+1) Initial there is no selected options.
+PASS optionsLength is 2
+PASS selectedOptions.length is 0
+2) Select an option should update the selected options collection.
+PASS optionsLength is 2
+PASS selectedOptions.length is 1
+PASS selectedOptions[0].text is 'one'
+3) Select two options should update the selected options collection.
+PASS optionsLength is 2
+PASS selectedOptions.length is 2
+PASS selectedOptions[0].text is 'one'
+PASS selectedOptions[1].text is 'two'
+4) Adding a non selected option should not change the selected options collection.
+PASS optionsLength is 3
+PASS selectedOptions.length is 1
+PASS selectedOptions[0].text is 'one'
+5) Adding a selected option should change the selected options collection.
+PASS optionsLength is 4
+PASS selectedOptions.length is 2
+PASS selectedOptions[0].text is 'one'
+PASS selectedOptions[1].text is 'five'
+6) Unselect an option should update the selected options collection.
+PASS optionsLength is 4
+PASS selectedOptions.length is 1
+PASS selectedOptions[0].text is 'five'
+7) Remove an option unselected should not update the selected options collection.
+PASS optionsLength is 3
+PASS selectedOptions.length is 1
+PASS selectedOptions[0].text is 'five'
+8) Remove an option selected should update the selected options collection.
+PASS optionsLength is 2
+PASS selectedOptions.length is 0
+9) Change multiple attribute to false should update selectedOptions.
+PASS optionsLength is 2
+PASS selectedOptions.length is 1
+PASS selectedOptions[0].text is 'two'
+10) Even with an option disabled selectedOptions should be updated.
+PASS optionsLength is 2
+PASS selectedOptions.length is 1
+PASS selectedOptions[0].text is 'one'
+11) Even with select element disabled, the selectedOptions should be updated.
+PASS optionsLength is 2
+PASS selectedOptions.length is 2
+PASS selectedOptions[0].text is 'one'
+PASS selectedOptions[1].text is 'two'
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/dom/HTMLSelectElement/select-selectedOptions.html (0 => 121392)


--- trunk/LayoutTests/fast/dom/HTMLSelectElement/select-selectedOptions.html	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/HTMLSelectElement/select-selectedOptions.html	2012-06-28 01:05:27 UTC (rev 121392)
@@ -0,0 +1,129 @@
+<!DOCTYPE html>
+<select id="test" size="3" multiple="multiple">
+</select>
+<div id="console"></div>
+<script src=""
+<script>
+function reset(mySelect) {
+    mySelect.length = 0;
+    mySelect.multiple = true;
+    mySelect.options[mySelect.length] = new Option("one", "value", false);
+    mySelect.options[mySelect.length] = new Option("two", "value", false);
+}
+
+function deepCopy(array)
+{
+    var copy=[];
+    for(var i=0;i<array.length;i++)
+        copy.push(array[i]);
+    return copy;
+ }
+
+var mySelect = document.getElementById("test");
+reset(mySelect);
+var i = 0;
+
+// We use this local variable as shouldBe will modify the dom tree version. Any dom tree version update invalidates
+// the caches therefore we need to make sure that we store the values before calling shouldBe.
+var selectedOptions;
+var optionsLength = 0;
+
+debug((++i) + ") Initial there is no selected options.");
+optionsLength = mySelect.options.length;
+selectedOptions = deepCopy(mySelect.selectedOptions);
+shouldBe("optionsLength", "2");
+shouldBe("selectedOptions.length", "0");
+
+debug((++i) + ") Select an option should update the selected options collection.");
+mySelect.options[0].selected = true;
+optionsLength = mySelect.options.length;
+selectedOptions = deepCopy(mySelect.selectedOptions);
+shouldBe("optionsLength", "2");
+shouldBe("selectedOptions.length", "1");
+shouldBe("selectedOptions[0].text", "'one'");
+
+debug((++i) + ") Select two options should update the selected options collection.");
+mySelect.options[1].selected = true;
+optionsLength = mySelect.options.length;
+selectedOptions = deepCopy(mySelect.selectedOptions);
+shouldBe("optionsLength", "2");
+shouldBe("selectedOptions.length", "2");
+shouldBe("selectedOptions[0].text", "'one'");
+shouldBe("selectedOptions[1].text", "'two'");
+
+mySelect.options[1].selected = false;
+debug((++i) + ") Adding a non selected option should not change the selected options collection.");
+mySelect.options[mySelect.length] = new Option("three", "value", false);
+optionsLength = mySelect.options.length;
+selectedOptions = deepCopy(mySelect.selectedOptions);
+shouldBe("optionsLength", "3");
+shouldBe("selectedOptions.length", "1");
+shouldBe("selectedOptions[0].text", "'one'");
+
+debug((++i) + ") Adding a selected option should change the selected options collection.");
+mySelect.options[mySelect.length] = new Option("five", "value", true, true);
+selectedOptionsLength = mySelect.selectedOptions.length;
+optionsLength = mySelect.options.length;
+selectedOptions = mySelect.selectedOptions;
+shouldBe("optionsLength", "4");
+shouldBe("selectedOptions.length", "2");
+shouldBe("selectedOptions[0].text", "'one'");
+shouldBe("selectedOptions[1].text", "'five'");
+
+debug((++i) + ") Unselect an option should update the selected options collection.");
+mySelect.options[0].selected = false;
+optionsLength = mySelect.options.length;
+selectedOptions = deepCopy(mySelect.selectedOptions);
+shouldBe("optionsLength", "4");
+shouldBe("selectedOptions.length", "1");
+shouldBe("selectedOptions[0].text", "'five'");
+
+debug((++i) + ") Remove an option unselected should not update the selected options collection.");
+mySelect.remove(0);
+selectedOptionsLength = mySelect.selectedOptions.length;
+optionsLength = mySelect.options.length;
+selectedOptions = deepCopy(mySelect.selectedOptions);
+shouldBe("optionsLength", "3");
+shouldBe("selectedOptions.length", "1");
+shouldBe("selectedOptions[0].text", "'five'");
+
+debug((++i) + ") Remove an option selected should update the selected options collection.");
+mySelect.remove(2);
+optionsLength = mySelect.options.length;
+selectedOptions = deepCopy(mySelect.selectedOptions);
+shouldBe("optionsLength", "2");
+shouldBe("selectedOptions.length", "0");
+
+mySelect.options[0].selected = true;
+mySelect.options[1].selected = true;
+debug((++i) + ") Change multiple attribute to false should update selectedOptions.");
+mySelect.multiple = false;
+optionsLength = mySelect.options.length;
+selectedOptions = deepCopy(mySelect.selectedOptions);
+shouldBe("optionsLength", "2");
+shouldBe("selectedOptions.length", "1");
+shouldBe("selectedOptions[0].text", "'two'");
+
+reset(mySelect);
+debug((++i) + ") Even with an option disabled selectedOptions should be updated.");
+mySelect.options[0].disabled = true;
+mySelect.options[0].selected = true;
+optionsLength = mySelect.options.length;
+selectedOptions = deepCopy(mySelect.selectedOptions);
+shouldBe("optionsLength", "2");
+shouldBe("selectedOptions.length", "1");
+shouldBe("selectedOptions[0].text", "'one'");
+
+debug((++i) + ") Even with select element disabled, the selectedOptions should be updated.");
+mySelect.disabled = true;
+mySelect.options[1].selected = true;
+optionsLength = mySelect.options.length;
+selectedOptions = deepCopy(mySelect.selectedOptions);
+shouldBe("optionsLength", "2");
+shouldBe("selectedOptions.length", "2");
+shouldBe("selectedOptions[0].text", "'one'");
+shouldBe("selectedOptions[1].text", "'two'");
+
+debug("");
+</script>
+<script src=""

Modified: trunk/LayoutTests/fast/dom/htmlcollection-non-html-expected.txt (121391 => 121392)


--- trunk/LayoutTests/fast/dom/htmlcollection-non-html-expected.txt	2012-06-28 00:49:55 UTC (rev 121391)
+++ trunk/LayoutTests/fast/dom/htmlcollection-non-html-expected.txt	2012-06-28 01:05:27 UTC (rev 121392)
@@ -4,6 +4,7 @@
 
 
 PASS select.options.length is 0
+PASS select.selectedOptions.length is 0
 PASS select.options.length is 1
 PASS document.images.length is 0
 PASS document.images.length is 1

Modified: trunk/LayoutTests/fast/dom/htmlcollection-non-html.html (121391 => 121392)


--- trunk/LayoutTests/fast/dom/htmlcollection-non-html.html	2012-06-28 00:49:55 UTC (rev 121391)
+++ trunk/LayoutTests/fast/dom/htmlcollection-non-html.html	2012-06-28 01:05:27 UTC (rev 121392)
@@ -67,6 +67,7 @@
   elem = document.createElementNS(ns, "option");
   select.appendChild(elem);
   shouldBe("select.options.length", "0");
+  shouldBe("select.selectedOptions.length", "0");
 
   elem = document.createElement("option");
   select.appendChild(elem);

Modified: trunk/Source/WebCore/ChangeLog (121391 => 121392)


--- trunk/Source/WebCore/ChangeLog	2012-06-28 00:49:55 UTC (rev 121391)
+++ trunk/Source/WebCore/ChangeLog	2012-06-28 01:05:27 UTC (rev 121392)
@@ -1,3 +1,41 @@
+2012-06-27  Alexis Menard  <alexis.men...@openbossa.org>
+
+        Implement selectedOptions attribute of HTMLSelectElement.
+        https://bugs.webkit.org/show_bug.cgi?id=80631
+
+        Reviewed by Ryosuke Niwa.
+
+        Add a new collection as a member of HTMLSelectElement which is
+        used to store the selected elements. Extend HTMLCollection to
+        support the new collection type needed by this feature. Make sure
+        that we invalidate the collection when the select state of an
+        option changes as the select state change does not trigger a dom
+        tree version change.
+
+        Reference : http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#dom-select-selectedoptions
+
+        Test: fast/dom/HTMLSelectElement/select-selectedOptions.html
+
+        * html/CollectionType.h:
+        * html/HTMLCollection.cpp:
+        (WebCore::shouldIncludeChildren):
+        (WebCore::HTMLCollection::clearCache):
+        (WebCore):
+        (WebCore::HTMLCollection::isAcceptableElement):
+        * html/HTMLCollection.h:
+        (HTMLCollection):
+        * html/HTMLOptionElement.cpp:
+        (WebCore::HTMLOptionElement::setSelectedState):
+        * html/HTMLSelectElement.cpp:
+        (WebCore::HTMLSelectElement::selectedOptions):
+        (WebCore):
+        (WebCore::HTMLSelectElement::invalidateSelectedItems):
+        (WebCore::HTMLSelectElement::setRecalcListItems):
+        * html/HTMLSelectElement.h:
+        (WebCore):
+        (HTMLSelectElement):
+        * html/HTMLSelectElement.idl:
+
 2012-06-27  Daniel Cheng  <dch...@chromium.org>
 
         Fix crash in Frame::nodeImage.

Modified: trunk/Source/WebCore/html/CollectionType.h (121391 => 121392)


--- trunk/Source/WebCore/html/CollectionType.h	2012-06-28 00:49:55 UTC (rev 121391)
+++ trunk/Source/WebCore/html/CollectionType.h	2012-06-28 01:05:27 UTC (rev 121392)
@@ -51,6 +51,7 @@
     TSectionRows, // all row elements in this table section
     TRCells,      // all cells in this row
     SelectOptions,
+    SelectedOptions,
     DataListOptions,
     MapAreas,
 

Modified: trunk/Source/WebCore/html/HTMLCollection.cpp (121391 => 121392)


--- trunk/Source/WebCore/html/HTMLCollection.cpp	2012-06-28 00:49:55 UTC (rev 121391)
+++ trunk/Source/WebCore/html/HTMLCollection.cpp	2012-06-28 01:05:27 UTC (rev 121392)
@@ -52,6 +52,7 @@
     case MapAreas:
     case OtherCollection:
     case SelectOptions:
+    case SelectedOptions:
     case DataListOptions:
     case WindowNamedItems:
 #if ENABLE(MICRODATA)
@@ -98,6 +99,11 @@
     m_cache.version = docversion;
 }
 
+void HTMLCollection::clearCache()
+{
+    m_cache.clear();
+}
+
 inline bool HTMLCollection::isAcceptableElement(Element* element) const
 {
     if (!element->isHTMLElement() && !(m_type == DocAll || m_type == NodeChildren))
@@ -118,6 +124,8 @@
         return element->hasLocalName(trTag);
     case SelectOptions:
         return element->hasLocalName(optionTag);
+    case SelectedOptions:
+        return element->hasLocalName(optionTag) && toHTMLOptionElement(element)->selected();
     case DataListOptions:
         if (element->hasLocalName(optionTag)) {
             HTMLOptionElement* option = static_cast<HTMLOptionElement*>(element);

Modified: trunk/Source/WebCore/html/HTMLCollection.h (121391 => 121392)


--- trunk/Source/WebCore/html/HTMLCollection.h	2012-06-28 00:49:55 UTC (rev 121391)
+++ trunk/Source/WebCore/html/HTMLCollection.h	2012-06-28 01:05:27 UTC (rev 121392)
@@ -67,11 +67,11 @@
     Node* base() const { return m_base; }
     CollectionType type() const { return static_cast<CollectionType>(m_type); }
 
+    void clearCache();
+    void invalidateCacheIfNeeded() const;
 protected:
     HTMLCollection(Node* base, CollectionType);
 
-    void invalidateCacheIfNeeded() const;
-
     virtual void updateNameCache() const;
     virtual Element* itemAfter(Element*) const;
 

Modified: trunk/Source/WebCore/html/HTMLOptionElement.cpp (121391 => 121392)


--- trunk/Source/WebCore/html/HTMLOptionElement.cpp	2012-06-28 00:49:55 UTC (rev 121391)
+++ trunk/Source/WebCore/html/HTMLOptionElement.cpp	2012-06-28 01:05:27 UTC (rev 121392)
@@ -245,6 +245,9 @@
 
     m_isSelected = selected;
     setNeedsStyleRecalc();
+
+    if (HTMLSelectElement* select = ownerSelectElement())
+        select->invalidateSelectedItems();
 }
 
 void HTMLOptionElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)

Modified: trunk/Source/WebCore/html/HTMLSelectElement.cpp (121391 => 121392)


--- trunk/Source/WebCore/html/HTMLSelectElement.cpp	2012-06-28 00:49:55 UTC (rev 121391)
+++ trunk/Source/WebCore/html/HTMLSelectElement.cpp	2012-06-28 01:05:27 UTC (rev 121392)
@@ -350,6 +350,13 @@
     return childContext.isOnUpperEncapsulationBoundary() && HTMLFormControlElementWithState::childShouldCreateRenderer(childContext);
 }
 
+HTMLCollection* HTMLSelectElement::selectedOptions()
+{
+    if (!m_selectedOptionsCollection)
+        m_selectedOptionsCollection = HTMLCollection::create(this, SelectedOptions);
+    return m_selectedOptionsCollection.get();
+}
+
 HTMLOptionsCollection* HTMLSelectElement::options()
 {
     if (!m_optionsCollection)
@@ -700,6 +707,12 @@
     return m_listItems;
 }
 
+void HTMLSelectElement::invalidateSelectedItems()
+{
+    if (m_selectedOptionsCollection)
+        m_selectedOptionsCollection->clearCache();
+}
+
 void HTMLSelectElement::setRecalcListItems()
 {
     m_shouldRecalcListItems = true;
@@ -709,6 +722,8 @@
     setNeedsStyleRecalc();
     if (!inDocument() && m_optionsCollection)
         m_optionsCollection->invalidateCacheIfNeeded();
+    if (!inDocument() && m_selectedOptionsCollection)
+        m_selectedOptionsCollection->invalidateCacheIfNeeded();
 }
 
 void HTMLSelectElement::recalcListItems(bool updateSelectedStates) const

Modified: trunk/Source/WebCore/html/HTMLSelectElement.h (121391 => 121392)


--- trunk/Source/WebCore/html/HTMLSelectElement.h	2012-06-28 00:49:55 UTC (rev 121391)
+++ trunk/Source/WebCore/html/HTMLSelectElement.h	2012-06-28 01:05:27 UTC (rev 121392)
@@ -34,7 +34,6 @@
 namespace WebCore {
 
 class HTMLOptionElement;
-class HTMLOptionsCollection;
 
 class HTMLSelectElement : public HTMLFormControlElementWithState {
 public:
@@ -64,10 +63,12 @@
     void setValue(const String&);
 
     HTMLOptionsCollection* options();
+    HTMLCollection* selectedOptions();
 
     void optionElementChildrenChanged();
 
     void setRecalcListItems();
+    void invalidateSelectedItems();
     void updateListItemSelectedStates();
 
     const Vector<HTMLElement*>& listItems() const;
@@ -180,6 +181,7 @@
     virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
 
     OwnPtr<HTMLOptionsCollection> m_optionsCollection;
+    OwnPtr<HTMLCollection> m_selectedOptionsCollection;
 
     // m_listItems contains HTMLOptionElement, HTMLOptGroupElement, and HTMLHRElement objects.
     mutable Vector<HTMLElement*> m_listItems;

Modified: trunk/Source/WebCore/html/HTMLSelectElement.idl (121391 => 121392)


--- trunk/Source/WebCore/html/HTMLSelectElement.idl	2012-06-28 00:49:55 UTC (rev 121391)
+++ trunk/Source/WebCore/html/HTMLSelectElement.idl	2012-06-28 01:05:27 UTC (rev 121392)
@@ -53,6 +53,7 @@
 #else
         void remove(in long index);
 #endif
+        readonly attribute HTMLCollection selectedOptions;
         attribute long selectedIndex;
         attribute [TreatNullAs=NullString] DOMString value;
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to