]> git.immae.eu Git - perso/Immae/Projets/packagist/ludivine-ckeditor-component.git/blame - sources/plugins/indentblock/plugin.js
Validation initiale
[perso/Immae/Projets/packagist/ludivine-ckeditor-component.git] / sources / plugins / indentblock / plugin.js
CommitLineData
c63493c8
IB
1/**\r
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.\r
3 * For licensing, see LICENSE.md or http://ckeditor.com/license\r
4 */\r
5\r
6/**\r
7 * @fileOverview Handles the indentation of block elements.\r
8 */\r
9\r
10( function() {\r
11 'use strict';\r
12\r
13 var $listItem = CKEDITOR.dtd.$listItem,\r
14 $list = CKEDITOR.dtd.$list,\r
15 TRISTATE_DISABLED = CKEDITOR.TRISTATE_DISABLED,\r
16 TRISTATE_OFF = CKEDITOR.TRISTATE_OFF;\r
17\r
18 CKEDITOR.plugins.add( 'indentblock', {\r
19 requires: 'indent',\r
20 init: function( editor ) {\r
21 var globalHelpers = CKEDITOR.plugins.indent,\r
22 classes = editor.config.indentClasses;\r
23\r
24 // Register commands.\r
25 globalHelpers.registerCommands( editor, {\r
26 indentblock: new commandDefinition( editor, 'indentblock', true ),\r
27 outdentblock: new commandDefinition( editor, 'outdentblock' )\r
28 } );\r
29\r
30 function commandDefinition() {\r
31 globalHelpers.specificDefinition.apply( this, arguments );\r
32\r
33 this.allowedContent = {\r
34 'div h1 h2 h3 h4 h5 h6 ol p pre ul': {\r
35 // Do not add elements, but only text-align style if element is validated by other rule.\r
36 propertiesOnly: true,\r
37 styles: !classes ? 'margin-left,margin-right' : null,\r
38 classes: classes || null\r
39 }\r
40 };\r
41\r
42 this.contentTransformations = [\r
43 [ 'div: splitMarginShorthand' ],\r
44 [ 'h1: splitMarginShorthand' ],\r
45 [ 'h2: splitMarginShorthand' ],\r
46 [ 'h3: splitMarginShorthand' ],\r
47 [ 'h4: splitMarginShorthand' ],\r
48 [ 'h5: splitMarginShorthand' ],\r
49 [ 'h6: splitMarginShorthand' ],\r
50 [ 'ol: splitMarginShorthand' ],\r
51 [ 'p: splitMarginShorthand' ],\r
52 [ 'pre: splitMarginShorthand' ],\r
53 [ 'ul: splitMarginShorthand' ]\r
54 ];\r
55\r
56 if ( this.enterBr )\r
57 this.allowedContent.div = true;\r
58\r
59 this.requiredContent = ( this.enterBr ? 'div' : 'p' ) +\r
60 ( classes ? '(' + classes.join( ',' ) + ')' : '{margin-left}' );\r
61\r
62 this.jobs = {\r
63 '20': {\r
64 refresh: function( editor, path ) {\r
65 var firstBlock = path.block || path.blockLimit;\r
66\r
67 // Switch context from somewhere inside list item to list item,\r
68 // if not found just assign self (doing nothing).\r
69 if ( !firstBlock.is( $listItem ) ) {\r
70 var ascendant = firstBlock.getAscendant( $listItem );\r
71\r
72 firstBlock = ( ascendant && path.contains( ascendant ) ) || firstBlock;\r
73 }\r
74\r
75 // Switch context from list item to list\r
76 // because indentblock can indent entire list\r
77 // but not a single list element.\r
78\r
79 if ( firstBlock.is( $listItem ) )\r
80 firstBlock = firstBlock.getParent();\r
81\r
82 // [-] Context in the path or ENTER_BR\r
83 //\r
84 // Don't try to indent if the element is out of\r
85 // this plugin's scope. This assertion is omitted\r
86 // if ENTER_BR is in use since there may be no block\r
87 // in the path.\r
88\r
89 if ( !this.enterBr && !this.getContext( path ) )\r
90 return TRISTATE_DISABLED;\r
91\r
92 else if ( classes ) {\r
93\r
94 // [+] Context in the path or ENTER_BR\r
95 // [+] IndentClasses\r
96 //\r
97 // If there are indentation classes, check if reached\r
98 // the highest level of indentation. If so, disable\r
99 // the command.\r
100\r
101 if ( indentClassLeft.call( this, firstBlock, classes ) )\r
102 return TRISTATE_OFF;\r
103 else\r
104 return TRISTATE_DISABLED;\r
105 } else {\r
106\r
107 // [+] Context in the path or ENTER_BR\r
108 // [-] IndentClasses\r
109 // [+] Indenting\r
110 //\r
111 // No indent-level limitations due to indent classes.\r
112 // Indent-like command can always be executed.\r
113\r
114 if ( this.isIndent )\r
115 return TRISTATE_OFF;\r
116\r
117 // [+] Context in the path or ENTER_BR\r
118 // [-] IndentClasses\r
119 // [-] Indenting\r
120 // [-] Block in the path\r
121 //\r
122 // No block in path. There's no element to apply indentation\r
123 // so disable the command.\r
124\r
125 else if ( !firstBlock )\r
126 return TRISTATE_DISABLED;\r
127\r
128 // [+] Context in the path or ENTER_BR\r
129 // [-] IndentClasses\r
130 // [-] Indenting\r
131 // [+] Block in path.\r
132 //\r
133 // Not using indentClasses but there is firstBlock.\r
134 // We can calculate current indentation level and\r
135 // try to increase/decrease it.\r
136\r
137 else {\r
138 return CKEDITOR[\r
139 ( getIndent( firstBlock ) || 0 ) <= 0 ? 'TRISTATE_DISABLED' : 'TRISTATE_OFF'\r
140 ];\r
141 }\r
142 }\r
143 },\r
144\r
145 exec: function( editor ) {\r
146 var selection = editor.getSelection(),\r
147 range = selection && selection.getRanges()[ 0 ],\r
148 nearestListBlock;\r
149\r
150 // If there's some list in the path, then it will be\r
151 // a full-list indent by increasing or decreasing margin property.\r
152 if ( ( nearestListBlock = editor.elementPath().contains( $list ) ) )\r
153 indentElement.call( this, nearestListBlock, classes );\r
154\r
155 // If no list in the path, use iterator to indent all the possible\r
156 // paragraphs in the range, creating them if necessary.\r
157 else {\r
158 var iterator = range.createIterator(),\r
159 enterMode = editor.config.enterMode,\r
160 block;\r
161\r
162 iterator.enforceRealBlocks = true;\r
163 iterator.enlargeBr = enterMode != CKEDITOR.ENTER_BR;\r
164\r
165 while ( ( block = iterator.getNextParagraph( enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ) ) ) {\r
166 if ( !block.isReadOnly() )\r
167 indentElement.call( this, block, classes );\r
168 }\r
169 }\r
170\r
171 return true;\r
172 }\r
173 }\r
174 };\r
175 }\r
176\r
177 CKEDITOR.tools.extend( commandDefinition.prototype, globalHelpers.specificDefinition.prototype, {\r
178 // Elements that, if in an elementpath, will be handled by this\r
179 // command. They restrict the scope of the plugin.\r
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 },\r
181\r
182 // A regex built on config#indentClasses to detect whether an\r
183 // element has some indentClass or not.\r
184 classNameRegex: classes ? new RegExp( '(?:^|\\s+)(' + classes.join( '|' ) + ')(?=$|\\s)' ) : null\r
185 } );\r
186 }\r
187 } );\r
188\r
189 // Generic indentation procedure for indentation of any element\r
190 // either with margin property or config#indentClass.\r
191 function indentElement( element, classes, dir ) {\r
192 if ( element.getCustomData( 'indent_processed' ) )\r
193 return;\r
194\r
195 var editor = this.editor,\r
196 isIndent = this.isIndent;\r
197\r
198 if ( classes ) {\r
199 // Transform current class f to indent step index.\r
200 var indentClass = element.$.className.match( this.classNameRegex ),\r
201 indentStep = 0;\r
202\r
203 if ( indentClass ) {\r
204 indentClass = indentClass[ 1 ];\r
205 indentStep = CKEDITOR.tools.indexOf( classes, indentClass ) + 1;\r
206 }\r
207\r
208 // Operate on indent step index, transform indent step index\r
209 // back to class name.\r
210 if ( ( indentStep += isIndent ? 1 : -1 ) < 0 )\r
211 return;\r
212\r
213 indentStep = Math.min( indentStep, classes.length );\r
214 indentStep = Math.max( indentStep, 0 );\r
215 element.$.className = CKEDITOR.tools.ltrim( element.$.className.replace( this.classNameRegex, '' ) );\r
216\r
217 if ( indentStep > 0 )\r
218 element.addClass( classes[ indentStep - 1 ] );\r
219 } else {\r
220 var indentCssProperty = getIndentCss( element, dir ),\r
221 currentOffset = parseInt( element.getStyle( indentCssProperty ), 10 ),\r
222 indentOffset = editor.config.indentOffset || 40;\r
223\r
224 if ( isNaN( currentOffset ) )\r
225 currentOffset = 0;\r
226\r
227 currentOffset += ( isIndent ? 1 : -1 ) * indentOffset;\r
228\r
229 if ( currentOffset < 0 )\r
230 return;\r
231\r
232 currentOffset = Math.max( currentOffset, 0 );\r
233 currentOffset = Math.ceil( currentOffset / indentOffset ) * indentOffset;\r
234\r
235 element.setStyle(\r
236 indentCssProperty,\r
237 currentOffset ? currentOffset + ( editor.config.indentUnit || 'px' ) : ''\r
238 );\r
239\r
240 if ( element.getAttribute( 'style' ) === '' )\r
241 element.removeAttribute( 'style' );\r
242 }\r
243\r
244 CKEDITOR.dom.element.setMarker( this.database, element, 'indent_processed', 1 );\r
245\r
246 return;\r
247 }\r
248\r
249 // Method that checks if current indentation level for an element\r
250 // reached the limit determined by config#indentClasses.\r
251 function indentClassLeft( node, classes ) {\r
252 var indentClass = node.$.className.match( this.classNameRegex ),\r
253 isIndent = this.isIndent;\r
254\r
255 // If node has one of the indentClasses:\r
256 // * If it holds the topmost indentClass, then\r
257 // no more classes have left.\r
258 // * If it holds any other indentClass, it can use the next one\r
259 // or the previous one.\r
260 // * Outdent is always possible. We can remove indentClass.\r
261 if ( indentClass )\r
262 return isIndent ? indentClass[ 1 ] != classes.slice( -1 ) : true;\r
263\r
264 // If node has no class which belongs to indentClasses,\r
265 // then it is at 0-level. It can be indented but not outdented.\r
266 else\r
267 return isIndent;\r
268 }\r
269\r
270 // Determines indent CSS property for an element according to\r
271 // what is the direction of such element. It can be either `margin-left`\r
272 // or `margin-right`.\r
273 function getIndentCss( element, dir ) {\r
274 return ( dir || element.getComputedStyle( 'direction' ) ) == 'ltr' ? 'margin-left' : 'margin-right';\r
275 }\r
276\r
277 // Return the numerical indent value of margin-left|right of an element,\r
278 // considering element's direction. If element has no margin specified,\r
279 // NaN is returned.\r
280 function getIndent( element ) {\r
281 return parseInt( element.getStyle( getIndentCss( element ) ), 10 );\r
282 }\r
283} )();\r
284\r
285/**\r
286 * A list of classes to use for indenting the contents. If set to `null`, no classes will be used\r
287 * and instead the {@link #indentUnit} and {@link #indentOffset} properties will be used.\r
288 *\r
289 * // Use the 'Indent1', 'Indent2', 'Indent3' classes.\r
290 * config.indentClasses = ['Indent1', 'Indent2', 'Indent3'];\r
291 *\r
292 * @cfg {Array} [indentClasses=null]\r
293 * @member CKEDITOR.config\r
294 */\r
295\r
296/**\r
297 * The size in {@link CKEDITOR.config#indentUnit indentation units} of each indentation step.\r
298 *\r
299 * config.indentOffset = 4;\r
300 *\r
301 * @cfg {Number} [indentOffset=40]\r
302 * @member CKEDITOR.config\r
303 */\r
304\r
305/**\r
306 * The unit used for {@link CKEDITOR.config#indentOffset indentation offset}.\r
307 *\r
308 * config.indentUnit = 'em';\r
309 *\r
310 * @cfg {String} [indentUnit='px']\r
311 * @member CKEDITOR.config\r
312 */\r