bug 761901 - HTML5 progress accessible should fire value change event r=tbsaunde
authorJames Kitchener <jkitch.bug@gmail.com>
Mon, 15 Oct 2012 23:05:20 -0400
changeset 110502 ef03cd944ba8930ce7bb781016f7371f062a6fa1
parent 110501 9fd563bfcf501899da930cf750546711ecf202f8
child 110503 2297babdb84d22a4ae731d3592658350a1c0794d
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewerstbsaunde
bugs761901
milestone19.0a1
bug 761901 - HTML5 progress accessible should fire value change event r=tbsaunde
accessible/src/generic/Accessible.h
accessible/src/generic/DocAccessible.cpp
accessible/src/generic/FormControlAccessible.h
accessible/src/generic/RootAccessible.cpp
accessible/tests/mochitest/events/test_valuechange.html
--- a/accessible/src/generic/Accessible.h
+++ b/accessible/src/generic/Accessible.h
@@ -500,16 +500,18 @@ public:
   inline bool IsXULDeck() const { return mFlags & eXULDeckAccessible; }
 
   inline bool IsListControl() const { return mFlags & eListControlAccessible; }
 
   inline bool IsMenuButton() const { return mFlags & eMenuButtonAccessible; }
 
   inline bool IsMenuPopup() const { return mFlags & eMenuPopupAccessible; }
 
+  inline bool IsProgress() const { return mFlags & eProgressAccessible; }
+
   inline bool IsRoot() const { return mFlags & eRootAccessible; }
   mozilla::a11y::RootAccessible* AsRoot();
 
   virtual mozilla::a11y::TableAccessible* AsTable() { return nullptr; }
 
   virtual mozilla::a11y::TableCellAccessible* AsTableCell() { return nullptr; }
 
   inline bool IsTextLeaf() const { return mFlags & eTextLeafAccessible; }
@@ -771,20 +773,21 @@ protected:
     eHyperTextAccessible = 1 << 12,
     eHTMLFileInputAccessible = 1 << 13,
     eHTMLListItemAccessible = 1 << 14,
     eImageAccessible = 1 << 15,
     eImageMapAccessible = 1 << 16,
     eListControlAccessible = 1 << 17,
     eMenuButtonAccessible = 1 << 18,
     eMenuPopupAccessible = 1 << 19,
-    eRootAccessible = 1 << 20,
-    eTextLeafAccessible = 1 << 21,
-    eXULDeckAccessible = 1 << 22,
-    eXULTreeAccessible = 1 << 23
+    eProgressAccessible = 1 << 20,
+    eRootAccessible = 1 << 21,
+    eTextLeafAccessible = 1 << 22,
+    eXULDeckAccessible = 1 << 23,
+    eXULTreeAccessible = 1 << 24
   };
 
   //////////////////////////////////////////////////////////////////////////////
   // Miscellaneous helpers
 
   /**
    * Return ARIA role (helper method).
    */
--- a/accessible/src/generic/DocAccessible.cpp
+++ b/accessible/src/generic/DocAccessible.cpp
@@ -1117,16 +1117,24 @@ DocAccessible::AttributeChangedImpl(nsIC
   }
 
   if (aAttribute == nsGkAtoms::contenteditable) {
     nsRefPtr<AccEvent> editableChangeEvent =
       new AccStateChangeEvent(aContent, states::EDITABLE);
     FireDelayedAccessibleEvent(editableChangeEvent);
     return;
   }
+
+  if (aAttribute == nsGkAtoms::value) {
+    Accessible* accessible = GetAccessible(aContent);
+    if(accessible->IsProgress()) {
+      FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
+                                 aContent);
+    }
+  }
 }
 
 // DocAccessible protected member
 void
 DocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
 {
   // Note: For universal/global ARIA states and properties we don't care if
   // there is an ARIA role present or not.
--- a/accessible/src/generic/FormControlAccessible.h
+++ b/accessible/src/generic/FormControlAccessible.h
@@ -16,17 +16,17 @@ namespace a11y {
   */
 template<int Max>
 class ProgressMeterAccessible : public LeafAccessible
 {
 public:
   ProgressMeterAccessible(nsIContent* aContent, DocAccessible* aDoc) :
     LeafAccessible(aContent, aDoc)
   {
-    mFlags = mFlags | eHasNumericValue;
+    mFlags |= eHasNumericValue | eProgressAccessible;
   }
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIACCESSIBLEVALUE
 
   // Accessible
   virtual void Value(nsString& aValue);
   virtual mozilla::a11y::role NativeRole();
--- a/accessible/src/generic/RootAccessible.cpp
+++ b/accessible/src/generic/RootAccessible.cpp
@@ -470,19 +470,23 @@ RootAccessible::ProcessDOMEvent(nsIDOMEv
 
     FocusMgr()->ActiveItemChanged(nullptr);
 #ifdef A11Y_LOG
     if (logging::IsEnabled(logging::eFocus))
       logging::ActiveItemChangeCausedBy("DOMMenuBarInactive", accessible);
 #endif
   }
   else if (eventType.EqualsLiteral("ValueChange")) {
-    targetDocument->
-      FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
-                                 targetNode, AccEvent::eRemoveDupes);
+
+    //We don't process 'ValueChange' events for progress meters since we listen
+    //@value attribute change for them.
+    if (!accessible->IsProgress())
+      targetDocument->
+        FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
+                                   targetNode);
   }
 #ifdef DEBUG_DRAGDROPSTART
   else if (eventType.EqualsLiteral("mouseover")) {
     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_DRAGDROP_START,
                             accessible);
   }
 #endif
 }
