JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.4.2
[ckeditor.git] / _source / plugins / tab / plugin.js
index 55c210a..42255b1 100644 (file)
@@ -1,15 +1,21 @@
 /*\r
-Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.\r
+Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.\r
 For licensing, see LICENSE.html or http://ckeditor.com/license\r
 */\r
 \r
 (function()\r
 {\r
+       var meta =\r
+       {\r
+               editorFocus : false,\r
+               modes : { wysiwyg:1, source:1 }\r
+       };\r
+\r
        var blurCommand =\r
                {\r
                        exec : function( editor )\r
                        {\r
-                               editor.container.focusNext( true );\r
+                               editor.container.focusNext( true, editor.tabIndex );\r
                        }\r
                };\r
 \r
@@ -17,9 +23,81 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                {\r
                        exec : function( editor )\r
                        {\r
-                               editor.container.focusPrevious( true );\r
+                               editor.container.focusPrevious( true, editor.tabIndex );\r
+                       }\r
+               };\r
+\r
+       function selectNextCellCommand( backward )\r
+       {\r
+               return {\r
+                       editorFocus : false,\r
+                       canUndo : false,\r
+                       modes : { wysiwyg : 1 },\r
+                       exec : function( editor )\r
+                       {\r
+                               if ( editor.focusManager.hasFocus )\r
+                               {\r
+                                       var sel = editor.getSelection(),\r
+                                               ancestor = sel.getCommonAncestor(),\r
+                                               cell;\r
+\r
+                                       if ( ( cell = ( ancestor.getAscendant( 'td', true ) || ancestor.getAscendant( 'th', true ) ) ) )\r
+                                       {\r
+                                               var resultRange = new CKEDITOR.dom.range( editor.document ),\r
+                                                               next = CKEDITOR.tools.tryThese( function()\r
+                                                               {\r
+                                                                       var row = cell.getParent(),\r
+                                                                                       next = row.$.cells[ cell.$.cellIndex + ( backward ? - 1 : 1 ) ];\r
+\r
+                                                                       // Invalid any empty value.\r
+                                                                       next.parentNode.parentNode;\r
+                                                                       return next;\r
+                                                               },\r
+                                                               function()\r
+                                                               {\r
+                                                                       var row = cell.getParent(),\r
+                                                                                       table = row.getAscendant( 'table' ),\r
+                                                                                       nextRow = table.$.rows[ row.$.rowIndex + ( backward ? - 1 : 1 ) ];\r
+\r
+                                                                       return nextRow.cells[ backward? nextRow.cells.length -1 : 0 ];\r
+                                                               });\r
+\r
+                                               // Clone one more row at the end of table and select the first newly established cell.\r
+                                               if ( ! ( next || backward ) )\r
+                                               {\r
+                                                       var table = cell.getAscendant( 'table' ).$,\r
+                                                                       cells = cell.getParent().$.cells;\r
+\r
+                                                       var newRow = new CKEDITOR.dom.element( table.insertRow( -1 ), editor.document );\r
+\r
+                                                       for ( var i = 0, count = cells.length ; i < count; i++ )\r
+                                                       {\r
+                                                               var newCell = newRow.append( new CKEDITOR.dom.element(\r
+                                                                               cells[ i ], editor.document ).clone( false, false ) );\r
+                                                               !CKEDITOR.env.ie && newCell.appendBogus();\r
+                                                       }\r
+\r
+                                                       resultRange.moveToElementEditStart( newRow );\r
+                                               }\r
+                                               else if ( next )\r
+                                               {\r
+                                                       next = new CKEDITOR.dom.element( next );\r
+                                                       resultRange.moveToElementEditStart( next );\r
+                                                       // Avoid selecting empty block makes the cursor blind.\r
+                                                       if ( !( resultRange.checkStartOfBlock() && resultRange.checkEndOfBlock() ) )\r
+                                                               resultRange.selectNodeContents( next );\r
+                                               }\r
+                                               else\r
+                                                       return true;\r
+\r
+                                               resultRange.select( true );\r
+                                               return true;\r
+                                       }\r
+                               }\r
+                               return false;\r
                        }\r
                };\r
+       }\r
 \r
        CKEDITOR.plugins.add( 'tab',\r
        {\r
@@ -27,57 +105,59 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 \r
                init : function( editor )\r
                {\r
-                       // Register the keystrokes.\r
-                       var keystrokes = editor.keystrokeHandler.keystrokes;\r
-                       keystrokes[ 9 /* TAB */ ] = 'tab';\r
-                       keystrokes[ CKEDITOR.SHIFT + 9 /* TAB */ ] = 'shiftTab';\r
-\r
-                       var tabSpaces = editor.config.tabSpaces,\r
+                       var tabTools = editor.config.enableTabKeyTools !== false,\r
+                               tabSpaces = editor.config.tabSpaces || 0,\r
                                tabText = '';\r
 \r
                        while ( tabSpaces-- )\r
                                tabText += '\xa0';\r
 \r
-                       // Register the "tab" and "shiftTab" commands.\r
-                       editor.addCommand( 'tab',\r
-                               {\r
-                                       exec : function( editor )\r
+                       if ( tabText )\r
+                       {\r
+                               editor.on( 'key', function( ev )\r
                                        {\r
-                                               // Fire the "tab" event, making it possible to\r
-                                               // customize the TAB key behavior on specific cases.\r
-                                               if ( !editor.fire( 'tab' ) )\r
+                                               if ( ev.data.keyCode == 9 )     // TAB\r
                                                {\r
-                                                       if ( tabText.length > 0 )\r
-                                                               editor.insertHtml( tabText );\r
-                                                       else\r
-                                                       {\r
-                                                               // All browsers jump to the next field on TAB,\r
-                                                               // except Safari, so we have to do that manually\r
-                                                               // here.\r
-                                                               /// https://bugs.webkit.org/show_bug.cgi?id=20597\r
-                                                               return editor.execCommand( 'blur' );\r
-                                                       }\r
+                                                       editor.insertHtml( tabText );\r
+                                                       ev.cancel();\r
                                                }\r
+                                       });\r
+                       }\r
 \r
-                                               return true;\r
-                                       }\r
+                       if ( tabTools )\r
+                       {\r
+                               editor.on( 'key', function( ev )\r
+                               {\r
+                                       if ( ev.data.keyCode == 9 && editor.execCommand( 'selectNextCell' ) ||  // TAB\r
+                                                       ev.data.keyCode == ( CKEDITOR.SHIFT + 9 ) && editor.execCommand( 'selectPreviousCell' ) )       // SHIFT+TAB\r
+                                               ev.cancel();\r
                                });\r
+                       }\r
 \r
-                       editor.addCommand( 'shiftTab',\r
-                               {\r
-                                       exec : function( editor )\r
+                       if ( CKEDITOR.env.webkit || CKEDITOR.env.gecko )\r
+                       {\r
+                               editor.on( 'key', function( ev )\r
                                        {\r
-                                               // Fire the "tab" event, making it possible to\r
-                                               // customize the TAB key behavior on specific cases.\r
-                                               if ( !editor.fire( 'shiftTab' ) )\r
-                                                       return editor.execCommand( 'blurBack' );\r
+                                               var keyCode = ev.data.keyCode;\r
 \r
-                                               return true;\r
-                                       }\r
-                               });\r
+                                               if ( keyCode == 9 && !tabText )                         // TAB\r
+                                               {\r
+                                                       ev.cancel();\r
+                                                       editor.execCommand( 'blur' );\r
+                                               }\r
 \r
-                       editor.addCommand( 'blur', blurCommand );\r
-                       editor.addCommand( 'blurBack', blurBackCommand );\r
+                                               if ( keyCode == ( CKEDITOR.SHIFT + 9 ) )        // SHIFT+TAB\r
+                                               {\r
+                                                       editor.execCommand( 'blurBack' );\r
+                                                       ev.cancel();\r
+                                               }\r
+                                       });\r
+                       }\r
+\r
+                       editor.addCommand( 'blur', CKEDITOR.tools.extend( blurCommand, meta ) );\r
+                       editor.addCommand( 'blurBack', CKEDITOR.tools.extend( blurBackCommand, meta ) );\r
+                       editor.addCommand( 'selectNextCell', selectNextCellCommand() );\r
+                       editor.addCommand( 'selectPreviousCell', selectNextCellCommand( true ) );\r
                }\r
        });\r
 })();\r
