]> git.immae.eu Git - perso/Immae/Projets/packagist/connexionswing-ckeditor-component.git/blob - sources/plugins/table/dialogs/table.js
Upgrade to 4.5.7 and add some plugin
[perso/Immae/Projets/packagist/connexionswing-ckeditor-component.git] / sources / plugins / table / dialogs / table.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 ( function() {
7 var defaultToPixel = CKEDITOR.tools.cssLength;
8
9 var commitValue = function( data ) {
10 var id = this.id;
11 if ( !data.info )
12 data.info = {};
13 data.info[ id ] = this.getValue();
14 };
15
16 function tableColumns( table ) {
17 var cols = 0,
18 maxCols = 0;
19 for ( var i = 0, row, rows = table.$.rows.length; i < rows; i++ ) {
20 row = table.$.rows[ i ], cols = 0;
21 for ( var j = 0, cell, cells = row.cells.length; j < cells; j++ ) {
22 cell = row.cells[ j ];
23 cols += cell.colSpan;
24 }
25
26 cols > maxCols && ( maxCols = cols );
27 }
28
29 return maxCols;
30 }
31
32
33 // Whole-positive-integer validator.
34 function validatorNum( msg ) {
35 return function() {
36 var value = this.getValue(),
37 pass = !!( CKEDITOR.dialog.validate.integer()( value ) && value > 0 );
38
39 if ( !pass ) {
40 alert( msg ); // jshint ignore:line
41 this.select();
42 }
43
44 return pass;
45 };
46 }
47
48 function tableDialog( editor, command ) {
49 var makeElement = function( name ) {
50 return new CKEDITOR.dom.element( name, editor.document );
51 };
52
53 var editable = editor.editable();
54
55 var dialogadvtab = editor.plugins.dialogadvtab;
56
57 return {
58 title: editor.lang.table.title,
59 minWidth: 310,
60 minHeight: CKEDITOR.env.ie ? 310 : 280,
61
62 onLoad: function() {
63 var dialog = this;
64
65 var styles = dialog.getContentElement( 'advanced', 'advStyles' );
66
67 if ( styles ) {
68 styles.on( 'change', function() {
69 // Synchronize width value.
70 var width = this.getStyle( 'width', '' ),
71 txtWidth = dialog.getContentElement( 'info', 'txtWidth' );
72
73 txtWidth && txtWidth.setValue( width, true );
74
75 // Synchronize height value.
76 var height = this.getStyle( 'height', '' ),
77 txtHeight = dialog.getContentElement( 'info', 'txtHeight' );
78
79 txtHeight && txtHeight.setValue( height, true );
80 } );
81 }
82 },
83
84 onShow: function() {
85 // Detect if there's a selected table.
86 var selection = editor.getSelection(),
87 ranges = selection.getRanges(),
88 table;
89
90 var rowsInput = this.getContentElement( 'info', 'txtRows' ),
91 colsInput = this.getContentElement( 'info', 'txtCols' ),
92 widthInput = this.getContentElement( 'info', 'txtWidth' ),
93 heightInput = this.getContentElement( 'info', 'txtHeight' );
94
95 if ( command == 'tableProperties' ) {
96 var selected = selection.getSelectedElement();
97 if ( selected && selected.is( 'table' ) )
98 table = selected;
99 else if ( ranges.length > 0 ) {
100 // Webkit could report the following range on cell selection (#4948):
101 // <table><tr><td>[&nbsp;</td></tr></table>]
102 if ( CKEDITOR.env.webkit )
103 ranges[ 0 ].shrink( CKEDITOR.NODE_ELEMENT );
104
105 table = editor.elementPath( ranges[ 0 ].getCommonAncestor( true ) ).contains( 'table', 1 );
106 }
107
108 // Save a reference to the selected table, and push a new set of default values.
109 this._.selectedElement = table;
110 }
111
112 // Enable or disable the row, cols, width fields.
113 if ( table ) {
114 this.setupContent( table );
115 rowsInput && rowsInput.disable();
116 colsInput && colsInput.disable();
117 } else {
118 rowsInput && rowsInput.enable();
119 colsInput && colsInput.enable();
120 }
121
122 // Call the onChange method for the widht and height fields so
123 // they get reflected into the Advanced tab.
124 widthInput && widthInput.onChange();
125 heightInput && heightInput.onChange();
126 },
127 onOk: function() {
128 var selection = editor.getSelection(),
129 bms = this._.selectedElement && selection.createBookmarks();
130
131 var table = this._.selectedElement || makeElement( 'table' ),
132 data = {};
133
134 this.commitContent( data, table );
135
136 if ( data.info ) {
137 var info = data.info;
138
139 // Generate the rows and cols.
140 if ( !this._.selectedElement ) {
141 var tbody = table.append( makeElement( 'tbody' ) ),
142 rows = parseInt( info.txtRows, 10 ) || 0,
143 cols = parseInt( info.txtCols, 10 ) || 0;
144
145 for ( var i = 0; i < rows; i++ ) {
146 var row = tbody.append( makeElement( 'tr' ) );
147 for ( var j = 0; j < cols; j++ ) {
148 var cell = row.append( makeElement( 'td' ) );
149 cell.appendBogus();
150 }
151 }
152 }
153
154 // Modify the table headers. Depends on having rows and cols generated
155 // correctly so it can't be done in commit functions.
156
157 // Should we make a <thead>?
158 var headers = info.selHeaders;
159 if ( !table.$.tHead && ( headers == 'row' || headers == 'both' ) ) {
160 var thead = new CKEDITOR.dom.element( table.$.createTHead() );
161 tbody = table.getElementsByTag( 'tbody' ).getItem( 0 );
162 var theRow = tbody.getElementsByTag( 'tr' ).getItem( 0 );
163
164 // Change TD to TH:
165 for ( i = 0; i < theRow.getChildCount(); i++ ) {
166 var th = theRow.getChild( i );
167 // Skip bookmark nodes. (#6155)
168 if ( th.type == CKEDITOR.NODE_ELEMENT && !th.data( 'cke-bookmark' ) ) {
169 th.renameNode( 'th' );
170 th.setAttribute( 'scope', 'col' );
171 }
172 }
173 thead.append( theRow.remove() );
174 }
175
176 if ( table.$.tHead !== null && !( headers == 'row' || headers == 'both' ) ) {
177 // Move the row out of the THead and put it in the TBody:
178 thead = new CKEDITOR.dom.element( table.$.tHead );
179 tbody = table.getElementsByTag( 'tbody' ).getItem( 0 );
180
181 var previousFirstRow = tbody.getFirst();
182 while ( thead.getChildCount() > 0 ) {
183 theRow = thead.getFirst();
184 for ( i = 0; i < theRow.getChildCount(); i++ ) {
185 var newCell = theRow.getChild( i );
186 if ( newCell.type == CKEDITOR.NODE_ELEMENT ) {
187 newCell.renameNode( 'td' );
188 newCell.removeAttribute( 'scope' );
189 }
190 }
191 theRow.insertBefore( previousFirstRow );
192 }
193 thead.remove();
194 }
195
196 // Should we make all first cells in a row TH?
197 if ( !this.hasColumnHeaders && ( headers == 'col' || headers == 'both' ) ) {
198 for ( row = 0; row < table.$.rows.length; row++ ) {
199 newCell = new CKEDITOR.dom.element( table.$.rows[ row ].cells[ 0 ] );
200 newCell.renameNode( 'th' );
201 newCell.setAttribute( 'scope', 'row' );
202 }
203 }
204
205 // Should we make all first TH-cells in a row make TD? If 'yes' we do it the other way round :-)
206 if ( ( this.hasColumnHeaders ) && !( headers == 'col' || headers == 'both' ) ) {
207 for ( i = 0; i < table.$.rows.length; i++ ) {
208 row = new CKEDITOR.dom.element( table.$.rows[ i ] );
209 if ( row.getParent().getName() == 'tbody' ) {
210 newCell = new CKEDITOR.dom.element( row.$.cells[ 0 ] );
211 newCell.renameNode( 'td' );
212 newCell.removeAttribute( 'scope' );
213 }
214 }
215 }
216
217 // Set the width and height.
218 info.txtHeight ? table.setStyle( 'height', info.txtHeight ) : table.removeStyle( 'height' );
219 info.txtWidth ? table.setStyle( 'width', info.txtWidth ) : table.removeStyle( 'width' );
220
221 if ( !table.getAttribute( 'style' ) )
222 table.removeAttribute( 'style' );
223 }
224
225 // Insert the table element if we're creating one.
226 if ( !this._.selectedElement ) {
227 editor.insertElement( table );
228 // Override the default cursor position after insertElement to place
229 // cursor inside the first cell (#7959), IE needs a while.
230 setTimeout( function() {
231 var firstCell = new CKEDITOR.dom.element( table.$.rows[ 0 ].cells[ 0 ] );
232 var range = editor.createRange();
233 range.moveToPosition( firstCell, CKEDITOR.POSITION_AFTER_START );
234 range.select();
235 }, 0 );
236 }
237 // Properly restore the selection, (#4822) but don't break
238 // because of this, e.g. updated table caption.
239 else {
240 try {
241 selection.selectBookmarks( bms );
242 } catch ( er ) {
243 }
244 }
245 },
246 contents: [ {
247 id: 'info',
248 label: editor.lang.table.title,
249 elements: [ {
250 type: 'hbox',
251 widths: [ null, null ],
252 styles: [ 'vertical-align:top' ],
253 children: [ {
254 type: 'vbox',
255 padding: 0,
256 children: [ {
257 type: 'text',
258 id: 'txtRows',
259 'default': 3,
260 label: editor.lang.table.rows,
261 required: true,
262 controlStyle: 'width:5em',
263 validate: validatorNum( editor.lang.table.invalidRows ),
264 setup: function( selectedElement ) {
265 this.setValue( selectedElement.$.rows.length );
266 },
267 commit: commitValue
268 },
269 {
270 type: 'text',
271 id: 'txtCols',
272 'default': 2,
273 label: editor.lang.table.columns,
274 required: true,
275 controlStyle: 'width:5em',
276 validate: validatorNum( editor.lang.table.invalidCols ),
277 setup: function( selectedTable ) {
278 this.setValue( tableColumns( selectedTable ) );
279 },
280 commit: commitValue
281 },
282 {
283 type: 'html',
284 html: '&nbsp;'
285 },
286 {
287 type: 'select',
288 id: 'selHeaders',
289 requiredContent: 'th',
290 'default': '',
291 label: editor.lang.table.headers,
292 items: [
293 [ editor.lang.table.headersNone, '' ],
294 [ editor.lang.table.headersRow, 'row' ],
295 [ editor.lang.table.headersColumn, 'col' ],
296 [ editor.lang.table.headersBoth, 'both' ]
297 ],
298 setup: function( selectedTable ) {
299 // Fill in the headers field.
300 var dialog = this.getDialog();
301 dialog.hasColumnHeaders = true;
302
303 // Check if all the first cells in every row are TH
304 for ( var row = 0; row < selectedTable.$.rows.length; row++ ) {
305 // If just one cell isn't a TH then it isn't a header column
306 var headCell = selectedTable.$.rows[ row ].cells[ 0 ];
307 if ( headCell && headCell.nodeName.toLowerCase() != 'th' ) {
308 dialog.hasColumnHeaders = false;
309 break;
310 }
311 }
312
313 // Check if the table contains <thead>.
314 if ( ( selectedTable.$.tHead !== null ) )
315 this.setValue( dialog.hasColumnHeaders ? 'both' : 'row' );
316 else
317 this.setValue( dialog.hasColumnHeaders ? 'col' : '' );
318 },
319 commit: commitValue
320 },
321 {
322 type: 'text',
323 id: 'txtBorder',
324 requiredContent: 'table[border]',
325 // Avoid setting border which will then disappear.
326 'default': editor.filter.check( 'table[border]' ) ? 1 : 0,
327 label: editor.lang.table.border,
328 controlStyle: 'width:3em',
329 validate: CKEDITOR.dialog.validate.number( editor.lang.table.invalidBorder ),
330 setup: function( selectedTable ) {
331 this.setValue( selectedTable.getAttribute( 'border' ) || '' );
332 },
333 commit: function( data, selectedTable ) {
334 if ( this.getValue() )
335 selectedTable.setAttribute( 'border', this.getValue() );
336 else
337 selectedTable.removeAttribute( 'border' );
338 }
339 },
340 {
341 id: 'cmbAlign',
342 type: 'select',
343 requiredContent: 'table[align]',
344 'default': '',
345 label: editor.lang.common.align,
346 items: [
347 [ editor.lang.common.notSet, '' ],
348 [ editor.lang.common.alignLeft, 'left' ],
349 [ editor.lang.common.alignCenter, 'center' ],
350 [ editor.lang.common.alignRight, 'right' ]
351 ],
352 setup: function( selectedTable ) {
353 this.setValue( selectedTable.getAttribute( 'align' ) || '' );
354 },
355 commit: function( data, selectedTable ) {
356 if ( this.getValue() )
357 selectedTable.setAttribute( 'align', this.getValue() );
358 else
359 selectedTable.removeAttribute( 'align' );
360 }
361 } ]
362 },
363 {
364 type: 'vbox',
365 padding: 0,
366 children: [ {
367 type: 'hbox',
368 widths: [ '5em' ],
369 children: [ {
370 type: 'text',
371 id: 'txtWidth',
372 requiredContent: 'table{width}',
373 controlStyle: 'width:5em',
374 label: editor.lang.common.width,
375 title: editor.lang.common.cssLengthTooltip,
376 // Smarter default table width. (#9600)
377 'default': editor.filter.check( 'table{width}' ) ? ( editable.getSize( 'width' ) < 500 ? '100%' : 500 ) : 0,
378 getValue: defaultToPixel,
379 validate: CKEDITOR.dialog.validate.cssLength( editor.lang.common.invalidCssLength.replace( '%1', editor.lang.common.width ) ),
380 onChange: function() {
381 var styles = this.getDialog().getContentElement( 'advanced', 'advStyles' );
382 styles && styles.updateStyle( 'width', this.getValue() );
383 },
384 setup: function( selectedTable ) {
385 var val = selectedTable.getStyle( 'width' );
386 this.setValue( val );
387 },
388 commit: commitValue
389 } ]
390 },
391 {
392 type: 'hbox',
393 widths: [ '5em' ],
394 children: [ {
395 type: 'text',
396 id: 'txtHeight',
397 requiredContent: 'table{height}',
398 controlStyle: 'width:5em',
399 label: editor.lang.common.height,
400 title: editor.lang.common.cssLengthTooltip,
401 'default': '',
402 getValue: defaultToPixel,
403 validate: CKEDITOR.dialog.validate.cssLength( editor.lang.common.invalidCssLength.replace( '%1', editor.lang.common.height ) ),
404 onChange: function() {
405 var styles = this.getDialog().getContentElement( 'advanced', 'advStyles' );
406 styles && styles.updateStyle( 'height', this.getValue() );
407 },
408
409 setup: function( selectedTable ) {
410 var val = selectedTable.getStyle( 'height' );
411 val && this.setValue( val );
412 },
413 commit: commitValue
414 } ]
415 },
416 {
417 type: 'html',
418 html: '&nbsp;'
419 },
420 {
421 type: 'text',
422 id: 'txtCellSpace',
423 requiredContent: 'table[cellspacing]',
424 controlStyle: 'width:3em',
425 label: editor.lang.table.cellSpace,
426 'default': editor.filter.check( 'table[cellspacing]' ) ? 1 : 0,
427 validate: CKEDITOR.dialog.validate.number( editor.lang.table.invalidCellSpacing ),
428 setup: function( selectedTable ) {
429 this.setValue( selectedTable.getAttribute( 'cellSpacing' ) || '' );
430 },
431 commit: function( data, selectedTable ) {
432 if ( this.getValue() )
433 selectedTable.setAttribute( 'cellSpacing', this.getValue() );
434 else
435 selectedTable.removeAttribute( 'cellSpacing' );
436 }
437 },
438 {
439 type: 'text',
440 id: 'txtCellPad',
441 requiredContent: 'table[cellpadding]',
442 controlStyle: 'width:3em',
443 label: editor.lang.table.cellPad,
444 'default': editor.filter.check( 'table[cellpadding]' ) ? 1 : 0,
445 validate: CKEDITOR.dialog.validate.number( editor.lang.table.invalidCellPadding ),
446 setup: function( selectedTable ) {
447 this.setValue( selectedTable.getAttribute( 'cellPadding' ) || '' );
448 },
449 commit: function( data, selectedTable ) {
450 if ( this.getValue() )
451 selectedTable.setAttribute( 'cellPadding', this.getValue() );
452 else
453 selectedTable.removeAttribute( 'cellPadding' );
454 }
455 } ]
456 } ]
457 },
458 {
459 type: 'html',
460 align: 'right',
461 html: ''
462 },
463 {
464 type: 'vbox',
465 padding: 0,
466 children: [ {
467 type: 'text',
468 id: 'txtCaption',
469 requiredContent: 'caption',
470 label: editor.lang.table.caption,
471 setup: function( selectedTable ) {
472 this.enable();
473
474 var nodeList = selectedTable.getElementsByTag( 'caption' );
475 if ( nodeList.count() > 0 ) {
476 var caption = nodeList.getItem( 0 );
477 var firstElementChild = caption.getFirst( CKEDITOR.dom.walker.nodeType( CKEDITOR.NODE_ELEMENT ) );
478
479 if ( firstElementChild && !firstElementChild.equals( caption.getBogus() ) ) {
480 this.disable();
481 this.setValue( caption.getText() );
482 return;
483 }
484
485 caption = CKEDITOR.tools.trim( caption.getText() );
486 this.setValue( caption );
487 }
488 },
489 commit: function( data, table ) {
490 if ( !this.isEnabled() )
491 return;
492
493 var caption = this.getValue(),
494 captionElement = table.getElementsByTag( 'caption' );
495 if ( caption ) {
496 if ( captionElement.count() > 0 ) {
497 captionElement = captionElement.getItem( 0 );
498 captionElement.setHtml( '' );
499 } else {
500 captionElement = new CKEDITOR.dom.element( 'caption', editor.document );
501 if ( table.getChildCount() )
502 captionElement.insertBefore( table.getFirst() );
503 else
504 captionElement.appendTo( table );
505 }
506 captionElement.append( new CKEDITOR.dom.text( caption, editor.document ) );
507 } else if ( captionElement.count() > 0 ) {
508 for ( var i = captionElement.count() - 1; i >= 0; i-- )
509 captionElement.getItem( i ).remove();
510 }
511 }
512 },
513 {
514 type: 'text',
515 id: 'txtSummary',
516 bidi: true,
517 requiredContent: 'table[summary]',
518 label: editor.lang.table.summary,
519 setup: function( selectedTable ) {
520 this.setValue( selectedTable.getAttribute( 'summary' ) || '' );
521 },
522 commit: function( data, selectedTable ) {
523 if ( this.getValue() )
524 selectedTable.setAttribute( 'summary', this.getValue() );
525 else
526 selectedTable.removeAttribute( 'summary' );
527 }
528 } ]
529 } ]
530 },
531 dialogadvtab && dialogadvtab.createAdvancedTab( editor, null, 'table' )
532 ] };
533 }
534
535 CKEDITOR.dialog.add( 'table', function( editor ) {
536 return tableDialog( editor, 'table' );
537 } );
538 CKEDITOR.dialog.add( 'tableProperties', function( editor ) {
539 return tableDialog( editor, 'tableProperties' );
540 } );
541 } )();