[orca] Treat (un)ordered HTML lists without list items as if they were divs



commit eada21891337a1657009b268e395f14a569a09db
Author: Joanmarie Diggs <jdiggs igalia com>
Date:   Tue Sep 1 13:04:25 2015 -0400

    Treat (un)ordered HTML lists without list items as if they were divs

 src/orca/scripts/web/braille_generator.py          |    2 +
 src/orca/scripts/web/script_utilities.py           |   22 +++++
 src/orca/scripts/web/speech_generator.py           |    2 +
 test/html/ul-no-li.html                            |    9 ++
 .../firefox/line_nav_lists_without_items.params    |    1 +
 .../firefox/line_nav_lists_without_items.py        |   87 ++++++++++++++++++++
 6 files changed, 123 insertions(+), 0 deletions(-)
---
diff --git a/src/orca/scripts/web/braille_generator.py b/src/orca/scripts/web/braille_generator.py
index 74b176e..ecf4642 100644
--- a/src/orca/scripts/web/braille_generator.py
+++ b/src/orca/scripts/web/braille_generator.py
@@ -122,6 +122,8 @@ class BrailleGenerator(braille_generator.BrailleGenerator):
             oldRole = self._overrideRole(pyatspi.ROLE_LINK, args)
         elif self._script.utilities.isStatic(obj):
             oldRole = self._overrideRole('ROLE_STATIC', args)
