/*\r
-Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.\r
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.\r
For licensing, see LICENSE.html or http://ckeditor.com/license\r
*/\r
\r
CKEDITOR.dom.element.clearAllMarkers = function( database )\r
{\r
for ( var i in database )\r
- CKEDITOR.dom.element.clearMarkers( database, database[i], true );\r
+ CKEDITOR.dom.element.clearMarkers( database, database[i], 1 );\r
};\r
\r
CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatabase )\r
}\r
};\r
\r
+( function()\r
+{\r
+\r
CKEDITOR.tools.extend( CKEDITOR.dom.element.prototype,\r
/** @lends CKEDITOR.dom.element.prototype */\r
{\r
\r
/**\r
* Moves the selection focus to this element.\r
+ * @function\r
+ * @param {Boolean} defer Whether to asynchronously defer the\r
+ * execution by 100 ms.\r
* @example\r
* var element = CKEDITOR.document.getById( 'myTextarea' );\r
* <b>element.focus()</b>;\r
*/\r
- focus : function()\r
+ focus : ( function()\r
{\r
+ function exec()\r
+ {\r
// IE throws error if the element is not visible.\r
try\r
{\r
}\r
catch (e)\r
{}\r
- },\r
+ }\r
+\r
+ return function( defer )\r
+ {\r
+ if ( defer )\r
+ CKEDITOR.tools.setTimeout( exec, 100, this );\r
+ else\r
+ exec.call( this );\r
+ };\r
+ })(),\r
\r
/**\r
* Gets the inner HTML of this element.\r
name = 'className';\r
break;\r
\r
+ case 'http-equiv':\r
+ name = 'httpEquiv';\r
+ break;\r
+\r
+ case 'name':\r
+ return this.$.name;\r
+\r
case 'tabindex':\r
var tabIndex = standard.call( this, name );\r
\r
}\r
\r
case 'hspace':\r
- return this.$.hspace;\r
+ case 'value':\r
+ return this.$[ name ];\r
\r
case 'style':\r
// IE does not return inline styles via getAttribute(). See #2947.\r
return this.$.style.cssText;\r
+\r
+ case 'contenteditable':\r
+ case 'contentEditable':\r
+ return this.$.attributes.getNamedItem( 'contentEditable' ).specified ?\r
+ this.$.getAttribute( 'contentEditable' ) : null;\r
}\r
\r
return standard.call( this, name );\r
:\r
function( propertyName )\r
{\r
- return this.getWindow().$.getComputedStyle( this.$, '' ).getPropertyValue( propertyName );\r
+ var style = this.getWindow().$.getComputedStyle( this.$, null );\r
+\r
+ // Firefox may return null if we call the above on a hidden iframe. (#9117)\r
+ return style ? style.getPropertyValue( propertyName ) : '';\r
},\r
\r
/**\r
* in the future.\r
* @returns {String} The text value.\r
* @example\r
- * var element = CKEDITOR.dom.element.createFromHtml( '<div>Same <i>text</i>.</div>' );\r
+ * var element = CKEDITOR.dom.element.createFromHtml( '<div>Sample <i>text</i>.</div>' );\r
* alert( <b>element.getText()</b> ); // "Sample text."\r
*/\r
getText : function()\r
// Cache the lowercased name inside a closure.\r
var nodeName = this.$.nodeName.toLowerCase();\r
\r
- if ( CKEDITOR.env.ie )\r
+ if ( CKEDITOR.env.ie && ! ( document.documentMode > 8 ) )\r
{\r
var scopeName = this.$.scopeName;\r
if ( scopeName != 'HTML' )\r
return false;\r
},\r
\r
- isEditable : function()\r
+ /**\r
+ * Decide whether one element is able to receive cursor.\r
+ * @param {Boolean} [textCursor=true] Only consider element that could receive text child.\r
+ */\r
+ isEditable : function( textCursor )\r
{\r
- // Get the element name.\r
var name = this.getName();\r
\r
- // Get the element DTD (defaults to span for unknown elements).\r
- var dtd = !CKEDITOR.dtd.$nonEditable[ name ]\r
- && ( CKEDITOR.dtd[ name ] || CKEDITOR.dtd.span );\r
+ if ( this.isReadOnly()\r
+ || this.getComputedStyle( 'display' ) == 'none'\r
+ || this.getComputedStyle( 'visibility' ) == 'hidden'\r
+ || this.is( 'a' ) && this.data( 'cke-saved-name' ) && !this.getChildCount()\r
+ || CKEDITOR.dtd.$nonEditable[ name ]\r
+ || CKEDITOR.dtd.$empty[ name ] )\r
+ {\r
+ return false;\r
+ }\r
\r
- // In the DTD # == text node.\r
- return ( dtd && dtd['#'] );\r
+ if ( textCursor !== false )\r
+ {\r
+ // Get the element DTD (defaults to span for unknown elements).\r
+ var dtd = CKEDITOR.dtd[ name ] || CKEDITOR.dtd.span;\r
+ // In the DTD # == text node.\r
+ return ( dtd && dtd[ '#'] );\r
+ }\r
+\r
+ return true;\r
},\r
\r
isIdentical : function( otherElement )\r
var thisLength = thisAttribs.length,\r
otherLength = otherAttribs.length;\r
\r
- if ( !CKEDITOR.env.ie && thisLength != otherLength )\r
- return false;\r
-\r
for ( var i = 0 ; i < thisLength ; i++ )\r
{\r
var attribute = thisAttribs[ i ];\r
\r
- if ( ( !CKEDITOR.env.ie || ( attribute.specified && attribute.nodeName != '_cke_expando' ) ) && attribute.nodeValue != otherElement.getAttribute( attribute.nodeName ) )\r
+ if ( attribute.nodeName == '_moz_dirty' )\r
+ continue;\r
+\r
+ if ( ( !CKEDITOR.env.ie || ( attribute.specified && attribute.nodeName != 'data-cke-expando' ) ) && attribute.nodeValue != otherElement.getAttribute( attribute.nodeName ) )\r
return false;\r
}\r
\r
for ( i = 0 ; i < otherLength ; i++ )\r
{\r
attribute = otherAttribs[ i ];\r
- if ( attribute.specified && attribute.nodeName != '_cke_expando'\r
+ if ( attribute.specified && attribute.nodeName != 'data-cke-expando'\r
&& attribute.nodeValue != this.getAttribute( attribute.nodeName ) )\r
return false;\r
}\r
*/\r
isVisible : function()\r
{\r
- var isVisible = !!this.$.offsetHeight && this.getComputedStyle( 'visibility' ) != 'hidden',\r
+ var isVisible = ( this.$.offsetHeight || this.$.offsetWidth ) && this.getComputedStyle( 'visibility' ) != 'hidden',\r
elementWindow,\r
elementWindowFrame;\r
\r
}\r
}\r
\r
- return isVisible;\r
+ return !!isVisible;\r
},\r
\r
/**\r
{\r
var child = children.getItem( i );\r
\r
- if ( child.type == CKEDITOR.NODE_ELEMENT && child.getAttribute( '_fck_bookmark' ) )\r
+ if ( child.type == CKEDITOR.NODE_ELEMENT && child.data( 'cke-bookmark' ) )\r
continue;\r
\r
if ( child.type == CKEDITOR.NODE_ELEMENT && !child.isEmptyInlineRemoveable()\r
},\r
\r
/**\r
- * Indicates that the element has defined attributes.\r
+ * Checks if the element has any defined attributes.\r
+ * @function\r
* @returns {Boolean} True if the element has attributes.\r
* @example\r
- * var element = CKEDITOR.dom.element.createFromHtml( '<div title="Test">Example</div>' );\r
- * alert( <b>element.hasAttributes()</b> ); "true"\r
+ * var element = CKEDITOR.dom.element.createFromHtml( '<div title="Test">Example</div>' );\r
+ * alert( <b>element.hasAttributes()</b> ); // "true"\r
* @example\r
- * var element = CKEDITOR.dom.element.createFromHtml( '<div>Example</div>' );\r
- * alert( <b>element.hasAttributes()</b> ); "false"\r
+ * var element = CKEDITOR.dom.element.createFromHtml( '<div>Example</div>' );\r
+ * alert( <b>element.hasAttributes()</b> ); // "false"\r
*/\r
hasAttributes :\r
CKEDITOR.env.ie && ( CKEDITOR.env.ie7Compat || CKEDITOR.env.ie6Compat ) ?\r
return true;\r
\r
// Attributes to be ignored.\r
- case '_cke_expando' :\r
+ case 'data-cke-expando' :\r
continue;\r
\r
/*jsl:fallthru*/\r
attrsNum = attrs.length;\r
\r
// The _moz_dirty attribute might get into the element after pasting (#5455)\r
- var execludeAttrs = { _cke_expando : 1, _moz_dirty : 1 };\r
+ var execludeAttrs = { 'data-cke-expando' : 1, _moz_dirty : 1 };\r
\r
return attrsNum > 0 &&\r
( attrsNum > 2 ||\r
},\r
\r
/**\r
- * Indicates whether a specified attribute is defined for this element.\r
+ * Checks if the specified attribute is defined for this element.\r
* @returns {Boolean} True if the specified attribute is defined.\r
- * @param (String) name The attribute name.\r
+ * @param {String} name The attribute name.\r
* @example\r
*/\r
- hasAttribute : function( name )\r
+ hasAttribute : (function()\r
{\r
- var $attr = this.$.attributes.getNamedItem( name );\r
- return !!( $attr && $attr.specified );\r
- },\r
+ function standard( name )\r
+ {\r
+ var $attr = this.$.attributes.getNamedItem( name );\r
+ return !!( $attr && $attr.specified );\r
+ }\r
+\r
+ return ( CKEDITOR.env.ie && CKEDITOR.env.version < 8 ) ?\r
+ function( name )\r
+ {\r
+ // On IE < 8 the name attribute cannot be retrieved\r
+ // right after the element creation and setting the\r
+ // name with setAttribute.\r
+ if ( name == 'name' )\r
+ return !!this.$.name;\r
+\r
+ return standard.call( this, name );\r
+ }\r
+ :\r
+ standard;\r
+ })(),\r
\r
/**\r
* Hides this element (display:none).\r
}\r
},\r
\r
+ /**\r
+ * Merges sibling elements that are identical to this one.<br>\r
+ * <br>\r
+ * Identical child elements are also merged. For example:<br>\r
+ * <b><i></i></b><b><i></i></b> => <b><i></i></b>\r
+ * @function\r
+ * @param {Boolean} [inlineOnly] Allow only inline elements to be merged. Defaults to "true".\r
+ */\r
mergeSiblings : ( function()\r
{\r
function mergeElements( element, sibling, isNext )\r
// queuing them to be moved later. (#5567)\r
var pendingNodes = [];\r
\r
- while ( sibling.getAttribute( '_fck_bookmark' )\r
+ while ( sibling.data( 'cke-bookmark' )\r
|| sibling.isEmptyInlineRemoveable() )\r
{\r
pendingNodes.push( sibling );\r
}\r
}\r
\r
- return function()\r
+ return function( inlineOnly )\r
{\r
- // Merge empty links and anchors also. (#5567)\r
- if ( !( CKEDITOR.dtd.$removeEmpty[ this.getName() ] || this.is( 'a' ) ) )\r
+ if ( ! ( inlineOnly === false\r
+ || CKEDITOR.dtd.$removeEmpty[ this.getName() ]\r
+ || this.is( 'a' ) ) ) // Merge empty links and anchors also. (#5567)\r
+ {\r
return;\r
+ }\r
\r
mergeElements( this, this.getNext(), true );\r
mergeElements( this, this.getPrevious() );\r
this.$.tabIndex = value;\r
else if ( name == 'checked' )\r
this.$.checked = value;\r
+ else if ( name == 'contenteditable' )\r
+ standard.call( this, 'contentEditable', value );\r
+ else\r
+ standard.apply( this, arguments );\r
+ return this;\r
+ };\r
+ }\r
+ else if ( CKEDITOR.env.ie8Compat && CKEDITOR.env.secure )\r
+ {\r
+ return function( name, value )\r
+ {\r
+ // IE8 throws error when setting src attribute to non-ssl value. (#7847)\r
+ if ( name == 'src' && value.match( /^http:\/\// ) )\r
+ try { standard.apply( this, arguments ); } catch( e ){}\r
else\r
standard.apply( this, arguments );\r
return this;\r
name = 'className';\r
else if ( name == 'tabindex' )\r
name = 'tabIndex';\r
+ else if ( name == 'contenteditable' )\r
+ name = 'contentEditable';\r
standard.call( this, name );\r
};\r
}\r
*/\r
removeStyle : function( name )\r
{\r
- this.setStyle( name, '' );\r
- if ( this.$.style.removeAttribute )\r
- this.$.style.removeAttribute( CKEDITOR.tools.cssStyleToDomStyle( name ) );\r
+ // Removes the specified property from the current style object.\r
+ var $ = this.$.style;\r
+\r
+ // "removeProperty" need to be specific on the following styles.\r
+ if ( !$.removeProperty && ( name == 'border' || name == 'margin' || name == 'padding' ) )\r
+ {\r
+ var names = expandedRules( name );\r
+ for ( var i = 0 ; i < names.length ; i++ )\r
+ this.removeStyle( names[ i ] );\r
+ return;\r
+ }\r
+\r
+ $.removeProperty ? $.removeProperty( name ) : $.removeAttribute( CKEDITOR.tools.cssStyleToDomStyle( name ) );\r
\r
if ( !this.$.style.cssText )\r
this.removeAttribute( 'style' );\r
*/\r
setOpacity : function( opacity )\r
{\r
- if ( CKEDITOR.env.ie )\r
+ if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 )\r
{\r
opacity = Math.round( opacity * 100 );\r
this.setStyle( 'filter', opacity >= 100 ? '' : 'progid:DXImageTransform.Microsoft.Alpha(opacity=' + opacity + ')' );\r
function()\r
{\r
this.$.style.MozUserSelect = 'none';\r
- this.on( 'dragstart', function (evt) { evt.data.preventDefault(); } );\r
+ this.on( 'dragstart', function( evt ) { evt.data.preventDefault(); } );\r
}\r
: CKEDITOR.env.webkit ?\r
function()\r
{\r
this.$.style.KhtmlUserSelect = 'none';\r
- this.on( 'dragstart', function (evt) { evt.data.preventDefault(); } );\r
+ this.on( 'dragstart', function( evt ) { evt.data.preventDefault(); } );\r
}\r
:\r
function()\r
if ( CKEDITOR.env.ie || CKEDITOR.env.opera )\r
{\r
var element = this.$,\r
+ elements = element.getElementsByTagName("*"),\r
e,\r
i = 0;\r
\r
element.unselectable = 'on';\r
\r
- while ( ( e = element.all[ i++ ] ) )\r
+ while ( ( e = elements[ i++ ] ) )\r
{\r
switch ( e.tagName.toLowerCase() )\r
{\r
getDocumentPosition : function( refDocument )\r
{\r
var x = 0, y = 0,\r
- body = this.getDocument().getBody(),\r
- quirks = this.getDocument().$.compatMode == 'BackCompat';\r
-\r
- var doc = this.getDocument();\r
+ doc = this.getDocument(),\r
+ body = doc.getBody(),\r
+ quirks = doc.$.compatMode == 'BackCompat';\r
\r
if ( document.documentElement[ "getBoundingClientRect" ] )\r
{\r
return { x : x, y : y };\r
},\r
\r
- scrollIntoView : function( alignTop )\r
+ /**\r
+ * Make any page element visible inside the browser viewport.\r
+ * @param {Boolean} [alignToTop]\r
+ */\r
+ scrollIntoView : function( alignToTop )\r
{\r
- // Get the element window.\r
- var win = this.getWindow(),\r
- winHeight = win.getViewPaneSize().height;\r
-\r
- // Starts from the offset that will be scrolled with the negative value of\r
- // the visible window height.\r
- var offset = winHeight * -1;\r
-\r
- // Append the view pane's height if align to top.\r
- // Append element height if we are aligning to the bottom.\r
- if ( alignTop )\r
- offset += winHeight;\r
- else\r
+ var parent = this.getParent();\r
+ if ( !parent ) return;\r
+\r
+ // Scroll the element into parent container from the inner out.\r
+ do\r
+ {\r
+ // Check ancestors that overflows.\r
+ var overflowed =\r
+ parent.$.clientWidth && parent.$.clientWidth < parent.$.scrollWidth\r
+ || parent.$.clientHeight && parent.$.clientHeight < parent.$.scrollHeight;\r
+\r
+ if ( overflowed )\r
+ this.scrollIntoParent( parent, alignToTop, 1 );\r
+\r
+ // Walk across the frame.\r
+ if ( parent.is( 'html' ) )\r
+ {\r
+ var win = parent.getWindow();\r
+\r
+ // Avoid security error.\r
+ try\r
+ {\r
+ var iframe = win.$.frameElement;\r
+ iframe && ( parent = new CKEDITOR.dom.element( iframe ) );\r
+ }\r
+ catch(er){}\r
+ }\r
+ }\r
+ while ( ( parent = parent.getParent() ) );\r
+ },\r
+\r
+ /**\r
+ * Make any page element visible inside one of the ancestors by scrolling the parent.\r
+ * @param {CKEDITOR.dom.element|CKEDITOR.dom.window} parent The container to scroll into.\r
+ * @param {Boolean} [alignToTop] Align the element's top side with the container's\r
+ * when <code>true</code> is specified; align the bottom with viewport bottom when\r
+ * <code>false</code> is specified. Otherwise scroll on either side with the minimum\r
+ * amount to show the element.\r
+ * @param {Boolean} [hscroll] Whether horizontal overflow should be considered.\r
+ */\r
+ scrollIntoParent : function( parent, alignToTop, hscroll )\r
+ {\r
+ !parent && ( parent = this.getWindow() );\r
+\r
+ var doc = parent.getDocument();\r
+ var isQuirks = doc.$.compatMode == 'BackCompat';\r
+\r
+ // On window <html> is scrolled while quirks scrolls <body>.\r
+ if ( parent instanceof CKEDITOR.dom.window )\r
+ parent = isQuirks ? doc.getBody() : doc.getDocumentElement();\r
+\r
+ // Scroll the parent by the specified amount.\r
+ function scrollBy( x, y )\r
{\r
- offset += this.$.offsetHeight || 0;\r
+ // Webkit doesn't support "scrollTop/scrollLeft"\r
+ // on documentElement/body element.\r
+ if ( /body|html/.test( parent.getName() ) )\r
+ parent.getWindow().$.scrollBy( x, y );\r
+ else\r
+ {\r
+ parent.$[ 'scrollLeft' ] += x;\r
+ parent.$[ 'scrollTop' ] += y;\r
+ }\r
+ }\r
+\r
+ // Figure out the element position relative to the specified window.\r
+ function screenPos( element, refWin )\r
+ {\r
+ var pos = { x: 0, y: 0 };\r
+\r
+ if ( !( element.is( isQuirks ? 'body' : 'html' ) ) )\r
+ {\r
+ var box = element.$.getBoundingClientRect();\r
+ pos.x = box.left, pos.y = box.top;\r
+ }\r
\r
- // Consider the margin in the scroll, which is ok for our current needs, but\r
- // needs investigation if we will be using this function in other places.\r
- offset += parseInt( this.getComputedStyle( 'marginBottom' ) || 0, 10 ) || 0;\r
+ var win = element.getWindow();\r
+ if ( !win.equals( refWin ) )\r
+ {\r
+ var outerPos = screenPos( CKEDITOR.dom.element.get( win.$.frameElement ), refWin );\r
+ pos.x += outerPos.x, pos.y += outerPos.y;\r
+ }\r
+\r
+ return pos;\r
}\r
\r
- // Append the offsets for the entire element hierarchy.\r
- var elementPosition = this.getDocumentPosition();\r
- offset += elementPosition.y;\r
+ // calculated margin size.\r
+ function margin( element, side )\r
+ {\r
+ return parseInt( element.getComputedStyle( 'margin-' + side ) || 0, 10 ) || 0;\r
+ }\r
+\r
+ var win = parent.getWindow();\r
+\r
+ var thisPos = screenPos( this, win ),\r
+ parentPos = screenPos( parent, win ),\r
+ eh = this.$.offsetHeight,\r
+ ew = this.$.offsetWidth,\r
+ ch = parent.$.clientHeight,\r
+ cw = parent.$.clientWidth,\r
+ lt,\r
+ br;\r
+\r
+ // Left-top margins.\r
+ lt =\r
+ {\r
+ x : thisPos.x - margin( this, 'left' ) - parentPos.x || 0,\r
+ y : thisPos.y - margin( this, 'top' ) - parentPos.y|| 0\r
+ };\r
+\r
+ // Bottom-right margins.\r
+ br =\r
+ {\r
+ x : thisPos.x + ew + margin( this, 'right' ) - ( ( parentPos.x ) + cw ) || 0,\r
+ y : thisPos.y + eh + margin( this, 'bottom' ) - ( ( parentPos.y ) + ch ) || 0\r
+ };\r
\r
- // offset value might be out of range(nagative), fix it(#3692).\r
- offset = offset < 0 ? 0 : offset;\r
+ // 1. Do the specified alignment as much as possible;\r
+ // 2. Otherwise be smart to scroll only the minimum amount;\r
+ // 3. Never cut at the top;\r
+ // 4. DO NOT scroll when already visible.\r
+ if ( lt.y < 0 || br.y > 0 )\r
+ {\r
+ scrollBy( 0,\r
+ alignToTop === true ? lt.y :\r
+ alignToTop === false ? br.y :\r
+ lt.y < 0 ? lt.y : br.y );\r
+ }\r
\r
- // Scroll the window to the desired position, if not already visible(#3795).\r
- var currentScroll = win.getScrollPosition().y;\r
- if ( offset > currentScroll || offset < currentScroll - winHeight )\r
- win.$.scrollTo( 0, offset );\r
+ if ( hscroll && ( lt.x < 0 || br.x > 0 ) )\r
+ scrollBy( lt.x < 0 ? lt.x : br.x, 0 );\r
},\r
\r
setState : function( state )\r
\r
// Replace the node.\r
this.getParent() && this.$.parentNode.replaceChild( newNode.$, this.$ );\r
- newNode.$._cke_expando = this.$._cke_expando;\r
+ newNode.$[ 'data-cke-expando' ] = this.$[ 'data-cke-expando' ];\r
this.$ = newNode.$;\r
},\r
\r
if ( !event.data.getTarget().hasClass( 'cke_enable_context_menu' ) )\r
event.data.preventDefault();\r
} );\r
+ },\r
+\r
+ /**\r
+ * Gets element's direction. Supports both CSS 'direction' prop and 'dir' attr.\r
+ */\r
+ getDirection : function( useComputed )\r
+ {\r
+ return useComputed ?\r
+ this.getComputedStyle( 'direction' )\r
+ // Webkit: offline element returns empty direction (#8053).\r
+ || this.getDirection()\r
+ || this.getDocument().$.dir\r
+ || this.getDocument().getBody().getDirection( 1 )\r
+ : this.getStyle( 'direction' ) || this.getAttribute( 'dir' );\r
+ },\r
+\r
+ /**\r
+ * Gets, sets and removes custom data to be stored as HTML5 data-* attributes.\r
+ * @param {String} name The name of the attribute, excluding the 'data-' part.\r
+ * @param {String} [value] The value to set. If set to false, the attribute will be removed.\r
+ * @example\r
+ * element.data( 'extra-info', 'test' ); // appended the attribute data-extra-info="test" to the element\r
+ * alert( element.data( 'extra-info' ) ); // "test"\r
+ * element.data( 'extra-info', false ); // remove the data-extra-info attribute from the element\r
+ */\r
+ data : function ( name, value )\r
+ {\r
+ name = 'data-' + name;\r
+ if ( value === undefined )\r
+ return this.getAttribute( name );\r
+ else if ( value === false )\r
+ this.removeAttribute( name );\r
+ else\r
+ this.setAttribute( name, value );\r
+\r
+ return null;\r
}\r
});\r
+\r
+ var sides = {\r
+ width : [ "border-left-width", "border-right-width","padding-left", "padding-right" ],\r
+ height : [ "border-top-width", "border-bottom-width", "padding-top", "padding-bottom" ]\r
+ };\r
+\r
+ // Generate list of specific style rules, applicable to margin/padding/border.\r
+ function expandedRules( style )\r
+ {\r
+ var sides = [ 'top', 'left', 'right', 'bottom' ], components;\r
+\r
+ if ( style == 'border' )\r
+ components = [ 'color', 'style', 'width' ];\r
+\r
+ var styles = [];\r
+ for ( var i = 0 ; i < sides.length ; i++ )\r
+ {\r
+\r
+ if ( components )\r
+ {\r
+ for ( var j = 0 ; j < components.length ; j++ )\r
+ styles.push( [ style, sides[ i ], components[j] ].join( '-' ) );\r
+ }\r
+ else\r
+ styles.push( [ style, sides[ i ] ].join( '-' ) );\r
+ }\r
+\r
+ return styles;\r
+ }\r
+\r
+ function marginAndPaddingSize( type )\r
+ {\r
+ var adjustment = 0;\r
+ for ( var i = 0, len = sides[ type ].length; i < len; i++ )\r
+ adjustment += parseInt( this.getComputedStyle( sides [ type ][ i ] ) || 0, 10 ) || 0;\r
+ return adjustment;\r
+ }\r
+\r
+ /**\r
+ * Sets the element size considering the box model.\r
+ * @name CKEDITOR.dom.element.prototype.setSize\r
+ * @function\r
+ * @param {String} type The dimension to set. It accepts "width" and "height".\r
+ * @param {Number} size The length unit in px.\r
+ * @param {Boolean} isBorderBox Apply the size based on the border box model.\r
+ */\r
+ CKEDITOR.dom.element.prototype.setSize = function( type, size, isBorderBox )\r
+ {\r
+ if ( typeof size == 'number' )\r
+ {\r
+ if ( isBorderBox && !( CKEDITOR.env.ie && CKEDITOR.env.quirks ) )\r
+ size -= marginAndPaddingSize.call( this, type );\r
+\r
+ this.setStyle( type, size + 'px' );\r
+ }\r
+ };\r
+\r
+ /**\r
+ * Gets the element size, possibly considering the box model.\r
+ * @name CKEDITOR.dom.element.prototype.getSize\r
+ * @function\r
+ * @param {String} type The dimension to get. It accepts "width" and "height".\r
+ * @param {Boolean} isBorderBox Get the size based on the border box model.\r
+ */\r
+ CKEDITOR.dom.element.prototype.getSize = function( type, isBorderBox )\r
+ {\r
+ var size = Math.max( this.$[ 'offset' + CKEDITOR.tools.capitalize( type ) ],\r
+ this.$[ 'client' + CKEDITOR.tools.capitalize( type ) ] ) || 0;\r
+\r
+ if ( isBorderBox )\r
+ size -= marginAndPaddingSize.call( this, type );\r
+\r
+ return size;\r
+ };\r
+})();\r