--- a/accessible/tests/mochitest/events/test_valuechange.html
+++ b/accessible/tests/mochitest/events/test_valuechange.html
@@ -21,86 +21,106 @@
 
 
     /**
      * Do tests.
      */
     var gQueue = null;
 
     // Value change invoker
-    function changeValue(aNodeOrID, aValuenow, aValuetext)
+    function changeARIAValue(aNodeOrID, aValuenow, aValuetext)
     {
       this.DOMNode = getNode(aNodeOrID);
 
-      this.invoke = function changeValue_invoke() {
+      this.invoke = function changeARIAValue_invoke() {
 
         // Note: this should not fire an EVENT_VALUE_CHANGE when aria-valuetext
         // is not empty
         if (aValuenow != undefined)
           this.DOMNode.setAttribute("aria-valuenow", aValuenow);
  
         // Note: this should always fire an EVENT_VALUE_CHANGE
         if (aValuetext != undefined)
           this.DOMNode.setAttribute("aria-valuetext", aValuetext);
       }
 
-      this.check = function changeValue_check() {
+      this.check = function changeARIAValue_check() {
         var acc = getAccessible(aNodeOrID, [nsIAccessibleValue]);
         if (!acc)
           return;
 
         // Note: always test against valuetext first because the existence of 
         // aria-valuetext takes precedence over aria-valuenow in gecko.
         is(acc.value, (aValuetext != undefined)? aValuetext : aValuenow,
             "Wrong value of " + prettyName(aNodeOrID));
       }
 
-      this.getID = function changeValue_getID() {
+      this.getID = function changeARIAValue_getID() {
         return prettyName(aNodeOrID) + " value changed";
       }
     }
 
-    function changeInputValue(aID, aValue)
+    function changeValue(aID, aValue)
     {
       this.DOMNode = getNode(aID);
 
-      this.invoke = function changeInputValue_invoke()
+      this.invoke = function changeValue_invoke()
       {
         this.DOMNode.value = aValue;
       }
 
-      this.check = function changeInputValue_check()
+      this.check = function changeValue_check()
       {
         var acc = getAccessible(this.DOMNode);
         is(acc.value, aValue, "Wrong value for " + prettyName(aID));
       }
 
-      this.getID = function changeInputValue_getID()
+      this.getID = function changeValue_getID()
       {
         return prettyName(aID) + " value changed";
       }
     }
 
+    function changeProcessValue(aID, aValue) {
+        this.DOMNode = getNode(aID);
+
+        this.invoke = function changeProcessValue_invoke() {
+            this.DOMNode.value = aValue;
+        }
+
+        this.check = function changeProcessValue_check() {
+            var acc = getAccessible(this.DOMNode);
+            is(acc.value, aValue+"%", "Wrong value for " + prettyName(aID));
+        }
+
+        this.getID = function changeProcessValue_getID() {
+            return prettyName(aID) + " value changed";
+        }
+    }
+
     function doTests()
     {
       // Test initial values
       testValue("slider_vn", "5", 5, 0, 1000, 0);
       testValue("slider_vnvt", "plain", 0, 0, 5, 0);
       testValue("slider_vt", "hi", 0, 0, 3, 0);
       testValue("scrollbar", "5", 5, 0, 1000, 0);
+      testValue("progress", "22%", 22, 0, 100, 0);
 
       // Test value change events
       gQueue = new eventQueue(nsIAccessibleEvent.EVENT_VALUE_CHANGE);
 
-      gQueue.push(new changeValue("slider_vn", "6", undefined));
-      gQueue.push(new changeValue("slider_vt", undefined, "hey!"));
-      gQueue.push(new changeValue("slider_vnvt", "3", "sweet"));
-      gQueue.push(new changeValue("scrollbar", "6", undefined));
+      gQueue.push(new changeARIAValue("slider_vn", "6", undefined));
+      gQueue.push(new changeARIAValue("slider_vt", undefined, "hey!"));
+      gQueue.push(new changeARIAValue("slider_vnvt", "3", "sweet"));
+      gQueue.push(new changeARIAValue("scrollbar", "6", undefined));
 
-      gQueue.push(new changeInputValue("combobox", "hello"));
+      gQueue.push(new changeValue("combobox", "hello"));
+
+      gQueue.push(new changeProcessValue("progress", "50"));
 
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
   </script>
 </head>
@@ -117,16 +137,22 @@
     title="We dont expose new aria role 'scrollbar' and property aria-orientation">
    Mozilla Bug 529289
   </a>
   <a target="_blank"
     href="https://bugzilla.mozilla.org/show_bug.cgi?id=703202"
     title="ARIA comboboxes don't fire value change events">
    Mozilla Bug 703202
   </a>
+  <a target="_blank"
+    href="https://bugzilla.mozilla.org/show_bug.cgi?id=761901"
+    title=" HTML5 progress accessible should fire value change event">
+   Mozilla Bug 761901
+  </a>
+
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
   <div id="eventdump"></div>
 
   <!-- ARIA sliders -->
@@ -140,10 +166,14 @@
        aria-valuemin="0" aria-valuemax="5">sweetness slider</div>
 
   <!-- ARIA scrollbar -->
   <div id="scrollbar" role="scrollbar" aria-valuenow="5"
        aria-valuemin="0" aria-valuemax="1000">slider</div>
 
   <!-- ARIA combobox -->
   <input id="combobox" role="combobox" aria-autocomplete="inline">
+
+  <!-- progress bar -->
+  <progress id="progress" value="22" max="100"></progress>
+
 </body>
 </html>