+        elif self._script.utilities.treatAsDiv(obj):
+            oldRole = self._overrideRole(pyatspi.ROLE_SECTION, args)
 
         if obj.getRole() == pyatspi.ROLE_MENU_ITEM:
             comboBox = self._script.utilities.ancestorWithRole(
diff --git a/src/orca/scripts/web/script_utilities.py b/src/orca/scripts/web/script_utilities.py
index 9f95b12..0a55e6f 100644
--- a/src/orca/scripts/web/script_utilities.py
+++ b/src/orca/scripts/web/script_utilities.py
@@ -67,6 +67,7 @@ class Utilities(script_utilities.Utilities):
         self._inferredLabels = {}
         self._text = {}
         self._tag = {}
+        self._treatAsDiv = {}
         self._currentObjectContents = None
         self._currentSentenceContents = None
         self._currentLineContents = None
@@ -103,6 +104,7 @@ class Utilities(script_utilities.Utilities):
         self._isUselessImage = {}
         self._inferredLabels = {}
         self._tag = {}
+        self._treatAsDiv = {}
         self._cleanupContexts()
 
     def clearContentCache(self):
@@ -1315,6 +1317,26 @@ class Utilities(script_utilities.Utilities):
         self._isTextBlockElement[hash(obj)] = rv
         return rv
 
+    def treatAsDiv(self, obj):
+        rv = self._treatAsDiv.get(hash(obj))
+        if rv is not None:
+            return rv
+
+        try:
+            role = obj.getRole()
+            childCount = obj.childCount
+        except:
+            msg = "WEB: Exception getting role and childCount for %s" % obj
+            debug.println(debug.LEVEL_INFO, msg)
+            return False
+
+        rv = False
+        if role == pyatspi.ROLE_LIST:
+            rv = not (childCount and obj[0].getRole() == pyatspi.ROLE_LIST_ITEM)
+
+        self._treatAsDiv[hash(obj)] = rv
+        return rv
+
     def speakMathSymbolNames(self, obj=None):
         obj = obj or orca_state.locusOfFocus
         return self.isMath(obj)
diff --git a/src/orca/scripts/web/speech_generator.py b/src/orca/scripts/web/speech_generator.py
index fde769c..6965d42 100644
--- a/src/orca/scripts/web/speech_generator.py
+++ b/src/orca/scripts/web/speech_generator.py
@@ -405,6 +405,8 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
             oldRole = self._overrideRole('default', args)
         elif self._script.utilities.isLink(obj):
             oldRole = self._overrideRole(pyatspi.ROLE_LINK, args)
+        elif self._script.utilities.treatAsDiv(obj):
+            oldRole = self._overrideRole(pyatspi.ROLE_SECTION, args)
         else:
             oldRole = self._overrideRole(self._getAlternativeRole(obj, **args), args)
 
diff --git a/test/html/ul-no-li.html b/test/html/ul-no-li.html
new file mode 100644
index 0000000..3b41431
--- /dev/null
+++ b/test/html/ul-no-li.html
@@ -0,0 +1,9 @@
+<html>
+<body>
+<ul>Line 1</ul>
+<ul><div>Line 2<div></ul>
+<ui>Line <a href="foo">3</a></ul>
+<ul><ul>Line 4</ul></ul>
+<ul><li>Line 5</li></ul>
+</body>
+</html>
diff --git a/test/keystrokes/firefox/line_nav_lists_without_items.params 
b/test/keystrokes/firefox/line_nav_lists_without_items.params
new file mode 100644
index 0000000..eb28780
--- /dev/null
+++ b/test/keystrokes/firefox/line_nav_lists_without_items.params
@@ -0,0 +1 @@
+PARAMS=$TEST_DIR/../../html/ul-no-li.html
diff --git a/test/keystrokes/firefox/line_nav_lists_without_items.py 
b/test/keystrokes/firefox/line_nav_lists_without_items.py
new file mode 100644
index 0000000..1700854
--- /dev/null
+++ b/test/keystrokes/firefox/line_nav_lists_without_items.py
@@ -0,0 +1,87 @@
+#!/usr/bin/python
+
+from macaroon.playback import *
+import utils
+
+sequence = MacroSequence()
+
+# Work around some new quirk in Gecko that causes this test to fail if
+# run via the test harness rather than manually.
+sequence.append(KeyComboAction("<Control>r"))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("<Control>Home"))
+sequence.append(utils.AssertPresentationAction(
+    "1. Top of file",
+    ["BRAILLE LINE:  'Line 1'",
+     "     VISIBLE:  'Line 1', cursor=1",
+     "SPEECH OUTPUT: 'Line 1'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "2. Line Down",
+    ["BRAILLE LINE:  'Line 2'",
+     "     VISIBLE:  'Line 2', cursor=1",
+     "SPEECH OUTPUT: 'Line 2'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "3. Line Down",
+    ["BRAILLE LINE:  'Line 3'",
+     "     VISIBLE:  'Line 3', cursor=1",
+     "SPEECH OUTPUT: 'Line'",
+     "SPEECH OUTPUT: '3 link.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "4. Line Down",
+    ["BRAILLE LINE:  'Line 4'",
+     "     VISIBLE:  'Line 4', cursor=1",
+     "SPEECH OUTPUT: 'Line 4'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "5. Line Down",
+    ["BRAILLE LINE:  '• Line 5'",
+     "     VISIBLE:  '• Line 5', cursor=1",
+     "SPEECH OUTPUT: '• Line 5.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "6. Line Up",
+    ["BRAILLE LINE:  'Line 4'",
+     "     VISIBLE:  'Line 4', cursor=1",
+     "SPEECH OUTPUT: 'Line 4'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "7. Line Up",
+    ["BRAILLE LINE:  'Line 3'",
+     "     VISIBLE:  'Line 3', cursor=1",
+     "SPEECH OUTPUT: 'Line'",
+     "SPEECH OUTPUT: '3 link.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "8. Line Up",
+    ["BRAILLE LINE:  'Line 2'",
+     "     VISIBLE:  'Line 2', cursor=1",
+     "SPEECH OUTPUT: 'Line 2'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "9. Line Up",
+    ["BRAILLE LINE:  'Line 1'",
+     "     VISIBLE:  'Line 1', cursor=1",
+     "SPEECH OUTPUT: 'Line 1'"]))
+
+sequence.append(utils.AssertionSummaryAction())
+sequence.start()


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]