]>
Commit | Line | Data |
---|---|---|
7adcb81e | 1 | /**\r |
3b35bd27 | 2 | * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.\r |
7adcb81e IB |
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license\r |
4 | */\r | |
5 | \r | |
6 | /**\r | |
7 | * @fileOverview Justify commands.\r | |
8 | */\r | |
9 | \r | |
10 | ( function() {\r | |
11 | function getAlignment( element, useComputedState ) {\r | |
12 | useComputedState = useComputedState === undefined || useComputedState;\r | |
13 | \r | |
14 | var align;\r | |
15 | if ( useComputedState )\r | |
16 | align = element.getComputedStyle( 'text-align' );\r | |
17 | else {\r | |
18 | while ( !element.hasAttribute || !( element.hasAttribute( 'align' ) || element.getStyle( 'text-align' ) ) ) {\r | |
19 | var parent = element.getParent();\r | |
20 | if ( !parent )\r | |
21 | break;\r | |
22 | element = parent;\r | |
23 | }\r | |
24 | align = element.getStyle( 'text-align' ) || element.getAttribute( 'align' ) || '';\r | |
25 | }\r | |
26 | \r | |
27 | // Sometimes computed values doesn't tell.\r | |
28 | align && ( align = align.replace( /(?:-(?:moz|webkit)-)?(?:start|auto)/i, '' ) );\r | |
29 | \r | |
30 | !align && useComputedState && ( align = element.getComputedStyle( 'direction' ) == 'rtl' ? 'right' : 'left' );\r | |
31 | \r | |
32 | return align;\r | |
33 | }\r | |
34 | \r | |
35 | function justifyCommand( editor, name, value ) {\r | |
36 | this.editor = editor;\r | |
37 | this.name = name;\r | |
38 | this.value = value;\r | |
39 | this.context = 'p';\r | |
40 | \r | |
41 | var classes = editor.config.justifyClasses,\r | |
42 | blockTag = editor.config.enterMode == CKEDITOR.ENTER_P ? 'p' : 'div';\r | |
43 | \r | |
44 | if ( classes ) {\r | |
45 | switch ( value ) {\r | |
46 | case 'left':\r | |
47 | this.cssClassName = classes[ 0 ];\r | |
48 | break;\r | |
49 | case 'center':\r | |
50 | this.cssClassName = classes[ 1 ];\r | |
51 | break;\r | |
52 | case 'right':\r | |
53 | this.cssClassName = classes[ 2 ];\r | |
54 | break;\r | |
55 | case 'justify':\r | |
56 | this.cssClassName = classes[ 3 ];\r | |
57 | break;\r | |
58 | }\r | |
59 | \r | |
60 | this.cssClassRegex = new RegExp( '(?:^|\\s+)(?:' + classes.join( '|' ) + ')(?=$|\\s)' );\r | |
61 | this.requiredContent = blockTag + '(' + this.cssClassName + ')';\r | |
62 | }\r | |
63 | else {\r | |
64 | this.requiredContent = blockTag + '{text-align}';\r | |
65 | }\r | |
66 | \r | |
67 | this.allowedContent = {\r | |
68 | 'caption div h1 h2 h3 h4 h5 h6 p pre td th li': {\r | |
69 | // Do not add elements, but only text-align style if element is validated by other rule.\r | |
70 | propertiesOnly: true,\r | |
71 | styles: this.cssClassName ? null : 'text-align',\r | |
72 | classes: this.cssClassName || null\r | |
73 | }\r | |
74 | };\r | |
75 | \r | |
76 | // In enter mode BR we need to allow here for div, because when non other\r | |
77 | // feature allows div justify is the only plugin that uses it.\r | |
78 | if ( editor.config.enterMode == CKEDITOR.ENTER_BR )\r | |
79 | this.allowedContent.div = true;\r | |
80 | }\r | |
81 | \r | |
82 | function onDirChanged( e ) {\r | |
83 | var editor = e.editor;\r | |
84 | \r | |
85 | var range = editor.createRange();\r | |
86 | range.setStartBefore( e.data.node );\r | |
87 | range.setEndAfter( e.data.node );\r | |
88 | \r | |
89 | var walker = new CKEDITOR.dom.walker( range ),\r | |
90 | node;\r | |
91 | \r | |
92 | while ( ( node = walker.next() ) ) {\r | |
93 | if ( node.type == CKEDITOR.NODE_ELEMENT ) {\r | |
94 | // A child with the defined dir is to be ignored.\r | |
95 | if ( !node.equals( e.data.node ) && node.getDirection() ) {\r | |
96 | range.setStartAfter( node );\r | |
97 | walker = new CKEDITOR.dom.walker( range );\r | |
98 | continue;\r | |
99 | }\r | |
100 | \r | |
101 | // Switch the alignment.\r | |
102 | var classes = editor.config.justifyClasses;\r | |
103 | if ( classes ) {\r | |
104 | // The left align class.\r | |
105 | if ( node.hasClass( classes[ 0 ] ) ) {\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 | node.removeClass( classes[ 2 ] );\r | |
112 | node.addClass( classes[ 0 ] );\r | |
113 | }\r | |
114 | }\r | |
115 | \r | |
116 | // Always switch CSS margins.\r | |
117 | var style = 'text-align';\r | |
118 | var align = node.getStyle( style );\r | |
119 | \r | |
120 | if ( align == 'left' )\r | |
121 | node.setStyle( style, 'right' );\r | |
122 | else if ( align == 'right' )\r | |
123 | node.setStyle( style, 'left' );\r | |
124 | }\r | |
125 | }\r | |
126 | }\r | |
127 | \r | |
128 | justifyCommand.prototype = {\r | |
129 | exec: function( editor ) {\r | |
130 | var selection = editor.getSelection(),\r | |
131 | enterMode = editor.config.enterMode;\r | |
132 | \r | |
133 | if ( !selection )\r | |
134 | return;\r | |
135 | \r | |
136 | var bookmarks = selection.createBookmarks(),\r | |
137 | ranges = selection.getRanges();\r | |
138 | \r | |
139 | var cssClassName = this.cssClassName,\r | |
140 | iterator, block;\r | |
141 | \r | |
142 | var useComputedState = editor.config.useComputedState;\r | |
143 | useComputedState = useComputedState === undefined || useComputedState;\r | |
144 | \r | |
145 | for ( var i = ranges.length - 1; i >= 0; i-- ) {\r | |
146 | iterator = ranges[ i ].createIterator();\r | |
147 | iterator.enlargeBr = enterMode != CKEDITOR.ENTER_BR;\r | |
148 | \r | |
149 | while ( ( block = iterator.getNextParagraph( enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ) ) ) {\r | |
150 | if ( block.isReadOnly() )\r | |
151 | continue;\r | |
152 | \r | |
153 | block.removeAttribute( 'align' );\r | |
154 | block.removeStyle( 'text-align' );\r | |
155 | \r | |
156 | // Remove any of the alignment classes from the className.\r | |
157 | var className = cssClassName && ( block.$.className = CKEDITOR.tools.ltrim( block.$.className.replace( this.cssClassRegex, '' ) ) );\r | |
158 | \r | |
159 | var apply = ( this.state == CKEDITOR.TRISTATE_OFF ) && ( !useComputedState || ( getAlignment( block, true ) != this.value ) );\r | |
160 | \r | |
161 | if ( cssClassName ) {\r | |
162 | // Append the desired class name.\r | |
163 | if ( apply )\r | |
164 | block.addClass( cssClassName );\r | |
165 | else if ( !className )\r | |
166 | block.removeAttribute( 'class' );\r | |
167 | } else if ( apply ) {\r | |
168 | block.setStyle( 'text-align', this.value );\r | |
169 | }\r | |
170 | }\r | |
171 | \r | |
172 | }\r | |
173 | \r | |
174 | editor.focus();\r | |
175 | editor.forceNextSelectionCheck();\r | |
176 | selection.selectBookmarks( bookmarks );\r | |
177 | },\r | |
178 | \r | |
179 | refresh: function( editor, path ) {\r | |
180 | var firstBlock = path.block || path.blockLimit;\r | |
181 | \r | |
182 | this.setState( firstBlock.getName() != 'body' && getAlignment( firstBlock, this.editor.config.useComputedState ) == this.value ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );\r | |
183 | }\r | |
184 | };\r | |
185 | \r | |
186 | CKEDITOR.plugins.add( 'justify', {\r | |
187 | // jscs:disable maximumLineLength\r | |
3b35bd27 | 188 | lang: 'af,ar,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%\r |
7adcb81e IB |
189 | // jscs:enable maximumLineLength\r |
190 | icons: 'justifyblock,justifycenter,justifyleft,justifyright', // %REMOVE_LINE_CORE%\r | |
191 | hidpi: true, // %REMOVE_LINE_CORE%\r | |
192 | init: function( editor ) {\r | |
193 | if ( editor.blockless )\r | |
194 | return;\r | |
195 | \r | |
196 | var left = new justifyCommand( editor, 'justifyleft', 'left' ),\r | |
197 | center = new justifyCommand( editor, 'justifycenter', 'center' ),\r | |
198 | right = new justifyCommand( editor, 'justifyright', 'right' ),\r | |
199 | justify = new justifyCommand( editor, 'justifyblock', 'justify' );\r | |
200 | \r | |
201 | editor.addCommand( 'justifyleft', left );\r | |
202 | editor.addCommand( 'justifycenter', center );\r | |
203 | editor.addCommand( 'justifyright', right );\r | |
204 | editor.addCommand( 'justifyblock', justify );\r | |
205 | \r | |
206 | if ( editor.ui.addButton ) {\r | |
207 | editor.ui.addButton( 'JustifyLeft', {\r | |
208 | label: editor.lang.justify.left,\r | |
209 | command: 'justifyleft',\r | |
210 | toolbar: 'align,10'\r | |
211 | } );\r | |
212 | editor.ui.addButton( 'JustifyCenter', {\r | |
213 | label: editor.lang.justify.center,\r | |
214 | command: 'justifycenter',\r | |
215 | toolbar: 'align,20'\r | |
216 | } );\r | |
217 | editor.ui.addButton( 'JustifyRight', {\r | |
218 | label: editor.lang.justify.right,\r | |
219 | command: 'justifyright',\r | |
220 | toolbar: 'align,30'\r | |
221 | } );\r | |
222 | editor.ui.addButton( 'JustifyBlock', {\r | |
223 | label: editor.lang.justify.block,\r | |
224 | command: 'justifyblock',\r | |
225 | toolbar: 'align,40'\r | |
226 | } );\r | |
227 | }\r | |
228 | \r | |
229 | editor.on( 'dirChanged', onDirChanged );\r | |
230 | }\r | |
231 | } );\r | |
232 | } )();\r | |
233 | \r | |
234 | /**\r | |
235 | * List of classes to use for aligning the contents. If it's `null`, no classes will be used\r | |
236 | * and instead the corresponding CSS values will be used.\r | |
237 | *\r | |
238 | * The array should contain 4 members, in the following order: left, center, right, justify.\r | |
239 | *\r | |
240 | * // Use the classes 'AlignLeft', 'AlignCenter', 'AlignRight', 'AlignJustify'\r | |
241 | * config.justifyClasses = [ 'AlignLeft', 'AlignCenter', 'AlignRight', 'AlignJustify' ];\r | |
242 | *\r | |
243 | * @cfg {Array} [justifyClasses=null]\r | |
244 | * @member CKEDITOR.config\r | |
245 | */\r |