JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.2
[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, editor.tabIndex );\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, editor.tabIndex );\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                         var tabSpaces = editor.config.tabSpaces || 0,\r
37                                 tabText = '';\r
38 \r
39                         while ( tabSpaces-- )\r
40                                 tabText += '\xa0';\r
41 \r
42                         if ( tabText )\r
43                         {\r
44                                 editor.on( 'key', function( ev )\r
45                                         {\r
46                                                 if ( ev.data.keyCode == 9 )     // TAB\r
47                                                 {\r
48                                                         editor.insertHtml( tabText );\r
49                                                         ev.cancel();\r
50                                                 }\r
51                                         });\r
52                         }\r
53 \r
54                         if ( CKEDITOR.env.webkit )\r
55                         {\r
56                                 editor.on( 'key', function( ev )\r
57                                         {\r
58                                                 var keyCode = ev.data.keyCode;\r
59 \r
60                                                 if ( keyCode == 9 && !tabText )                         // TAB\r
61                                                 {\r
62                                                         ev.cancel();\r
63                                                         editor.execCommand( 'blur' );\r
64                                                 }\r
65 \r
66                                                 if ( keyCode == ( CKEDITOR.SHIFT + 9 ) )        // SHIFT+TAB\r
67                                                 {\r
68                                                         editor.execCommand( 'blurBack' );\r
69                                                         ev.cancel();\r
70                                                 }\r
71                                         });\r
72                         }\r
73 \r
74                         editor.addCommand( 'blur', CKEDITOR.tools.extend( blurCommand, meta ) );\r
75                         editor.addCommand( 'blurBack', CKEDITOR.tools.extend( blurBackCommand, meta ) );\r
76                 }\r
77         });\r
78 })();\r
79 \r
80 /**\r
81  * Moves the UI focus to the element following this element in the tabindex\r
82  * order.\r
83  * @example\r
84  * var element = CKEDITOR.document.getById( 'example' );\r
85  * element.focusNext();\r
86  */\r
87 CKEDITOR.dom.element.prototype.focusNext = function( ignoreChildren, indexToUse )\r
88 {\r
89         var $ = this.$,\r
90                 curTabIndex = ( indexToUse === undefined ? this.getTabIndex() : indexToUse ),\r
91                 passedCurrent, enteredCurrent,\r
92                 elected, electedTabIndex,\r
93                 element, elementTabIndex;\r
94 \r
95         if ( curTabIndex <= 0 )\r
96         {\r
97                 // If this element has tabindex <= 0 then we must simply look for any\r
98                 // element following it containing tabindex=0.\r
99 \r
100                 element = this.getNextSourceNode( ignoreChildren, CKEDITOR.NODE_ELEMENT );\r
101 \r
102                 while ( element )\r
103                 {\r
104                         if ( element.isVisible() && element.getTabIndex() === 0 )\r
105                         {\r
106                                 elected = element;\r
107                                 break;\r
108                         }\r
109 \r
110                         element = element.getNextSourceNode( false, CKEDITOR.NODE_ELEMENT );\r
111                 }\r
112         }\r
113         else\r
114         {\r
115                 // If this element has tabindex > 0 then we must look for:\r
116                 //              1. An element following this element with the same tabindex.\r
117                 //              2. The first element in source other with the lowest tabindex\r
118                 //                 that is higher than this element tabindex.\r
119                 //              3. The first element with tabindex=0.\r
120 \r
121                 element = this.getDocument().getBody().getFirst();\r
122 \r
123                 while ( ( element = element.getNextSourceNode( false, CKEDITOR.NODE_ELEMENT ) ) )\r
124                 {\r
125                         if ( !passedCurrent )\r
126                         {\r
127                                 if ( !enteredCurrent && element.equals( this ) )\r
128                                 {\r
129                                         enteredCurrent = true;\r
130 \r
131                                         // Ignore this element, if required.\r
132                                         if ( ignoreChildren )\r
133                                         {\r
134                                                 if ( !( element = element.getNextSourceNode( true, CKEDITOR.NODE_ELEMENT ) ) )\r
135                                                         break;\r
136                                                 passedCurrent = 1;\r
137                                         }\r
138                                 }\r
139                                 else if ( enteredCurrent && !this.contains( element ) )\r
140                                         passedCurrent = 1;\r
141                         }\r
142 \r
143                         if ( !element.isVisible() || ( elementTabIndex = element.getTabIndex() ) < 0 )\r
144                                 continue;\r
145 \r
146                         if ( passedCurrent && elementTabIndex == curTabIndex )\r
147                         {\r
148                                 elected = element;\r
149                                 break;\r
150                         }\r
151 \r
152                         if ( elementTabIndex > curTabIndex && ( !elected || !electedTabIndex || elementTabIndex < electedTabIndex ) )\r
153                         {\r
154                                 elected = element;\r
155                                 electedTabIndex = elementTabIndex;\r
156                         }\r
157                         else if ( !elected && elementTabIndex === 0 )\r
158                         {\r
159                                 elected = element;\r
160                                 electedTabIndex = elementTabIndex;\r
161                         }\r
162                 }\r
163         }\r
164 \r
165         if ( elected )\r
166                 elected.focus();\r
167 };\r
168 \r
169 /**\r
170  * Moves the UI focus to the element before this element in the tabindex order.\r
171  * @example\r
172  * var element = CKEDITOR.document.getById( 'example' );\r
173  * element.focusPrevious();\r
174  */\r
175 CKEDITOR.dom.element.prototype.focusPrevious = function( ignoreChildren, indexToUse )\r
176 {\r
177         var $ = this.$,\r
178                 curTabIndex = ( indexToUse === undefined ? this.getTabIndex() : indexToUse ),\r
179                 passedCurrent, enteredCurrent,\r
180                 elected,\r
181                 electedTabIndex = 0,\r
182                 elementTabIndex;\r
183 \r
184         var element = this.getDocument().getBody().getLast();\r
185 \r
186         while ( ( element = element.getPreviousSourceNode( false, CKEDITOR.NODE_ELEMENT ) ) )\r
187         {\r
188                 if ( !passedCurrent )\r
189                 {\r
190                         if ( !enteredCurrent && element.equals( this ) )\r
191                         {\r
192                                 enteredCurrent = true;\r
193 \r
194                                 // Ignore this element, if required.\r
195                                 if ( ignoreChildren )\r
196                                 {\r
197                                         if ( !( element = element.getPreviousSourceNode( true, CKEDITOR.NODE_ELEMENT ) ) )\r
198                                                 break;\r
199                                         passedCurrent = 1;\r
200                                 }\r
201                         }\r
202                         else if ( enteredCurrent && !this.contains( element ) )\r
203                                 passedCurrent = 1;\r
204                 }\r
205 \r
206                 if ( !element.isVisible() || ( elementTabIndex = element.getTabIndex() ) < 0 )\r
207                         continue;\r
208 \r
209                 if ( curTabIndex <= 0 )\r
210                 {\r
211                         // If this element has tabindex <= 0 then we must look for:\r
212                         //              1. An element before this one containing tabindex=0.\r
213                         //              2. The last element with the highest tabindex.\r
214 \r
215                         if ( passedCurrent && elementTabIndex === 0 )\r
216                         {\r
217                                 elected = element;\r
218                                 break;\r
219                         }\r
220 \r
221                         if ( elementTabIndex > electedTabIndex )\r
222                         {\r
223                                 elected = element;\r
224                                 electedTabIndex = elementTabIndex;\r
225                         }\r
226                 }\r
227                 else\r
228                 {\r
229                         // If this element has tabindex > 0 we must look for:\r
230                         //              1. An element preceeding this one, with the same tabindex.\r
231                         //              2. The last element in source other with the highest tabindex\r
232                         //                 that is lower than this element tabindex.\r
233 \r
234                         if ( passedCurrent && elementTabIndex == curTabIndex )\r
235                         {\r
236                                 elected = element;\r
237                                 break;\r
238                         }\r
239 \r
240                         if ( elementTabIndex < curTabIndex && ( !elected || elementTabIndex > electedTabIndex ) )\r
241                         {\r
242                                 elected = element;\r
243                                 electedTabIndex = elementTabIndex;\r
244                         }\r
245                 }\r
246         }\r
247 \r
248         if ( elected )\r
249                 elected.focus();\r
250 };\r
251 \r
252 /**\r
253  * Intructs the editor to add a number of spaces (&amp;nbsp;) to the text when\r
254  * hitting the TAB key. If set to zero, the TAB key will be used to move the\r
255  * cursor focus to the next element in the page, out of the editor focus.\r
256  * @name CKEDITOR.config.tabSpaces\r
257  * @type Number\r
258  * @default 0\r
259  * @example\r
260  * config.tabSpaces = 4;\r
261  */\r