diff --git a/_source/core/config.js b/_source/core/config.js index e2ea7d01a4..e727cfd01b 100644 --- a/_source/core/config.js +++ b/_source/core/config.js @@ -146,7 +146,7 @@ CKEDITOR.config = { * config.plugins = 'basicstyles,button,htmldataprocessor,toolbar,wysiwygarea'; */ - plugins: 'basicstyles,blockquote,button,clipboard,elementspath,find,flash,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,newpage,pagebreak,pastefromword,pastetext,preview,print,removeformat,smiley,showblocks,sourcearea,table,specialchar,tab,templates,toolbar,undo,wysiwygarea', + plugins: 'basicstyles,blockquote,button,clipboard,elementspath,find,flash,format,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,newpage,pagebreak,pastefromword,pastetext,preview,print,removeformat,smiley,showblocks,sourcearea,table,specialchar,tab,templates,toolbar,undo,wysiwygarea', /** * The theme to be used to build the UI. diff --git a/_source/core/dom/domobject.js b/_source/core/dom/domobject.js index 545c803ef9..65001ba9e8 100644 --- a/_source/core/dom/domobject.js +++ b/_source/core/dom/domobject.js @@ -133,7 +133,7 @@ CKEDITOR.dom.domObject.prototype = (function() { * element.setCustomData( 'hasCustomData', true ); */ domObjectProto.setCustomData = function( key, value ) { - var expandoNumber = this.$._cke_expando || ( this.$._cke_expando = CKEDITOR.tools.getNextNumber() ), + var expandoNumber = this.getUniqueId(), dataSlot = customData[ expandoNumber ] || ( customData[ expandoNumber ] = {} ); dataSlot[ key ] = value; @@ -170,6 +170,10 @@ CKEDITOR.dom.domObject.prototype = (function() { return retval || null; }; + domObjectProto.getUniqueId = function() { + return this.$._cke_expando || ( this.$._cke_expando = CKEDITOR.tools.getNextNumber() ); + }; + // Implement CKEDITOR.event. CKEDITOR.event.implementOn( domObjectProto ); diff --git a/_source/core/dom/element.js b/_source/core/dom/element.js index eec5f2ea0b..290fddc520 100644 --- a/_source/core/dom/element.js +++ b/_source/core/dom/element.js @@ -151,6 +151,11 @@ CKEDITOR.tools.extend( CKEDITOR.dom.element.prototype, } }, + hasClass: function( className ) { + var regex = new RegExp( '(?:^|\\s+)' + className + '(?=\\s|$)', '' ); + return regex.test( this.$.className ); + }, + /** * Append a node as a child of this element. * @param {CKEDITOR.dom.node|String} node The node or element name to be @@ -180,6 +185,12 @@ CKEDITOR.tools.extend( CKEDITOR.dom.element.prototype, return node; }, + appendHtml: function( html ) { + var temp = new CKEDITOR.dom.element( 'div', this.getDocument() ); + temp.setHtml( html ); + temp.moveChildren( this ); + }, + /** * Append text to this element. * @param {String} text The text to be appended. diff --git a/_source/core/editor.js b/_source/core/editor.js index 52183535a9..361a5f8323 100644 --- a/_source/core/editor.js +++ b/_source/core/editor.js @@ -69,10 +69,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license if ( instanceConfig ) CKEDITOR.tools.extend( editor.config, instanceConfig, true ); - // Fire the "configLoaded" event. - editor.fireOnce( 'configLoaded' ); - - loadLang( editor ); + onConfigLoaded( editor ); }); // The instance config may override the customConfig setting to avoid @@ -87,6 +84,19 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // ##### END: Config Privates + var onConfigLoaded = function( editor ) { + // Set config related properties. + + editor.skinPath = CKEDITOR.getUrl( '_source/' + // %REMOVE_LINE% + 'skins/' + editor.config.skin + '/' ); + + // Fire the "configLoaded" event. + editor.fireOnce( 'configLoaded' ); + + // Load language file. + loadLang( editor ); + }; + var loadLang = function( editor ) { CKEDITOR.lang.load( editor.config.defaultLanguage, editor.config.autoLanguage, function( languageCode, lang ) { editor.langCode = languageCode; diff --git a/_source/core/plugins.js b/_source/core/plugins.js index 724cc6c89d..e4dca0f059 100644 --- a/_source/core/plugins.js +++ b/_source/core/plugins.js @@ -40,8 +40,20 @@ CKEDITOR.plugins.load = CKEDITOR.tools.override( CKEDITOR.plugins.load, function if ( requiredPlugins.length ) loadPlugins.call( this, requiredPlugins ); - else if ( callback ) - callback.call( scope || window, allPlugins ); + else { + // Call the "onLoad" function for all plugins. + for ( pluginName in allPlugins ) { + plugin = allPlugins[ pluginName ]; + if ( plugin.onLoad && !plugin.onLoad._called ) { + plugin.onLoad(); + plugin.onLoad._called = 1; + } + } + + // Call the callback. + if ( callback ) + callback.call( scope || window, allPlugins ); + } }, this ); }; diff --git a/_source/core/tools.js b/_source/core/tools.js index b072c2d1b2..204a547024 100644 --- a/_source/core/tools.js +++ b/_source/core/tools.js @@ -8,307 +8,366 @@ For licensing, see LICENSE.html or http://ckeditor.com/license * utility functions. */ -/** - * Utility functions. - * @namespace - * @example - */ -CKEDITOR.tools = { - arrayCompare: function( arrayA, arrayB ) { - if ( !arrayA && !arrayB ) - return true; +(function() { + var functions = []; - if ( !arrayA || !arrayB || arrayA.length != arrayB.length ) - return false; + /** + * Utility functions. + * @namespace + * @example + */ + CKEDITOR.tools = { + arrayCompare: function( arrayA, arrayB ) { + if ( !arrayA && !arrayB ) + return true; - for ( var i = 0; i < arrayA.length; i++ ) { - if ( arrayA[ i ] != arrayB[ i ] ) + if ( !arrayA || !arrayB || arrayA.length != arrayB.length ) return false; - } - return true; - }, + for ( var i = 0; i < arrayA.length; i++ ) { + if ( arrayA[ i ] != arrayB[ i ] ) + return false; + } - /** - * Copy the properties from one object to another. By default, properties - * already present in the target object are not overwritten. - * @param {Object} target The object to be extended. - * @param {Object} source[,souce(n)] The objects from which copy - * properties. Any number of objects can be passed to this function. - * @param {Boolean} [overwrite] Indicates that properties already present - * in the target object must be overwritten. This must be the last - * parameter in the function call. - * @returns {Object} the extended object (target). - * @example - * // Create the sample object. - * var myObject = - * { - * prop1 : true - * }; - * - * // Extend the above object with two properties. - * CKEDITOR.tools.extend( myObject, - * { - * prop2 : true, - * prop3 : true - * } ); - * - * // Alert "prop1", "prop2" and "prop3". - * for ( var p in myObject ) - * alert( p ); - */ - extend: function( target ) { - var argsLength = arguments.length, - overwrite = arguments[ argsLength - 1 ]; + return true; + }, - if ( typeof overwrite == 'boolean' ) - argsLength--; - else - overwrite = false; + /** + * Copy the properties from one object to another. By default, properties + * already present in the target object are not overwritten. + * @param {Object} target The object to be extended. + * @param {Object} source[,souce(n)] The objects from which copy + * properties. Any number of objects can be passed to this function. + * @param {Boolean} [overwrite] Indicates that properties already present + * in the target object must be overwritten. This must be the last + * parameter in the function call. + * @returns {Object} the extended object (target). + * @example + * // Create the sample object. + * var myObject = + * { + * prop1 : true + * }; + * + * // Extend the above object with two properties. + * CKEDITOR.tools.extend( myObject, + * { + * prop2 : true, + * prop3 : true + * } ); + * + * // Alert "prop1", "prop2" and "prop3". + * for ( var p in myObject ) + * alert( p ); + */ + extend: function( target ) { + var argsLength = arguments.length, + overwrite = arguments[ argsLength - 1 ]; + + if ( typeof overwrite == 'boolean' ) + argsLength--; + else + overwrite = false; - for ( var i = 1; i < argsLength; i++ ) { - var source = arguments[ i ]; + for ( var i = 1; i < argsLength; i++ ) { + var source = arguments[ i ]; - for ( var propertyName in source ) { - if ( overwrite || target[ propertyName ] == undefined ) - target[ propertyName ] = source[ propertyName ]; + for ( var propertyName in source ) { + if ( overwrite || target[ propertyName ] == undefined ) + target[ propertyName ] = source[ propertyName ]; + } } - } - return target; - }, + return target; + }, - /** - * Creates an object which is an instance of a class which prototype is a - * predefined object. All properties defined in the source object are - * automatically inherited by the resulting object, including future - * changes to it. - * @param {Object} source The source object to be used as the prototype for - * the final object. - * @returns {Object} The resulting copy. - */ - prototypedCopy: function( source ) { - var copy = function() {}; - copy.prototype = source; - return new copy(); - }, + /** + * Creates an object which is an instance of a class which prototype is a + * predefined object. All properties defined in the source object are + * automatically inherited by the resulting object, including future + * changes to it. + * @param {Object} source The source object to be used as the prototype for + * the final object. + * @returns {Object} The resulting copy. + */ + prototypedCopy: function( source ) { + var copy = function() {}; + copy.prototype = source; + return new copy(); + }, - /** - * Checks if an object is an Array. - * @param {Object} object The object to be checked. - * @type Boolean - * @returns true if the object is an Array, otherwise false. - * @example - * alert( CKEDITOR.tools.isArray( [] ) ); // "true" - * alert( CKEDITOR.tools.isArray( 'Test' ) ); // "false" - */ - isArray: function( object ) { - return ( !!object && object instanceof Array ); - }, + /** + * Checks if an object is an Array. + * @param {Object} object The object to be checked. + * @type Boolean + * @returns true if the object is an Array, otherwise false. + * @example + * alert( CKEDITOR.tools.isArray( [] ) ); // "true" + * alert( CKEDITOR.tools.isArray( 'Test' ) ); // "false" + */ + isArray: function( object ) { + return ( !!object && object instanceof Array ); + }, - /** - * Transforms a CSS property name to its relative DOM style name. - * @param {String} cssName The CSS property name. - * @returns {String} The transformed name. - * @example - * alert( CKEDITOR.tools.cssStyleToDomStyle( 'background-color' ) ); // "backgroundColor" - * alert( CKEDITOR.tools.cssStyleToDomStyle( 'float' ) ); // "cssFloat" - */ - cssStyleToDomStyle: function( cssName ) { - if ( cssName == 'float' ) - return 'cssFloat'; - else { - return cssName.replace( /-./g, function( match ) { - return match.substr( 1 ).toUpperCase(); - }); - } - }, + /** + * Transforms a CSS property name to its relative DOM style name. + * @param {String} cssName The CSS property name. + * @returns {String} The transformed name. + * @example + * alert( CKEDITOR.tools.cssStyleToDomStyle( 'background-color' ) ); // "backgroundColor" + * alert( CKEDITOR.tools.cssStyleToDomStyle( 'float' ) ); // "cssFloat" + */ + cssStyleToDomStyle: function( cssName ) { + if ( cssName == 'float' ) + return 'cssFloat'; + else { + return cssName.replace( /-./g, function( match ) { + return match.substr( 1 ).toUpperCase(); + }); + } + }, - /** - * Replace special HTML characters in a string with their relative HTML - * entity values. - * @param {String} text The string to be encoded. - * @returns {String} The encode string. - * @example - * alert( CKEDITOR.tools.htmlEncode( 'A > B & C < D' ) ); // "A &gt; B &amp; C &lt; D" - */ - htmlEncode: function( text ) { - var standard = function( text ) { - var span = new CKEDITOR.dom.element( 'span' ); - span.setText( text ); - return span.getHtml(); + /** + * Replace special HTML characters in a string with their relative HTML + * entity values. + * @param {String} text The string to be encoded. + * @returns {String} The encode string. + * @example + * alert( CKEDITOR.tools.htmlEncode( 'A > B & C < D' ) ); // "A &gt; B &amp; C &lt; D" + */ + htmlEncode: function( text ) { + var standard = function( text ) { + var span = new CKEDITOR.dom.element( 'span' ); + span.setText( text ); + return span.getHtml(); + }; + + this.htmlEncode = ( standard( '>' ) == '>' ) ? + function( text ) { + // WebKit does't encode the ">" character, which makes sense, but + // it's different than other browsers. + return standard( text ).replace( />/g, '>' ); + } : standard; + + return this.htmlEncode( text ); + }, + + /** + * Gets a unique number for this CKEDITOR execution session. It returns + * progressive numbers starting at 1. + * @function + * @returns {Number} A unique number. + * @example + * alert( CKEDITOR.tools.getNextNumber() ); // "1" (e.g.) + * alert( CKEDITOR.tools.getNextNumber() ); // "2" + */ + getNextNumber: (function() { + var last = 0; + return function() { + return ++last; }; + })(), - this.htmlEncode = ( standard( '>' ) == '>' ) ? - function( text ) { - // WebKit does't encode the ">" character, which makes sense, but - // it's different than other browsers. - return standard( text ).replace( />/g, '>' ); - } : standard; + /** + * Creates a function override. + * @param {Function} originalFunction The function to be overridden. + * @param {Function} functionBuilder A function that returns the new + * function. The original function reference will be passed to this + * function. + * @returns {Function} The new function. + * @example + * var example = + * { + * myFunction : function( name ) + * { + * alert( 'Name: ' + name ); + * } + * }; + * + * example.myFunction = CKEDITOR.tools.override( example.myFunction, function( myFunctionOriginal ) + * { + * return function( name ) + * { + * alert( 'Override Name: ' + name ); + * myFunctionOriginal.call( this, name ); + * }; + * }); + */ + override: function( originalFunction, functionBuilder ) { + return functionBuilder( originalFunction ); + }, - return this.htmlEncode( text ); - }, + /** + * Executes a function after specified delay. + * @param {Function} func The function to be executed. + * @param {Number} [milliseconds] The amount of time (millisecods) to wait + * to fire the function execution. Defaults to zero. + * @param {Object} [scope] The object to hold the function execution scope + * (the "this" object). By default the "window" object. + * @param {Object|Array} [args] A single object, or an array of objects, to + * pass as arguments to the function. + * @param {Object} [ownerWindow] The window that will be used to set the + * timeout. By default the current "window". + * @returns {Object} A value that can be used to cancel the function execution. + * @example + * CKEDITOR.tools.setTimeout( + * function() + * { + * alert( 'Executed after 2 seconds' ); + * }, + * 2000 ); + */ + setTimeout: function( func, milliseconds, scope, args, ownerWindow ) { + if ( !ownerWindow ) + ownerWindow = window; - /** - * Gets a unique number for this CKEDITOR execution session. It returns - * progressive numbers starting at 1. - * @function - * @returns {Number} A unique number. - * @example - * alert( CKEDITOR.tools.getNextNumber() ); // "1" (e.g.) - * alert( CKEDITOR.tools.getNextNumber() ); // "2" - */ - getNextNumber: (function() { - var last = 0; - return function() { - return ++last; - }; - })(), + if ( !scope ) + scope = ownerWindow; - /** - * Creates a function override. - * @param {Function} originalFunction The function to be overridden. - * @param {Function} functionBuilder A function that returns the new - * function. The original function reference will be passed to this - * function. - * @returns {Function} The new function. - * @example - * var example = - * { - * myFunction : function( name ) - * { - * alert( 'Name: ' + name ); - * } - * }; - * - * example.myFunction = CKEDITOR.tools.override( example.myFunction, function( myFunctionOriginal ) - * { - * return function( name ) - * { - * alert( 'Override Name: ' + name ); - * myFunctionOriginal.call( this, name ); - * }; - * }); - */ - override: function( originalFunction, functionBuilder ) { - return functionBuilder( originalFunction ); - }, + return ownerWindow.setTimeout( function() { + if ( args ) + func.apply( scope, [].concat( args ) ); + else + func.apply( scope ); + }, milliseconds || 0 ); + }, - /** - * Executes a function after specified delay. - * @param {Function} func The function to be executed. - * @param {Number} [milliseconds] The amount of time (millisecods) to wait - * to fire the function execution. Defaults to zero. - * @param {Object} [scope] The object to hold the function execution scope - * (the "this" object). By default the "window" object. - * @param {Object|Array} [args] A single object, or an array of objects, to - * pass as arguments to the function. - * @param {Object} [ownerWindow] The window that will be used to set the - * timeout. By default the current "window". - * @returns {Object} A value that can be used to cancel the function execution. - * @example - * CKEDITOR.tools.setTimeout( - * function() - * { - * alert( 'Executed after 2 seconds' ); - * }, - * 2000 ); - */ - setTimeout: function( func, milliseconds, scope, args, ownerWindow ) { - if ( !ownerWindow ) - ownerWindow = window; + /** + * Remove spaces from the start and the end of a string. The following + * characters are removed: space, tab, line break, line feed. + * @function + * @param {String} str The text from which remove the spaces. + * @returns {String} The modified string without the boundary spaces. + * @example + * alert( CKEDITOR.tools.trim( ' example ' ); // "example" + */ + trim: (function() { + // We are not using \s because we don't want "non-breaking spaces" to be caught. + var trimRegex = /(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g; + return function( str ) { + return str.replace( trimRegex, '' ); + }; + })(), - if ( !scope ) - scope = ownerWindow; + /** + * Remove spaces from the start (left) of a string. The following + * characters are removed: space, tab, line break, line feed. + * @function + * @param {String} str The text from which remove the spaces. + * @returns {String} The modified string excluding the removed spaces. + * @example + * alert( CKEDITOR.tools.ltrim( ' example ' ); // "example " + */ + ltrim: (function() { + // We are not using \s because we don't want "non-breaking spaces" to be caught. + var trimRegex = /^[ \t\n\r]+/g; + return function( str ) { + return str.replace( trimRegex, '' ); + }; + })(), - return ownerWindow.setTimeout( function() { - if ( args ) - func.apply( scope, [].concat( args ) ); - else - func.apply( scope ); - }, milliseconds || 0 ); - }, + /** + * Remove spaces from the end (right) of a string. The following + * characters are removed: space, tab, line break, line feed. + * @function + * @param {String} str The text from which remove the spaces. + * @returns {String} The modified string excluding the removed spaces. + * @example + * alert( CKEDITOR.tools.ltrim( ' example ' ); // " example" + */ + rtrim: (function() { + // We are not using \s because we don't want "non-breaking spaces" to be caught. + var trimRegex = /[ \t\n\r]+$/g; + return function( str ) { + return str.replace( trimRegex, '' ); + }; + })(), - /** - * Remove spaces from the start and the end of a string. The following - * characters are removed: space, tab, line break, line feed. - * @function - * @param {String} str The text from which remove the spaces. - * @returns {String} The modified string without the boundary spaces. - * @example - * alert( CKEDITOR.tools.trim( ' example ' ); // "example" - */ - trim: (function() { - // We are not using \s because we don't want "non-breaking spaces" to be caught. - var trimRegex = /(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g; - return function( str ) { - return str.replace( trimRegex, '' ); - }; - })(), + /** + * Returns the index of an element in an array. + * @param {Array} array The array to be searched. + * @param {Object} entry The element to be found. + * @returns {Number} The (zero based) index of the first entry that matches + * the entry, or -1 if not found. + * @example + * var letters = [ 'a', 'b', 0, 'c', false ]; + * alert( CKEDITOR.tools.indexOf( letters, '0' ) ); "-1" because 0 !== '0' + * alert( CKEDITOR.tools.indexOf( letters, false ) ); "4" because 0 !== false + */ + indexOf: + // #2514: We should try to use Array.indexOf if it does exist. + ( Array.prototype.indexOf ) ? + function( array, entry ) { + return array.indexOf( entry ); + } : function( array, entry ) { + for ( var i = 0, len = array.length; i < len; i++ ) { + if ( array[ i ] === entry ) + return i; + } + return -1; + }, - /** - * Remove spaces from the start (left) of a string. The following - * characters are removed: space, tab, line break, line feed. - * @function - * @param {String} str The text from which remove the spaces. - * @returns {String} The modified string excluding the removed spaces. - * @example - * alert( CKEDITOR.tools.ltrim( ' example ' ); // "example " - */ - ltrim: (function() { - // We are not using \s because we don't want "non-breaking spaces" to be caught. - var trimRegex = /^[ \t\n\r]+/g; - return function( str ) { - return str.replace( trimRegex, '' ); - }; - })(), + bind: function( func, obj ) { + return function() { + return func.apply( obj, arguments ); + }; + }, - /** - * Remove spaces from the end (right) of a string. The following - * characters are removed: space, tab, line break, line feed. - * @function - * @param {String} str The text from which remove the spaces. - * @returns {String} The modified string excluding the removed spaces. - * @example - * alert( CKEDITOR.tools.ltrim( ' example ' ); // " example" - */ - rtrim: (function() { - // We are not using \s because we don't want "non-breaking spaces" to be caught. - var trimRegex = /[ \t\n\r]+$/g; - return function( str ) { - return str.replace( trimRegex, '' ); - }; - })(), + createClass: function( definition ) { + var $ = definition.$, + baseClass = definition.base, + privates = definition.privates || definition._, + proto = definition.proto, + statics = definition.statics; - /** - * Returns the index of an element in an array. - * @param {Array} array The array to be searched. - * @param {Object} entry The element to be found. - * @returns {Number} The (zero based) index of the first entry that matches - * the entry, or -1 if not found. - * @example - * var letters = [ 'a', 'b', 0, 'c', false ]; - * alert( CKEDITOR.tools.indexOf( letters, '0' ) ); "-1" because 0 !== '0' - * alert( CKEDITOR.tools.indexOf( letters, false ) ); "4" because 0 !== false - */ - indexOf: - // #2514: We should try to use Array.indexOf if it does exist. - ( Array.prototype.indexOf ) ? - function( array, entry ) { - return array.indexOf( entry ); - } : function( array, entry ) { - for ( var i = 0, len = array.length; i < len; i++ ) { - if ( array[ i ] === entry ) - return i; + if ( privates ) { + var originalConstructor = $; + $ = function() { + originalConstructor.apply( this, arguments ); + + // Create (and get) the private namespace. + var _ = this._ || ( this._ = {} ); + + // Make some magic so "this" will refer to the main + // instance when coding private functions. + for ( var privateName in privates ) { + var priv = privates[ privateName ]; + + _[ privateName ] = ( typeof priv == 'function' ) ? CKEDITOR.tools.bind( priv, this ) : priv; + } + }; + } + + if ( baseClass ) { + $.prototype = this.prototypedCopy( baseClass.prototype ); + + $.prototype.base = function() { + this.base = baseClass.prototype.base; + baseClass.apply( this, arguments ); + this.base = arguments.callee; + }; + } + + if ( proto ) + this.extend( $.prototype, proto, true ); + + if ( statics ) + this.extend( $, statics, true ); + + return $; + }, + + addFunction: function( fn, scope ) { + return functions.push( function() { + fn.apply( scope || this, arguments ); + }) - 1; + }, + + callFunction: function( index ) { + var fn = functions[ index ]; + return fn.apply( window, Array.prototype.slice.call( arguments, 1 ) ); } - return -1; - }, - - bind: function( func, obj ) { - return function() { - return func.apply( obj, arguments ); - }; - } -}; + }; +})(); // PACKAGER_RENAME( CKEDITOR.tools ) diff --git a/_source/core/ui.js b/_source/core/ui.js index 69036f6c25..54e4bbefcd 100644 --- a/_source/core/ui.js +++ b/_source/core/ui.js @@ -44,9 +44,10 @@ CKEDITOR.ui.prototype = { * }); */ add: function( name, type, definition ) { - var item = this._.handlers[ type ].create( definition ); - item.name = name; - this._.items[ name ] = item; + this._.items[ name ] = { + type: type, + args: Array.prototype.slice.call( arguments, 2 ) + }; }, /** @@ -54,8 +55,11 @@ CKEDITOR.ui.prototype = { * @param {String} name The UI item hame. * @example */ - get: function( name ) { - return this._.items[ name ] || null; + create: function( name ) { + var item = this._.items[ name ], + handler = item && this._.handlers[ item.type ]; + + return handler && handler.create.apply( this, item.args ); }, /** diff --git a/_source/lang/en.js b/_source/lang/en.js index 750895f17c..3d063f0497 100644 --- a/_source/lang/en.js +++ b/_source/lang/en.js @@ -413,5 +413,21 @@ CKEDITOR.lang[ 'en' ] = { emptyListMsg: '(No templates defined)' }, - showBlocks: 'Show Blocks' + showBlocks: 'Show Blocks', + + format: { + label: 'Format', + panelTitle: 'Paragraph Format', + + tag_p: 'Normal', + tag_pre: 'Formatted', + tag_address: 'Address', + tag_h1: 'Heading 1', + tag_h2: 'Heading 2', + tag_h3: 'Heading 3', + tag_h4: 'Heading 4', + tag_h5: 'Heading 5', + tag_h6: 'Heading 6', + tag_div: 'Normal (DIV)' + } }; diff --git a/_source/plugins/floatpanel/plugin.js b/_source/plugins/floatpanel/plugin.js new file mode 100644 index 0000000000..508b6f84f0 --- /dev/null +++ b/_source/plugins/floatpanel/plugin.js @@ -0,0 +1,108 @@ +/* +Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ + +CKEDITOR.plugins.add( 'floatpanel', { + requires: [ 'panel' ] +}); + +(function() { + var panels = {}; + + function getPanel( doc, parentElement, definition ) { + // Generates the panel key: docId-eleId-CSSs + var key = doc.getUniqueId() + '-' + parentElement.getUniqueId() + + ( ( definition.css && ( '-' + definition.css ) ) || '' ); + + var panel = panels[ key ]; + + if ( !panel ) { + panel = panels[ key ] = new CKEDITOR.ui.panel( doc, definition ); + panel.element = parentElement.append( CKEDITOR.dom.element.createFromHtml( panel.renderHtml(), doc ) ); + + panel.element.setStyles({ + display: 'none', + position: 'absolute' + }); + } + + return panel; + } + + CKEDITOR.ui.floatPanel = CKEDITOR.tools.createClass({ + $: function( parentElement, definition ) { + definition.forceIFrame = true; + + var doc = parentElement.getDocument(), + panel = getPanel( doc, parentElement, definition ), + element = panel.element, + iframe = element.getFirst(); + + this.element = element; + + this._ = { + // The panel that will be floating. + panel: panel, + document: doc, + iframe: iframe + } + }, + + proto: { + addBlock: function( name, block ) { + return this._.panel.addBlock( name, block ); + }, + + addListBlock: function( name, multiSelect ) { + return this._.panel.addListBlock( name, multiSelect ); + }, + + showBlock: function( name, offsetParent, corner, offsetX, offsetY ) { + this._.panel.showBlock( name ); + + var element = this.element, + iframe = this._.iframe, + position = offsetParent.getDocumentPosition(); + + var left = position.x + ( offsetX || 0 ), + top = position.y + ( offsetY || 0 ); + + if ( corner == 2 || corner == 3 ) + left += offsetParent.$.offsetWidth - 1; + + if ( corner == 3 || corner == 4 ) + top += offsetParent.$.offsetHeight - 1; + + element.setStyles({ + left: left + 'px', + top: top + 'px', + display: '' + }); + + // Configure the IFrame blur event. Do that only once. + if ( !this._.blurSet ) { + // Non IE prefer the event into a window object. + var focused = CKEDITOR.env.ie ? iframe : new CKEDITOR.dom.window( iframe.$.contentWindow ); + + focused.on( 'blur', CKEDITOR.tools.bind( this.hide, this ) ); + + this._.blurSet = 1; + } + + // Set the IFrame focus, so the blur event gets fired. + setTimeout( function() { + iframe.$.contentWindow.focus(); + }, 0 ); + + if ( this.onShow ) + this.onShow.call( this ); + }, + + hide: function() { + if ( !this.onHide || this.onHide.call( this ) !== true ) + this.element.setStyle( 'display', 'none' ); + } + } + }); +})(); diff --git a/_source/plugins/format/plugin.js b/_source/plugins/format/plugin.js new file mode 100644 index 0000000000..d18ed4bc4c --- /dev/null +++ b/_source/plugins/format/plugin.js @@ -0,0 +1,102 @@ +/* +Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ + +CKEDITOR.plugins.add( 'format', { + requires: [ 'richcombo' ], + + init: function( editor ) { + var config = editor.config, + lang = editor.lang.format; + + var saveRanges; + + // Gets the list of tags from the settings. + var tags = config.format_tags.split( ',' ); + + // Create style objects for all defined styles. + var styles = {}; + for ( var i = 0; i < tags.length; i++ ) { + var tag = tags[ i ]; + styles[ tag ] = new CKEDITOR.style( config[ 'format_' + tag ] ); + } + + editor.ui.addRichCombo( 'Format', { + label: lang.label, + title: lang.panelTitle, + className: 'cke_format', + multiSelect: false, + + panel: { + css: [ config.contentsCss, editor.skinPath + 'editor.css' ], + className: 'cke_skin_default' + }, + + init: function() { + this.startGroup( lang.panelTitle ); + + for ( var tag in styles ) { + var label = lang[ 'tag_' + tag ]; + + // Add the tag entry to the panel list. + this.add( tag, '<' + tag + '>' + label + '', label ); + } + }, + + onClick: function( value ) { + editor.focus(); + + if ( saveRanges ) { + editor.getSelection().selectRanges( saveRanges ); + saveRanges = false; + } + + styles[ value ].apply( editor.document ); + }, + + onRender: function() { + editor.on( 'selectionChange', function( ev ) { + var currentTag = this.getValue(); + + var elementPath = ev.data.path; + + for ( var tag in styles ) { + if ( styles[ tag ].checkActive( elementPath ) ) { + if ( tag != currentTag ) + this.setValue( tag, editor.lang.format[ 'tag_' + tag ] ); + return; + } + } + + // If no styles match, just empty it. + this.setValue( '' ); + }, this ); + }, + + onOpen: function() { + if ( CKEDITOR.env.ie ) { + editor.focus(); + saveRanges = editor.getSelection().getRanges(); + } + }, + + onClose: function() { + saveRanges = null; + } + }); + } +}); + +CKEDITOR.config.format_tags = 'p,h1,h2,h3,h4,h5,h6,pre,address,div'; + +CKEDITOR.config.format_p = { element: 'p' }; +CKEDITOR.config.format_div = { element: 'div' }; +CKEDITOR.config.format_pre = { element: 'pre' }; +CKEDITOR.config.format_address = { element: 'address' }; +CKEDITOR.config.format_h1 = { element: 'h1' }; +CKEDITOR.config.format_h2 = { element: 'h2' }; +CKEDITOR.config.format_h3 = { element: 'h3' }; +CKEDITOR.config.format_h4 = { element: 'h4' }; +CKEDITOR.config.format_h5 = { element: 'h5' }; +CKEDITOR.config.format_h6 = { element: 'h6' }; diff --git a/_source/plugins/listblock/plugin.js b/_source/plugins/listblock/plugin.js new file mode 100644 index 0000000000..4b06271adb --- /dev/null +++ b/_source/plugins/listblock/plugin.js @@ -0,0 +1,117 @@ +/* +Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ + +CKEDITOR.plugins.add( 'listblock', { + requires: [ 'panel' ], + + onLoad: function() { + CKEDITOR.ui.panel.prototype.addListBlock = function( name, multiSelect ) { + return this.addBlock( name, new CKEDITOR.ui.listBlock( this.getHolderElement(), multiSelect ) ); + }; + + CKEDITOR.ui.listBlock = CKEDITOR.tools.createClass({ + base: CKEDITOR.ui.panel.block, + + $: function( blockHolder, multiSelect ) { + // Call the base contructor. + this.base( blockHolder ); + + this.multiSelect = !!multiSelect; + + this._ = { + pendingHtml: [], + items: {} + }; + }, + + _: { + close: function() { + if ( this._.started ) { + this._.pendingHtml.push( '' ); + delete this._.started; + } + }, + + getClick: function() { + if ( !this._.click ) { + this._.click = CKEDITOR.tools.addFunction( function( value ) { + var marked = true; + + if ( this.multiSelect ) + marked = this.toggle( value ); + else + this.mark( value ); + + if ( this.onClick ) + this.onClick( value, marked ); + }, this ); + } + return this._.click; + } + }, + + proto: { + add: function( value, html ) { + var pendingHtml = this._.pendingHtml, + id = CKEDITOR.tools.getNextNumber(); + + if ( !this._.started ) { + pendingHtml.push( '