DLynch has uploaded a new change for review.
https://gerrit.wikimedia.org/r/282964
Change subject: ve.ui.TabbableElements: JS replacement for unreliable tabIndex
......................................................................
ve.ui.TabbableElements: JS replacement for unreliable tabIndex
Pull this behavior out of the FindAndReplaceDialog so it can be reused
elsewhere.
Change-Id: Ifd477bad499785f49f05a6c6d4f4ae956b1d8b8a
---
M .jsduck/categories.json
M build/modules.json
M demos/ve/desktop.html
M demos/ve/mobile.html
M src/ui/dialogs/ve.ui.FindAndReplaceDialog.js
A src/ui/ve.ui.TabbableElements.js
M tests/index.html
7 files changed, 114 insertions(+), 27 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/VisualEditor/VisualEditor
refs/changes/64/282964/1
diff --git a/.jsduck/categories.json b/.jsduck/categories.json
index 9400a67..ba74e16 100644
--- a/.jsduck/categories.json
+++ b/.jsduck/categories.json
@@ -149,7 +149,8 @@
"ve.ui.Overlay",
"ve.ui.*Toolbar",
"ve.ui.DebugBar",
- "ve.ui.Trigger"
+ "ve.ui.Trigger",
+ "ve.ui.TabbableElements"
]
},
{
diff --git a/build/modules.json b/build/modules.json
index 602b779..40f7b85 100644
--- a/build/modules.json
+++ b/build/modules.json
@@ -446,6 +446,7 @@
"src/ui/ve.ui.DataTransferItem.js",
"src/ui/ve.ui.WindowManager.js",
"src/ui/ve.ui.NodeWindow.js",
+ "src/ui/ve.ui.TabbableElements.js",
"src/ui/windowmanagers/ve.ui.SurfaceWindowManager.js",
"src/ui/actions/ve.ui.AnnotationAction.js",
"src/ui/actions/ve.ui.ContentAction.js",
diff --git a/demos/ve/desktop.html b/demos/ve/desktop.html
index f4eed5a..a40be38 100644
--- a/demos/ve/desktop.html
+++ b/demos/ve/desktop.html
@@ -405,6 +405,7 @@
<script src="../../src/ui/ve.ui.DataTransferItem.js"></script>
<script src="../../src/ui/ve.ui.WindowManager.js"></script>
<script src="../../src/ui/ve.ui.NodeWindow.js"></script>
+ <script src="../../src/ui/ve.ui.TabbableElements.js"></script>
<script
src="../../src/ui/windowmanagers/ve.ui.SurfaceWindowManager.js"></script>
<script
src="../../src/ui/actions/ve.ui.AnnotationAction.js"></script>
<script
src="../../src/ui/actions/ve.ui.ContentAction.js"></script>
diff --git a/demos/ve/mobile.html b/demos/ve/mobile.html
index b7b6f9b..b100434 100644
--- a/demos/ve/mobile.html
+++ b/demos/ve/mobile.html
@@ -406,6 +406,7 @@
<script src="../../src/ui/ve.ui.DataTransferItem.js"></script>
<script src="../../src/ui/ve.ui.WindowManager.js"></script>
<script src="../../src/ui/ve.ui.NodeWindow.js"></script>
+ <script src="../../src/ui/ve.ui.TabbableElements.js"></script>
<script
src="../../src/ui/windowmanagers/ve.ui.SurfaceWindowManager.js"></script>
<script
src="../../src/ui/actions/ve.ui.AnnotationAction.js"></script>
<script
src="../../src/ui/actions/ve.ui.ContentAction.js"></script>
diff --git a/src/ui/dialogs/ve.ui.FindAndReplaceDialog.js
b/src/ui/dialogs/ve.ui.FindAndReplaceDialog.js
index 26e40ca..d2a88ba 100644
--- a/src/ui/dialogs/ve.ui.FindAndReplaceDialog.js
+++ b/src/ui/dialogs/ve.ui.FindAndReplaceDialog.js
@@ -156,8 +156,10 @@
this.replaceAllButton.connect( this, { click: 'onReplaceAllButtonClick'
} );
doneButton.connect( this, { click: 'close' } );
- this.findText.$input.on( 'keydown', this.onFindTextKeyDown.bind( this )
);
- this.replaceText.$input.on( 'keydown', this.onReplaceTextKeyDown.bind(
this ) );
+ this.tabbableElements = new ve.ui.TabbableElements( {
+ elements: [ this.findText.$input[ 0 ], this.replaceText.$input[
0 ] ],
+ loop: false
+ } );
// Initialization
this.$content.addClass( 've-ui-findAndReplaceDialog-content' );
@@ -313,30 +315,6 @@
this.findPrevious();
} else {
this.findNext();
- }
-};
-
-/**
- * Handle keydown events on the find text input
- *
- * @param {jQuery.Event} e
- */
-ve.ui.FindAndReplaceDialog.prototype.onFindTextKeyDown = function ( e ) {
- if ( e.which === OO.ui.Keys.TAB && !e.shiftKey ) {
- this.replaceText.$input.focus();
- e.preventDefault();
- }
-};
-
-/**
- * Handle keydown events on the replace text input
- *
- * @param {jQuery.Event} e
- */
-ve.ui.FindAndReplaceDialog.prototype.onReplaceTextKeyDown = function ( e ) {
- if ( e.which === OO.ui.Keys.TAB && e.shiftKey ) {
- this.findText.$input.focus();
- e.preventDefault();
}
};
diff --git a/src/ui/ve.ui.TabbableElements.js b/src/ui/ve.ui.TabbableElements.js
new file mode 100644
index 0000000..5f36243
--- /dev/null
+++ b/src/ui/ve.ui.TabbableElements.js
@@ -0,0 +1,104 @@
+/*!
+ * VisualEditor TabbableElements class.
+ *
+ * @copyright 2011-2016 VisualEditor Team and others; see
http://ve.mit-license.org
+ */
+
+/**
+ * Tabbable Elements mixin constructor
+ *
+ * @class
+ * @constructor
+ *
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [loop=true] Whether to loop between the start / end of the
element set
+ * @cfg {boolean} [trap=false] Whether to allow the focus to leave off the
start / end of the element set
+ * @cfg {Array} [elements] Initial set of elements to apply behavior to
+ */
+ve.ui.TabbableElements = function VeUiTabbableElements( config ) {
+ config = $.extend( { loop: true, trap: false }, config );
+
+ this.shouldLoop = config.loop;
+ this.shouldTrap = config.trap;
+
+ if ( config.elements ) {
+ this.setElements( config.elements );
+ }
+
+ this.onElementKeyDownBound = this.onElementKeyDown.bind( this );
+};
+
+/* Setup */
+
+OO.initClass( ve.ui.TabbableElements );
+
+/* Methods */
+
+/**
+ * Set the elements to be tabbed between
+ *
+ * @param {HTMLElement[]} elements list of elements in the order they should
be tabbed through
+ */
+ve.ui.TabbableElements.prototype.setElements = function ( elements ) {
+ $( this.elements ).off( 'keydown', this.onElementKeyDownBound );
+
+ this.elements = elements;
+
+ $( elements ).on( 'keydown', this.onElementKeyDownBound );
+};
+
+/**
+ * Add an element to the tabbable set
+ *
+ * @param {HTMLElement} element
+ * @param {number} index
+ */
+ve.ui.TabbableElements.prototype.addElement = function ( element, index ) {
+ this.setElements( this.elements.slice().splice( index, 0, element ) );
+};
+
+/**
+ * Remove an element from the tabbable set
+ *
+ * @param {HTMLElement} element
+ */
+ve.ui.TabbableElements.prototype.removeElement = function ( element ) {
+ this.setElements( this.elements.slice().splice( this.elements.indexOf(
element ), 1 ) );
+};
+
+/**
+ * Handle keydown events on elements
+ *
+ * @param {jQuery.Event} e
+ */
+ve.ui.TabbableElements.prototype.onElementKeyDown = function ( e ) {
+ var index = this.elements.indexOf( e.currentTarget );
+
+ if ( e.which !== OO.ui.Keys.TAB ) {
+ return;
+ }
+
+ if ( index === -1 ) {
+ return;
+ }
+
+ index += e.shiftKey ? -1 : 1;
+
+ if ( ( index < 0 || index >= this.elements.length ) ) {
+ if ( this.shouldLoop ) {
+ if ( index < 0 ) {
+ index = this.elements.length;
+ } else {
+ index = 0;
+ }
+ } else if ( this.shouldTrap ) {
+ e.preventDefault();
+ return;
+ } else {
+ return;
+ }
+ }
+
+ e.preventDefault();
+ this.elements[ index ].focus();
+};
diff --git a/tests/index.html b/tests/index.html
index 2ccfd40..00a8592 100644
--- a/tests/index.html
+++ b/tests/index.html
@@ -330,6 +330,7 @@
<script src="../src/ui/ve.ui.DataTransferItem.js"></script>
<script src="../src/ui/ve.ui.WindowManager.js"></script>
<script src="../src/ui/ve.ui.NodeWindow.js"></script>
+ <script src="../src/ui/ve.ui.TabbableElements.js"></script>
<script
src="../src/ui/windowmanagers/ve.ui.SurfaceWindowManager.js"></script>
<script
src="../src/ui/actions/ve.ui.AnnotationAction.js"></script>
<script src="../src/ui/actions/ve.ui.ContentAction.js"></script>
--
To view, visit https://gerrit.wikimedia.org/r/282964
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ifd477bad499785f49f05a6c6d4f4ae956b1d8b8a
Gerrit-PatchSet: 1
Gerrit-Project: VisualEditor/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: DLynch <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits