]> git.immae.eu Git - perso/Immae/Projets/packagist/connexionswing-ckeditor-component.git/blob - sources/plugins/tabletools/dialogs/tableCell.js
Upgrade to 4.5.7 and add some plugin
[perso/Immae/Projets/packagist/connexionswing-ckeditor-component.git] / sources / plugins / tabletools / dialogs / tableCell.js
1 /**
2 * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6 CKEDITOR.dialog.add( 'cellProperties', function( editor ) {
7 var langTable = editor.lang.table,
8 langCell = langTable.cell,
9 langCommon = editor.lang.common,
10 validate = CKEDITOR.dialog.validate,
11 widthPattern = /^(\d+(?:\.\d+)?)(px|%)$/,
12 spacer = { type: 'html', html: ' ' },
13 rtl = editor.lang.dir == 'rtl',
14 colorDialog = editor.plugins.colordialog;
15
16 // Returns a function, which runs regular "setup" for all selected cells to find out
17 // whether the initial value of the field would be the same for all cells. If so,
18 // the value is displayed just as if a regular "setup" was executed. Otherwise,
19 // i.e. when there are several cells of different value of the property, a field
20 // gets empty value.
21 //
22 // * @param {Function} setup Setup function which returns a value instead of setting it.
23 // * @returns {Function} A function to be used in dialog definition.
24 function setupCells( setup ) {
25 return function( cells ) {
26 var fieldValue = setup( cells[ 0 ] );
27
28 // If one of the cells would have a different value of the
29 // property, set the empty value for a field.
30 for ( var i = 1; i < cells.length; i++ ) {
31 if ( setup( cells[ i ] ) !== fieldValue ) {
32 fieldValue = null;
33 break;
34 }
35 }
36
37 // Setting meaningful or empty value only makes sense
38 // when setup returns some value. Otherwise, a *default* value
39 // is used for that field.
40 if ( typeof fieldValue != 'undefined' ) {
41 this.setValue( fieldValue );
42
43 // The only way to have an empty select value in Firefox is
44 // to set a negative selectedIndex.
45 if ( CKEDITOR.env.gecko && this.type == 'select' && !fieldValue )
46 this.getInputElement().$.selectedIndex = -1;
47 }
48 };
49 }
50
51 // Reads the unit of width property of the table cell.
52 //
53 // * @param {CKEDITOR.dom.element} cell An element representing table cell.
54 // * @returns {String} A unit of width: 'px', '%' or undefined if none.
55 function getCellWidthType( cell ) {
56 var match = widthPattern.exec(
57 cell.getStyle( 'width' ) || cell.getAttribute( 'width' ) );
58
59 if ( match )
60 return match[ 2 ];
61 }
62
63 return {
64 title: langCell.title,
65 minWidth: CKEDITOR.env.ie && CKEDITOR.env.quirks ? 450 : 410,
66 minHeight: CKEDITOR.env.ie && ( CKEDITOR.env.ie7Compat || CKEDITOR.env.quirks ) ? 230 : 220,
67 contents: [ {
68 id: 'info',
69 label: langCell.title,
70 accessKey: 'I',
71 elements: [ {
72 type: 'hbox',
73 widths: [ '40%', '5%', '40%' ],
74 children: [ {
75 type: 'vbox',
76 padding: 0,
77 children: [ {
78 type: 'hbox',
79 widths: [ '70%', '30%' ],
80 children: [ {
81 type: 'text',
82 id: 'width',
83 width: '100px',
84 label: langCommon.width,
85 validate: validate.number( langCell.invalidWidth ),
86
87 // Extra labelling of width unit type.
88 onLoad: function() {
89 var widthType = this.getDialog().getContentElement( 'info', 'widthType' ),
90 labelElement = widthType.getElement(),
91 inputElement = this.getInputElement(),
92 ariaLabelledByAttr = inputElement.getAttribute( 'aria-labelledby' );
93
94 inputElement.setAttribute( 'aria-labelledby', [ ariaLabelledByAttr, labelElement.$.id ].join( ' ' ) );
95 },
96
97 setup: setupCells( function( element ) {
98 var widthAttr = parseInt( element.getAttribute( 'width' ), 10 ),
99 widthStyle = parseInt( element.getStyle( 'width' ), 10 );
100
101 return !isNaN( widthStyle ) ? widthStyle :
102 !isNaN( widthAttr ) ? widthAttr : '';
103 } ),
104 commit: function( element ) {
105 var value = parseInt( this.getValue(), 10 ),
106
107 // There might be no widthType value, i.e. when multiple cells are
108 // selected but some of them have width expressed in pixels and some
109 // of them in percent. Try to re-read the unit from the cell in such
110 // case (#11439).
111 unit = this.getDialog().getValueOf( 'info', 'widthType' ) || getCellWidthType( element );
112
113 if ( !isNaN( value ) )
114 element.setStyle( 'width', value + unit );
115 else
116 element.removeStyle( 'width' );
117
118 element.removeAttribute( 'width' );
119 },
120 'default': ''
121 },
122 {
123 type: 'select',
124 id: 'widthType',
125 label: editor.lang.table.widthUnit,
126 labelStyle: 'visibility:hidden',
127 'default': 'px',
128 items: [
129 [ langTable.widthPx, 'px' ],
130 [ langTable.widthPc, '%' ]
131 ],
132 setup: setupCells( getCellWidthType )
133 } ]
134 },
135 {
136 type: 'hbox',
137 widths: [ '70%', '30%' ],
138 children: [ {
139 type: 'text',
140 id: 'height',
141 label: langCommon.height,
142 width: '100px',
143 'default': '',
144 validate: validate.number( langCell.invalidHeight ),
145
146 // Extra labelling of height unit type.
147 onLoad: function() {
148 var heightType = this.getDialog().getContentElement( 'info', 'htmlHeightType' ),
149 labelElement = heightType.getElement(),
150 inputElement = this.getInputElement(),
151 ariaLabelledByAttr = inputElement.getAttribute( 'aria-labelledby' );
152
153 inputElement.setAttribute( 'aria-labelledby', [ ariaLabelledByAttr, labelElement.$.id ].join( ' ' ) );
154 },
155
156 setup: setupCells( function( element ) {
157 var heightAttr = parseInt( element.getAttribute( 'height' ), 10 ),
158 heightStyle = parseInt( element.getStyle( 'height' ), 10 );
159
160 return !isNaN( heightStyle ) ? heightStyle :
161 !isNaN( heightAttr ) ? heightAttr : '';
162 } ),
163 commit: function( element ) {
164 var value = parseInt( this.getValue(), 10 );
165
166 if ( !isNaN( value ) )
167 element.setStyle( 'height', CKEDITOR.tools.cssLength( value ) );
168 else
169 element.removeStyle( 'height' );
170
171 element.removeAttribute( 'height' );
172 }
173 },
174 {
175 id: 'htmlHeightType',
176 type: 'html',
177 html: '<br />' + langTable.widthPx
178 } ]
179 },
180 spacer,
181 {
182 type: 'select',
183 id: 'wordWrap',
184 label: langCell.wordWrap,
185 'default': 'yes',
186 items: [
187 [ langCell.yes, 'yes' ],
188 [ langCell.no, 'no' ]
189 ],
190 setup: setupCells( function( element ) {
191 var wordWrapAttr = element.getAttribute( 'noWrap' ),
192 wordWrapStyle = element.getStyle( 'white-space' );
193
194 if ( wordWrapStyle == 'nowrap' || wordWrapAttr )
195 return 'no';
196 } ),
197 commit: function( element ) {
198 if ( this.getValue() == 'no' )
199 element.setStyle( 'white-space', 'nowrap' );
200 else
201 element.removeStyle( 'white-space' );
202
203 element.removeAttribute( 'noWrap' );
204 }
205 },
206 spacer,
207 {
208 type: 'select',
209 id: 'hAlign',
210 label: langCell.hAlign,
211 'default': '',
212 items: [
213 [ langCommon.notSet, '' ],
214 [ langCommon.alignLeft, 'left' ],
215 [ langCommon.alignCenter, 'center' ],
216 [ langCommon.alignRight, 'right' ],
217 [ langCommon.alignJustify, 'justify' ]
218 ],
219 setup: setupCells( function( element ) {
220 var alignAttr = element.getAttribute( 'align' ),
221 textAlignStyle = element.getStyle( 'text-align' );
222
223 return textAlignStyle || alignAttr || '';
224 } ),
225 commit: function( selectedCell ) {
226 var value = this.getValue();
227
228 if ( value )
229 selectedCell.setStyle( 'text-align', value );
230 else
231 selectedCell.removeStyle( 'text-align' );
232
233 selectedCell.removeAttribute( 'align' );
234 }
235 },
236 {
237 type: 'select',
238 id: 'vAlign',
239 label: langCell.vAlign,
240 'default': '',
241 items: [
242 [ langCommon.notSet, '' ],
243 [ langCommon.alignTop, 'top' ],
244 [ langCommon.alignMiddle, 'middle' ],
245 [ langCommon.alignBottom, 'bottom' ],
246 [ langCell.alignBaseline, 'baseline' ]
247 ],
248 setup: setupCells( function( element ) {
249 var vAlignAttr = element.getAttribute( 'vAlign' ),
250 vAlignStyle = element.getStyle( 'vertical-align' );
251
252 switch ( vAlignStyle ) {
253 // Ignore all other unrelated style values..
254 case 'top':
255 case 'middle':
256 case 'bottom':
257 case 'baseline':
258 break;
259 default:
260 vAlignStyle = '';
261 }
262
263 return vAlignStyle || vAlignAttr || '';
264 } ),
265 commit: function( element ) {
266 var value = this.getValue();
267
268 if ( value )
269 element.setStyle( 'vertical-align', value );
270 else
271 element.removeStyle( 'vertical-align' );
272
273 element.removeAttribute( 'vAlign' );
274 }
275 } ]
276 },
277 spacer,
278 {
279 type: 'vbox',
280 padding: 0,
281 children: [ {
282 type: 'select',
283 id: 'cellType',
284 label: langCell.cellType,
285 'default': 'td',
286 items: [
287 [ langCell.data, 'td' ],
288 [ langCell.header, 'th' ]
289 ],
290 setup: setupCells( function( selectedCell ) {
291 return selectedCell.getName();
292 } ),
293 commit: function( selectedCell ) {
294 selectedCell.renameNode( this.getValue() );
295 }
296 },
297 spacer,
298 {
299 type: 'text',
300 id: 'rowSpan',
301 label: langCell.rowSpan,
302 'default': '',
303 validate: validate.integer( langCell.invalidRowSpan ),
304 setup: setupCells( function( selectedCell ) {
305 var attrVal = parseInt( selectedCell.getAttribute( 'rowSpan' ), 10 );
306 if ( attrVal && attrVal != 1 )
307 return attrVal;
308 } ),
309 commit: function( selectedCell ) {
310 var value = parseInt( this.getValue(), 10 );
311 if ( value && value != 1 )
312 selectedCell.setAttribute( 'rowSpan', this.getValue() );
313 else
314 selectedCell.removeAttribute( 'rowSpan' );
315 }
316 },
317 {
318 type: 'text',
319 id: 'colSpan',
320 label: langCell.colSpan,
321 'default': '',
322 validate: validate.integer( langCell.invalidColSpan ),
323 setup: setupCells( function( element ) {
324 var attrVal = parseInt( element.getAttribute( 'colSpan' ), 10 );
325 if ( attrVal && attrVal != 1 )
326 return attrVal;
327 } ),
328 commit: function( selectedCell ) {
329 var value = parseInt( this.getValue(), 10 );
330 if ( value && value != 1 )
331 selectedCell.setAttribute( 'colSpan', this.getValue() );
332 else
333 selectedCell.removeAttribute( 'colSpan' );
334 }
335 },
336 spacer,
337 {
338 type: 'hbox',
339 padding: 0,
340 widths: [ '60%', '40%' ],
341 children: [ {
342 type: 'text',
343 id: 'bgColor',
344 label: langCell.bgColor,
345 'default': '',
346 setup: setupCells( function( element ) {
347 var bgColorAttr = element.getAttribute( 'bgColor' ),
348 bgColorStyle = element.getStyle( 'background-color' );
349
350 return bgColorStyle || bgColorAttr;
351 } ),
352 commit: function( selectedCell ) {
353 var value = this.getValue();
354
355 if ( value )
356 selectedCell.setStyle( 'background-color', this.getValue() );
357 else
358 selectedCell.removeStyle( 'background-color' );
359
360 selectedCell.removeAttribute( 'bgColor' );
361 }
362 },
363 colorDialog ? {
364 type: 'button',
365 id: 'bgColorChoose',
366 'class': 'colorChooser', // jshint ignore:line
367 label: langCell.chooseColor,
368 onLoad: function() {
369 // Stick the element to the bottom (#5587)
370 this.getElement().getParent().setStyle( 'vertical-align', 'bottom' );
371 },
372 onClick: function() {
373 editor.getColorFromDialog( function( color ) {
374 if ( color )
375 this.getDialog().getContentElement( 'info', 'bgColor' ).setValue( color );
376 this.focus();
377 }, this );
378 }
379 } : spacer ]
380 },
381 spacer,
382 {
383 type: 'hbox',
384 padding: 0,
385 widths: [ '60%', '40%' ],
386 children: [ {
387 type: 'text',
388 id: 'borderColor',
389 label: langCell.borderColor,
390 'default': '',
391 setup: setupCells( function( element ) {
392 var borderColorAttr = element.getAttribute( 'borderColor' ),
393 borderColorStyle = element.getStyle( 'border-color' );
394
395 return borderColorStyle || borderColorAttr;
396 } ),
397 commit: function( selectedCell ) {
398 var value = this.getValue();
399 if ( value )
400 selectedCell.setStyle( 'border-color', this.getValue() );
401 else
402 selectedCell.removeStyle( 'border-color' );
403
404 selectedCell.removeAttribute( 'borderColor' );
405 }
406 },
407
408 colorDialog ? {
409 type: 'button',
410 id: 'borderColorChoose',
411 'class': 'colorChooser', // jshint ignore:line
412 label: langCell.chooseColor,
413 style: ( rtl ? 'margin-right' : 'margin-left' ) + ': 10px',
414 onLoad: function() {
415 // Stick the element to the bottom (#5587)
416 this.getElement().getParent().setStyle( 'vertical-align', 'bottom' );
417 },
418 onClick: function() {
419 editor.getColorFromDialog( function( color ) {
420 if ( color )
421 this.getDialog().getContentElement( 'info', 'borderColor' ).setValue( color );
422 this.focus();
423 }, this );
424 }
425 } : spacer ]
426 } ]
427 } ]
428 } ]
429 } ],
430 onShow: function() {
431 this.cells = CKEDITOR.plugins.tabletools.getSelectedCells( this._.editor.getSelection() );
432 this.setupContent( this.cells );
433 },
434 onOk: function() {
435 var selection = this._.editor.getSelection(),
436 bookmarks = selection.createBookmarks();
437
438 var cells = this.cells;
439 for ( var i = 0; i < cells.length; i++ )
440 this.commitContent( cells[ i ] );
441
442 this._.editor.forceNextSelectionCheck();
443 selection.selectBookmarks( bookmarks );
444 this._.editor.selectionChange();
445 },
446 onLoad: function() {
447 var saved = {};
448
449 // Prevent from changing cell properties when the field's value
450 // remains unaltered, i.e. when selected multiple cells and dialog loaded
451 // only the properties of the first cell (#11439).
452 this.foreach( function( field ) {
453 if ( !field.setup || !field.commit )
454 return;
455
456 // Save field's value every time after "setup" is called.
457 field.setup = CKEDITOR.tools.override( field.setup, function( orgSetup ) {
458 return function() {
459 orgSetup.apply( this, arguments );
460 saved[ field.id ] = field.getValue();
461 };
462 } );
463
464 // Compare saved value with actual value. Update cell only if value has changed.
465 field.commit = CKEDITOR.tools.override( field.commit, function( orgCommit ) {
466 return function() {
467 if ( saved[ field.id ] !== field.getValue() )
468 orgCommit.apply( this, arguments );
469 };
470 } );
471 } );
472 }
473 };
474 } );