]>
git.immae.eu Git - perso/Immae/Projets/packagist/connexionswing-ckeditor-component.git/blob - sources/plugins/div/dialogs/div.js
2 * Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
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
);
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() {
28 // Customzie from specialize blockLimit elements
29 var definition
= CKEDITOR
.tools
.extend( {}, CKEDITOR
.dtd
.$blockLimit
);
31 if ( editor
.config
.div_wrapTable
) {
38 // DTD of 'div' element
39 var dtd
= CKEDITOR
.dtd
.div
;
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
;
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();
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
;
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
) ) {
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 );
73 if ( !field
.commit
) {
74 // Set element attributes assigned by the dialog
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
) {
84 element
.setAttribute( field
.id
, fieldValue
);
86 element
.removeAttribute( field
.id
);
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.
98 // node markers store.
100 // All block level elements which contained by the ranges.
101 var containedBlocks
= [],
104 // Get all ranges from the selection.
105 var selection
= editor
.getSelection(),
106 ranges
= selection
.getRanges();
107 var bookmarks
= selection
.createBookmarks();
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() ) {
117 childNodes
= block
.getChildren();
118 for ( j
= 0; j
< childNodes
.count(); j
++ )
119 addSafely( containedBlocks
, childNodes
.getItem( j
), database
);
121 while ( !dtd
[ block
.getName() ] && !block
.equals( ranges
[ i
].root
) )
122 block
= block
.getParent();
123 addSafely( containedBlocks
, block
, database
);
128 CKEDITOR
.dom
.element
.clearAllMarkers( database
);
130 var blockGroups
= groupByDivLimit( containedBlocks
);
131 var ancestor
, divElement
;
133 for ( i
= 0; i
< blockGroups
.length
; i
++ ) {
134 var currentNode
= blockGroups
[ i
][ 0 ];
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
] );
141 divElement
= new CKEDITOR
.dom
.element( 'div', editor
.document
);
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
];
147 while ( !currentNode
.getParent().equals( ancestor
) )
148 currentNode
= currentNode
.getParent();
150 // This could introduce some duplicated elements in array.
151 blockGroups
[ i
][ j
] = currentNode
;
154 // Wrapped blocks counting
155 for ( j
= 0; j
< blockGroups
[ i
].length
; j
++ ) {
156 currentNode
= blockGroups
[ i
][ j
];
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 );
162 // Establish new container, wrapping all elements in this group.
164 divElement
.insertBefore( currentNode
);
166 divElement
.append( currentNode
);
170 CKEDITOR
.dom
.element
.clearAllMarkers( database
);
171 containers
.push( divElement
);
174 selection
.selectBookmarks( bookmarks
);
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
) {
188 for ( var i
= 0; i
< nodes
.length
; i
++ ) {
190 var limit
= getDivContainer( block
);
191 if ( !limit
.equals( lastDivLimit
) ) {
192 lastDivLimit
= limit
;
195 groups
[ groups
.length
- 1 ].push( block
);
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
);
206 // Commit this field and broadcast to target fields.
207 this.commit( element
, true );
209 targetFields
= [].concat( targetFields
);
210 var length
= targetFields
.length
,
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 );
219 // Registered 'CKEDITOR.style' instances.
222 // Hold a collection of created block container elements.
227 title: editor
.lang
.div
.title
,
232 label: editor
.lang
.common
.generalTab
,
233 title: editor
.lang
.common
.generalTab
,
236 widths: [ '50%', '50%' ],
240 style: 'width: 100%;',
241 label: editor
.lang
.div
.styleSelectLabel
,
243 // Options are loaded dynamically.
245 [ editor
.lang
.common
.notSet
, '' ]
247 onChange: function() {
248 commitInternally
.call( this, [ 'info:elementStyle', 'info:class', 'advanced:dir', 'advanced:style' ] );
250 setup: function( element
) {
251 for ( var name
in styles
)
252 styles
[ name
].checkElementRemovable( element
, true, editor
) && this.setValue( name
, 1 );
254 commit: function( element
) {
256 if ( ( styleName
= this.getValue() ) ) {
257 var style
= styles
[ styleName
];
258 style
.applyToObject( element
, editor
);
261 element
.removeAttribute( 'style' );
268 requiredContent: 'div(cke-xyz)', // Random text like 'xyz' will check if all are allowed.
269 label: editor
.lang
.common
.cssClass
,
276 label: editor
.lang
.common
.advancedTab
,
277 title: editor
.lang
.common
.advancedTab
,
283 widths: [ '50%', '50%' ],
287 requiredContent: 'div[id]',
288 label: editor
.lang
.common
.id
,
294 requiredContent: 'div[lang]',
295 label: editor
.lang
.common
.langCode
,
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
,
308 commit: function( element
) {
309 element
.setAttribute( 'style', this.getValue() );
318 requiredContent: 'div[title]',
319 style: 'width: 100%;',
320 label: editor
.lang
.common
.advisoryTitle
,
327 requiredContent: 'div[dir]',
328 style: 'width: 100%;',
329 label: editor
.lang
.common
.langDir
,
332 [ editor
.lang
.common
.notSet
, '' ],
333 [ editor
.lang
.common
.langDirLtr
, 'ltr' ],
334 [ editor
.lang
.common
.langDirRtl
, 'rtl' ]
340 setupFields
.call( this );
342 // Preparing for the 'elementStyle' field.
344 stylesField
= this.getContentElement( 'info', 'elementStyle' );
346 // Reuse the 'stylescombo' plugin's styles definition.
347 editor
.getStylesSet( function( stylesDefinitions
) {
348 var styleName
, style
;
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
);
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
);
367 // We should disable the content element
368 // it if no options are available at all.
369 stylesField
[ stylesField
.items
.length
> 1 ? 'enable' : 'disable' ]();
371 // Now setup the field value manually if dialog was opened on element. (#9689)
372 setTimeout( function() {
373 dialog
._element
&& stylesField
.setup( dialog
._element
);
378 // Whether always create new container regardless of existed
380 if ( command
== 'editdiv' ) {
381 // Try to discover the containers that already existed in
383 // update dialog field values
384 this.setupContent( this._element
= CKEDITOR
.plugins
.div
.getSurroundDiv( editor
) );
388 if ( command
== 'editdiv' )
389 containers
= [ this._element
];
391 containers
= createDiv( editor
, true );
393 // Update elements attributes
394 var size
= containers
.length
;
395 for ( var i
= 0; i
< size
; i
++ ) {
396 this.commitContent( containers
[ i
] );
398 // Remove empty 'style' attribute.
399 !containers
[ i
].getAttribute( 'style' ) && containers
[ i
].removeAttribute( 'style' );
405 // Remove style only when editing existing DIV. (#6315)
406 if ( command
== 'editdiv' )
407 this._element
.removeCustomData( 'elementStyle' );
408 delete this._element
;
413 CKEDITOR
.dialog
.add( 'creatediv', function( editor
) {
414 return divDialog( editor
, 'creatediv' );
417 CKEDITOR
.dialog
.add( 'editdiv', function( editor
) {
418 return divDialog( editor
, 'editdiv' );
424 * Whether to wrap the entire table instead of individual cells when creating a `<div>` in a table cell.
426 * config.div_wrapTable = true;
428 * @cfg {Boolean} [div_wrapTable=false]
429 * @member CKEDITOR.config