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