JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.6.3
[ckeditor.git] / _source / plugins / justify / plugin.js
1 /*\r
2 Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.\r
3 For licensing, see LICENSE.html or http://ckeditor.com/license\r
4 */\r
5 \r
6 /**\r
7  * @file Justify commands.\r
8  */\r
9 \r
10 (function()\r
11 {\r
12         function getAlignment( element, useComputedState )\r
13         {\r
14                 useComputedState = useComputedState === undefined || useComputedState;\r
15 \r
16                 var align;\r
17                 if ( useComputedState )\r
18                         align = element.getComputedStyle( 'text-align' );\r
19                 else\r
20                 {\r
21                         while ( !element.hasAttribute || !( element.hasAttribute( 'align' ) || element.getStyle( 'text-align' ) ) )\r
22                         {\r
23                                 var parent = element.getParent();\r
24                                 if ( !parent )\r
25                                         break;\r
26                                 element = parent;\r
27                         }\r
28                         align = element.getStyle( 'text-align' ) || element.getAttribute( 'align' ) || '';\r
29                 }\r
30 \r
31                 // Sometimes computed values doesn't tell.\r
32                 align && ( align = align.replace( /(?:-(?:moz|webkit)-)?(?:start|auto)/i, '' ) );\r
33 \r
34                 !align && useComputedState && ( align = element.getComputedStyle( 'direction' ) == 'rtl' ? 'right' : 'left' );\r
35 \r
36                 return align;\r
37         }\r
38 \r
39         function onSelectionChange( evt )\r
40         {\r
41                 if ( evt.editor.readOnly )\r
42                         return;\r
43 \r
44                 evt.editor.getCommand( this.name ).refresh( evt.data.path );\r
45         }\r
46 \r
47         function justifyCommand( editor, name, value )\r
48         {\r
49                 this.editor = editor;\r
50                 this.name = name;\r
51                 this.value = value;\r
52 \r
53                 var classes = editor.config.justifyClasses;\r
54                 if ( classes )\r
55                 {\r
56                         switch ( value )\r
57                         {\r
58                                 case 'left' :\r
59                                         this.cssClassName = classes[0];\r
60                                         break;\r
61                                 case 'center' :\r
62                                         this.cssClassName = classes[1];\r
63                                         break;\r
64                                 case 'right' :\r
65                                         this.cssClassName = classes[2];\r
66                                         break;\r
67                                 case 'justify' :\r
68                                         this.cssClassName = classes[3];\r
69                                         break;\r
70                         }\r
71 \r
72                         this.cssClassRegex = new RegExp( '(?:^|\\s+)(?:' + classes.join( '|' ) + ')(?=$|\\s)' );\r
73                 }\r
74         }\r
75 \r
76         function onDirChanged( e )\r
77         {\r
78                 var editor = e.editor;\r
79 \r
80                 var range = new CKEDITOR.dom.range( editor.document );\r
81                 range.setStartBefore( e.data.node );\r
82                 range.setEndAfter( e.data.node );\r
83 \r
84                 var walker = new CKEDITOR.dom.walker( range ),\r
85                         node;\r
86 \r
87                 while ( ( node = walker.next() ) )\r
88                 {\r
89                         if ( node.type == CKEDITOR.NODE_ELEMENT )\r
90                         {\r
91                                 // A child with the defined dir is to be ignored.\r
92                                 if ( !node.equals( e.data.node ) && node.getDirection() )\r
93                                 {\r
94                                         range.setStartAfter( node );\r
95                                         walker = new CKEDITOR.dom.walker( range );\r
96                                         continue;\r
97                                 }\r
98 \r
99                                 // Switch the alignment.\r
100                                 var classes = editor.config.justifyClasses;\r
101                                 if ( classes )\r
102                                 {\r
103                                         // The left align class.\r
104                                         if ( node.hasClass( classes[ 0 ] ) )\r
105                                         {\r
106                                                 node.removeClass( classes[ 0 ] );\r
107                                                 node.addClass( classes[ 2 ] );\r
108                                         }\r
109                                         // The right align class.\r
110                                         else if ( node.hasClass( classes[ 2 ] ) )\r
111                                         {\r
112                                                 node.removeClass( classes[ 2 ] );\r
113                                                 node.addClass( classes[ 0 ] );\r
114                                         }\r
115                                 }\r
116 \r
117                                 // Always switch CSS margins.\r
118                                 var style = 'text-align';\r
119                                 var align = node.getStyle( style );\r
120 \r
121                                 if ( align == 'left' )\r
122                                         node.setStyle( style, 'right' );\r
123                                 else if ( align == 'right' )\r
124                                         node.setStyle( style, 'left' );\r
125                         }\r
126                 }\r
127         }\r
128 \r
129         justifyCommand.prototype = {\r
130                 exec : function( editor )\r
131                 {\r
132                         var selection = editor.getSelection(),\r
133                                 enterMode = editor.config.enterMode;\r
134 \r
135                         if ( !selection )\r
136                                 return;\r
137 \r
138                         var bookmarks = selection.createBookmarks(),\r
139                                 ranges = selection.getRanges( true );\r
140 \r
141                         var cssClassName = this.cssClassName,\r
142                                 iterator,\r
143                                 block;\r
144 \r
145                         var useComputedState = editor.config.useComputedState;\r
146                         useComputedState = useComputedState === undefined || useComputedState;\r
147 \r
148                         for ( var i = ranges.length - 1 ; i >= 0 ; i-- )\r
149                         {\r
150                                 iterator = ranges[ i ].createIterator();\r
151                                 iterator.enlargeBr = enterMode != CKEDITOR.ENTER_BR;\r
152 \r
153                                 while ( ( block = iterator.getNextParagraph( enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ) ) )\r
154                                 {\r
155                                         block.removeAttribute( 'align' );\r
156                                         block.removeStyle( 'text-align' );\r
157 \r
158                                         // Remove any of the alignment classes from the className.\r
159                                         var className = cssClassName && ( block.$.className =\r
160                                                 CKEDITOR.tools.ltrim( block.$.className.replace( this.cssClassRegex, '' ) ) );\r
161 \r
162                                         var apply =\r
163                                                 ( this.state == CKEDITOR.TRISTATE_OFF ) &&\r
164                                                 ( !useComputedState || ( getAlignment( block, true ) != this.value ) );\r
165 \r
166                                         if ( cssClassName )\r
167                                         {\r
168                                                 // Append the desired class name.\r
169                                                 if ( apply )\r
170                                                         block.addClass( cssClassName );\r
171                                                 else if ( !className )\r
172                                                         block.removeAttribute( 'class' );\r
173                                         }\r
174                                         else if ( apply )\r
175                                                 block.setStyle( 'text-align', this.value );\r
176                                 }\r
177 \r
178                         }\r
179 \r
180                         editor.focus();\r
181                         editor.forceNextSelectionCheck();\r
182                         selection.selectBookmarks( bookmarks );\r
183                 },\r
184 \r
185                 refresh : function( path )\r
186                 {\r
187                         var firstBlock = path.block || path.blockLimit;\r
188 \r
189                         this.setState( firstBlock.getName() != 'body' &&\r
190                                 getAlignment( firstBlock, this.editor.config.useComputedState ) == this.value ?\r
191                                 CKEDITOR.TRISTATE_ON :\r
192                                 CKEDITOR.TRISTATE_OFF );\r
193                 }\r
194         };\r
195 \r
196         CKEDITOR.plugins.add( 'justify',\r
197         {\r
198                 init : function( editor )\r
199                 {\r
200                         var left = new justifyCommand( editor, 'justifyleft', 'left' ),\r
201                                 center = new justifyCommand( editor, 'justifycenter', 'center' ),\r
202                                 right = new justifyCommand( editor, 'justifyright', 'right' ),\r
203                                 justify = new justifyCommand( editor, 'justifyblock', 'justify' );\r
204 \r
205                         editor.addCommand( 'justifyleft', left );\r
206                         editor.addCommand( 'justifycenter', center );\r
207                         editor.addCommand( 'justifyright', right );\r
208                         editor.addCommand( 'justifyblock', justify );\r
209 \r
210                         editor.ui.addButton( 'JustifyLeft',\r
211                                 {\r
212                                         label : editor.lang.justify.left,\r
213                                         command : 'justifyleft'\r
214                                 } );\r
215                         editor.ui.addButton( 'JustifyCenter',\r
216                                 {\r
217                                         label : editor.lang.justify.center,\r
218                                         command : 'justifycenter'\r
219                                 } );\r
220                         editor.ui.addButton( 'JustifyRight',\r
221                                 {\r
222                                         label : editor.lang.justify.right,\r
223                                         command : 'justifyright'\r
224                                 } );\r
225                         editor.ui.addButton( 'JustifyBlock',\r
226                                 {\r
227                                         label : editor.lang.justify.block,\r
228                                         command : 'justifyblock'\r
229                                 } );\r
230 \r
231                         editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, left ) );\r
232                         editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, right ) );\r
233                         editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, center ) );\r
234                         editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, justify ) );\r
235                         editor.on( 'dirChanged', onDirChanged );\r
236                 },\r
237 \r
238                 requires : [ 'domiterator' ]\r
239         });\r
240 })();\r
241 \r
242  /**\r
243  * List of classes to use for aligning the contents. If it's null, no classes will be used\r
244  * and instead the corresponding CSS values will be used. The array should contain 4 members, in the following order: left, center, right, justify.\r
245  * @name CKEDITOR.config.justifyClasses\r
246  * @type Array\r
247  * @default null\r
248  * @example\r
249  * // Use the classes 'AlignLeft', 'AlignCenter', 'AlignRight', 'AlignJustify'\r
250  * config.justifyClasses = [ 'AlignLeft', 'AlignCenter', 'AlignRight', 'AlignJustify' ];\r
251  */\r