diff options
Diffstat (limited to '_source/core')
49 files changed, 774 insertions, 273 deletions
diff --git a/_source/core/_bootstrap.js b/_source/core/_bootstrap.js index 36d9d91..3bbd778 100644 --- a/_source/core/_bootstrap.js +++ b/_source/core/_bootstrap.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -12,12 +12,17 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // Check is High Contrast is active by creating a temporary element with a // background image. - var testImage = ( CKEDITOR.env.ie && CKEDITOR.env.version < 7 ) ? ( CKEDITOR.basePath + 'images/spacer.gif' ) : 'about:blank'; + var useSpacer = CKEDITOR.env.ie && CKEDITOR.env.version < 7, + useBlank = CKEDITOR.env.ie && CKEDITOR.env.version == 7; + + + var backgroundImageUrl = useSpacer ? ( CKEDITOR.basePath + 'images/spacer.gif' ) : + useBlank ? 'about:blank' : 'data:image/png;base64,'; var hcDetect = CKEDITOR.dom.element.createFromHtml( '<div style="width:0px;height:0px;' + 'position:absolute;left:-10000px;' + - 'background-image:url(' + testImage + ')"></div>', CKEDITOR.document ); + 'background-image:url(' + backgroundImageUrl + ')"></div>', CKEDITOR.document ); hcDetect.appendTo( CKEDITOR.document.getHead() ); diff --git a/_source/core/ajax.js b/_source/core/ajax.js index 82ad4d5..176d1a2 100644 --- a/_source/core/ajax.js +++ b/_source/core/ajax.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/ckeditor.js b/_source/core/ckeditor.js index 298d36d..700bad2 100644 --- a/_source/core/ckeditor.js +++ b/_source/core/ckeditor.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/ckeditor_base.js b/_source/core/ckeditor_base.js index 496bd1f..cfaa9e4 100644 --- a/_source/core/ckeditor_base.js +++ b/_source/core/ckeditor_base.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -12,7 +12,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // Must be updated on changes in the script, as well as updated in the // ckeditor_source.js and ckeditor_basic_source.js files. -// if(!window.CKEDITOR)window.CKEDITOR=(function(){var a={timestamp:'',version:'3.0.1',rev:'4391',_:{},status:'unloaded',basePath:(function(){var d=window.CKEDITOR_BASEPATH||'';if(!d){var e=document.getElementsByTagName('script');for(var f=0;f<e.length;f++){var g=e[f].src.match(/(^|.*[\\\/])ckeditor(?:_basic)?(?:_source)?.js(?:\?.*)?$/i);if(g){d=g[1];break;}}}if(d.indexOf('://')==-1)if(d.indexOf('/')===0)d=location.href.match(/^.*?:\/\/[^\/]*/)[0]+d;else d=location.href.match(/^[^\?]*\/(?:)/)[0]+d;return d;})(),getUrl:function(d){if(d.indexOf('://')==-1&&d.indexOf('/')!==0)d=this.basePath+d;if(this.timestamp&&d.charAt(d.length-1)!='/')d+=(d.indexOf('?')>=0?'&':'?')+('t=')+this.timestamp;return d;}},b=window.CKEDITOR_GETURL;if(b){var c=a.getUrl;a.getUrl=function(d){return b.call(a,d)||c.call(a,d);};}return a;})(); +// if(!window.CKEDITOR)window.CKEDITOR=(function(){var a={timestamp:'',version:'3.1',rev:'4891',_:{},status:'unloaded',basePath:(function(){var d=window.CKEDITOR_BASEPATH||'';if(!d){var e=document.getElementsByTagName('script');for(var f=0;f<e.length;f++){var g=e[f].src.match(/(^|.*[\\\/])ckeditor(?:_basic)?(?:_source)?.js(?:\?.*)?$/i);if(g){d=g[1];break;}}}if(d.indexOf('://')==-1)if(d.indexOf('/')===0)d=location.href.match(/^.*?:\/\/[^\/]*/)[0]+d;else d=location.href.match(/^[^\?]*\/(?:)/)[0]+d;return d;})(),getUrl:function(d){if(d.indexOf('://')==-1&&d.indexOf('/')!==0)d=this.basePath+d;if(this.timestamp&&d.charAt(d.length-1)!='/')d+=(d.indexOf('?')>=0?'&':'?')+('t=')+this.timestamp;return d;}},b=window.CKEDITOR_GETURL;if(b){var c=a.getUrl;a.getUrl=function(d){return b.call(a,d)||c.call(a,d);};}return a;})(); // #### Raw code // ATTENTION: read the above "Compressed Code" notes when changing this code. @@ -43,7 +43,7 @@ if ( !window.CKEDITOR ) // The production implementation contains a fixed timestamp, unique // for each release, generated by the releaser. // (Base 36 value of each component of YYMMDDHH - 4 chars total - e.g. 87bm == 08071122) - timestamp : '99GE', + timestamp : 'A06B', /** * Contains the CKEditor version number. @@ -51,7 +51,7 @@ if ( !window.CKEDITOR ) * @example * alert( CKEDITOR.version ); // e.g. 'CKEditor 3.0 Beta' */ - version : '3.0.1', + version : '3.1', /** * Contains the CKEditor revision number. @@ -60,7 +60,7 @@ if ( !window.CKEDITOR ) * @example * alert( CKEDITOR.revision ); // e.g. '3975' */ - revision : '4391', + revision : '4891', /** * Private object used to hold core stuff. It should not be used out of diff --git a/_source/core/ckeditor_basic.js b/_source/core/ckeditor_basic.js index 3401f1d..f736e25 100644 --- a/_source/core/ckeditor_basic.js +++ b/_source/core/ckeditor_basic.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/command.js b/_source/core/command.js index f44538c..e56ca6c 100644 --- a/_source/core/command.js +++ b/_source/core/command.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/commanddefinition.js b/_source/core/commanddefinition.js index 860b130..b3ed92c 100644 --- a/_source/core/commanddefinition.js +++ b/_source/core/commanddefinition.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/config.js b/_source/core/config.js index 8294777..1df0cb2 100644 --- a/_source/core/config.js +++ b/_source/core/config.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -40,7 +40,7 @@ CKEDITOR.config = * // Do not load any custom configuration file. * CKEDITOR.replace( 'myfiled', { customConfig : '' } ); */ - customConfig : CKEDITOR.getUrl( 'config.js' ), + customConfig : 'config.js', /** * Whether the replaced element (usually a textarea) is to be updated @@ -167,6 +167,20 @@ CKEDITOR.config = docType : '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">', /** + * Sets the 'id' attribute to be used on body if it doesn't have one. + * @type String + * @default '' + */ + bodyId : '', + + /** + * Sets the 'class' attribute to be used on body if it doesn't have one. + * @type String + * @default '' + */ + bodyClass : '', + + /** * Indicates whether the contents to be edited are being inputted as a full * HTML page. A full page includes the <html>, <head> and * <body> tags. The final output will also reflect this setting, @@ -198,7 +212,7 @@ CKEDITOR.config = * @type String * @example */ - plugins : 'about,basicstyles,blockquote,button,clipboard,colorbutton,colordialog,contextmenu,elementspath,enterkey,entities,filebrowser,find,flash,font,format,forms,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,maximize,newpage,pagebreak,pastefromword,pastetext,popup,preview,print,removeformat,resize,save,scayt,smiley,showblocks,sourcearea,stylescombo,table,tabletools,specialchar,tab,templates,toolbar,undo,wysiwygarea,wsc', + plugins : 'about,basicstyles,blockquote,button,clipboard,colorbutton,colordialog,contextmenu,div,elementspath,enterkey,entities,filebrowser,find,flash,font,format,forms,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,maximize,newpage,pagebreak,pastefromword,pastetext,popup,preview,print,removeformat,resize,save,scayt,smiley,showblocks,showborders,sourcearea,stylescombo,table,tabletools,specialchar,tab,templates,toolbar,undo,wysiwygarea,wsc', /** * List of additional plugins to be loaded. This is a tool setting which @@ -283,7 +297,6 @@ CKEDITOR.config = * config.baseFloatZIndex = 2000 */ baseFloatZIndex : 10000 - }; // PACKAGER_RENAME( CKEDITOR.config ) diff --git a/_source/core/dom.js b/_source/core/dom.js index 1fb9903..fed9690 100644 --- a/_source/core/dom.js +++ b/_source/core/dom.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/dom/comment.js b/_source/core/dom/comment.js new file mode 100644 index 0000000..9e9c9b7 --- /dev/null +++ b/_source/core/dom/comment.js @@ -0,0 +1,32 @@ +/* +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ + +/** + * @fileOverview Defines the {@link CKEDITOR.dom.comment} class, which represents + * a DOM comment node. + */ + +CKEDITOR.dom.comment = CKEDITOR.tools.createClass( +{ + base : CKEDITOR.dom.node, + + $ : function( text, ownerDocument ) + { + if ( typeof text == 'string' ) + text = ( ownerDocument ? ownerDocument.$ : document ).createComment( text ); + + this.base( text ); + }, + + proto : + { + type : CKEDITOR.NODE_COMMENT, + + getOuterHtml : function() + { + return '<!--' + this.$.nodeValue + '-->'; + } + } +}); diff --git a/_source/core/dom/document.js b/_source/core/dom/document.js index dfe9a3c..0575338 100644 --- a/_source/core/dom/document.js +++ b/_source/core/dom/document.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -52,6 +52,21 @@ CKEDITOR.tools.extend( CKEDITOR.dom.document.prototype, } }, + appendStyleText : function( cssStyleText ) + { + if ( this.$.createStyleSheet ) + { + var styleSheet = this.$.createStyleSheet( "" ); + styleSheet.cssText = cssStyleText ; + } + else + { + var style = new CKEDITOR.dom.element( 'style', this ); + style.append( new CKEDITOR.dom.text( cssStyleText, this ) ); + this.getHead().append( style ); + } + }, + createElement : function( name, attribsAndStyles ) { var element = new CKEDITOR.dom.element( name, this ); diff --git a/_source/core/dom/documentfragment.js b/_source/core/dom/documentfragment.js index ed04202..69bc70e 100644 --- a/_source/core/dom/documentfragment.js +++ b/_source/core/dom/documentfragment.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ /** diff --git a/_source/core/dom/domobject.js b/_source/core/dom/domobject.js index 983f523..a2964b8 100644 --- a/_source/core/dom/domobject.js +++ b/_source/core/dom/domobject.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/dom/element.js b/_source/core/dom/element.js index 5a96a0f..2f58326 100644 --- a/_source/core/dom/element.js +++ b/_source/core/dom/element.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -256,15 +256,15 @@ CKEDITOR.tools.extend( CKEDITOR.dom.element.prototype, * @param {CKEDITOR.dom.element} parent The anscestor element to get broken. * @example * // Before breaking: - * // <b>This <i>is some<span /> sample</i> test text</b> - * // If "element" is <span /> and "parent" is <i>: - * // <b>This <i>is some</i><span /><i> sample</i> test text</b> + * // <b>This <i>is some<span /> sample</i> test text</b> + * // If "element" is <span /> and "parent" is <i>: + * // <b>This <i>is some</i><span /><i> sample</i> test text</b> * element.breakParent( parent ); * @example * // Before breaking: - * // <b>This <i>is some<span /> sample</i> test text</b> - * // If "element" is <span /> and "parent" is <b>: - * // <b>This <i>is some</i></b><span /><b><i> sample</i> test text</b> + * // <b>This <i>is some<span /> sample</i> test text</b> + * // If "element" is <span /> and "parent" is <b>: + * // <b>This <i>is some</i></b><span /><b><i> sample</i> test text</b> * element.breakParent( parent ); */ breakParent : function( parent ) @@ -328,7 +328,9 @@ CKEDITOR.tools.extend( CKEDITOR.dom.element.prototype, */ getHtml : function() { - return this.$.innerHTML; + var retval = this.$.innerHTML; + // Strip <?xml:namespace> tags in IE. (#3341). + return CKEDITOR.env.ie ? retval.replace( /<\?[^>]*>/g, '' ) : retval; }, getOuterHtml : function() @@ -425,8 +427,16 @@ CKEDITOR.tools.extend( CKEDITOR.dom.element.prototype, break; case 'checked': - return this.$.checked; - break; + { + var attr = this.$.attributes.getNamedItem( name ), + attrValue = attr.specified ? attr.nodeValue // For value given by parser. + : this.$.checked; // For value created via DOM interface. + + return attrValue ? 'checked' : null; + } + + case 'hspace': + return this.$.hspace; case 'style': // IE does not return inline styles via getAttribute(). See #2947. @@ -627,6 +637,7 @@ CKEDITOR.tools.extend( CKEDITOR.dom.element.prototype, /** * Gets the first child node of this element. + * @param {Function} evaluator Filtering the result node. * @returns {CKEDITOR.dom.node} The first child node or null if not * available. * @example @@ -634,10 +645,14 @@ CKEDITOR.tools.extend( CKEDITOR.dom.element.prototype, * var first = <b>element.getFirst()</b>; * alert( first.getName() ); // "b" */ - getFirst : function() + getFirst : function( evaluator ) { - var $ = this.$.firstChild; - return $ ? new CKEDITOR.dom.node( $ ) : null; + var first = this.$.firstChild, + retval = first && new CKEDITOR.dom.node( first ); + if ( retval && evaluator && !evaluator( retval ) ) + retval = retval.getNext( evaluator ); + + return retval; }, /** @@ -722,8 +737,8 @@ CKEDITOR.tools.extend( CKEDITOR.dom.element.prototype, for ( i = 0 ; i < otherLength ; i++ ) { attribute = otherAttribs[ i ]; - - if ( ( !CKEDITOR.env.ie || ( attribute.specified && attribute.nodeName != '_cke_expando' ) ) && attribute.nodeValue != thisAttribs.getAttribute( attribute.nodeName ) ) + if ( attribute.specified && attribute.nodeName != '_cke_expando' + && attribute.nodeValue != this.getAttribute( attribute.nodeName ) ) return false; } } @@ -739,7 +754,24 @@ CKEDITOR.tools.extend( CKEDITOR.dom.element.prototype, */ isVisible : function() { - return this.$.offsetWidth && ( this.$.style.visibility != 'hidden' ); + var isVisible = !!this.$.offsetHeight && this.getComputedStyle( 'visibility' ) != 'hidden', + elementWindow, + elementWindowFrame; + + // Webkit and Opera report non-zero offsetHeight despite that + // element is inside an invisible iframe. (#4542) + if ( isVisible && ( CKEDITOR.env.webkit || CKEDITOR.env.opera ) ) + { + elementWindow = this.getWindow(); + + if ( !elementWindow.equals( CKEDITOR.document.getWindow() ) + && ( elementWindowFrame = elementWindow.$.frameElement ) ) + { + isVisible = new CKEDITOR.dom.element( elementWindowFrame ).isVisible(); + } + } + + return isVisible; }, /** @@ -971,10 +1003,9 @@ CKEDITOR.tools.extend( CKEDITOR.dom.element.prototype, */ removeStyle : function( name ) { + this.setStyle( name, '' ); if ( this.$.style.removeAttribute ) this.$.style.removeAttribute( CKEDITOR.tools.cssStyleToDomStyle( name ) ); - else - this.setStyle( name, '' ); if ( !this.$.style.cssText ) this.removeAttribute( 'style' ); @@ -1306,16 +1337,22 @@ CKEDITOR.tools.extend( CKEDITOR.dom.element.prototype, { var attribute = attributes[n]; + // Lowercase attribute name hard rule is broken for + // some attribute on IE, e.g. CHECKED. + var attrName = attribute.nodeName.toLowerCase(), + attrValue; + + // We can set the type only once, so do it with the proper value, not copying it. + if ( attrName in skipAttributes ) + continue; + + if( attrName == 'checked' && ( attrValue = this.getAttribute( attrName ) ) ) + dest.setAttribute( attrName, attrValue ); // IE BUG: value attribute is never specified even if it exists. - if ( attribute.specified || - ( CKEDITOR.env.ie && attribute.nodeValue && attribute.nodeName.toLowerCase() == 'value' ) ) + else if ( attribute.specified || + ( CKEDITOR.env.ie && attribute.nodeValue && attrName == 'value' ) ) { - var attrName = attribute.nodeName; - // We can set the type only once, so do it with the proper value, not copying it. - if ( attrName in skipAttributes ) - continue; - - var attrValue = this.getAttribute( attrName ); + attrValue = this.getAttribute( attrName ); if ( attrValue === null ) attrValue = attribute.nodeValue; diff --git a/_source/core/dom/elementpath.js b/_source/core/dom/elementpath.js index df75554..74641ae 100644 --- a/_source/core/dom/elementpath.js +++ b/_source/core/dom/elementpath.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/dom/event.js b/_source/core/dom/event.js index 41cbd48..24b75d0 100644 --- a/_source/core/dom/event.js +++ b/_source/core/dom/event.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/dom/node.js b/_source/core/dom/node.js index a32e45a..24e3894 100644 --- a/_source/core/dom/node.js +++ b/_source/core/dom/node.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/dom/nodelist.js b/_source/core/dom/nodelist.js index c0f4087..155f0ad 100644 --- a/_source/core/dom/nodelist.js +++ b/_source/core/dom/nodelist.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/dom/range.js b/_source/core/dom/range.js index cd7ba9d..d3ad684 100644 --- a/_source/core/dom/range.js +++ b/_source/core/dom/range.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -278,7 +278,7 @@ CKEDITOR.dom.range = function( document ) if ( CKEDITOR.tools.trim( node.getText() ).length ) return false; } - else + else if( node.type == CKEDITOR.NODE_ELEMENT ) { // If there are non-empty inline elements (e.g. <img />), then we're not // at the start. @@ -308,6 +308,15 @@ CKEDITOR.dom.range = function( document ) || node.getParent().hasAttribute( '_fck_bookmark' ); } + var whitespaceEval = new CKEDITOR.dom.walker.whitespaces(), + bookmarkEval = new CKEDITOR.dom.walker.bookmark(); + + function nonWhitespaceOrBookmarkEval( node ) + { + // Whitespaces and bookmark nodes are to be ignored. + return !whitespaceEval( node ) && !bookmarkEval( node ); + } + CKEDITOR.dom.range.prototype = { clone : function() @@ -1183,7 +1192,8 @@ CKEDITOR.dom.range = function( document ) this.setStartAt( blockBoundary, !blockBoundary.is( 'br' ) && - ( !enlargeable || blockBoundary.contains( enlargeable ) ) ? + ( !enlargeable && this.checkStartOfBlock() + || enlargeable && blockBoundary.contains( enlargeable ) ) ? CKEDITOR.POSITION_AFTER_START : CKEDITOR.POSITION_AFTER_END ); @@ -1208,8 +1218,8 @@ CKEDITOR.dom.range = function( document ) // the document position of it with 'enlargeable' node. this.setEndAt( blockBoundary, - !blockBoundary.is( 'br' ) && - ( !enlargeable || blockBoundary.contains( enlargeable ) ) ? + ( !enlargeable && this.checkEndOfBlock() + || enlargeable && blockBoundary.contains( enlargeable ) ) ? CKEDITOR.POSITION_BEFORE_END : CKEDITOR.POSITION_BEFORE_START ); // We must include the <br> at the end of range if there's @@ -1457,18 +1467,7 @@ CKEDITOR.dom.range = function( document ) } else { - // Extract the contents of the block from the selection point to the end - // of its contents. - this.setEndAt( startBlock, CKEDITOR.POSITION_BEFORE_END ); - var documentFragment = this.extractContents(); - - // Duplicate the block element after it. - endBlock = startBlock.clone( false ); - - // Place the extracted contents into the duplicated block. - documentFragment.appendTo( endBlock ); - endBlock.insertAfter( startBlock ); - this.moveToPosition( startBlock, CKEDITOR.POSITION_AFTER_END ); + endBlock = this.splitElement( startBlock ); // In Gecko, the last child node must be a bogus <br>. // Note: bogus <br> added under <ul> or <ol> would cause @@ -1488,6 +1487,33 @@ CKEDITOR.dom.range = function( document ) }, /** + * Branch the specified element from the collapsed range position and + * place the caret between the two result branches. + * Note: The range must be collapsed and been enclosed by this element. + * @param {CKEDITOR.dom.element} element + * @return {CKEDITOR.dom.element} Root element of the new branch after the split. + */ + splitElement : function( toSplit ) + { + if ( !this.collapsed ) + return null; + + // Extract the contents of the block from the selection point to the end + // of its contents. + this.setEndAt( toSplit, CKEDITOR.POSITION_BEFORE_END ); + var documentFragment = this.extractContents(); + + // Duplicate the element after it. + var clone = toSplit.clone( false ); + + // Place the extracted contents into the duplicated element. + documentFragment.appendTo( clone ); + clone.insertAfter( toSplit ); + this.moveToPosition( toSplit, CKEDITOR.POSITION_AFTER_END ); + return clone; + }, + + /** * Check whether current range is on the inner edge of the specified element. * @param {Number} checkType ( CKEDITOR.START | CKEDITOR.END ) The checking side. * @param {CKEDITOR.dom.element} element The target element to check. @@ -1579,34 +1605,69 @@ CKEDITOR.dom.range = function( document ) }, /** - * Moves the range boundaries to the first editing point inside an + * Moves the range boundaries to the first/end editing point inside an * element. For example, in an element tree like * "<p><b><i></i></b> Text</p>", the start editing point is * "<p><b><i>^</i></b> Text</p>" (inside <i>). - * @param {CKEDITOR.dom.element} targetElement The element into which - * look for the editing spot. + * @param {CKEDITOR.dom.element} el The element into which look for the + * editing spot. + * @param {Boolean} isMoveToEnd Whether move to the end editable position. */ - moveToElementEditStart : function( targetElement ) + moveToElementEditablePosition : function( el, isMoveToEnd ) { - var editableElement; + var isEditable; - while ( targetElement && targetElement.type == CKEDITOR.NODE_ELEMENT ) + while ( el && el.type == CKEDITOR.NODE_ELEMENT ) { - if ( targetElement.isEditable() ) - editableElement = targetElement; - else if ( editableElement ) - break ; // If we already found an editable element, stop the loop. + isEditable = el.isEditable(); - targetElement = targetElement.getFirst(); - } + // If an editable element is found, move inside it. + if ( isEditable ) + this.moveToPosition( el, isMoveToEnd ? + CKEDITOR.POSITION_BEFORE_END : + CKEDITOR.POSITION_AFTER_START ); + // Stop immediately if we've found a non editable inline element (e.g <img>). + else if ( CKEDITOR.dtd.$inline[ el.getName() ] ) + { + this.moveToPosition( el, isMoveToEnd ? + CKEDITOR.POSITION_AFTER_END : + CKEDITOR.POSITION_BEFORE_START ); + return true; + } - if ( editableElement ) - { - this.moveToPosition(editableElement, CKEDITOR.POSITION_AFTER_START); - return true; + // Non-editable non-inline elements are to be bypassed, getting the next one. + if ( CKEDITOR.dtd.$empty[ el.getName() ] ) + el = el[ isMoveToEnd ? 'getPrevious' : 'getNext' ]( nonWhitespaceOrBookmarkEval ); + else + el = el[ isMoveToEnd ? 'getLast' : 'getFirst' ]( nonWhitespaceOrBookmarkEval ); + + // Stop immediately if we've found a text node. + if ( el && el.type == CKEDITOR.NODE_TEXT ) + { + this.moveToPosition( el, isMoveToEnd ? + CKEDITOR.POSITION_AFTER_END : + CKEDITOR.POSITION_BEFORE_START ); + return true; + } } - else - return false; + + return isEditable; + }, + + /** + *@see {CKEDITOR.dom.range.moveToElementEditablePosition} + */ + moveToElementEditStart : function( target ) + { + return this.moveToElementEditablePosition( target ); + }, + + /** + *@see {CKEDITOR.dom.range.moveToElementEditablePosition} + */ + moveToElementEditEnd : function( target ) + { + return this.moveToElementEditablePosition( target, true ); }, /** diff --git a/_source/core/dom/text.js b/_source/core/dom/text.js index 1f8b192..407c47f 100644 --- a/_source/core/dom/text.js +++ b/_source/core/dom/text.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/dom/walker.js b/_source/core/dom/walker.js index 766eaa2..2010078 100644 --- a/_source/core/dom/walker.js +++ b/_source/core/dom/walker.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -47,7 +47,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license { return ( ( !movingOut || !limitLTR.equals( node ) ) && ( !blockerLTR || !node.equals( blockerLTR ) ) - && ( node.type != CKEDITOR.NODE_ELEMENT || node.getName() != 'body' ) ); + && ( node.type != CKEDITOR.NODE_ELEMENT || !movingOut || node.getName() != 'body' ) ); }; } @@ -62,7 +62,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license { return ( ( !movingOut || !limitRTL.equals( node ) ) && ( !blockerRTL || !node.equals( blockerRTL ) ) - && ( node.type != CKEDITOR.NODE_ELEMENT || node.getName() != 'body' ) ); + && ( node.type != CKEDITOR.NODE_ELEMENT || !movingOut || node.getName() != 'body' ) ); }; } @@ -78,7 +78,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license if ( stopGuard( node, movingOut ) === false ) return false; - return userGuard( node ); + return userGuard( node, movingOut ); }; } else @@ -396,7 +396,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license }; /** - * Whether the node contains only white-spaces characters. + * Whether the node is a text node containing only whitespaces characters. * @param isReject */ CKEDITOR.dom.walker.whitespaces = function( isReject ) @@ -408,4 +408,44 @@ For licensing, see LICENSE.html or http://ckeditor.com/license return isReject ^ isWhitespace; }; }; + + /** + * Whether the node is invisible in wysiwyg mode. + * @param isReject + */ + CKEDITOR.dom.walker.invisible = function( isReject ) + { + var whitespace = CKEDITOR.dom.walker.whitespaces(); + return function( node ) + { + // Nodes that take no spaces in wysiwyg: + // 1. White-spaces but not including NBSP; + // 2. Empty inline elements, e.g. <b></b> we're checking here + // 'offsetHeight' instead of 'offsetWidth' for properly excluding + // all sorts of empty paragraph, e.g. <br />. + var isInvisible = whitespace( node ) || node.is && !node.$.offsetHeight; + return isReject ^ isInvisible; + }; + }; + + var tailNbspRegex = /^[\t\r\n ]*(?: |\xa0)$/, + isNotWhitespaces = CKEDITOR.dom.walker.whitespaces( true ), + isNotBookmark = CKEDITOR.dom.walker.bookmark( false, true ), + fillerEvaluator = function( element ) + { + return isNotBookmark( element ) && isNotWhitespaces( element ); + }; + + // Check if there's a filler node at the end of an element, and return it. + CKEDITOR.dom.element.prototype.getBogus = function () + { + var tail = this.getLast( fillerEvaluator ); + if ( tail && ( !CKEDITOR.env.ie ? tail.is && tail.is( 'br' ) + : tail.getText && tailNbspRegex.test( tail.getText() ) ) ) + { + return tail; + } + return false; + }; + })(); diff --git a/_source/core/dom/window.js b/_source/core/dom/window.js index 813a799..c9fb002 100644 --- a/_source/core/dom/window.js +++ b/_source/core/dom/window.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/dtd.js b/_source/core/dtd.js index 0149334..52b39cf 100644 --- a/_source/core/dtd.js +++ b/_source/core/dtd.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -32,7 +32,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license */ CKEDITOR.dtd = (function() { - var X = CKEDITOR.tools.extend, + var X = CKEDITOR.tools.extend, A = {isindex:1,fieldset:1}, B = {input:1,button:1,select:1,textarea:1,label:1}, @@ -51,14 +51,22 @@ CKEDITOR.dtd = (function() N = {'#':1}, O = X({param:1},K), P = X({form:1},A,D,E,I), - Q = {li:1}; + Q = {li:1}, + R = {style:1,script:1}, + S = {base:1,link:1,meta:1,title:1}, + T = X(S,R), + U = {head:1,body:1}, + V = {html:1}; var block = {address:1,blockquote:1,center:1,dir:1,div:1,dl:1,fieldset:1,form:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,hr:1,isindex:1,menu:1,noframes:1,ol:1,p:1,pre:1,table:1,ul:1}; - return /** @lends CKEDITOR.dtd */ { + return /** @lends CKEDITOR.dtd */ { // The "$" items have been added manually. + // List of elements living outside body. + $nonBodyContent: X(V,U,S), + /** * List of block elements, like "p" or "div". * @type Object @@ -66,7 +74,16 @@ CKEDITOR.dtd = (function() */ $block : block, - $body : X({script:1}, block), + /** + * List of block limit elements. + * @type Object + * @example + */ + $blockLimit : { body:1,div:1,td:1,th:1,caption:1,form:1 }, + + $inline : L, // Just like span. + + $body : X({script:1,style:1}, block), $cdata : {script:1,style:1}, @@ -97,7 +114,7 @@ CKEDITOR.dtd = (function() * @type Object * @example */ - $nonEditable : {applet:1,button:1,embed:1,iframe:1,map:1,object:1,option:1,script:1,textarea:1}, + $nonEditable : {applet:1,button:1,embed:1,iframe:1,map:1,object:1,option:1,script:1,textarea:1,param:1}, /** * List of elements that can be ignored if empty, like "b" or "span". @@ -120,6 +137,15 @@ CKEDITOR.dtd = (function() */ $tableContent : {caption:1,col:1,colgroup:1,tbody:1,td:1,tfoot:1,th:1,thead:1,tr:1}, + html: U, + head: T, + style: N, + script: N, + body: P, + base: {}, + link: {}, + meta: {}, + title: N, col : {}, tr : {td:1,th:1}, img : {}, @@ -144,7 +170,7 @@ CKEDITOR.dtd = (function() form : X(A,D,E,I), select : {optgroup:1,option:1}, font : L, - ins : P, + ins : L, menu : Q, abbr : L, label : L, @@ -179,7 +205,7 @@ CKEDITOR.dtd = (function() map : X({area:1,form:1,p:1},A,F,E), applet : O, dl : {dt:1,dd:1}, - del : P, + del : L, isindex : {}, fieldset : X({legend:1},K), thead : M, diff --git a/_source/core/editor.js b/_source/core/editor.js index dec0313..f37691a 100644 --- a/_source/core/editor.js +++ b/_source/core/editor.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -33,6 +33,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license if ( !customConfig ) return false; + customConfig = CKEDITOR.getUrl( customConfig ); + var loadedConfig = loadConfigLoaded[ customConfig ] || ( loadConfigLoaded[ customConfig ] = {} ); // If the custom config has already been downloaded, reuse it. @@ -44,7 +46,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // If there is no other customConfig in the chain, fire the // "configLoaded" event. - if ( editor.config.customConfig == customConfig || !loadConfig( editor ) ) + if ( CKEDITOR.getUrl( editor.config.customConfig ) == customConfig || !loadConfig( editor ) ) editor.fireOnce( 'customConfigLoaded' ); } else @@ -124,7 +126,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license editor.fireOnce( 'configLoaded' ); // Load language file. - loadLang( editor ); + loadSkin( editor ); }; var loadLang = function( editor ) @@ -246,7 +248,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // Load the editor skin. editor.fire( 'pluginsLoaded' ); - loadSkin( editor ); + loadTheme( editor ); }); }); }; @@ -255,7 +257,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license { CKEDITOR.skins.load( editor, 'editor', function() { - loadTheme( editor ); + loadLang( editor ); }); }; @@ -467,6 +469,7 @@ CKEDITOR.tools.extend( CKEDITOR.editor.prototype, this.theme.destroy( this ); this.fire( 'destroy' ); CKEDITOR.remove( this ); + CKEDITOR.fire( 'instanceDestroyed', null, this ); }, /** @@ -572,7 +575,11 @@ CKEDITOR.tools.extend( CKEDITOR.editor.prototype, }, /** - * Sets the editor data. The data must be provided in raw format. + * Sets the editor data. The data must be provided in raw format (HTML). + * <b>Note:</b> This's an asynchronous method, the {@param callback} + * function should be relied on if you want to interact with the editor + * after data is fully loaded. + * * @param {String} data HTML code to replace the curent content in the editor. * @param {Function} callback Function to be called after the setData is completed. * @example @@ -649,10 +656,15 @@ CKEDITOR.tools.extend( CKEDITOR.editor.prototype, var element = this.element; if ( element && this.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) { + var data = this.getData(); + + if( this.config.htmlEncodeOutput ) + data = CKEDITOR.tools.htmlEncode( data ); + if ( element.is( 'textarea' ) ) - element.setValue( this.getData() ); + element.setValue( data ); else - element.setHtml( this.getData() ); + element.setHtml( data ); } } }); @@ -669,3 +681,12 @@ CKEDITOR.on( 'loaded', function() pending[ i ]._init(); } }); + +/** + * Whether escape HTML when editor update original input element. + * @name CKEDITOR.config.htmlEncodeOutput + * @type {Boolean} + * @default false + * @example + * config.htmlEncodeOutput = true; + */ diff --git a/_source/core/editor_basic.js b/_source/core/editor_basic.js index 12b2d31..f03eacf 100644 --- a/_source/core/editor_basic.js +++ b/_source/core/editor_basic.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -131,16 +131,17 @@ if ( !CKEDITOR.editor ) */ CKEDITOR.editor.appendTo = function( elementOrId, config ) { - if ( typeof elementOrId != 'object' ) + var element = elementOrId; + if ( typeof element != 'object' ) { - elementOrId = document.getElementById( elementOrId ); + element = document.getElementById( elementOrId ); - if ( !elementOrId ) + if( !element ) throw '[CKEDITOR.editor.appendTo] The element with id "' + elementOrId + '" was not found.'; } // Create the editor instance. - return new CKEDITOR.editor( config, elementOrId, CKEDITOR.ELEMENT_MODE_APPENDTO ); + return new CKEDITOR.editor( config, element, CKEDITOR.ELEMENT_MODE_APPENDTO ); }; CKEDITOR.editor.prototype = diff --git a/_source/core/env.js b/_source/core/env.js index 5fa36ca..86a6713 100644 --- a/_source/core/env.js +++ b/_source/core/env.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/event.js b/_source/core/event.js index 1d5a77f..d508910 100644 --- a/_source/core/event.js +++ b/_source/core/event.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/eventInfo.js b/_source/core/eventInfo.js index b750a6b..dd79a52 100644 --- a/_source/core/eventInfo.js +++ b/_source/core/eventInfo.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/focusmanager.js b/_source/core/focusmanager.js index 74e4b54..0ebfb05 100644 --- a/_source/core/focusmanager.js +++ b/_source/core/focusmanager.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/htmlparser.js b/_source/core/htmlparser.js index f4cdf28..e71f79f 100644 --- a/_source/core/htmlparser.js +++ b/_source/core/htmlparser.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/htmlparser/basicwriter.js b/_source/core/htmlparser/basicwriter.js index db6ef0a..16e2666 100644 --- a/_source/core/htmlparser/basicwriter.js +++ b/_source/core/htmlparser/basicwriter.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -117,6 +117,7 @@ CKEDITOR.htmlParser.basicWriter = CKEDITOR.tools.createClass( reset : function() { this._.output = []; + this._.indent = false; }, /** diff --git a/_source/core/htmlparser/cdata.js b/_source/core/htmlparser/cdata.js index 45f48d0..d407278 100644 --- a/_source/core/htmlparser/cdata.js +++ b/_source/core/htmlparser/cdata.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -19,7 +19,6 @@ For licensing, see LICENSE.html or http://ckeditor.com/license * @example */ this.value = value; - }; CKEDITOR.htmlParser.cdata.prototype = diff --git a/_source/core/htmlparser/comment.js b/_source/core/htmlparser/comment.js index 9665e27..9cf7ebc 100644 --- a/_source/core/htmlparser/comment.js +++ b/_source/core/htmlparser/comment.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -44,11 +44,12 @@ CKEDITOR.htmlParser.comment.prototype = if ( filter ) { - if ( !( comment = filter.onComment( comment ) ) ) + if ( !( comment = filter.onComment( comment, this ) ) ) return; if ( typeof comment != 'string' ) { + comment.parent = this.parent; comment.writeHtml( writer, filter ); return; } diff --git a/_source/core/htmlparser/element.js b/_source/core/htmlparser/element.js index 50f6f77..ae834de 100644 --- a/_source/core/htmlparser/element.js +++ b/_source/core/htmlparser/element.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -25,7 +25,7 @@ CKEDITOR.htmlParser.element = function( name, attributes ) * @type Object * @example */ - this.attributes = attributes; + this.attributes = attributes || ( attributes = {} ); /** * The nodes that are direct children of this element. @@ -34,8 +34,10 @@ CKEDITOR.htmlParser.element = function( name, attributes ) */ this.children = []; + var tagName = attributes._cke_real_element_type || name; + var dtd = CKEDITOR.dtd, - isBlockLike = !!( dtd.$block[ name ] || dtd.$listItem[ name ] || dtd.$tableContent[ name ] ), + isBlockLike = !!( dtd.$nonBodyContent[ tagName ] || dtd.$block[ tagName ] || dtd.$listItem[ tagName ] || dtd.$tableContent[ tagName ] || dtd.$nonEditable[ tagName ] || tagName == 'br' ), isEmpty = !!dtd.$empty[ name ]; this.isEmpty = isEmpty; @@ -99,18 +101,27 @@ CKEDITOR.htmlParser.element = function( name, attributes ) { var attributes = this.attributes; - // The "_cke_replacedata" indicates that this element is replacing - // a data snippet, which should be outputted as is. - if ( attributes._cke_replacedata ) - { - writer.write( attributes._cke_replacedata ); - return; - } - // Ignore cke: prefixes when writing HTML. var element = this, writeName = element.name, - a, value; + a, newAttrName, value; + + var isChildrenFiltered; + + /** + * Providing an option for bottom-up filtering order ( element + * children to be pre-filtered before the element itself ). + */ + element.filterChildren = function() + { + if( !isChildrenFiltered ) + { + var writer = new CKEDITOR.htmlParser.basicWriter(); + CKEDITOR.htmlParser.fragment.prototype.writeChildrenHtml.call( element, writer, filter ); + element.children = new CKEDITOR.htmlParser.fragment.fromHtml( writer.getHtml() ).children; + isChildrenFiltered = 1; + } + }; if ( filter ) { @@ -124,13 +135,26 @@ CKEDITOR.htmlParser.element = function( name, attributes ) if ( !( element = filter.onElement( element ) ) ) return; + element.parent = this.parent; + if ( element.name == writeName ) break; + // If the element has been replaced with something of a + // different type, then make the replacement write itself. + if ( element.type != CKEDITOR.NODE_ELEMENT ) + { + element.writeHtml( writer, filter ); + return; + } + writeName = element.name; - if ( !writeName ) // Send children. + + // This indicate that the element has been dropped by + // filter but not the children. + if ( !writeName ) { - CKEDITOR.htmlParser.fragment.prototype.writeHtml.apply( element, arguments ); + this.writeChildrenHtml.call( element, writer, isChildrenFiltered ? null : filter ); return; } } @@ -143,41 +167,56 @@ CKEDITOR.htmlParser.element = function( name, attributes ) // Open element tag. writer.openTag( writeName, attributes ); - if ( writer.sortAttributes ) + // Copy all attributes to an array. + var attribsArray = []; + // Iterate over the attributes twice since filters may alter + // other attributes. + for( var i = 0 ; i < 2; i++ ) { - // Copy all attributes to an array. - var attribsArray = []; for ( a in attributes ) { + newAttrName = a; value = attributes[ a ]; - - if ( filter && ( !( a = filter.onAttributeName( a ) ) || ( value = filter.onAttribute( element, a, value ) ) === false ) ) - continue; - - attribsArray.push( [ a, value ] ); + if( i == 1 ) + attribsArray.push( [ a, value ] ); + else if ( filter ) + { + while ( true ) + { + if ( !( newAttrName = filter.onAttributeName( a ) ) ) + { + delete attributes[ a ]; + break; + } + else if( newAttrName != a ) + { + delete attributes[ a ]; + a = newAttrName; + continue; + } + else + break; + } + if( newAttrName ) + { + if( ( value = filter.onAttribute( element, newAttrName, value ) ) === false ) + delete attributes[ newAttrName ]; + else + attributes [ newAttrName ] = value; + } + } } - - // Sort the attributes by name. + } + // Sort the attributes by name. + if ( writer.sortAttributes ) attribsArray.sort( sortAttribs ); - // Send the attributes. - for ( var i = 0, len = attribsArray.length ; i < len ; i++ ) - { - var attrib = attribsArray[ i ]; - writer.attribute( attrib[0], attrib[1] ); - } - } - else + // Send the attributes. + var len = attribsArray.length; + for ( i = 0 ; i < len ; i++ ) { - for ( a in attributes ) - { - value = attributes[ a ]; - - if ( filter && ( !( a = filter.onAttributeName( a ) ) || ( value = filter.onAttribute( element, a, value ) ) === false ) ) - continue; - - writer.attribute( a, value ); - } + var attrib = attribsArray[ i ]; + writer.attribute( attrib[0], attrib[1] ); } // Close the tag. @@ -185,12 +224,17 @@ CKEDITOR.htmlParser.element = function( name, attributes ) if ( !element.isEmpty ) { - // Send children. - CKEDITOR.htmlParser.fragment.prototype.writeHtml.apply( element, arguments ); - + this.writeChildrenHtml.call( element, writer, isChildrenFiltered ? null : filter ); // Close the element. writer.closeTag( writeName ); } + }, + + writeChildrenHtml : function( writer, filter ) + { + // Send children. + CKEDITOR.htmlParser.fragment.prototype.writeChildrenHtml.apply( this, arguments ); + } }; })(); diff --git a/_source/core/htmlparser/filter.js b/_source/core/htmlparser/filter.js index 08d5d0a..e683f9a 100644 --- a/_source/core/htmlparser/filter.js +++ b/_source/core/htmlparser/filter.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -45,6 +45,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // Add the comment. this._.comment = transformNamedItem( this._.comment, rules.comment, priority ) || this._.comment; + + // Add root fragment. + this._.root = transformNamedItem( this._.root, rules.root, priority ) || this._.root; }, onElementName : function( name ) @@ -63,10 +66,16 @@ For licensing, see LICENSE.html or http://ckeditor.com/license return textFilter ? textFilter.filter( text ) : text; }, - onComment : function( commentText ) + onComment : function( commentText, comment ) { var textFilter = this._.comment; - return textFilter ? textFilter.filter( commentText ) : commentText; + return textFilter ? textFilter.filter( commentText, comment ) : commentText; + }, + + onFragment : function( element ) + { + var rootFilter = this._.root; + return rootFilter ? rootFilter.filter( element ) : element; }, onElement : function( element ) @@ -74,10 +83,10 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // We must apply filters set to the specific element name as // well as those set to the generic $ name. So, add both to an // array and process them in a small loop. - var filters = [ this._.elements[ element.name ], this._.elements.$ ], + var filters = [ this._.elements[ '^' ], this._.elements[ element.name ], this._.elements.$ ], filter, ret; - for ( var i = 0 ; i < 2 ; i++ ) + for ( var i = 0 ; i < 3 ; i++ ) { filter = filters[ i ]; if ( filter ) @@ -88,13 +97,27 @@ For licensing, see LICENSE.html or http://ckeditor.com/license return null; if ( ret && ret != element ) - return this.onElement( ret ); + return this.onNode( ret ); + + // The non-root element has been dismissed by one of the filters. + if ( element.parent && !element.name ) + break; } } return element; }, + onNode : function( node ) + { + var type = node.type; + + return type == CKEDITOR.NODE_ELEMENT ? this.onElement( node ) : + type == CKEDITOR.NODE_TEXT ? new CKEDITOR.htmlParser.text( this.onText( node.value ) ) : + type == CKEDITOR.NODE_COMMENT ? new CKEDITOR.htmlParser.comment( this.onComment( node.value ) ): + null; + }, + onAttribute : function( element, name, value ) { var filter = this._.attributes[ name ]; @@ -127,6 +150,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license function addItemsToList( list, items, priority ) { + if( typeof items == 'function' ) + items = [ items ]; + var i, j, listLength = list.length, itemsLength = items && items.length; @@ -141,8 +167,11 @@ For licensing, see LICENSE.html or http://ckeditor.com/license for ( j = itemsLength - 1 ; j >= 0 ; j-- ) { var item = items[ j ]; - item.pri = priority; - list.splice( i, 0, item ); + if ( item ) + { + item.pri = priority; + list.splice( i, 0, item ); + } } } } diff --git a/_source/core/htmlparser/fragment.js b/_source/core/htmlparser/fragment.js index 57edbfd..bfaea45 100644 --- a/_source/core/htmlparser/fragment.js +++ b/_source/core/htmlparser/fragment.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -114,7 +114,9 @@ CKEDITOR.htmlParser.fragment = function() elementName = realElementName; else elementName = element.name; - if ( !( elementName in CKEDITOR.dtd.$body ) ) + if ( elementName + && !( elementName in CKEDITOR.dtd.$body ) + && !( elementName in CKEDITOR.dtd.$nonBodyContent ) ) { var savedCurrent = currentNode; @@ -179,32 +181,32 @@ CKEDITOR.htmlParser.fragment = function() return; } - var currentName = currentNode.name, - currentDtd = ( currentName && CKEDITOR.dtd[ currentName ] ) || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ); + var currentName = currentNode.name; + + var currentDtd = currentName + && ( CKEDITOR.dtd[ currentName ] + || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ) ); // If the element cannot be child of the current element. - if ( !element.isUnknown && !currentNode.isUnknown && !currentDtd[ tagName ] ) + if ( currentDtd // Fragment could receive any elements. + && !element.isUnknown && !currentNode.isUnknown && !currentDtd[ tagName ] ) { - // If this is the fragment node, just ignore this tag and add - // its children. - if ( !currentName ) - return; var reApply = false, addPoint; // New position to start adding nodes. - // Fixing malformed nested lists(#3828). + // Fixing malformed nested lists by moving it into a previous list item. (#3828) if( tagName in listBlocks && currentName in listBlocks ) { var children = currentNode.children, lastChild = children[ children.length - 1 ]; - // Move inner list into to previous list item if any. - if( lastChild && lastChild.name in listItems ) - returnPoint = currentNode, addPoint = lastChild; - // Move inner list outside in the worst case. - else - addElement( currentNode, currentNode.parent ); + + // Establish the list item if it's not existed. + if ( !( lastChild && lastChild.name in listItems ) ) + addElement( ( lastChild = new CKEDITOR.htmlParser.element( 'li' ) ), currentNode ); + + returnPoint = currentNode, addPoint = lastChild; } // If the element name is the same as the current element name, // then just close the current one and append the new one to the @@ -264,22 +266,28 @@ CKEDITOR.htmlParser.fragment = function() parser.onTagClose = function( tagName ) { - var index = 0, - pendingAdd = [], + // Check if there is any pending tag to be closed. + for ( var i = pendingInline.length - 1 ; i >= 0 ; i-- ) + { + // If found, just remove it from the list. + if ( tagName == pendingInline[ i ].name ) + { + pendingInline.splice( i, 1 ); + return; + } + } + + var pendingAdd = [], + newPendingInline = [], candidate = currentNode; while ( candidate.type && candidate.name != tagName ) { - // If this is an inline element, add it to the pending list, so - // it will continue after the closing tag. + // If this is an inline element, add it to the pending list, if we're + // really closing one of the parents element later, they will continue + // after it. if ( !candidate._.isBlockLike ) - { - pendingInline.unshift( candidate ); - - // Increase the index, so it will not get checked again in - // the pending list check that follows. - index++; - } + newPendingInline.unshift( candidate ); // This node should be added to it's parent at this point. But, // it should happen only if the closing tag is really closing @@ -292,7 +300,7 @@ CKEDITOR.htmlParser.fragment = function() if ( candidate.type ) { // Add all elements that have been found in the above loop. - for ( var i = 0 ; i < pendingAdd.length ; i++ ) + for ( i = 0 ; i < pendingAdd.length ; i++ ) { var node = pendingAdd[ i ]; addElement( node, node.parent ); @@ -309,27 +317,12 @@ CKEDITOR.htmlParser.fragment = function() // addElement changed the currentNode. if ( candidate == currentNode ) currentNode = currentNode.parent; - } - // The tag is not actually closing anything, thus we need invalidate - // the pending elements.(#3862) - else - { - pendingInline.splice( 0, index ); - index = 0; - } - // Check if there is any pending tag to be closed. - for ( ; index < pendingInline.length ; index++ ) - { - // If found, just remove it from the list. - if ( tagName == pendingInline[ index ].name ) - { - pendingInline.splice( index, 1 ); - - // Decrease the index so we continue from the next one. - index--; - } + pendingInline = pendingInline.concat( newPendingInline ); } + + if( tagName == 'body' ) + fixForBody = false; }; parser.onText = function( text ) @@ -345,8 +338,12 @@ CKEDITOR.htmlParser.fragment = function() checkPending(); - if ( fixForBody && !currentNode.type ) + if ( fixForBody + && ( !currentNode.type || currentNode.name == 'body' ) + && CKEDITOR.tools.trim( text ) ) + { this.onTagOpen( fixForBody, {} ); + } // Shrinking consequential spaces into one single for all elements // text contents. @@ -375,7 +372,9 @@ CKEDITOR.htmlParser.fragment = function() var parent = currentNode.parent, node = currentNode; - if ( fixForBody && !parent.type && !CKEDITOR.dtd.$body[ node.name ] ) + if ( fixForBody + && ( !parent.type || parent.name == 'body' ) + && !CKEDITOR.dtd.$body[ node.name ] ) { currentNode = parent; parser.onTagOpen( fixForBody, {} ); @@ -444,7 +443,25 @@ CKEDITOR.htmlParser.fragment = function() */ writeHtml : function( writer, filter ) { - for ( var i = 0, len = this.children.length ; i < len ; i++ ) + var isChildrenFiltered; + this.filterChildren = function() + { + var writer = new CKEDITOR.htmlParser.basicWriter(); + this.writeChildrenHtml.call( this, writer, filter, true ); + var html = writer.getHtml(); + this.children = new CKEDITOR.htmlParser.fragment.fromHtml( html ).children; + isChildrenFiltered = 1; + }; + + // Filtering the root fragment before anything else. + !this.name && filter && filter.onFragment( this ); + + this.writeChildrenHtml( writer, isChildrenFiltered ? null : filter ); + }, + + writeChildrenHtml : function( writer, filter ) + { + for ( var i = 0 ; i < this.children.length ; i++ ) this.children[i].writeHtml( writer, filter ); } }; diff --git a/_source/core/htmlparser/text.js b/_source/core/htmlparser/text.js index c32299a..ad4ed1f 100644 --- a/_source/core/htmlparser/text.js +++ b/_source/core/htmlparser/text.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/imagecacher.js b/_source/core/imagecacher.js index c5399df..a7fd693 100644 --- a/_source/core/imagecacher.js +++ b/_source/core/imagecacher.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/lang.js b/_source/core/lang.js index f6c107d..cdd327e 100644 --- a/_source/core/lang.js +++ b/_source/core/lang.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/loader.js b/_source/core/loader.js index 6a862cb..aa84f07 100644 --- a/_source/core/loader.js +++ b/_source/core/loader.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -23,7 +23,7 @@ if ( !CKEDITOR.loader ) // Table of script names and their dependencies. var scripts = { - 'core/_bootstrap' : [ 'core/config', 'core/ckeditor', 'core/plugins', 'core/scriptloader', 'core/tools', /* The following are entries that we want to force loading at the end to avoid dependence recursion */ 'core/dom/elementpath', 'core/dom/text', 'core/dom/range' ], + 'core/_bootstrap' : [ 'core/config', 'core/ckeditor', 'core/plugins', 'core/scriptloader', 'core/tools', /* The following are entries that we want to force loading at the end to avoid dependence recursion */ 'core/dom/comment', 'core/dom/elementpath', 'core/dom/text', 'core/dom/range' ], 'core/ajax' : [ 'core/xml' ], 'core/ckeditor' : [ 'core/ckeditor_basic', 'core/dom', 'core/dtd', 'core/dom/document', 'core/dom/element', 'core/editor', 'core/event', 'core/htmlparser', 'core/htmlparser/element', 'core/htmlparser/fragment', 'core/htmlparser/filter', 'core/htmlparser/basicwriter', 'core/tools' ], 'core/ckeditor_base' : [], @@ -31,6 +31,7 @@ if ( !CKEDITOR.loader ) 'core/command' : [], 'core/config' : [ 'core/ckeditor_base' ], 'core/dom' : [], + 'core/dom/comment' : [ 'core/dom/node' ], 'core/dom/document' : [ 'core/dom', 'core/dom/domobject', 'core/dom/window' ], 'core/dom/documentfragment' : [ 'core/dom/element' ], 'core/dom/element' : [ 'core/dom', 'core/dom/document', 'core/dom/domobject', 'core/dom/node', 'core/dom/nodelist', 'core/tools' ], @@ -106,7 +107,7 @@ if ( !CKEDITOR.loader ) return path; })(); - var timestamp = '99GE'; + var timestamp = 'A06B'; var getUrl = function( resource ) { diff --git a/_source/core/plugindefinition.js b/_source/core/plugindefinition.js index 42a5740..350f73d 100644 --- a/_source/core/plugindefinition.js +++ b/_source/core/plugindefinition.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/plugins.js b/_source/core/plugins.js index 2ddd178..e541d79 100644 --- a/_source/core/plugins.js +++ b/_source/core/plugins.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/resourcemanager.js b/_source/core/resourcemanager.js index 8b21867..289bdfb 100644 --- a/_source/core/resourcemanager.js +++ b/_source/core/resourcemanager.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -86,7 +86,8 @@ CKEDITOR.resourceManager.prototype = if ( this.registered[ name ] ) throw '[CKEDITOR.resourceManager.add] The resource name "' + name + '" is already registered.'; - this.registered[ name ] = definition || {}; + CKEDITOR.fire( name + CKEDITOR.tools.capitalize( this.fileName ) + 'Ready', + this.registered[ name ] = definition || {} ); }, /** diff --git a/_source/core/scriptloader.js b/_source/core/scriptloader.js index e5b5dea..3a606ee 100644 --- a/_source/core/scriptloader.js +++ b/_source/core/scriptloader.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -51,7 +51,7 @@ CKEDITOR.scriptLoader = (function() * alert( 'Number of failures: ' + failed.length ); * }); */ - load : function( scriptUrl, callback, scope, noCheck ) + load : function( scriptUrl, callback, scope, noCheck, showBusy ) { var isString = ( typeof scriptUrl == 'string' ); @@ -87,7 +87,10 @@ CKEDITOR.scriptLoader = (function() ( success ? completed : failed ).push( url ); if ( --scriptCount <= 0 ) + { + showBusy && CKEDITOR.document.getDocumentElement().removeStyle( 'cursor' ); doCallback( success ); + } }; var onLoad = function( url, success ) @@ -167,6 +170,7 @@ CKEDITOR.scriptLoader = (function() CKEDITOR.fire( 'download', url ); // @Packager.RemoveLine }; + showBusy && CKEDITOR.document.getDocumentElement().setStyle( 'cursor', 'wait' ); for ( var i = 0 ; i < scriptCount ; i++ ) { loadScript( scriptUrl[ i ] ); diff --git a/_source/core/skins.js b/_source/core/skins.js index 74379e7..7003ba0 100644 --- a/_source/core/skins.js +++ b/_source/core/skins.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -20,11 +20,20 @@ CKEDITOR.skins = (function() var preloaded = {}; var paths = {}; - var loadedPart = function( skinName, part, callback ) + var loadPart = function( editor, skinName, part, callback ) { // Get the skin definition. var skinDefinition = loaded[ skinName ]; + if ( !editor.skin ) + { + editor.skin = skinDefinition; + + // Trigger init function if any. + if ( skinDefinition.init ) + skinDefinition.init( editor ); + } + var appendSkinPath = function( fileNames ) { for ( var n = 0 ; n < fileNames.length ; n++ ) @@ -33,6 +42,18 @@ CKEDITOR.skins = (function() } }; + function fixCSSTextRelativePath( cssStyleText, baseUrl ) + { + return cssStyleText.replace( /url\s*\(([\s'"]*)(.*?)([\s"']*)\)/g, + function( match, opener, path, closer ) + { + if ( /^\/|^\w?:/.test( path ) ) + return match; + else + return 'url(' + baseUrl + opener + path + closer + ')'; + } ); + } + // Check if we need to preload images from it. if ( !preloaded[ skinName ] ) { @@ -43,7 +64,7 @@ CKEDITOR.skins = (function() CKEDITOR.imageCacher.load( preload, function() { preloaded[ skinName ] = 1; - loadedPart( skinName, part, callback ); + loadPart( editor, skinName, part, callback ); } ); return; } @@ -96,10 +117,23 @@ CKEDITOR.skins = (function() // Load the "css" pieces. if ( !cssIsLoaded ) { - appendSkinPath( part.css ); + var cssPart = part.css; + + if ( CKEDITOR.tools.isArray( cssPart ) ) + { + appendSkinPath( cssPart ); + for ( var c = 0 ; c < cssPart.length ; c++ ) + CKEDITOR.document.appendStyleSheet( cssPart[ c ] ); + } + else + { + cssPart = fixCSSTextRelativePath( + cssPart, CKEDITOR.getUrl( paths[ skinName ] ) ); + // Processing Inline CSS part. + CKEDITOR.document.appendStyleText( cssPart ); + } - for ( var c = 0 ; c < part.css.length ; c++ ) - CKEDITOR.document.appendStyleSheet( part.css[ c ] ); + part.css = cssPart; cssIsLoaded = 1; } @@ -156,29 +190,13 @@ CKEDITOR.skins = (function() skinPath = editor.skinPath; if ( loaded[ skinName ] ) - { - loadedPart( skinName, skinPart, callback ); - - // Get the skin definition. - var skinDefinition = loaded[ skinName ]; - - // Trigger init function if any. - if ( skinDefinition.init ) - skinDefinition.init( editor ); - } + loadPart( editor, skinName, skinPart, callback ); else { paths[ skinName ] = skinPath; CKEDITOR.scriptLoader.load( skinPath + 'skin.js', function() { - loadedPart( skinName, skinPart, callback ); - - // Get the skin definition. - var skinDefinition = loaded[ skinName ]; - - // Trigger init function if any. - if ( skinDefinition.init ) - skinDefinition.init( editor ); + loadPart( editor, skinName, skinPart, callback ); }); } } diff --git a/_source/core/themes.js b/_source/core/themes.js index c350c3f..c597fe2 100644 --- a/_source/core/themes.js +++ b/_source/core/themes.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/tools.js b/_source/core/tools.js index a02f3ba..6e448ea 100644 --- a/_source/core/tools.js +++ b/_source/core/tools.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -19,6 +19,22 @@ For licensing, see LICENSE.html or http://ckeditor.com/license */ CKEDITOR.tools = { + /** + * Compare the elements of two arrays. + * @param {Array} arrayA An array to be compared. + * @param {Array} arrayB The other array to be compared. + * @returns {Boolean} "true" is the arrays have the same lenght and + * their elements match. + * @example + * var a = [ 1, 'a', 3 ]; + * var b = [ 1, 3, 'a' ]; + * var c = [ 1, 'a', 3 ]; + * var d = [ 1, 'a', 3, 4 ]; + * + * alert( CKEDITOR.tools.arrayCompare( a, b ) ); // false + * alert( CKEDITOR.tools.arrayCompare( a, c ) ); // true + * alert( CKEDITOR.tools.arrayCompare( a, d ) ); // false + */ arrayCompare : function( arrayA, arrayB ) { if ( !arrayA && !arrayB ) @@ -80,7 +96,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license || ( obj instanceof String ) || ( obj instanceof Number ) || ( obj instanceof Boolean ) - || ( obj instanceof Date ) ) + || ( obj instanceof Date ) + || ( obj instanceof RegExp) ) { return obj; } @@ -98,6 +115,15 @@ For licensing, see LICENSE.html or http://ckeditor.com/license }, /** + * Turn the first letter of string to upper-case. + * @param {String} str + */ + capitalize: function( str ) + { + return str.charAt( 0 ).toUpperCase() + str.substring( 1 ).toLowerCase(); + }, + + /** * Copy the properties from one object to another. By default, properties * already present in the target object <strong>are not</strong> overwritten. * @param {Object} target The object to be extended. @@ -189,6 +215,15 @@ For licensing, see LICENSE.html or http://ckeditor.com/license return ( !!object && object instanceof Array ); }, + isEmpty : function ( object ) + { + for ( var i in object ) + { + if ( object.hasOwnProperty( i ) ) + return false; + } + return true; + }, /** * Transforms a CSS property name to its relative DOM style name. * @param {String} cssName The CSS property name. @@ -220,6 +255,27 @@ For licensing, see LICENSE.html or http://ckeditor.com/license } )(), /** + * Build the HTML snippet of a set of <style>/<link>. + * @param css {String|Array} Each of which are url (absolute) of a CSS file or + * a trunk of style text. + */ + buildStyleHtml : function ( css ) + { + css = [].concat( css ); + var item, retval = []; + for ( var i = 0; i < css.length; i++ ) + { + item = css[ i ]; + // Is CSS style text ? + if ( /@import|[{}]/.test(item) ) + retval.push('<style>' + item + '</style>'); + else + retval.push('<link type="text/css" rel=stylesheet href="' + item + '">'); + } + return retval.join( '' ); + }, + + /** * Replace special HTML characters in a string with their relative HTML * entity values. * @param {String} text The string to be encoded. @@ -267,6 +323,19 @@ For licensing, see LICENSE.html or http://ckeditor.com/license }, /** + * Replace characters can't be represented through CSS Selectors string + * by CSS Escape Notation where the character escape sequence consists + * of a backslash character (\) followed by the orginal characters. + * Ref: http://www.w3.org/TR/css3-selectors/#grammar + * @param cssSelectText + * @return the escaped selector text. + */ + escapeCssSelector : function( cssSelectText ) + { + return cssSelectText.replace( /[\s#:.,$*^\[\]()~=+>]/g, '\\$&' ); + }, + + /** * Gets a unique number for this CKEDITOR execution session. It returns * progressive numbers starting at 1. * @function @@ -439,6 +508,24 @@ For licensing, see LICENSE.html or http://ckeditor.com/license return -1; }, + /** + * Creates a function that will always execute in the context of a + * specified object. + * @param {Function} func The function to be executed. + * @param {Object} obj The object to which bind the execution context. + * @returns {Function} The function that can be used to execute the + * "func" function in the context of "obj". + * @example + * var obj = { text : 'My Object' }; + * + * function alertText() + * { + * alert( this.text ); + * } + * + * var newFunc = <b>CKEDITOR.tools.bind( alertText, obj )</b>; + * newFunc(); // Alerts "My Object". + */ bind : function( func, obj ) { return function() { return func.apply( obj, arguments ); }; @@ -450,11 +537,11 @@ For licensing, see LICENSE.html or http://ckeditor.com/license * <ul> * <li> Static fields </li> * <li> Private fields </li> - * <li> Public(prototype) fields </li> + * <li> Public (prototype) fields </li> * <li> Chainable base class constructor </li> * </ul> - * - * @param {Object} definiton (Optional)The class definiton object. + * @param {Object} definiton The class definiton object. + * @returns {Function} A class-like JavaScript function. */ createClass : function( definition ) { @@ -507,6 +594,22 @@ For licensing, see LICENSE.html or http://ckeditor.com/license return $; }, + /** + * Creates a function reference that can be called later using + * CKEDITOR.tools.callFunction. This approach is specially useful to + * make DOM attribute function calls to JavaScript defined functions. + * @param {Function} fn The function to be executed on call. + * @param {Object} [scope] The object to have the context on "fn" execution. + * @returns {Number} A unique reference to be used in conjuction with + * CKEDITOR.tools.callFunction. + * @example + * var ref = <b>CKEDITOR.tools.addFunction</b>( + * function() + * { + * alert( 'Hello!'); + * }); + * CKEDITOR.tools.callFunction( ref ); // Hello! + */ addFunction : function( fn, scope ) { return functions.push( function() @@ -515,10 +618,26 @@ For licensing, see LICENSE.html or http://ckeditor.com/license }) - 1; }, - callFunction : function( index ) + /** + * Executes a function based on the reference created with + * CKEDITOR.tools.addFunction. + * @param {Number} ref The function reference created with + * CKEDITOR.tools.addFunction. + * @param {[Any,[Any,...]} params Any number of parameters to be passed + * to the executed function. + * @returns {Any} The return value of the function. + * @example + * var ref = CKEDITOR.tools.addFunction( + * function() + * { + * alert( 'Hello!'); + * }); + * <b>CKEDITOR.tools.callFunction( ref )</b>; // Hello! + */ + callFunction : function( ref ) { - var fn = functions[ index ]; - return fn.apply( window, Array.prototype.slice.call( arguments, 1 ) ); + var fn = functions[ ref ]; + return fn && fn.apply( window, Array.prototype.slice.call( arguments, 1 ) ); }, cssLength : (function() @@ -533,6 +652,22 @@ For licensing, see LICENSE.html or http://ckeditor.com/license repeat : function( str, times ) { return new Array( times + 1 ).join( str ); + }, + + tryThese : function() + { + var returnValue; + for ( var i = 0, length = arguments.length; i < length; i++ ) + { + var lambda = arguments[i]; + try + { + returnValue = lambda(); + break; + } + catch (e) {} + } + return returnValue; } }; })(); diff --git a/_source/core/ui.js b/_source/core/ui.js index e1c8d76..9bd2c07 100644 --- a/_source/core/ui.js +++ b/_source/core/ui.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/_source/core/xml.js b/_source/core/xml.js index 87d604b..74c4b9a 100644 --- a/_source/core/xml.js +++ b/_source/core/xml.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ |
