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