/*\r
-Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.\r
+Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.\r
For licensing, see LICENSE.html or http://ckeditor.com/license\r
*/\r
\r
(function()\r
{\r
- var widthPattern = /^(\d+(?:\.\d+)?)(px|%)$/,\r
- heightPattern = /^(\d+(?:\.\d+)?)px$/;\r
+ var defaultToPixel = CKEDITOR.tools.cssLength;\r
\r
var commitValue = function( data )\r
{\r
data.info[id] = this.getValue();\r
};\r
\r
+ function tableColumns( table )\r
+ {\r
+ var cols = 0, maxCols = 0;\r
+ for ( var i = 0, row, rows = table.$.rows.length; i < rows; i++ )\r
+ {\r
+ row = table.$.rows[ i ], cols = 0;\r
+ for ( var j = 0, cell, cells = row.cells.length; j < cells; j++ )\r
+ {\r
+ cell = row.cells[ j ];\r
+ cols += cell.colSpan;\r
+ }\r
+\r
+ cols > maxCols && ( maxCols = cols );\r
+ }\r
+\r
+ return maxCols;\r
+ }\r
+\r
+\r
+ // Whole-positive-integer validator.\r
+ function validatorNum( msg )\r
+ {\r
+ return function()\r
+ {\r
+ var value = this.getValue(),\r
+ pass = !!( CKEDITOR.dialog.validate.integer()( value ) && value > 0 );\r
+\r
+ if ( !pass )\r
+ {\r
+ alert( msg );\r
+ this.select();\r
+ }\r
+\r
+ return pass;\r
+ };\r
+ }\r
+\r
function tableDialog( editor, command )\r
{\r
- var makeElement = function( name ){ return new CKEDITOR.dom.element( name, editor.document ); };\r
+ var makeElement = function( name )\r
+ {\r
+ return new CKEDITOR.dom.element( name, editor.document );\r
+ };\r
+\r
+ var dialogadvtab = editor.plugins.dialogadvtab;\r
\r
return {\r
title : editor.lang.table.title,\r
minWidth : 310,\r
minHeight : CKEDITOR.env.ie ? 310 : 280,\r
+\r
+ onLoad : function()\r
+ {\r
+ var dialog = this;\r
+\r
+ var styles = dialog.getContentElement( 'advanced', 'advStyles' );\r
+\r
+ if ( styles )\r
+ {\r
+ styles.on( 'change', function( evt )\r
+ {\r
+ // Synchronize width value.\r
+ var width = this.getStyle( 'width', '' ),\r
+ txtWidth = dialog.getContentElement( 'info', 'txtWidth' );\r
+\r
+ txtWidth && txtWidth.setValue( width, true );\r
+\r
+ // Synchronize height value.\r
+ var height = this.getStyle( 'height', '' ),\r
+ txtHeight = dialog.getContentElement( 'info', 'txtHeight' );\r
+\r
+ txtHeight && txtHeight.setValue( height, true );\r
+ });\r
+ }\r
+ },\r
+\r
onShow : function()\r
{\r
// Detect if there's a selected table.\r
\r
var rowsInput = this.getContentElement( 'info', 'txtRows' ),\r
colsInput = this.getContentElement( 'info', 'txtCols' ),\r
- widthInput = this.getContentElement( 'info', 'txtWidth' );\r
+ widthInput = this.getContentElement( 'info', 'txtWidth' ),\r
+ heightInput = this.getContentElement( 'info', 'txtHeight' );\r
+\r
if ( command == 'tableProperties' )\r
{\r
- if ( ( selectedTable = editor.getSelection().getSelectedElement() ) )\r
- {\r
- if ( selectedTable.getName() != 'table' )\r
- selectedTable = null;\r
- }\r
+ if ( ( selectedTable = selection.getSelectedElement() ) )\r
+ selectedTable = selectedTable.getAscendant( 'table', true );\r
else if ( ranges.length > 0 )\r
{\r
+ // Webkit could report the following range on cell selection (#4948):\r
+ // <table><tr><td>[ </td></tr></table>]\r
+ if ( CKEDITOR.env.webkit )\r
+ ranges[ 0 ].shrink( CKEDITOR.NODE_ELEMENT );\r
+\r
var rangeRoot = ranges[0].getCommonAncestor( true );\r
selectedTable = rangeRoot.getAscendant( 'table', true );\r
}\r
this._.selectedElement = selectedTable;\r
}\r
\r
- // Enable, disable and select the row, cols, width fields.\r
+ // Enable or disable the row, cols, width fields.\r
if ( selectedTable )\r
{\r
this.setupContent( selectedTable );\r
rowsInput && rowsInput.disable();\r
colsInput && colsInput.disable();\r
- widthInput && widthInput.select();\r
}\r
else\r
{\r
rowsInput && rowsInput.enable();\r
colsInput && colsInput.enable();\r
- rowsInput && rowsInput.select();\r
}\r
+\r
+ // Call the onChange method for the widht and height fields so\r
+ // they get reflected into the Advanced tab.\r
+ widthInput && widthInput.onChange();\r
+ heightInput && heightInput.onChange();\r
},\r
onOk : function()\r
{\r
- if ( this._.selectedElement )\r
- {\r
- var selection = editor.getSelection(),\r
- bms = editor.getSelection().createBookmarks();\r
- }\r
+ var selection = editor.getSelection(),\r
+ bms = this._.selectedElement && selection.createBookmarks();\r
\r
var table = this._.selectedElement || makeElement( 'table' ),\r
me = this,\r
for ( i = 0 ; i < theRow.getChildCount() ; i++ )\r
{\r
var th = theRow.getChild( i );\r
- if ( th.type == CKEDITOR.NODE_ELEMENT )\r
+ // Skip bookmark nodes. (#6155)\r
+ if ( th.type == CKEDITOR.NODE_ELEMENT && !th.data( 'cke-bookmark' ) )\r
{\r
th.renameNode( 'th' );\r
th.setAttribute( 'scope', 'col' );\r
}\r
\r
// Set the width and height.\r
- var styles = [];\r
- if ( info.txtHeight )\r
- table.setStyle( 'height', CKEDITOR.tools.cssLength( info.txtHeight ) );\r
- else\r
- table.removeStyle( 'height' );\r
-\r
- if ( info.txtWidth )\r
- {\r
- var type = info.cmbWidthType || 'pixels';\r
- table.setStyle( 'width', info.txtWidth + ( type == 'pixels' ? 'px' : '%' ) );\r
- }\r
- else\r
- table.removeStyle( 'width' );\r
+ info.txtHeight ? table.setStyle( 'height', info.txtHeight ) : table.removeStyle( 'height' );\r
+ info.txtWidth ? table.setStyle( 'width', info.txtWidth ) : table.removeStyle( 'width' );\r
\r
if ( !table.getAttribute( 'style' ) )\r
table.removeAttribute( 'style' );\r
\r
// Insert the table element if we're creating one.\r
if ( !this._.selectedElement )\r
+ {\r
editor.insertElement( table );\r
- // Properly restore the selection inside table. (#4822)\r
+ // Override the default cursor position after insertElement to place\r
+ // cursor inside the first cell (#7959), IE needs a while.\r
+ setTimeout( function()\r
+ {\r
+ var firstCell = new CKEDITOR.dom.element( table.$.rows[ 0 ].cells[ 0 ] );\r
+ var range = new CKEDITOR.dom.range( editor.document );\r
+ range.moveToPosition( firstCell, CKEDITOR.POSITION_AFTER_START );\r
+ range.select( 1 );\r
+ }, 0 );\r
+ }\r
+ // Properly restore the selection, (#4822) but don't break\r
+ // because of this, e.g. updated table caption.\r
else\r
- selection.selectBookmarks( bms );\r
-\r
- return true;\r
+ try { selection.selectBookmarks( bms ); } catch( er ){}\r
},\r
contents : [\r
{\r
id : 'txtRows',\r
'default' : 3,\r
label : editor.lang.table.rows,\r
- style : 'width:5em',\r
- validate : function()\r
- {\r
- var pass = true,\r
- value = this.getValue();\r
- pass = pass && CKEDITOR.dialog.validate.integer()( value )\r
- && value > 0;\r
- if ( !pass )\r
- {\r
- alert( editor.lang.table.invalidRows );\r
- this.select();\r
- }\r
- return pass;\r
- },\r
+ required : true,\r
+ controlStyle : 'width:5em',\r
+ validate : validatorNum( editor.lang.table.invalidRows ),\r
setup : function( selectedElement )\r
{\r
this.setValue( selectedElement.$.rows.length );\r
id : 'txtCols',\r
'default' : 2,\r
label : editor.lang.table.columns,\r
- style : 'width:5em',\r
- validate : function()\r
- {\r
- var pass = true,\r
- value = this.getValue();\r
- pass = pass && CKEDITOR.dialog.validate.integer()( value )\r
- && value > 0;\r
- if ( !pass )\r
- {\r
- alert( editor.lang.table.invalidCols );\r
- this.select();\r
- }\r
- return pass;\r
- },\r
+ required : true,\r
+ controlStyle : 'width:5em',\r
+ validate : validatorNum( editor.lang.table.invalidCols ),\r
setup : function( selectedTable )\r
{\r
- this.setValue( selectedTable.$.rows[0].cells.length);\r
+ this.setValue( tableColumns( selectedTable ) );\r
},\r
commit : commitValue\r
},\r
for ( var row = 0 ; row < selectedTable.$.rows.length ; row++ )\r
{\r
// If just one cell isn't a TH then it isn't a header column\r
- if ( selectedTable.$.rows[row].cells[0].nodeName.toLowerCase() != 'th' )\r
+ var headCell = selectedTable.$.rows[row].cells[0];\r
+ if ( headCell && headCell.nodeName.toLowerCase() != 'th' )\r
{\r
dialog.hasColumnHeaders = false;\r
break;\r
id : 'txtBorder',\r
'default' : 1,\r
label : editor.lang.table.border,\r
- style : 'width:3em',\r
+ controlStyle : 'width:3em',\r
validate : CKEDITOR.dialog.validate['number']( editor.lang.table.invalidBorder ),\r
setup : function( selectedTable )\r
{\r
id : 'cmbAlign',\r
type : 'select',\r
'default' : '',\r
- label : editor.lang.table.align,\r
+ label : editor.lang.common.align,\r
items :\r
[\r
[ editor.lang.common.notSet , ''],\r
- [ editor.lang.table.alignLeft , 'left'],\r
- [ editor.lang.table.alignCenter , 'center'],\r
- [ editor.lang.table.alignRight , 'right']\r
+ [ editor.lang.common.alignLeft , 'left'],\r
+ [ editor.lang.common.alignCenter , 'center'],\r
+ [ editor.lang.common.alignRight , 'right']\r
],\r
setup : function( selectedTable )\r
{\r
{\r
type : 'text',\r
id : 'txtWidth',\r
- style : 'width:5em',\r
- label : editor.lang.table.width,\r
- 'default' : 200,\r
- validate : CKEDITOR.dialog.validate['number']( editor.lang.table.invalidWidth ),\r
-\r
- // Extra labelling of width unit type.\r
- onLoad : function()\r
+ controlStyle : 'width:5em',\r
+ label : editor.lang.common.width,\r
+ title : editor.lang.common.cssLengthTooltip,\r
+ 'default' : 500,\r
+ getValue : defaultToPixel,\r
+ validate : CKEDITOR.dialog.validate.cssLength( editor.lang.common.invalidCssLength.replace( '%1', editor.lang.common.width ) ),\r
+ onChange : function()\r
{\r
- var widthType = this.getDialog().getContentElement( 'info', 'cmbWidthType' ),\r
- labelElement = widthType.getElement(),\r
- inputElement = this.getInputElement(),\r
- ariaLabelledByAttr = inputElement.getAttribute( 'aria-labelledby' );\r
-\r
- inputElement.setAttribute( 'aria-labelledby', [ ariaLabelledByAttr, labelElement.$.id ].join( ' ' ) );\r
+ var styles = this.getDialog().getContentElement( 'advanced', 'advStyles' );\r
+ styles && styles.updateStyle( 'width', this.getValue() );\r
},\r
-\r
setup : function( selectedTable )\r
{\r
- var widthMatch = widthPattern.exec( selectedTable.$.style.width );\r
- if ( widthMatch )\r
- this.setValue( widthMatch[1] );\r
- else\r
- this.setValue( '' );\r
- },\r
- commit : commitValue\r
- },\r
- {\r
- id : 'cmbWidthType',\r
- type : 'select',\r
- label : editor.lang.table.widthUnit,\r
- labelStyle: 'visibility:hidden',\r
- 'default' : 'pixels',\r
- items :\r
- [\r
- [ editor.lang.table.widthPx , 'pixels'],\r
- [ editor.lang.table.widthPc , 'percents']\r
- ],\r
- setup : function( selectedTable )\r
- {\r
- var widthMatch = widthPattern.exec( selectedTable.$.style.width );\r
- if ( widthMatch )\r
- this.setValue( widthMatch[2] == 'px' ? 'pixels' : 'percents' );\r
+ var val = selectedTable.getStyle( 'width' );\r
+ val && this.setValue( val );\r
},\r
commit : commitValue\r
}\r
{\r
type : 'text',\r
id : 'txtHeight',\r
- style : 'width:5em',\r
- label : editor.lang.table.height,\r
+ controlStyle : 'width:5em',\r
+ label : editor.lang.common.height,\r
+ title : editor.lang.common.cssLengthTooltip,\r
'default' : '',\r
- validate : CKEDITOR.dialog.validate['number']( editor.lang.table.invalidHeight ),\r
-\r
- // Extra labelling of height unit type.\r
- onLoad : function()\r
+ getValue : defaultToPixel,\r
+ validate : CKEDITOR.dialog.validate.cssLength( editor.lang.common.invalidCssLength.replace( '%1', editor.lang.common.height ) ),\r
+ onChange : function()\r
{\r
- var heightType = this.getDialog().getContentElement( 'info', 'htmlHeightType' ),\r
- labelElement = heightType.getElement(),\r
- inputElement = this.getInputElement(),\r
- ariaLabelledByAttr = inputElement.getAttribute( 'aria-labelledby' );\r
-\r
- inputElement.setAttribute( 'aria-labelledby', [ ariaLabelledByAttr, labelElement.$.id ].join( ' ' ) );\r
+ var styles = this.getDialog().getContentElement( 'advanced', 'advStyles' );\r
+ styles && styles.updateStyle( 'height', this.getValue() );\r
},\r
\r
setup : function( selectedTable )\r
{\r
- var heightMatch = heightPattern.exec( selectedTable.$.style.height );\r
- if ( heightMatch )\r
- this.setValue( heightMatch[1] );\r
+ var val = selectedTable.getStyle( 'height' );\r
+ val && this.setValue( val );\r
},\r
commit : commitValue\r
- },\r
- {\r
- id : 'htmlHeightType',\r
- type : 'html',\r
- html : '<div><br />' + editor.lang.table.widthPx + '</div>'\r
}\r
]\r
},\r
{\r
type : 'text',\r
id : 'txtCellSpace',\r
- style : 'width:3em',\r
+ controlStyle : 'width:3em',\r
label : editor.lang.table.cellSpace,\r
'default' : 1,\r
- validate : CKEDITOR.dialog.validate['number']( editor.lang.table.invalidCellSpacing ),\r
+ validate : CKEDITOR.dialog.validate.number( editor.lang.table.invalidCellSpacing ),\r
setup : function( selectedTable )\r
{\r
this.setValue( selectedTable.getAttribute( 'cellSpacing' ) || '' );\r
{\r
type : 'text',\r
id : 'txtCellPad',\r
- style : 'width:3em',\r
+ controlStyle : 'width:3em',\r
label : editor.lang.table.cellPad,\r
'default' : 1,\r
- validate : CKEDITOR.dialog.validate['number']( editor.lang.table.invalidCellPadding ),\r
+ validate : CKEDITOR.dialog.validate.number( editor.lang.table.invalidCellPadding ),\r
setup : function( selectedTable )\r
{\r
this.setValue( selectedTable.getAttribute( 'cellPadding' ) || '' );\r
label : editor.lang.table.caption,\r
setup : function( selectedTable )\r
{\r
+ this.enable();\r
+\r
var nodeList = selectedTable.getElementsByTag( 'caption' );\r
if ( nodeList.count() > 0 )\r
{\r
var caption = nodeList.getItem( 0 );\r
- caption = ( caption.getChild( 0 ) && caption.getChild( 0 ).getText() ) || '';\r
- caption = CKEDITOR.tools.trim( caption );\r
+ var firstElementChild = caption.getFirst( CKEDITOR.dom.walker.nodeType( CKEDITOR.NODE_ELEMENT ) );\r
+\r
+ if ( firstElementChild && !firstElementChild.equals( caption.getBogus() ) )\r
+ {\r
+ this.disable();\r
+ this.setValue( caption.getText() );\r
+ return;\r
+ }\r
+\r
+ caption = CKEDITOR.tools.trim( caption.getText() );\r
this.setValue( caption );\r
}\r
},\r
commit : function( data, table )\r
{\r
+ if ( !this.isEnabled() )\r
+ return;\r
+\r
var caption = this.getValue(),\r
captionElement = table.getElementsByTag( 'caption' );\r
if ( caption )\r
]\r
}\r
]\r
- }\r
+ },\r
+ dialogadvtab && dialogadvtab.createAdvancedTab( editor )\r
]\r
};\r
}\r