Click here to Skip to main content
15,892,746 members
Articles / Web Development / ASP.NET

How to Integrate CKEditor with ASP.NET

Rate me:
Please Sign up or sign in to vote.
4.95/5 (20 votes)
22 Jan 2013CPOL3 min read 159.1K   16.9K   19  
This is meant for easy integration of CKEditor with ASP.NET
/*
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/

/**
 * @fileOverview Defines the {@link CKEDITOR.tools} object, which contains
 *		utility functions.
 */

(function()
{
	var functions = [];

	CKEDITOR.on( 'reset', function()
		{
			functions = [];
		});

	/**
	 * Utility functions.
	 * @namespace
	 * @example
	 */
	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 )
				return true;

			if ( !arrayA || !arrayB || arrayA.length != arrayB.length )
				return false;

			for ( var i = 0 ; i < arrayA.length ; i++ )
			{
				if ( arrayA[ i ] != arrayB[ i ] )
					return false;
			}

			return true;
		},

		/**
		 * Creates a deep copy of an object.
		 * Attention: there is no support for recursive references.
		 * @param {Object} object The object to be cloned.
		 * @returns {Object} The object clone.
		 * @example
		 * var obj =
		 *     {
		 *         name : 'John',
		 *         cars :
		 *             {
		 *                 Mercedes : { color : 'blue' },
		 *                 Porsche : { color : 'red' }
		 *             }
		 *     };
		 * var clone = CKEDITOR.tools.clone( obj );
		 * clone.name = 'Paul';
		 * clone.cars.Porsche.color = 'silver';
		 * alert( obj.name );	// John
		 * alert( clone.name );	// Paul
		 * alert( obj.cars.Porsche.color );	// red
		 * alert( clone.cars.Porsche.color );	// silver
		 */
		clone : function( obj )
		{
			var clone;

			// Array.
			if ( obj && ( obj instanceof Array ) )
			{
				clone = [];

				for ( var i = 0 ; i < obj.length ; i++ )
					clone[ i ] = this.clone( obj[ i ] );

				return clone;
			}

			// "Static" types.
			if ( obj === null
				|| ( typeof( obj ) != 'object' )
				|| ( obj instanceof String )
				|| ( obj instanceof Number )
				|| ( obj instanceof Boolean )
				|| ( obj instanceof Date )
				|| ( obj instanceof RegExp) )
			{
				return obj;
			}

			// Objects.
			clone = new obj.constructor();

			for ( var propertyName in obj )
			{
				var property = obj[ propertyName ];
				clone[ propertyName ] = this.clone( property );
			}

			return clone;
		},

		/**
		 * 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.
		 * @param {Object} source[,souce(n)] The objects from which copy
		 *		properties. Any number of objects can be passed to this function.
		 * @param {Boolean} [overwrite] If 'true' is specified it indicates that
		 *            properties already present in the target object could be
		 *            overwritten by subsequent objects.
		 * @param {Object} [properties] Only properties within the specified names
		 *            list will be received from the source object.
		 * @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, propertiesList;

			if ( typeof ( overwrite = arguments[ argsLength - 1 ] ) == 'boolean')
				argsLength--;
			else if ( typeof ( overwrite = arguments[ argsLength - 2 ] ) == 'boolean' )
			{
				propertiesList = arguments [ argsLength -1 ];
				argsLength-=2;
			}
			for ( var i = 1 ; i < argsLength ; i++ )
			{
				var source = arguments[ i ];
				for ( var propertyName in source )
				{
					// Only copy existed fields if in overwrite mode.
					if ( overwrite === true || target[ propertyName ] == undefined )
					{
						// Only copy  specified fields if list is provided.
						if ( !propertiesList || ( propertyName in propertiesList ) )
							target[ propertyName ] = source[ propertyName ];

					}
				}
			}

			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();
		},

		/**
		 * Checks if an object is an Array.
		 * @param {Object} object The object to be checked.
		 * @type Boolean
		 * @returns <i>true</i> if the object is an Array, otherwise <i>false</i>.
		 * @example
		 * alert( CKEDITOR.tools.isArray( [] ) );      // "true"
		 * alert( CKEDITOR.tools.isArray( 'Test' ) );  // "false"
		 */
		isArray : function( object )
		{
			return ( !!object && object instanceof Array );
		},

		/**
		 * Whether the object contains no properties of it's own.
 		 * @param object
		 */
		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.
		 * @returns {String} The transformed name.
		 * @example
		 * alert( CKEDITOR.tools.cssStyleToDomStyle( 'background-color' ) );  // "backgroundColor"
		 * alert( CKEDITOR.tools.cssStyleToDomStyle( 'float' ) );             // "cssFloat"
		 */
		cssStyleToDomStyle : ( function()
		{
			var test = document.createElement( 'div' ).style;

			var cssFloat = ( typeof test.cssFloat != 'undefined' ) ? 'cssFloat'
				: ( typeof test.styleFloat != 'undefined' ) ? 'styleFloat'
				: 'float';

			return function( cssName )
			{
				if ( cssName == 'float' )
					return cssFloat;
				else
				{
					return cssName.replace( /-./g, function( match )
						{
							return match.substr( 1 ).toUpperCase();
						});
				}
			};
		} )(),

		/**
		 * Build the HTML snippet of a set of &lt;style>/&lt;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.
		 * @returns {String} The encode string.
		 * @example
		 * alert( CKEDITOR.tools.htmlEncode( 'A > B & C < D' ) );  // "A &amp;gt; B &amp;amp; C &amp;lt; D"
		 */
		htmlEncode : function( text )
		{
			var standard = function( text )
			{
				var span = new CKEDITOR.dom.element( 'span' );
				span.setText( text );
				return span.getHtml();
			};

			var fix1 = ( standard( '\n' ).toLowerCase() == '<br>' ) ?
				function( text )
				{
					// #3874 IE and Safari encode line-break into <br>
					return standard( text ).replace( /<br>/gi, '\n' );
				} :
				standard;

			var fix2 = ( standard( '>' ) == '>' ) ?
				function( text )
				{
					// WebKit does't encode the ">" character, which makes sense, but
					// it's different than other browsers.
					return fix1( text ).replace( />/g, '&gt;' );
				} :
				fix1;

			var fix3 = ( standard( '  ' ) == '&nbsp; ' ) ?
				function( text )
				{
					// #3785 IE8 changes spaces (>= 2) to &nbsp;
					return fix2( text ).replace( /&nbsp;/g, ' ' );
				} :
				fix2;

			this.htmlEncode = fix3;

			return this.htmlEncode( text );
		},

		/**
		 * Replace special HTML characters in HTMLElement's attribute with their relative HTML entity values.
		 * @param {String} The attribute's value to be encoded.
		 * @returns {String} The encode value.
		 * @example
		 * element.setAttribute( 'title', '<a " b >' );
		 * alert( CKEDITOR.tools.htmlEncodeAttr( element.getAttribute( 'title' ) );  // "&gt;a &quot; b &lt;"
		 */
		htmlEncodeAttr : function( text )
		{
			return text.replace( /"/g, '&quot;' ).replace( /</g, '&lt;' ).replace( />/g, '&gt;' );
		},

		/**
		 * 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.<b>getNextNumber()</b> );  // "1" (e.g.)
		 * alert( CKEDITOR.tools.<b>getNextNumber()</b> );  // "2"
		 */
		getNextNumber : (function()
		{
			var last = 0;
			return function()
			{
				return ++last;
			};
		})(),

		/**
		 * Gets a unique ID for CKEditor's interface elements. It returns a
		 * string with the "cke_" prefix and a progressive number.
		 * @function
		 * @returns {String} A unique ID.
		 * @example
		 * alert( CKEDITOR.tools.<b>getNextId()</b> );  // "cke_1" (e.g.)
		 * alert( CKEDITOR.tools.<b>getNextId()</b> );  // "cke_2"
		 */
		getNextId : function()
		{
			return 'cke_' + this.getNextNumber();
		},

		/**
		 * 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 );
		},

		/**
		 * 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.<b>setTimeout(
		 *     function()
		 *     {
		 *         alert( 'Executed after 2 seconds' );
		 *     },
		 *     2000 )</b>;
		 */
		setTimeout : function( func, milliseconds, scope, args, ownerWindow )
		{
			if ( !ownerWindow )
				ownerWindow = window;

			if ( !scope )
				scope = ownerWindow;

			return ownerWindow.setTimeout(
				function()
				{
					if ( args )
						func.apply( scope, [].concat( args ) ) ;
					else
						func.apply( scope ) ;
				},
				milliseconds || 0 );
		},

		/**
		 * 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, '' ) ;
			};
		})(),

		/**
		 * 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, '' ) ;
			};
		})(),

		/**
		 * 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, '' ) ;
			};
		})(),

		/**
		 * 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;
				},

		/**
		 * 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 ); };
		},

		/**
		 * Class creation based on prototype inheritance, with supports of the
		 * following features:
		 * <ul>
		 * <li> Static fields </li>
		 * <li> Private fields </li>
		 * <li> Public (prototype) fields </li>
		 * <li> Chainable base class constructor </li>
		 * </ul>
		 * @param {Object} definition The class definition object.
		 * @returns {Function} A class-like JavaScript function.
		 */
		createClass : function( definition )
		{
			var $ = definition.$,
				baseClass = definition.base,
				privates = definition.privates || definition._,
				proto = definition.proto,
				statics = definition.statics;

			if ( privates )
			{
				var originalConstructor = $;
				$ = function()
				{
					// 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;
					}

					originalConstructor.apply( this, arguments );
				};
			}

			if ( baseClass )
			{
				$.prototype = this.prototypedCopy( baseClass.prototype );
				$.prototype.constructor = $;
				$.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 $;
		},

		/**
		 * 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()
				{
					return fn.apply( scope || this, arguments );
				}) - 1;
		},

		/**
		 * Removes the function reference created with {@see CKEDITOR.tools.addFunction}.
		 * @param {Number} ref The function reference created with
		 *		CKEDITOR.tools.addFunction.
		 */
		removeFunction : function( ref )
		{
			functions[ ref ] = null;
		},

		/**
		 * 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[ ref ];
			return fn && fn.apply( window, Array.prototype.slice.call( arguments, 1 ) );
		},

		/**
		 * Append the 'px' length unit to the size if it's missing.
		 * @param length
		 */
		cssLength : (function()
		{
			return function( length )
			{
				return length + ( !length || isNaN( Number( length ) ) ? '' : 'px' );
			};
		})(),

		/**
		 * Convert the specified CSS length value to the calculated pixel length inside this page.
		 * <strong>Note:</strong> Percentage based value is left intact.
		 * @param {String} cssLength CSS length value.
		 */
		convertToPx : ( function ()
			{
				var calculator;

				return function( cssLength )
				{
					if ( !calculator )
					{
						calculator = CKEDITOR.dom.element.createFromHtml(
								'<div style="position:absolute;left:-9999px;' +
								'top:-9999px;margin:0px;padding:0px;border:0px;"' +
								'></div>', CKEDITOR.document );
						CKEDITOR.document.getBody().append( calculator );
					}

					if ( !(/%$/).test( cssLength ) )
					{
						calculator.setStyle( 'width', cssLength );
						return calculator.$.clientWidth;
					}

					return cssLength;
				};
			} )(),

		/**
		 * String specified by {@param str} repeats {@param times} times.
		 * @param str
		 * @param times
		 */
		repeat : function( str, times )
		{
			return new Array( times + 1 ).join( str );
		},

		/**
		 * Return the first successfully executed function's return value that
		 * doesn't throw any exception.
		 */
		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;
		},

		/**
		 * Generate a combined key from a series of params.
		 * @param {String} subKey One or more string used as sub keys.
		 * @example
		 * var key = CKEDITOR.tools.genKey( 'key1', 'key2', 'key3' );
		 * alert( key );		// "key1-key2-key3".
		 */
		genKey : function()
		{
			return Array.prototype.slice.call( arguments ).join( '-' );
		},

		/**
		 * Try to avoid differences in the style attribute.
		 *
		 * @param {String} styleText The style data to be normalized.
		 * @param {Boolean} [nativeNormalize=false] Parse the data using the browser.
		 * @returns {String} The normalized value.
		 */
		normalizeCssText: function( styleText, nativeNormalize ) {
			var props = [],
				name,
				parsedProps = CKEDITOR.tools.parseCssText( styleText, true, nativeNormalize );

			for ( name in parsedProps )
				props.push( name + ':' + parsedProps[ name ] );

			props.sort();

			return props.length ? ( props.join( ';' ) + ';' ) : '';
		},

		/**
		 * Find and convert <code>rgb(x,x,x)</code> colors definition to hexadecimal notation.
		 * @param {String} styleText The style data (or just a string containing rgb colors) to be converted.
		 * @returns {String} The style data with rgb colors converted to hexadecimal equivalents.
		 */
		convertRgbToHex: function( styleText ) {
			return styleText.replace( /(?:rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\))/gi, function( match, red, green, blue ) {
				var color = [ red, green, blue ];
				// Add padding zeros if the hex value is less than 0x10.
				for ( var i = 0; i < 3; i++ )
					color[ i ] = ( '0' + parseInt( color[ i ], 10 ).toString( 16 ) ).slice( -2 );
				return '#' + color.join( '' );
			});
		},

		/**
		 * Turn inline style text properties into one hash.
		 *
		 * @param {String} styleText The style data to be parsed.
		 * @param {Boolean} [normalize=false] Normalize properties and values
		 * (e.g. trim spaces, convert to lower case).
		 * @param {Boolean} [nativeNormalize=false] Parse the data using the browser.
		 * @returns {String} The object containing parsed properties.
		 */
		parseCssText: function( styleText, normalize, nativeNormalize ) {
			var retval = {};

			if ( nativeNormalize ) {
				// Injects the style in a temporary span object, so the browser parses it,
				// retrieving its final format.
				var temp = new CKEDITOR.dom.element( 'span' );
				temp.setAttribute( 'style', styleText );
				styleText = CKEDITOR.tools.convertRgbToHex( temp.getAttribute( 'style' ) || '' );
			}

			// IE will leave a single semicolon when failed to parse the style text. (#3891)
			if ( !styleText || styleText == ';' )
				return retval;

			styleText.replace( /&quot;/g, '"' ).replace( /\s*([^:;\s]+)\s*:\s*([^;]+)\s*(?=;|$)/g, function( match, name, value ) {
				if ( normalize ) {
					name = name.toLowerCase();
					// Normalize font-family property, ignore quotes and being case insensitive. (#7322)
					// http://www.w3.org/TR/css3-fonts/#font-family-the-font-family-property
					if ( name == 'font-family' )
						value = value.toLowerCase().replace( /["']/g, '' ).replace( /\s*,\s*/g, ',' );
					value = CKEDITOR.tools.trim( value );
				}

				retval[ name ] = value;
			});
			return retval;
		}

	};
})();

// PACKAGER_RENAME( CKEDITOR.tools )

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Cefalo
Bangladesh Bangladesh
Hi,

I am Palash Debnath. I have been working on windows technologies since 2008. I started with ASP.NET. Then I moved to Windows Form and from the last year I have been working with Windows 8 app development. Work with Windows 10 apps development as well. Now I have been working with Microsoft Azure. I have completed my Undergraduate from Khulna University of Engineering in Computer Science & Engineering. Currently working as a Senior Software Engineer at Cefalo.

Comments and Discussions