@@ -89,10 +169,10 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
  * var element = CKEDITOR.document.getById( 'example' );\r
  * element.focusNext();\r
  */\r
-CKEDITOR.dom.element.prototype.focusNext = function( ignoreChildren )\r
+CKEDITOR.dom.element.prototype.focusNext = function( ignoreChildren, indexToUse )\r
 {\r
        var $ = this.$,\r
-               curTabIndex = this.getTabIndex(),\r
+               curTabIndex = ( indexToUse === undefined ? this.getTabIndex() : indexToUse ),\r
                passedCurrent, enteredCurrent,\r
                elected, electedTabIndex,\r
                element, elementTabIndex;\r
@@ -104,7 +184,7 @@ CKEDITOR.dom.element.prototype.focusNext = function( ignoreChildren )
 \r
                element = this.getNextSourceNode( ignoreChildren, CKEDITOR.NODE_ELEMENT );\r
 \r
-               while( element )\r
+               while ( element )\r
                {\r
                        if ( element.isVisible() && element.getTabIndex() === 0 )\r
                        {\r
@@ -125,7 +205,7 @@ CKEDITOR.dom.element.prototype.focusNext = function( ignoreChildren )
 \r
                element = this.getDocument().getBody().getFirst();\r
 \r
-               while( ( element = element.getNextSourceNode( false, CKEDITOR.NODE_ELEMENT ) ) )\r
+               while ( ( element = element.getNextSourceNode( false, CKEDITOR.NODE_ELEMENT ) ) )\r
                {\r
                        if ( !passedCurrent )\r
                        {\r
@@ -177,10 +257,10 @@ CKEDITOR.dom.element.prototype.focusNext = function( ignoreChildren )
  * var element = CKEDITOR.document.getById( 'example' );\r
  * element.focusPrevious();\r
  */\r
-CKEDITOR.dom.element.prototype.focusPrevious = function( ignoreChildren )\r
+CKEDITOR.dom.element.prototype.focusPrevious = function( ignoreChildren, indexToUse )\r
 {\r
        var $ = this.$,\r
-               curTabIndex = this.getTabIndex(),\r
+               curTabIndex = ( indexToUse === undefined ? this.getTabIndex() : indexToUse ),\r
                passedCurrent, enteredCurrent,\r
                elected,\r
                electedTabIndex = 0,\r
@@ -188,7 +268,7 @@ CKEDITOR.dom.element.prototype.focusPrevious = function( ignoreChildren )
 \r
        var element = this.getDocument().getBody().getLast();\r
 \r
-       while( ( element = element.getPreviousSourceNode( false, CKEDITOR.NODE_ELEMENT ) ) )\r
+       while ( ( element = element.getPreviousSourceNode( false, CKEDITOR.NODE_ELEMENT ) ) )\r
        {\r
                if ( !passedCurrent )\r
                {\r
@@ -258,9 +338,30 @@ CKEDITOR.dom.element.prototype.focusPrevious = function( ignoreChildren )
  * Intructs the editor to add a number of spaces (&amp;nbsp;) to the text when\r
  * hitting the TAB key. If set to zero, the TAB key will be used to move the\r
  * cursor focus to the next element in the page, out of the editor focus.\r
+ * @name CKEDITOR.config.tabSpaces\r
  * @type Number\r
  * @default 0\r
  * @example\r
  * config.tabSpaces = 4;\r
  */\r
-CKEDITOR.config.tabSpaces = 0 ;\r
+\r
+/**\r
+ * Allow context-sensitive tab key behaviors, including the following scenarios:\r
+ * <h5>When selection is anchored inside <b>table cells</b>:</h5>\r
+ * <ul>\r
+ *             <li>If TAB is pressed, select the contents of the "next" cell. If in the last cell in the table, add a new row to it and focus its first cell.</li>\r
+ *             <li>If SHIFT+TAB is pressed, select the contents of the "previous" cell. Do nothing when it's in the first cell.</li>\r
+ * </ul>\r
+ * @name CKEDITOR.config.enableTabKeyTools\r
+ * @type Boolean\r
+ * @default true\r
+ * @example\r
+ * config.enableTabKeyTools = false;\r
+ */\r
+\r
+// If the TAB key is not supposed to be enabled for navigation, the following\r
+// settings could be used alternatively:\r
+// config.keystrokes.push(\r
+//     [ CKEDITOR.ALT + 38 /*Arrow Up*/, 'selectPreviousCell' ],\r
+//     [ CKEDITOR.ALT + 40 /*Arrow Down*/, 'selectNextCell' ]\r
+// );\r