r1698 - in branches/experimental/tabbable: . tests

r1698 - in branches/experimental/tabbable: . tests


Author: scott.gonzalez
Date: Mon Jan 19 17:48:08 2009
New Revision: 1698
Modified:
branches/experimental/tabbable/tests/core.html
branches/experimental/tabbable/tests/core.js
branches/experimental/tabbable/ui.core.js
Log:
Tabbable: New tests for :focusable selector.
Modified: branches/experimental/tabbable/tests/core.html
==============================================================================
--- branches/experimental/tabbable/tests/core.html    (original)
+++ branches/experimental/tabbable/tests/core.html    Mon Jan 19 17:48:08 2009
@@ -24,71 +24,80 @@
<ol id="tests"></ol>
<div id="main" style="position: absolute; top: -10000px; border: 1px solid
black; padding: 10px; margin: 10px;">
-    <div id="wrap1">
-        <input id="input1-1" />
-        <input type="text" id="input1-2" />
-        <input type="checkbox" id="input1-3" />
-        <input type="radio" id="input1-4" />
-        <input type="button" id="input1-5" />
-        <input type="hidden" id="input1-6" />
-        <select id="input1-7"></select>
-        <textarea id="input1-8"></textarea>
-        <a href="#" id="anchor1-1">anchor</a>
-        <a id="anchor1-2">anchor</a>
-        <span id="span1-1"></span>
-        <div id="div1-1"></div>
+    <div>
+        <input id="visibleAncestor-inputTypeNone" />
+        <input type="text" id="visibleAncestor-inputTypeText" />
+        <input type="checkbox" id="visibleAncestor-inputTypeCheckbox" />
+        <input type="radio" id="visibleAncestor-inputTypeRadio" />
+        <input type="button" id="visibleAncestor-inputTypeButton" />
+        <input type="hidden" id="visibleAncestor-inputTypeHidden" />
+        <button id="visibleAncestor-button"></button>
+        <select id="visibleAncestor-select">
+            <option>option</option>
+        </select>
+        <textarea id="visibleAncestor-textarea"></textarea>
+        <object id="visibleAncestor-object"></object>
+        <a href="#" id="visibleAncestor-anchorWithHref">anchor</a>
+        <a id="visibleAncestor-anchorWithoutHref">anchor</a>
+        <map>
+            <area href="#" id="visibleAncestor-areaWithHref" alt="" />
+            <area id="visibleAncestor-areaWithoutHref" alt="" />
+        </map>
+        <span id="visibleAncestor-span"></span>
+        <div id="visibleAncestor-div"></div>
+        <span id="visibleAncestor-spanWithTabindex" tabindex="1"></span>
+        <div id="visibleAncestor-divWithTabindex" tabindex="-1"></div>
    </div>
-    <div id="wrap2">
-        <input id="input2-1" disabled="disabled" />
-        <input type="text" id="input2-2" disabled="disabled" />
-        <input type="checkbox" id="input2-3" disabled="disabled" />
-        <input type="radio" id="input2-4" disabled="disabled" />
-        <input type="button" id="input2-5" disabled="disabled" />
-        <input type="hidden" id="input2-6" disabled="disabled" />
-        <select id="input2-7" disabled="disabled"></select>
-        <textarea id="input2-8" disabled="disabled"></textarea>
+    
+    <div>
+        <input id="disabledElement-inputTypeNone" disabled="disabled" />
+        <input type="text" id="disabledElement-inputTypeText"
disabled="disabled" />
+        <input type="checkbox" id="disabledElement-inputTypeCheckbox"
disabled="disabled" />
+        <input type="radio" id="disabledElement-inputTypeRadio"
disabled="disabled" />
+        <input type="button" id="disabledElement-inputTypeButton"
disabled="disabled" />
+        <input type="hidden" id="disabledElement-inputTypeHidden"
disabled="disabled" />
+        <button id="disabledElement-button" disabled="disabled"></button>
+        <select id="disabledElement-select" disabled="disabled"></select>
+        <textarea id="disabledElement-textarea" disabled="disabled"></textarea>
    </div>
