2 Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
3 For licensing, see LICENSE.html or http://ckeditor.com/license
8 var widthPattern
= /^(\d+(?:\.\d+)?)(px|%)$/,
9 heightPattern
= /^(\d+(?:\.\d+)?)px$/;
11 var commitValue = function( data
)
16 data
.info
[id
] = this.getValue();
19 function tableDialog( editor
, command
)
21 var makeElement = function( name
){ return new CKEDITOR
.dom
.element( name
, editor
.document
); };
24 title
: editor
.lang
.table
.title
,
26 minHeight
: CKEDITOR
.env
.ie
? 310 : 280,
29 // Detect if there's a selected table.
30 var selection
= editor
.getSelection(),
31 ranges
= selection
.getRanges(),
34 var rowsInput
= this.getContentElement( 'info', 'txtRows' ),
35 colsInput
= this.getContentElement( 'info', 'txtCols' ),
36 widthInput
= this.getContentElement( 'info', 'txtWidth' );
37 if ( command
== 'tableProperties' )
39 if ( ( selectedTable
= editor
.getSelection().getSelectedElement() ) )
41 if ( selectedTable
.getName() != 'table' )
44 else if ( ranges
.length
> 0 )
46 var rangeRoot
= ranges
[0].getCommonAncestor( true );
47 selectedTable
= rangeRoot
.getAscendant( 'table', true );
50 // Save a reference to the selected table, and push a new set of default values.
51 this._
.selectedElement
= selectedTable
;
54 // Enable, disable and select the row, cols, width fields.
57 this.setupContent( selectedTable
);
58 rowsInput
&& rowsInput
.disable();
59 colsInput
&& colsInput
.disable();
60 widthInput
&& widthInput
.select();
64 rowsInput
&& rowsInput
.enable();
65 colsInput
&& colsInput
.enable();
66 rowsInput
&& rowsInput
.select();
71 if ( this._
.selectedElement
)
73 var selection
= editor
.getSelection(),
74 bms
= editor
.getSelection().createBookmarks();
77 var table
= this._
.selectedElement
|| makeElement( 'table' ),
81 this.commitContent( data
, table
);
87 // Generate the rows and cols.
88 if ( !this._
.selectedElement
)
90 var tbody
= table
.append( makeElement( 'tbody' ) ),
91 rows
= parseInt( info
.txtRows
, 10 ) || 0,
92 cols
= parseInt( info
.txtCols
, 10 ) || 0;
94 for ( var i
= 0 ; i
< rows
; i
++ )
96 var row
= tbody
.append( makeElement( 'tr' ) );
97 for ( var j
= 0 ; j
< cols
; j
++ )
99 var cell
= row
.append( makeElement( 'td' ) );
100 if ( !CKEDITOR
.env
.ie
)
101 cell
.append( makeElement( 'br' ) );
106 // Modify the table headers. Depends on having rows and cols generated
107 // correctly so it can't be done in commit functions.
109 // Should we make a <thead>?
110 var headers
= info
.selHeaders
;
111 if ( !table
.$.tHead
&& ( headers
== 'row' || headers
== 'both' ) )
113 var thead
= new CKEDITOR
.dom
.element( table
.$.createTHead() );
114 tbody
= table
.getElementsByTag( 'tbody' ).getItem( 0 );
115 var theRow
= tbody
.getElementsByTag( 'tr' ).getItem( 0 );
118 for ( i
= 0 ; i
< theRow
.getChildCount() ; i
++ )
120 var th
= theRow
.getChild( i
);
121 if ( th
.type
== CKEDITOR
.NODE_ELEMENT
)
123 th
.renameNode( 'th' );
124 th
.setAttribute( 'scope', 'col' );
127 thead
.append( theRow
.remove() );
130 if ( table
.$.tHead
!== null && !( headers
== 'row' || headers
== 'both' ) )
132 // Move the row out of the THead and put it in the TBody:
133 thead
= new CKEDITOR
.dom
.element( table
.$.tHead
);
134 tbody
= table
.getElementsByTag( 'tbody' ).getItem( 0 );
136 var previousFirstRow
= tbody
.getFirst();
137 while ( thead
.getChildCount() > 0 )
139 theRow
= thead
.getFirst();
140 for ( i
= 0; i
< theRow
.getChildCount() ; i
++ )
142 var newCell
= theRow
.getChild( i
);
143 if ( newCell
.type
== CKEDITOR
.NODE_ELEMENT
)
145 newCell
.renameNode( 'td' );
146 newCell
.removeAttribute( 'scope' );
149 theRow
.insertBefore( previousFirstRow
);
154 // Should we make all first cells in a row TH?
155 if ( !this.hasColumnHeaders
&& ( headers
== 'col' || headers
== 'both' ) )
157 for ( row
= 0 ; row
< table
.$.rows
.length
; row
++ )
159 newCell
= new CKEDITOR
.dom
.element( table
.$.rows
[ row
].cells
[ 0 ] );
160 newCell
.renameNode( 'th' );
161 newCell
.setAttribute( 'scope', 'row' );
165 // Should we make all first TH-cells in a row make TD? If 'yes' we do it the other way round :-)
166 if ( ( this.hasColumnHeaders
) && !( headers
== 'col' || headers
== 'both' ) )
168 for ( i
= 0 ; i
< table
.$.rows
.length
; i
++ )
170 row
= new CKEDITOR
.dom
.element( table
.$.rows
[i
] );
171 if ( row
.getParent().getName() == 'tbody' )
173 newCell
= new CKEDITOR
.dom
.element( row
.$.cells
[0] );
174 newCell
.renameNode( 'td' );
175 newCell
.removeAttribute( 'scope' );
180 // Set the width and height.
182 if ( info
.txtHeight
)
183 table
.setStyle( 'height', CKEDITOR
.tools
.cssLength( info
.txtHeight
) );
185 table
.removeStyle( 'height' );
189 var type
= info
.cmbWidthType
|| 'pixels';
190 table
.setStyle( 'width', info
.txtWidth
+ ( type
== 'pixels' ? 'px' : '%' ) );
193 table
.removeStyle( 'width' );
195 if ( !table
.getAttribute( 'style' ) )
196 table
.removeAttribute( 'style' );
199 // Insert the table element if we're creating one.
200 if ( !this._
.selectedElement
)
201 editor
.insertElement( table
);
202 // Properly restore the selection inside table. (#4822)
204 selection
.selectBookmarks( bms
);
211 label
: editor
.lang
.table
.title
,
216 widths
: [ null, null ],
217 styles
: [ 'vertical-align:top' ],
229 label
: editor
.lang
.table
.rows
,
231 validate : function()
234 value
= this.getValue();
235 pass
= pass
&& CKEDITOR
.dialog
.validate
.integer()( value
)
239 alert( editor
.lang
.table
.invalidRows
);
244 setup : function( selectedElement
)
246 this.setValue( selectedElement
.$.rows
.length
);
254 label
: editor
.lang
.table
.columns
,
256 validate : function()
259 value
= this.getValue();
260 pass
= pass
&& CKEDITOR
.dialog
.validate
.integer()( value
)
264 alert( editor
.lang
.table
.invalidCols
);
269 setup : function( selectedTable
)
271 this.setValue( selectedTable
.$.rows
[0].cells
.length
);
283 label
: editor
.lang
.table
.headers
,
286 [ editor
.lang
.table
.headersNone
, '' ],
287 [ editor
.lang
.table
.headersRow
, 'row' ],
288 [ editor
.lang
.table
.headersColumn
, 'col' ],
289 [ editor
.lang
.table
.headersBoth
, 'both' ]
291 setup : function( selectedTable
)
293 // Fill in the headers field.
294 var dialog
= this.getDialog();
295 dialog
.hasColumnHeaders
= true;
297 // Check if all the first cells in every row are TH
298 for ( var row
= 0 ; row
< selectedTable
.$.rows
.length
; row
++ )
300 // If just one cell isn't a TH then it isn't a header column
301 if ( selectedTable
.$.rows
[row
].cells
[0].nodeName
.toLowerCase() != 'th' )
303 dialog
.hasColumnHeaders
= false;
308 // Check if the table contains <thead>.
309 if ( ( selectedTable
.$.tHead
!== null) )
310 this.setValue( dialog
.hasColumnHeaders
? 'both' : 'row' );
312 this.setValue( dialog
.hasColumnHeaders
? 'col' : '' );
320 label
: editor
.lang
.table
.border
,
322 validate
: CKEDITOR
.dialog
.validate
['number']( editor
.lang
.table
.invalidBorder
),
323 setup : function( selectedTable
)
325 this.setValue( selectedTable
.getAttribute( 'border' ) || '' );
327 commit : function( data
, selectedTable
)
329 if ( this.getValue() )
330 selectedTable
.setAttribute( 'border', this.getValue() );
332 selectedTable
.removeAttribute( 'border' );
339 label
: editor
.lang
.table
.align
,
342 [ editor
.lang
.common
.notSet
, ''],
343 [ editor
.lang
.table
.alignLeft
, 'left'],
344 [ editor
.lang
.table
.alignCenter
, 'center'],
345 [ editor
.lang
.table
.alignRight
, 'right']
347 setup : function( selectedTable
)
349 this.setValue( selectedTable
.getAttribute( 'align' ) || '' );
351 commit : function( data
, selectedTable
)
353 if ( this.getValue() )
354 selectedTable
.setAttribute( 'align', this.getValue() );
356 selectedTable
.removeAttribute( 'align' );
375 label
: editor
.lang
.table
.width
,
377 validate
: CKEDITOR
.dialog
.validate
['number']( editor
.lang
.table
.invalidWidth
),
379 // Extra labelling of width unit type.
382 var widthType
= this.getDialog().getContentElement( 'info', 'cmbWidthType' ),
383 labelElement
= widthType
.getElement(),
384 inputElement
= this.getInputElement(),
385 ariaLabelledByAttr
= inputElement
.getAttribute( 'aria-labelledby' );
387 inputElement
.setAttribute( 'aria-labelledby', [ ariaLabelledByAttr
, labelElement
.$.id
].join( ' ' ) );
390 setup : function( selectedTable
)
392 var widthMatch
= widthPattern
.exec( selectedTable
.$.style
.width
);
394 this.setValue( widthMatch
[1] );
403 label
: editor
.lang
.table
.widthUnit
,
404 labelStyle
: 'visibility:hidden',
405 'default' : 'pixels',
408 [ editor
.lang
.table
.widthPx
, 'pixels'],
409 [ editor
.lang
.table
.widthPc
, 'percents']
411 setup : function( selectedTable
)
413 var widthMatch
= widthPattern
.exec( selectedTable
.$.style
.width
);
415 this.setValue( widthMatch
[2] == 'px' ? 'pixels' : 'percents' );
430 label
: editor
.lang
.table
.height
,
432 validate
: CKEDITOR
.dialog
.validate
['number']( editor
.lang
.table
.invalidHeight
),
434 // Extra labelling of height unit type.
437 var heightType
= this.getDialog().getContentElement( 'info', 'htmlHeightType' ),
438 labelElement
= heightType
.getElement(),
439 inputElement
= this.getInputElement(),
440 ariaLabelledByAttr
= inputElement
.getAttribute( 'aria-labelledby' );
442 inputElement
.setAttribute( 'aria-labelledby', [ ariaLabelledByAttr
, labelElement
.$.id
].join( ' ' ) );
445 setup : function( selectedTable
)
447 var heightMatch
= heightPattern
.exec( selectedTable
.$.style
.height
);
449 this.setValue( heightMatch
[1] );
454 id
: 'htmlHeightType',
456 html
: '<div><br />' + editor
.lang
.table
.widthPx
+ '</div>'
468 label
: editor
.lang
.table
.cellSpace
,
470 validate
: CKEDITOR
.dialog
.validate
['number']( editor
.lang
.table
.invalidCellSpacing
),
471 setup : function( selectedTable
)
473 this.setValue( selectedTable
.getAttribute( 'cellSpacing' ) || '' );
475 commit : function( data
, selectedTable
)
477 if ( this.getValue() )
478 selectedTable
.setAttribute( 'cellSpacing', this.getValue() );
480 selectedTable
.removeAttribute( 'cellSpacing' );
487 label
: editor
.lang
.table
.cellPad
,
489 validate
: CKEDITOR
.dialog
.validate
['number']( editor
.lang
.table
.invalidCellPadding
),
490 setup : function( selectedTable
)
492 this.setValue( selectedTable
.getAttribute( 'cellPadding' ) || '' );
494 commit : function( data
, selectedTable
)
496 if ( this.getValue() )
497 selectedTable
.setAttribute( 'cellPadding', this.getValue() );
499 selectedTable
.removeAttribute( 'cellPadding' );
519 label
: editor
.lang
.table
.caption
,
520 setup : function( selectedTable
)
522 var nodeList
= selectedTable
.getElementsByTag( 'caption' );
523 if ( nodeList
.count() > 0 )
525 var caption
= nodeList
.getItem( 0 );
526 caption
= ( caption
.getChild( 0 ) && caption
.getChild( 0 ).getText() ) || '';
527 caption
= CKEDITOR
.tools
.trim( caption
);
528 this.setValue( caption
);
531 commit : function( data
, table
)
533 var caption
= this.getValue(),
534 captionElement
= table
.getElementsByTag( 'caption' );
537 if ( captionElement
.count() > 0 )
539 captionElement
= captionElement
.getItem( 0 );
540 captionElement
.setHtml( '' );
544 captionElement
= new CKEDITOR
.dom
.element( 'caption', editor
.document
);
545 if ( table
.getChildCount() )
546 captionElement
.insertBefore( table
.getFirst() );
548 captionElement
.appendTo( table
);
550 captionElement
.append( new CKEDITOR
.dom
.text( caption
, editor
.document
) );
552 else if ( captionElement
.count() > 0 )
554 for ( var i
= captionElement
.count() - 1 ; i
>= 0 ; i
-- )
555 captionElement
.getItem( i
).remove();
562 label
: editor
.lang
.table
.summary
,
563 setup : function( selectedTable
)
565 this.setValue( selectedTable
.getAttribute( 'summary' ) || '' );
567 commit : function( data
, selectedTable
)
569 if ( this.getValue() )
570 selectedTable
.setAttribute( 'summary', this.getValue() );
572 selectedTable
.removeAttribute( 'summary' );
583 CKEDITOR
.dialog
.add( 'table', function( editor
)
585 return tableDialog( editor
, 'table' );
587 CKEDITOR
.dialog
.add( 'tableProperties', function( editor
)
589 return tableDialog( editor
, 'tableProperties' );