JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.1.1
[ckeditor.git] / _source / plugins / tab / plugin.js
1 /*\r
2 Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.\r
3 For licensing, see LICENSE.html or http://ckeditor.com/license\r
4 */\r
5 \r
6 (function()\r
7 {\r
8         var meta =\r
9         {\r
10                 editorFocus : false,\r
11                 modes : { wysiwyg:1, source:1 }\r
12         };\r
13 \r
14         var blurCommand =\r
15                 {\r
16                         exec : function( editor )\r
17                         {\r
18                                 editor.container.focusNext( true );\r
19                         }\r
20                 };\r
21 \r
22         var blurBackCommand =\r
23                 {\r
24                         exec : function( editor )\r
25                         {\r
26                                 editor.container.focusPrevious( true );\r
27                         }\r
28                 };\r
29 \r
30         CKEDITOR.plugins.add( 'tab',\r
31         {\r
32                 requires : [ 'keystrokes' ],\r
33 \r
34                 init : function( editor )\r
35                 {\r
36                         // Register the keystrokes.\r
37                         var keystrokes = editor.keystrokeHandler.keystrokes;\r
38                         keystrokes[ 9 /* TAB */ ] = 'tab';\r
39                         keystrokes[ CKEDITOR.SHIFT + 9 /* TAB */ ] = 'shiftTab';\r
40 \r
41                         var tabSpaces = editor.config.tabSpaces,\r
42                                 tabText = '';\r
43 \r
44                         while ( tabSpaces-- )\r
45                                 tabText += '\xa0';\r
46 \r
47                         // Register the "tab" and "shiftTab" commands.\r
48                         editor.addCommand( 'tab', CKEDITOR.tools.extend(\r
49                                 {\r
50                                         exec : function( editor )\r
51                                         {\r
52                                                 // Fire the "tab" event, making it possible to\r
53                                                 // customize the TAB key behavior on specific cases.\r
54                                                 if ( !editor.fire( 'tab' ) )\r
55                                                 {\r
56                                                         if ( tabText.length > 0 )\r
57                                                                 editor.insertHtml( tabText );\r
58                                                         else\r
59                                                         {\r
60                                                                 // All browsers jump to the next field on TAB,\r
61                                                                 // except Safari, so we have to do that manually\r
62                                                                 // here.\r
63                                                                 /// https://bugs.webkit.org/show_bug.cgi?id=20597\r
64                                                                 return editor.execCommand( 'blur' );\r
65                                                         }\r
66                                                 }\r
67 \r
68                                                 return true;\r
69                                         }\r
70                                 }, meta ) );\r
71 \r
72                         editor.addCommand( 'shiftTab', CKEDITOR.tools.extend(\r
73                                 {\r
74                                         exec : function( editor )\r
75                                         {\r
76                                                 // Fire the "tab" event, making it possible to\r
77                                                 // customize the TAB key behavior on specific cases.\r
78                                                 if ( !editor.fire( 'shiftTab' ) )\r
79                                                         return editor.execCommand( 'blurBack' );\r
80 \r
81                                                 return true;\r
82                                         }\r
83                                 }, meta ) );\r
84 \r
85                         editor.addCommand( 'blur', CKEDITOR.tools.extend( blurCommand, meta ) );\r
86                         editor.addCommand( 'blurBack', CKEDITOR.tools.extend( blurBackCommand, meta ) );\r
87                 }\r
88         });\r
89 })();\r
90 \r
91 /**\r
92  * Moves the UI focus to the element following this element in the tabindex\r
93  * order.\r
94  * @example\r
95  * var element = CKEDITOR.document.getById( 'example' );\r
96  * element.focusNext();\r
97  */\r
98 CKEDITOR.dom.element.prototype.focusNext = function( ignoreChildren )\r
99 {\r
100         var $ = this.$,\r
101                 curTabIndex = this.getTabIndex(),\r
102                 passedCurrent, enteredCurrent,\r
103                 elected, electedTabIndex,\r
104                 element, elementTabIndex;\r
105 \r
106         if ( curTabIndex <= 0 )\r
107         {\r
108                 // If this element has tabindex <= 0 then we must simply look for any\r
109                 // element following it containing tabindex=0.\r
110 \r
111                 element = this.getNextSourceNode( ignoreChildren, CKEDITOR.NODE_ELEMENT );\r
112 \r
113                 while ( element )\r
114                 {\r
115                         if ( element.isVisible() && element.getTabIndex() === 0 )\r
116                         {\r
117                                 elected = element;\r
118                                 break;\r
119                         }\r
120 \r
121                         element = element.getNextSourceNode( false, CKEDITOR.NODE_ELEMENT );\r
122                 }\r
123         }\r
124         else\r
125         {\r
126                 // If this element has tabindex > 0 then we must look for:\r
127                 //              1. An element following this element with the same tabindex.\r
128                 //              2. The first element in source other with the lowest tabindex\r
129                 //                 that is higher than this element tabindex.\r
130                 //              3. The first element with tabindex=0.\r
131 \r
132                 element = this.getDocument().getBody().getFirst();\r
133 \r
134                 while ( ( element = element.getNextSourceNode( false, CKEDITOR.NODE_ELEMENT ) ) )\r
135                 {\r
136                         if ( !passedCurrent )\r
137                         {\r
138                                 if ( !enteredCurrent && element.equals( this ) )\r
139                                 {\r
140                                         enteredCurrent = true;\r
141 \r
142                                         // Ignore this element, if required.\r
143                                         if ( ignoreChildren )\r
144                                         {\r
145                                                 if ( !( element = element.getNextSourceNode( true, CKEDITOR.NODE_ELEMENT ) ) )\r
146                                                         break;\r
147                                                 passedCurrent = 1;\r
148                                         }\r
149                                 }\r
150                                 else if ( enteredCurrent && !this.contains( element ) )\r
151                                         passedCurrent = 1;\r
152                         }\r
153 \r
154                         if ( !element.isVisible() || ( elementTabIndex = element.getTabIndex() ) < 0 )\r
155                                 continue;\r
156 \r
157                         if ( passedCurrent && elementTabIndex == curTabIndex )\r
158                         {\r
159                                 elected = element;\r
160                                 break;\r
161                         }\r
162 \r
163                         if ( elementTabIndex > curTabIndex && ( !elected || !electedTabIndex || elementTabIndex < electedTabIndex ) )\r
164                         {\r
165                                 elected = element;\r
166                                 electedTabIndex = elementTabIndex;\r
167                         }\r
168                         else if ( !elected && elementTabIndex === 0 )\r
169                         {\r
170                                 elected = element;\r
171                                 electedTabIndex = elementTabIndex;\r
172                         }\r
173                 }\r
174         }\r
175 \r
176         if ( elected )\r
177                 elected.focus();\r
178 };\r
179 \r
180 /**\r
181  * Moves the UI focus to the element before this element in the tabindex order.\r
182  * @example\r
183  * var element = CKEDITOR.document.getById( 'example' );\r
184  * element.focusPrevious();\r
185  */\r
186 CKEDITOR.dom.element.prototype.focusPrevious = function( ignoreChildren )\r
187 {\r
188         var $ = this.$,\r
189                 curTabIndex = this.getTabIndex(),\r
190                 passedCurrent, enteredCurrent,\r
191                 elected,\r
192                 electedTabIndex = 0,\r
193                 elementTabIndex;\r
194 \r
195         var element = this.getDocument().getBody().getLast();\r
196 \r
197         while ( ( element = element.getPreviousSourceNode( false, CKEDITOR.NODE_ELEMENT ) ) )\r
198         {\r
199                 if ( !passedCurrent )\r
200                 {\r
201                         if ( !enteredCurrent && element.equals( this ) )\r
202                         {\r
203                                 enteredCurrent = true;\r
204 \r
205                                 // Ignore this element, if required.\r
206                                 if ( ignoreChildren )\r
207                                 {\r
208                                         if ( !( element = element.getPreviousSourceNode( true, CKEDITOR.NODE_ELEMENT ) ) )\r
209                                                 break;\r
210                                         passedCurrent = 1;\r
211                                 }\r
212                         }\r
213                         else if ( enteredCurrent && !this.contains( element ) )\r
214                                 passedCurrent = 1;\r
215                 }\r
216 \r
217                 if ( !element.isVisible() || ( elementTabIndex = element.getTabIndex() ) < 0 )\r
218                         continue;\r
219 \r
220                 if ( curTabIndex <= 0 )\r
221                 {\r
222                         // If this element has tabindex <= 0 then we must look for:\r
223                         //              1. An element before this one containing tabindex=0.\r
224                         //              2. The last element with the highest tabindex.\r
225 \r
226                         if ( passedCurrent && elementTabIndex === 0 )\r
227                         {\r
228                                 elected = element;\r
229                                 break;\r
230                         }\r
231 \r
232                         if ( elementTabIndex > electedTabIndex )\r
233                         {\r
234                                 elected = element;\r
235                                 electedTabIndex = elementTabIndex;\r
236                         }\r
237                 }\r
238                 else\r
239                 {\r
240                         // If this element has tabindex > 0 we must look for:\r
241                         //              1. An element preceeding this one, with the same tabindex.\r
242                         //              2. The last element in source other with the highest tabindex\r
243                         //                 that is lower than this element tabindex.\r
244 \r
245                         if ( passedCurrent && elementTabIndex == curTabIndex )\r
246                         {\r
247                                 elected = element;\r
248                                 break;\r
249                         }\r
250 \r
251                         if ( elementTabIndex < curTabIndex && ( !elected || elementTabIndex > electedTabIndex ) )\r
252                         {\r
253                                 elected = element;\r
254                                 electedTabIndex = elementTabIndex;\r
255                         }\r
256                 }\r
257         }\r
258 \r
259         if ( elected )\r
260                 elected.focus();\r
261 };\r
262 \r
263 /**\r
264  * Intructs the editor to add a number of spaces (&amp;nbsp;) to the text when\r
265  * hitting the TAB key. If set to zero, the TAB key will be used to move the\r
266  * cursor focus to the next element in the page, out of the editor focus.\r
267  * @type Number\r
268  * @default 0\r
269  * @example\r
270  * config.tabSpaces = 4;\r
271  */\r
272 CKEDITOR.config.tabSpaces = 0 ;\r