]>
git.immae.eu Git - perso/Immae/Projets/packagist/piedsjaloux-ckeditor-component.git/blob - sources/plugins/indentblock/plugin.js
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
7 * @fileOverview Handles the indentation of block elements.
13 var $listItem
= CKEDITOR
.dtd
.$listItem
,
14 $list
= CKEDITOR
.dtd
.$list
,
15 TRISTATE_DISABLED
= CKEDITOR
.TRISTATE_DISABLED
,
16 TRISTATE_OFF
= CKEDITOR
.TRISTATE_OFF
;
18 CKEDITOR
.plugins
.add( 'indentblock', {
20 init: function( editor
) {
21 var globalHelpers
= CKEDITOR
.plugins
.indent
,
22 classes
= editor
.config
.indentClasses
;
25 globalHelpers
.registerCommands( editor
, {
26 indentblock: new commandDefinition( editor
, 'indentblock', true ),
27 outdentblock: new commandDefinition( editor
, 'outdentblock' )
30 function commandDefinition() {
31 globalHelpers
.specificDefinition
.apply( this, arguments
);
33 this.allowedContent
= {
34 'div h1 h2 h3 h4 h5 h6 ol p pre ul': {
35 // Do not add elements, but only text-align style if element is validated by other rule.
37 styles: !classes
? 'margin-left,margin-right' : null,
38 classes: classes
|| null
42 this.contentTransformations
= [
43 [ 'div: splitMarginShorthand' ],
44 [ 'h1: splitMarginShorthand' ],
45 [ 'h2: splitMarginShorthand' ],
46 [ 'h3: splitMarginShorthand' ],
47 [ 'h4: splitMarginShorthand' ],
48 [ 'h5: splitMarginShorthand' ],
49 [ 'h6: splitMarginShorthand' ],
50 [ 'ol: splitMarginShorthand' ],
51 [ 'p: splitMarginShorthand' ],
52 [ 'pre: splitMarginShorthand' ],
53 [ 'ul: splitMarginShorthand' ]
57 this.allowedContent
.div
= true;
59 this.requiredContent
= ( this.enterBr
? 'div' : 'p' ) +
60 ( classes
? '(' + classes
.join( ',' ) + ')' : '{margin-left}' );
64 refresh: function( editor
, path
) {
65 var firstBlock
= path
.block
|| path
.blockLimit
;
67 // Switch context from somewhere inside list item to list item,
68 // if not found just assign self (doing nothing).
69 if ( !firstBlock
.is( $listItem
) ) {
70 var ascendant
= firstBlock
.getAscendant( $listItem
);
72 firstBlock
= ( ascendant
&& path
.contains( ascendant
) ) || firstBlock
;
75 // Switch context from list item to list
76 // because indentblock can indent entire list
77 // but not a single list element.
79 if ( firstBlock
.is( $listItem
) )
80 firstBlock
= firstBlock
.getParent();
82 // [-] Context in the path or ENTER_BR
84 // Don't try to indent if the element is out of
85 // this plugin's scope. This assertion is omitted
86 // if ENTER_BR is in use since there may be no block
89 if ( !this.enterBr
&& !this.getContext( path
) )
90 return TRISTATE_DISABLED
;
94 // [+] Context in the path or ENTER_BR
97 // If there are indentation classes, check if reached
98 // the highest level of indentation. If so, disable
101 if ( indentClassLeft
.call( this, firstBlock
, classes
) )
104 return TRISTATE_DISABLED
;
107 // [+] Context in the path or ENTER_BR
111 // No indent-level limitations due to indent classes.
112 // Indent-like command can always be executed.
117 // [+] Context in the path or ENTER_BR
120 // [-] Block in the path
122 // No block in path. There's no element to apply indentation
123 // so disable the command.
125 else if ( !firstBlock
)
126 return TRISTATE_DISABLED
;
128 // [+] Context in the path or ENTER_BR
131 // [+] Block in path.
133 // Not using indentClasses but there is firstBlock.
134 // We can calculate current indentation level and
135 // try to increase/decrease it.
139 ( getIndent( firstBlock
) || 0 ) <= 0 ? 'TRISTATE_DISABLED' : 'TRISTATE_OFF'
145 exec: function( editor
) {
146 var selection
= editor
.getSelection(),
147 range
= selection
&& selection
.getRanges()[ 0 ],
150 // If there's some list in the path, then it will be
151 // a full-list indent by increasing or decreasing margin property.
152 if ( ( nearestListBlock
= editor
.elementPath().contains( $list
) ) )
153 indentElement
.call( this, nearestListBlock
, classes
);
155 // If no list in the path, use iterator to indent all the possible
156 // paragraphs in the range, creating them if necessary.
158 var iterator
= range
.createIterator(),
159 enterMode
= editor
.config
.enterMode
,
162 iterator
.enforceRealBlocks
= true;
163 iterator
.enlargeBr
= enterMode
!= CKEDITOR
.ENTER_BR
;
165 while ( ( block
= iterator
.getNextParagraph( enterMode
== CKEDITOR
.ENTER_P
? 'p' : 'div' ) ) ) {
166 if ( !block
.isReadOnly() )
167 indentElement
.call( this, block
, classes
);
177 CKEDITOR
.tools
.extend( commandDefinition
.prototype, globalHelpers
.specificDefinition
.prototype, {
178 // Elements that, if in an elementpath, will be handled by this
179 // command. They restrict the scope of the plugin.
180 context: { div: 1, dl: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, ul: 1, ol: 1, p: 1, pre: 1, table: 1 },
182 // A regex built on config#indentClasses to detect whether an
183 // element has some indentClass or not.
184 classNameRegex: classes
? new RegExp( '(?:^|\\s+)(' + classes
.join( '|' ) + ')(?=$|\\s)' ) : null
189 // Generic indentation procedure for indentation of any element
190 // either with margin property or config#indentClass.
191 function indentElement( element
, classes
, dir
) {
192 if ( element
.getCustomData( 'indent_processed' ) )
195 var editor
= this.editor
,
196 isIndent
= this.isIndent
;
199 // Transform current class f to indent step index.
200 var indentClass
= element
.$.className
.match( this.classNameRegex
),
204 indentClass
= indentClass
[ 1 ];
205 indentStep
= CKEDITOR
.tools
.indexOf( classes
, indentClass
) + 1;
208 // Operate on indent step index, transform indent step index
209 // back to class name.
210 if ( ( indentStep
+= isIndent
? 1 : -1 ) < 0 )
213 indentStep
= Math
.min( indentStep
, classes
.length
);
214 indentStep
= Math
.max( indentStep
, 0 );
215 element
.$.className
= CKEDITOR
.tools
.ltrim( element
.$.className
.replace( this.classNameRegex
, '' ) );
217 if ( indentStep
> 0 )
218 element
.addClass( classes
[ indentStep
- 1 ] );
220 var indentCssProperty
= getIndentCss( element
, dir
),
221 currentOffset
= parseInt( element
.getStyle( indentCssProperty
), 10 ),
222 indentOffset
= editor
.config
.indentOffset
|| 40;
224 if ( isNaN( currentOffset
) )
227 currentOffset
+= ( isIndent
? 1 : -1 ) * indentOffset
;
229 if ( currentOffset
< 0 )
232 currentOffset
= Math
.max( currentOffset
, 0 );
233 currentOffset
= Math
.ceil( currentOffset
/ indentOffset
) * indentOffset
;
237 currentOffset
? currentOffset
+ ( editor
.config
.indentUnit
|| 'px' ) : ''
240 if ( element
.getAttribute( 'style' ) === '' )
241 element
.removeAttribute( 'style' );
244 CKEDITOR
.dom
.element
.setMarker( this.database
, element
, 'indent_processed', 1 );
249 // Method that checks if current indentation level for an element
250 // reached the limit determined by config#indentClasses.
251 function indentClassLeft( node
, classes
) {
252 var indentClass
= node
.$.className
.match( this.classNameRegex
),
253 isIndent
= this.isIndent
;
255 // If node has one of the indentClasses:
256 // * If it holds the topmost indentClass, then
257 // no more classes have left.
258 // * If it holds any other indentClass, it can use the next one
259 // or the previous one.
260 // * Outdent is always possible. We can remove indentClass.
262 return isIndent
? indentClass
[ 1 ] != classes
.slice( -1 ) : true;
264 // If node has no class which belongs to indentClasses,
265 // then it is at 0-level. It can be indented but not outdented.
270 // Determines indent CSS property for an element according to
271 // what is the direction of such element. It can be either `margin-left`
272 // or `margin-right`.
273 function getIndentCss( element
, dir
) {
274 return ( dir
|| element
.getComputedStyle( 'direction' ) ) == 'ltr' ? 'margin-left' : 'margin-right';
277 // Return the numerical indent value of margin-left|right of an element,
278 // considering element's direction. If element has no margin specified,
280 function getIndent( element
) {
281 return parseInt( element
.getStyle( getIndentCss( element
) ), 10 );
286 * A list of classes to use for indenting the contents. If set to `null`, no classes will be used
287 * and instead the {@link #indentUnit} and {@link #indentOffset} properties will be used.
289 * // Use the 'Indent1', 'Indent2', 'Indent3' classes.
290 * config.indentClasses = ['Indent1', 'Indent2', 'Indent3'];
292 * @cfg {Array} [indentClasses=null]
293 * @member CKEDITOR.config
297 * The size in {@link CKEDITOR.config#indentUnit indentation units} of each indentation step.
299 * config.indentOffset = 4;
301 * @cfg {Number} [indentOffset=40]
302 * @member CKEDITOR.config
306 * The unit used for {@link CKEDITOR.config#indentOffset indentation offset}.
308 * config.indentUnit = 'em';
310 * @cfg {String} [indentUnit='px']
311 * @member CKEDITOR.config