diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2016-01-25 17:45:33 +0100 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2016-01-25 18:00:33 +0100 |
commit | 7adcb81e4f83f98c468889aaa5a85558ba88c770 (patch) | |
tree | 0d6ede733777b29060b48df4afaa2c64bfbae276 /sources/plugins/div/dialogs | |
download | connexionswing-ckeditor-component-7adcb81e4f83f98c468889aaa5a85558ba88c770.tar.gz connexionswing-ckeditor-component-7adcb81e4f83f98c468889aaa5a85558ba88c770.tar.zst connexionswing-ckeditor-component-7adcb81e4f83f98c468889aaa5a85558ba88c770.zip |
Initial commit4.5.6
Diffstat (limited to 'sources/plugins/div/dialogs')
-rw-r--r-- | sources/plugins/div/dialogs/div.js | 430 |
1 files changed, 430 insertions, 0 deletions
diff --git a/sources/plugins/div/dialogs/div.js b/sources/plugins/div/dialogs/div.js new file mode 100644 index 00000000..3914f071 --- /dev/null +++ b/sources/plugins/div/dialogs/div.js | |||
@@ -0,0 +1,430 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | |||
6 | ( function() { | ||
7 | |||
8 | // Add to collection with DUP examination. | ||
9 | // @param {Object} collection | ||
10 | // @param {Object} element | ||
11 | // @param {Object} database | ||
12 | function addSafely( collection, element, database ) { | ||
13 | // 1. IE doesn't support customData on text nodes; | ||
14 | // 2. Text nodes never get chance to appear twice; | ||
15 | if ( !element.is || !element.getCustomData( 'block_processed' ) ) { | ||
16 | element.is && CKEDITOR.dom.element.setMarker( database, element, 'block_processed', true ); | ||
17 | collection.push( element ); | ||
18 | } | ||
19 | } | ||
20 | |||
21 | // Dialog reused by both 'creatediv' and 'editdiv' commands. | ||
22 | // @param {Object} editor | ||
23 | // @param {String} command The command name which indicate what the current command is. | ||
24 | function divDialog( editor, command ) { | ||
25 | // Definition of elements at which div operation should stopped. | ||
26 | var divLimitDefinition = ( function() { | ||
27 | |||
28 | // Customzie from specialize blockLimit elements | ||
29 | var definition = CKEDITOR.tools.extend( {}, CKEDITOR.dtd.$blockLimit ); | ||
30 | |||
31 | if ( editor.config.div_wrapTable ) { | ||
32 | delete definition.td; | ||
33 | delete definition.th; | ||
34 | } | ||
35 | return definition; | ||
36 | } )(); | ||
37 | |||
38 | // DTD of 'div' element | ||
39 | var dtd = CKEDITOR.dtd.div; | ||
40 | |||
41 | // Get the first div limit element on the element's path. | ||
42 | // @param {Object} element | ||
43 | function getDivContainer( element ) { | ||
44 | var container = editor.elementPath( element ).blockLimit; | ||
45 | |||
46 | // Never consider read-only (i.e. contenteditable=false) element as | ||
47 | // a first div limit (#11083). | ||
48 | if ( container.isReadOnly() ) | ||
49 | container = container.getParent(); | ||
50 | |||
51 | // Dont stop at 'td' and 'th' when div should wrap entire table. | ||
52 | if ( editor.config.div_wrapTable && container.is( [ 'td', 'th' ] ) ) { | ||
53 | var parentPath = editor.elementPath( container.getParent() ); | ||
54 | container = parentPath.blockLimit; | ||
55 | } | ||
56 | |||
57 | return container; | ||
58 | } | ||
59 | |||
60 | // Init all fields' setup/commit function. | ||
61 | // @memberof divDialog | ||
62 | function setupFields() { | ||
63 | this.foreach( function( field ) { | ||
64 | // Exclude layout container elements | ||
65 | if ( /^(?!vbox|hbox)/.test( field.type ) ) { | ||
66 | if ( !field.setup ) { | ||
67 | // Read the dialog fields values from the specified | ||
68 | // element attributes. | ||
69 | field.setup = function( element ) { | ||
70 | field.setValue( element.getAttribute( field.id ) || '', 1 ); | ||
71 | }; | ||
72 | } | ||
73 | if ( !field.commit ) { | ||
74 | // Set element attributes assigned by the dialog | ||
75 | // fields. | ||
76 | field.commit = function( element ) { | ||
77 | var fieldValue = this.getValue(); | ||
78 | // ignore default element attribute values | ||
79 | if ( field.id == 'dir' && element.getComputedStyle( 'direction' ) == fieldValue ) { | ||
80 | return; | ||
81 | } | ||
82 | |||
83 | if ( fieldValue ) | ||
84 | element.setAttribute( field.id, fieldValue ); | ||
85 | else | ||
86 | element.removeAttribute( field.id ); | ||
87 | }; | ||
88 | } | ||
89 | } | ||
90 | } ); | ||
91 | } | ||
92 | |||
93 | // Wrapping 'div' element around appropriate blocks among the selected ranges. | ||
94 | // @param {Object} editor | ||
95 | function createDiv( editor ) { | ||
96 | // new adding containers OR detected pre-existed containers. | ||
97 | var containers = []; | ||
98 | // node markers store. | ||
99 | var database = {}; | ||
100 | // All block level elements which contained by the ranges. | ||
101 | var containedBlocks = [], | ||
102 | block; | ||
103 | |||
104 | // Get all ranges from the selection. | ||
105 | var selection = editor.getSelection(), | ||
106 | ranges = selection.getRanges(); | ||
107 | var bookmarks = selection.createBookmarks(); | ||
108 | var i, iterator; | ||
109 | |||
110 | // collect all included elements from dom-iterator | ||
111 | for ( i = 0; i < ranges.length; i++ ) { | ||
112 | iterator = ranges[ i ].createIterator(); | ||
113 | while ( ( block = iterator.getNextParagraph() ) ) { | ||
114 | // include contents of blockLimit elements. | ||
115 | if ( block.getName() in divLimitDefinition && !block.isReadOnly() ) { | ||
116 | var j, | ||
117 | childNodes = block.getChildren(); | ||
118 | for ( j = 0; j < childNodes.count(); j++ ) | ||
119 | addSafely( containedBlocks, childNodes.getItem( j ), database ); | ||
120 | } else { | ||
121 | while ( !dtd[ block.getName() ] && !block.equals( ranges[ i ].root ) ) | ||
122 | block = block.getParent(); | ||
123 | addSafely( containedBlocks, block, database ); | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | |||
128 | CKEDITOR.dom.element.clearAllMarkers( database ); | ||
129 | |||
130 | var blockGroups = groupByDivLimit( containedBlocks ); | ||
131 | var ancestor, divElement; | ||
132 | |||
133 | for ( i = 0; i < blockGroups.length; i++ ) { | ||
134 | var currentNode = blockGroups[ i ][ 0 ]; | ||
135 | |||
136 | // Calculate the common parent node of all contained elements. | ||
137 | ancestor = currentNode.getParent(); | ||
138 | for ( j = 1; j < blockGroups[ i ].length; j++ ) | ||
139 | ancestor = ancestor.getCommonAncestor( blockGroups[ i ][ j ] ); | ||
140 | |||
141 | divElement = new CKEDITOR.dom.element( 'div', editor.document ); | ||
142 | |||
143 | // Normalize the blocks in each group to a common parent. | ||
144 | for ( j = 0; j < blockGroups[ i ].length; j++ ) { | ||
145 | currentNode = blockGroups[ i ][ j ]; | ||
146 | |||
147 | while ( !currentNode.getParent().equals( ancestor ) ) | ||
148 | currentNode = currentNode.getParent(); | ||
149 | |||
150 | // This could introduce some duplicated elements in array. | ||
151 | blockGroups[ i ][ j ] = currentNode; | ||
152 | } | ||
153 | |||
154 | // Wrapped blocks counting | ||
155 | for ( j = 0; j < blockGroups[ i ].length; j++ ) { | ||
156 | currentNode = blockGroups[ i ][ j ]; | ||
157 | |||
158 | // Avoid DUP elements introduced by grouping. | ||
159 | if ( !( currentNode.getCustomData && currentNode.getCustomData( 'block_processed' ) ) ) { | ||
160 | currentNode.is && CKEDITOR.dom.element.setMarker( database, currentNode, 'block_processed', true ); | ||
161 | |||
162 | // Establish new container, wrapping all elements in this group. | ||
163 | if ( !j ) | ||
164 | divElement.insertBefore( currentNode ); | ||
165 | |||
166 | divElement.append( currentNode ); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | CKEDITOR.dom.element.clearAllMarkers( database ); | ||
171 | containers.push( divElement ); | ||
172 | } | ||
173 | |||
174 | selection.selectBookmarks( bookmarks ); | ||
175 | return containers; | ||
176 | } | ||
177 | |||
178 | // Divide a set of nodes to different groups by their path's blocklimit element. | ||
179 | // Note: the specified nodes should be in source order naturally, which mean they are supposed to producea by following class: | ||
180 | // * CKEDITOR.dom.range.Iterator | ||
181 | // * CKEDITOR.dom.domWalker | ||
182 | // @returns {Array[]} the grouped nodes | ||
183 | function groupByDivLimit( nodes ) { | ||
184 | var groups = [], | ||
185 | lastDivLimit = null, | ||
186 | block; | ||
187 | |||
188 | for ( var i = 0; i < nodes.length; i++ ) { | ||
189 | block = nodes[ i ]; | ||
190 | var limit = getDivContainer( block ); | ||
191 | if ( !limit.equals( lastDivLimit ) ) { | ||
192 | lastDivLimit = limit; | ||
193 | groups.push( [] ); | ||
194 | } | ||
195 | groups[ groups.length - 1 ].push( block ); | ||
196 | } | ||
197 | return groups; | ||
198 | } | ||
199 | |||
200 | // Synchronous field values to other impacted fields is required, e.g. div styles | ||
201 | // change should also alter inline-style text. | ||
202 | function commitInternally( targetFields ) { | ||
203 | var dialog = this.getDialog(), | ||
204 | element = dialog._element && dialog._element.clone() || new CKEDITOR.dom.element( 'div', editor.document ); | ||
205 | |||
206 | // Commit this field and broadcast to target fields. | ||
207 | this.commit( element, true ); | ||
208 | |||
209 | targetFields = [].concat( targetFields ); | ||
210 | var length = targetFields.length, | ||
211 | field; | ||
212 | for ( var i = 0; i < length; i++ ) { | ||
213 | field = dialog.getContentElement.apply( dialog, targetFields[ i ].split( ':' ) ); | ||
214 | field && field.setup && field.setup( element, true ); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | |||
219 | // Registered 'CKEDITOR.style' instances. | ||
220 | var styles = {}; | ||
221 | |||
222 | // Hold a collection of created block container elements. | ||
223 | var containers = []; | ||
224 | |||
225 | // @type divDialog | ||
226 | return { | ||
227 | title: editor.lang.div.title, | ||
228 | minWidth: 400, | ||
229 | minHeight: 165, | ||
230 | contents: [ { | ||
231 | id: 'info', | ||
232 | label: editor.lang.common.generalTab, | ||
233 | title: editor.lang.common.generalTab, | ||
234 | elements: [ { | ||
235 | type: 'hbox', | ||
236 | widths: [ '50%', '50%' ], | ||
237 | children: [ { | ||
238 | id: 'elementStyle', | ||
239 | type: 'select', | ||
240 | style: 'width: 100%;', | ||
241 | label: editor.lang.div.styleSelectLabel, | ||
242 | 'default': '', | ||
243 | // Options are loaded dynamically. | ||
244 | items: [ | ||
245 | [ editor.lang.common.notSet, '' ] | ||
246 | ], | ||
247 | onChange: function() { | ||
248 | commitInternally.call( this, [ 'info:elementStyle', 'info:class', 'advanced:dir', 'advanced:style' ] ); | ||
249 | }, | ||
250 | setup: function( element ) { | ||
251 | for ( var name in styles ) | ||
252 | styles[ name ].checkElementRemovable( element, true, editor ) && this.setValue( name, 1 ); | ||
253 | }, | ||
254 | commit: function( element ) { | ||
255 | var styleName; | ||
256 | if ( ( styleName = this.getValue() ) ) { | ||
257 | var style = styles[ styleName ]; | ||
258 | style.applyToObject( element, editor ); | ||
259 | } | ||
260 | else { | ||
261 | element.removeAttribute( 'style' ); | ||
262 | } | ||
263 | } | ||
264 | }, | ||
265 | { | ||
266 | id: 'class', | ||
267 | type: 'text', | ||
268 | requiredContent: 'div(cke-xyz)', // Random text like 'xyz' will check if all are allowed. | ||
269 | label: editor.lang.common.cssClass, | ||
270 | 'default': '' | ||
271 | } ] | ||
272 | } ] | ||
273 | }, | ||
274 | { | ||
275 | id: 'advanced', | ||
276 | label: editor.lang.common.advancedTab, | ||
277 | title: editor.lang.common.advancedTab, | ||
278 | elements: [ { | ||
279 | type: 'vbox', | ||
280 | padding: 1, | ||
281 | children: [ { | ||
282 | type: 'hbox', | ||
283 | widths: [ '50%', '50%' ], | ||
284 | children: [ { | ||
285 | type: 'text', | ||
286 | id: 'id', | ||
287 | requiredContent: 'div[id]', | ||
288 | label: editor.lang.common.id, | ||
289 | 'default': '' | ||
290 | }, | ||
291 | { | ||
292 | type: 'text', | ||
293 | id: 'lang', | ||
294 | requiredContent: 'div[lang]', | ||
295 | label: editor.lang.common.langCode, | ||
296 | 'default': '' | ||
297 | } ] | ||
298 | }, | ||
299 | { | ||
300 | type: 'hbox', | ||
301 | children: [ { | ||
302 | type: 'text', | ||
303 | id: 'style', | ||
304 | requiredContent: 'div{cke-xyz}', // Random text like 'xyz' will check if all are allowed. | ||
305 | style: 'width: 100%;', | ||
306 | label: editor.lang.common.cssStyle, | ||
307 | 'default': '', | ||
308 | commit: function( element ) { | ||
309 | element.setAttribute( 'style', this.getValue() ); | ||
310 | } | ||
311 | } ] | ||
312 | }, | ||
313 | { | ||
314 | type: 'hbox', | ||
315 | children: [ { | ||
316 | type: 'text', | ||
317 | id: 'title', | ||
318 | requiredContent: 'div[title]', | ||
319 | style: 'width: 100%;', | ||
320 | label: editor.lang.common.advisoryTitle, | ||
321 | 'default': '' | ||
322 | } ] | ||
323 | }, | ||
324 | { | ||
325 | type: 'select', | ||
326 | id: 'dir', | ||
327 | requiredContent: 'div[dir]', | ||
328 | style: 'width: 100%;', | ||
329 | label: editor.lang.common.langDir, | ||
330 | 'default': '', | ||
331 | items: [ | ||
332 | [ editor.lang.common.notSet, '' ], | ||
333 | [ editor.lang.common.langDirLtr, 'ltr' ], | ||
334 | [ editor.lang.common.langDirRtl, 'rtl' ] | ||
335 | ] | ||
336 | } ] } | ||
337 | ] | ||
338 | } ], | ||
339 | onLoad: function() { | ||
340 | setupFields.call( this ); | ||
341 | |||
342 | // Preparing for the 'elementStyle' field. | ||
343 | var dialog = this, | ||
344 | stylesField = this.getContentElement( 'info', 'elementStyle' ); | ||
345 | |||
346 | // Reuse the 'stylescombo' plugin's styles definition. | ||
347 | editor.getStylesSet( function( stylesDefinitions ) { | ||
348 | var styleName, style; | ||
349 | |||
350 | if ( stylesDefinitions ) { | ||
351 | // Digg only those styles that apply to 'div'. | ||
352 | for ( var i = 0; i < stylesDefinitions.length; i++ ) { | ||
353 | var styleDefinition = stylesDefinitions[ i ]; | ||
354 | if ( styleDefinition.element && styleDefinition.element == 'div' ) { | ||
355 | styleName = styleDefinition.name; | ||
356 | styles[ styleName ] = style = new CKEDITOR.style( styleDefinition ); | ||
357 | |||
358 | if ( editor.filter.check( style ) ) { | ||
359 | // Populate the styles field options with style name. | ||
360 | stylesField.items.push( [ styleName, styleName ] ); | ||
361 | stylesField.add( styleName, styleName ); | ||
362 | } | ||
363 | } | ||
364 | } | ||
365 | } | ||
366 | |||
367 | // We should disable the content element | ||
368 | // it if no options are available at all. | ||
369 | stylesField[ stylesField.items.length > 1 ? 'enable' : 'disable' ](); | ||
370 | |||
371 | // Now setup the field value manually if dialog was opened on element. (#9689) | ||
372 | setTimeout( function() { | ||
373 | dialog._element && stylesField.setup( dialog._element ); | ||
374 | }, 0 ); | ||
375 | } ); | ||
376 | }, | ||
377 | onShow: function() { | ||
378 | // Whether always create new container regardless of existed | ||
379 | // ones. | ||
380 | if ( command == 'editdiv' ) { | ||
381 | // Try to discover the containers that already existed in | ||
382 | // ranges | ||
383 | // update dialog field values | ||
384 | this.setupContent( this._element = CKEDITOR.plugins.div.getSurroundDiv( editor ) ); | ||
385 | } | ||
386 | }, | ||
387 | onOk: function() { | ||
388 | if ( command == 'editdiv' ) | ||
389 | containers = [ this._element ]; | ||
390 | else | ||
391 | containers = createDiv( editor, true ); | ||
392 | |||
393 | // Update elements attributes | ||
394 | var size = containers.length; | ||
395 | for ( var i = 0; i < size; i++ ) { | ||
396 | this.commitContent( containers[ i ] ); | ||
397 | |||
398 | // Remove empty 'style' attribute. | ||
399 | !containers[ i ].getAttribute( 'style' ) && containers[ i ].removeAttribute( 'style' ); | ||
400 | } | ||
401 | |||
402 | this.hide(); | ||
403 | }, | ||
404 | onHide: function() { | ||
405 | // Remove style only when editing existing DIV. (#6315) | ||
406 | if ( command == 'editdiv' ) | ||
407 | this._element.removeCustomData( 'elementStyle' ); | ||
408 | delete this._element; | ||
409 | } | ||
410 | }; | ||
411 | } | ||
412 | |||
413 | CKEDITOR.dialog.add( 'creatediv', function( editor ) { | ||
414 | return divDialog( editor, 'creatediv' ); | ||
415 | } ); | ||
416 | |||
417 | CKEDITOR.dialog.add( 'editdiv', function( editor ) { | ||
418 | return divDialog( editor, 'editdiv' ); | ||
419 | } ); | ||
420 | |||
421 | } )(); | ||
422 | |||
423 | /** | ||
424 | * Whether to wrap the entire table instead of individual cells when creating a `<div>` in a table cell. | ||
425 | * | ||
426 | * config.div_wrapTable = true; | ||
427 | * | ||
428 | * @cfg {Boolean} [div_wrapTable=false] | ||
429 | * @member CKEDITOR.config | ||
430 | */ | ||