-    <div id="wrap3">
-        <div id="wrap3-1" style="display: none;">
-            <input id="input3-1" />
-            <a href="#" id="anchor3-1">anchor</a>
+    
+    <div>
+        <div id="displayNoneAncestor" style="display: none;">
+            <input id="displayNoneAncestor-input" />
+            <span tabindex="1" id="displayNoneAncestor-span"></span>
        </div>
-        <div id="wrap3-2" style="visibility: hidden;">
-            <input id="input3-2" />
-            <a href="#" id="anchor3-2">anchor</a>
+        
+        <div id="visibilityHiddenAncestor" style="visibility: hidden;">
+            <input id="visibilityHiddenAncestor-input" />
+            <span tabindex="1" id="visibilityHiddenAncestor-span"></span>
        </div>
-        <input id="input3-3" style="display: none;">
-        <input id="input3-4" style="visibility: hidden;">
-    </div>
-    <div id="wrap4">
-        <input id="input4-1" tabindex="0" />
-        <input id="input4-2" tabindex="10" />
-        <input id="input4-3" tabindex="-1" />
-        <input id="input4-4" tabindex="-50" />
+        
+        <input id="displayNone-input" style="display: none;" />
+        <input id="visibilityHidden-input" style="visibility: hidden;" />
+        
+        <span tabindex="1" id="displayNone-span" style="display: none;"></span>
+        <span tabindex="1" id="visibilityHidden-span" style="visibility:
hidden;" />
    </div>
    
-    <div id="wrap4">
-        <input id="input4-1" tabindex="0" />
-        <input id="input4-2" tabindex="10" />
-        <input id="input4-3" tabindex="-1" />
-        <input id="input4-4" tabindex="-50" />
+    <div>
+        <input id="inputTabindex0" tabindex="0" />
+        <input id="inputTabindex10" tabindex="10" />
+        <input id="inputTabindex-1" tabindex="-1" />
+        <input id="inputTabindex-50" tabindex="-50" />
+        
+        <span id="spanTabindex0" tabindex="0"></span>
+        <span id="spanTabindex10" tabindex="10"></span>
+        <span id="spanTabindex-1" tabindex="-1"></span>
+        <span id="spanTabindex-50" tabindex="-50"></span>
    </div>
    
-    <div id="wrap5">
-        <div id="div5-1" tabindex="0"></div>
-        <div id="div5-2" tabindex="10"></div>
-        <div id="div5-3" tabindex="-1"></div>
-        <div id="div5-4" tabindex="-50"></div>
-        <div id="div5-5" tabindex="10" style="display: none;" /></div>
+    <div>
+        <input id="inputTabindexfoo" tabindex="foo" />
+        <input id="inputTabindex3foo" tabindex="3foo" />
+        
+        <span id="spanTabindexfoo" tabindex="foo"></span>
+        <span id="spanTabindex3foo" tabindex="3foo"></div>
    </div>
-    
-    <div id="wrap6">
-        <div id="div6-1"></div>
-        <div id="div6-2" tabindex="foo"></div>
-        <div id="div6-3" tabindex="3foo"></div>
-        <a href="#" id="anchor6-4" tabindex="foo">anchor</a>
-    </div>
-    
</div>
</body>
Modified: branches/experimental/tabbable/tests/core.js
==============================================================================
--- branches/experimental/tabbable/tests/core.js    (original)
+++ branches/experimental/tabbable/tests/core.js    Mon Jan 19 17:48:08 2009
@@ -5,6 +5,95 @@
module("selectors");
+function isFocusable(selector, msg) {
+    ok($(selector).is(':focusable'), msg);
+}
+
+function isNotFocusable(selector, msg) {
+    ok($(selector).length && !$(selector).is(':focusable'), msg);
+}
+
+test("focusable - visible, enabled elements", function() {
+    expect(18);
+    
+    isFocusable('#visibleAncestor-inputTypeNone', 'input, no type');
+    isFocusable('#visibleAncestor-inputTypeText', 'input, type text');
+    isFocusable('#visibleAncestor-inputTypeCheckbox', 'input, type checkbox');
+    isFocusable('#visibleAncestor-inputTypeRadio', 'input, type radio');
+    isFocusable('#visibleAncestor-inputTypeButton', 'input, type button');
+    isNotFocusable('#visibleAncestor-inputTypeHidden', 'input, type hidden');
+    isFocusable('#visibleAncestor-button', 'button');
+    isFocusable('#visibleAncestor-select', 'select');
+    isFocusable('#visibleAncestor-textarea', 'textarea');
+    isFocusable('#visibleAncestor-object', 'object');
+    isFocusable('#visibleAncestor-anchorWithHref', 'anchor with href');
+    isNotFocusable('#visibleAncestor-anchorWithoutHref', 'anchor without
href');
+    isFocusable('#visibleAncestor-areaWithHref', 'area with href');
+    isNotFocusable('#visibleAncestor-areaWithoutHref', 'area without href');
+    isNotFocusable('#visibleAncestor-span', 'span');
+    isNotFocusable('#visibleAncestor-div', 'div');
+    isFocusable("#visibleAncestor-spanWithTabindex", 'span with tabindex');
+    isFocusable("#visibleAncestor-divWithTabindex", 'div with tabindex');
+});
+
+test("focusable - disabled elements", function() {
+    expect(9);
+    
+    isNotFocusable('#disabledElement-inputTypeNone', 'input, no type');
+    isNotFocusable('#disabledElement-inputTypeText', 'input, type text');
+    isNotFocusable('#disabledElement-inputTypeCheckbox', 'input, type
checkbox');
+    isNotFocusable('#disabledElement-inputTypeRadio', 'input, type radio');
+    isNotFocusable('#disabledElement-inputTypeButton', 'input, type button');
+    isNotFocusable('#disabledElement-inputTypeHidden', 'input, type hidden');
+    isNotFocusable('#disabledElement-button', 'button');
+    isNotFocusable('#disabledElement-select', 'select');
+    isNotFocusable('#disabledElement-textarea', 'textarea');
+});
+
+test("focusable - hidden styles", function() {
+    expect(8);
+    
+    isNotFocusable('#displayNoneAncestor-input', 'input, display: none
parent');
+    isNotFocusable('#displayNoneAncestor-span', 'span with tabindex, display:
none parent');
+    
+    isNotFocusable('#visibilityHiddenAncestor-input', 'input, visibility:
hidden parent');
+    isNotFocusable('#visibilityHiddenAncestor-span', 'span with tabindex,
visibility: hidden parent');
+    
+    isNotFocusable('#displayNone-input', 'input, display: none');
+    isNotFocusable('#visibilityHidden-input', 'input, visibility: hidden');
+    
+    isNotFocusable('#displayNone-span', 'span with tabindex, display: none');
+    isNotFocusable('#visibilityHidden-span', 'span with tabindex, visibility:
hidden');
+});
+
+test("focusable - natively tabbable with various tabindex", function() {
+    expect(4);
+    
+    isFocusable('#inputTabindex0', 'input, tabindex 0');
+    isFocusable('#inputTabindex10', 'input, tabindex 10');
+    isFocusable('#inputTabindex-1', 'input, tabindex -1');
+    isFocusable('#inputTabindex-50', 'input, tabindex -50');
+});
+
+test("focusable - not natively tabbable with various tabindex",
function() {
+    expect(4);
+    
+    isFocusable('#spanTabindex0', 'span, tabindex 0');
+    isFocusable('#spanTabindex10', 'span, tabindex 10');
+    isFocusable('#spanTabindex-1', 'span, tabindex -1');
+    isFocusable('#spanTabindex-50', 'span, tabindex -50');
+});
+
+test("focusable - invalid tabindex", function() {
+    expect(4);
+    
+    isFocusable('#inputTabindexfoo', 'input, tabindex foo');
+    isFocusable('#inputTabindex3foo', 'input, tabindex 3foo');
+    isNotFocusable('#spanTabindexfoo', 'span tabindex foo');
+    isNotFocusable('#spanTabindex3foo', 'span, tabindex 3foo');
+});
+
+
test("tabbable - enabled elements", function() {
    expect(10);
    
@@ -77,69 +166,6 @@
    //do we have to mess with this?
    ok(!$('#div6-3').is(':tabbable'), 'div, tabindex 3foo');
    ok($('#anchor6-4').is(':tabbable'), 'a, tabindex foo');
-});
-
-//focus
-
-test("focusable - enabled elements", function() {
-    expect(10);
-    ok( $('#input1-1').is(':focusable'), 'input, no type');
-    ok( $('#input1-2').is(':focusable'), 'input, type text');
-    ok( $('#input1-3').is(':focusable'), 'input, type checkbox');
-    ok( $('#input1-4').is(':focusable'), 'input, type radio');
-    ok( $('#input1-5').is(':focusable'), 'input, type button');
-    ok(!$('#input1-6').is(':focusable'), 'input, type hidden');
-    ok( $('#input1-7').is(':focusable'), 'select');
-    ok( $('#input1-8').is(':focusable'), 'textarea');
-    ok( $('#anchor1-1').is(':focusable'), 'anchor with href');
-    ok(!$('#anchor1-2').is(':focusable'), 'anchor without href');
-});
-
-test("focusable - disabled elements", function() {
-    expect(8);
-    ok(!$('#input2-1').is(':focusable'), 'input, no type');
-    ok(!$('#input2-2').is(':focusable'), 'input, type text');
-    ok(!$('#input2-3').is(':focusable'), 'input, type checkbox');
-    ok(!$('#input2-4').is(':focusable'), 'input, type radio');
-    ok(!$('#input2-5').is(':focusable'), 'input, type button');
-    ok(!$('#input2-6').is(':focusable'), 'input, type hidden');
-    ok(!$('#input2-7').is(':focusable'), 'select');
-    ok(!$('#input2-8').is(':focusable'), 'textarea');
-});
-
-test("focusable - hidden styles", function() {
-    expect(6);
-    ok(!$('#input3-1').is(':focusable'), 'input, hidden wrapper - display:
none');
-    ok(!$('#anchor3-1').is(':focusable'), 'anchor, hidden wrapper - display:
none');
-    ok(!$('#input3-2').is(':focusable'), 'input, hidden wrapper - visibility:
hidden');
-    ok(!$('#anchor3-2').is(':focusable'), 'anchor, hidden wrapper -
visibility: hidden');
-    ok(!$('#input3-3').is(':focusable'), 'input, display: none');
-    ok(!$('#input3-4').is(':focusable'), 'input, visibility: hidden');
-});
-
-test("focusable - natively tabbable with various tabindex", function() {
-    expect(4);
-    ok( $('#input4-1').is(':focusable'), 'input, tabindex 0');
-    ok( $('#input4-2').is(':focusable'), 'input, tabindex 10');
-    ok($('#input4-3').is(':focusable'), 'input, tabindex -1');
-    ok($('#input4-4').is(':focusable'), 'input, tabindex -50');
-});
-
-test("focusable - not natively tabbable with tabindex", function() {
-    expect(5);
-    ok( $('#div5-1').is(':focusable'), 'div, tabindex 0');
-    ok( $('#div5-2').is(':focusable'), 'div, tabindex 10');
-    ok($('#div5-3').is(':focusable'), 'div, tabindex -1');
-    ok($('#div5-4').is(':focusable'), 'div, tabindex -50');
-    ok(!$('#div5-5').is(':focusable'), 'div, - display: none tabindex 10');
-});
-
-test("focusable - wrong or without tabindex", function() {
-    expect(4);
-    ok(!$('#div6-1').is(':focusable'), 'div, without tabindex');
-    ok(!$('#div6-2').is(':focusable'), 'div, tabindex foo');
-    ok(!$('#div6-3').is(':focusable'), 'div, tabindex 3foo');
-    ok($('#anchor6-4').is(':focusable'), 'a, tabindex foo');
});
})(jQuery);
Modified: branches/experimental/tabbable/ui.core.js
==============================================================================
--- branches/experimental/tabbable/ui.core.js    (original)
+++ branches/experimental/tabbable/ui.core.js    Mon Jan 19 17:48:08 2009
@@ -9,7 +9,9 @@
            : 'a' == nodeName || 'area' == nodeName
                ? element.href || !isNaN(tabIndex)
                : !isNaN(tabIndex))
-            && !$(element).closest(':hidden').length;
+            // the element and all of its ancestors must be visible
+            // the browser may report that the area is hidden
+            && !$(element)['area' ==
nodeName ? 'parents' : 'closest'](':hidden').length;
    },
    
    tabbable: function(element) {