]>
git.immae.eu Git - perso/Immae/Projets/packagist/piedsjaloux-ckeditor-component.git/blob - sources/core/tools.js
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
7 * @fileOverview Defines the {@link CKEDITOR.tools} object that contains
14 CKEDITOR
. env
. gecko
? '-moz-' :
15 CKEDITOR
. env
. webkit
? '-webkit-' :
16 CKEDITOR
. env
. ie
? '-ms-' :
22 tokenCharset = 'abcdefghijklmnopqrstuvwxyz0123456789',
23 TOKEN_COOKIE_NAME = 'ckCsrfToken',
26 allEscRegex = /&(lt|gt|amp|quot|nbsp|shy|#\d{1,5});/g,
35 allEscDecode = function( match, code ) {
36 if ( code[ 0 ] == ' # ' ) {
37 return String.fromCharCode( parseInt( code.slice( 1 ), 10 ) );
39 return namedEntities[ code ];
43 CKEDITOR.on( ' reset
', function() {
55 * Compares the elements of two arrays.
57 * var a = [ 1, ' a
', 3 ];
58 * var b = [ 1, 3, ' a
' ];
59 * var c = [ 1, ' a
', 3 ];
60 * var d = [ 1, ' a
', 3, 4 ];
62 * alert( CKEDITOR.tools.arrayCompare( a, b ) ); // false
63 * alert( CKEDITOR.tools.arrayCompare( a, c ) ); // true
64 * alert( CKEDITOR.tools.arrayCompare( a, d ) ); // false
66 * @param {Array} arrayA An array to be compared.
67 * @param {Array} arrayB The other array to be compared.
68 * @returns {Boolean} `true` if the arrays have the same length and
69 * their elements match.
71 arrayCompare: function( arrayA, arrayB ) {
72 if ( !arrayA && !arrayB )
75 if ( !arrayA || !arrayB || arrayA.length != arrayB.length )
78 for ( var i = 0; i < arrayA.length; i++ ) {
79 if ( arrayA[ i ] != arrayB[ i ] )
87 * Finds the index of the first element in an array for which the `compareFunction` returns `true`.
89 * CKEDITOR.tools.getIndex( [ 1, 2, 4, 3, 5 ], function( el ) {
94 * @param {Array} array Array to search in.
95 * @param {Function} compareFunction Compare function.
96 * @returns {Number} The index of the first matching element or `-1` if none matches.
98 getIndex: function( arr, compareFunction ) {
99 for ( var i = 0; i < arr.length; ++i ) {
100 if ( compareFunction( arr[ i ] ) )
107 * Creates a deep copy of an object.
109 * **Note**: Recursive references are not supported.
114 * Mercedes: { color: ' blue
' },
115 * Porsche: { color: ' red
' }
118 * var clone = CKEDITOR.tools.clone( obj );
119 * clone.name = ' Paul
';
120 * clone.cars.Porsche.color = ' silver
';
122 * alert( obj.name ); // ' John
'
123 * alert( clone.name ); // ' Paul
'
124 * alert( obj.cars.Porsche.color ); // ' red
'
125 * alert( clone.cars.Porsche.color ); // ' silver
'
127 * @param {Object} object The object to be cloned.
128 * @returns {Object} The object clone.
130 clone: function( obj ) {
134 if ( obj && ( obj instanceof Array ) ) {
137 for ( var i = 0; i < obj.length; i++ )
138 clone[ i ] = CKEDITOR.tools.clone( obj[ i ] );
144 if ( obj === null || ( typeof obj != ' object
' ) || ( obj instanceof String ) || ( obj instanceof Number ) || ( obj instanceof Boolean ) || ( obj instanceof Date ) || ( obj instanceof RegExp ) )
147 // DOM objects and window.
148 if ( obj.nodeType || obj.window === obj )
152 clone = new obj.constructor();
154 for ( var propertyName in obj ) {
155 var property = obj[ propertyName ];
156 clone[ propertyName ] = CKEDITOR.tools.clone( property );
163 * Turns the first letter of a string to upper-case.
165 * @param {String} str
166 * @param {Boolean} [keepCase] Keep the case of 2nd to last letter.
169 capitalize: function( str, keepCase ) {
170 return str.charAt( 0 ).toUpperCase() + ( keepCase ? str.slice( 1 ) : str.slice( 1 ).toLowerCase() );
174 * Copies the properties from one object to another. By default, properties
175 * already present in the target object **are not** overwritten.
177 * // Create the sample object.
182 * // Extend the above object with two properties.
183 * CKEDITOR.tools.extend( myObject, {
188 * // Alert ' prop1
', ' prop2
' and ' prop3
'.
189 * for ( var p in myObject )
192 * @param {Object} target The object to be extended.
193 * @param {Object...} source The object(s) from properties will be
194 * copied. Any number of objects can be passed to this function.
195 * @param {Boolean} [overwrite] If `true` is specified, it indicates that
196 * properties already present in the target object could be
197 * overwritten by subsequent objects.
198 * @param {Object} [properties] Only properties within the specified names
199 * list will be received from the source object.
200 * @returns {Object} The extended object (target).
202 extend: function( target ) {
203 var argsLength = arguments.length,
204 overwrite, propertiesList;
206 if ( typeof ( overwrite = arguments[ argsLength - 1 ] ) == ' boolean ' )
208 else if ( typeof ( overwrite = arguments[ argsLength - 2 ] ) == ' boolean ' ) {
209 propertiesList = arguments[ argsLength - 1 ];
212 for ( var i = 1; i < argsLength; i++ ) {
213 var source = arguments[ i ];
214 for ( var propertyName in source ) {
215 // Only copy existed fields if in overwrite mode.
216 if ( overwrite === true || target[ propertyName ] == null ) {
217 // Only copy specified fields if list is provided.
218 if ( !propertiesList || ( propertyName in propertiesList ) )
219 target[ propertyName ] = source[ propertyName ];
229 * Creates an object which is an instance of a class whose prototype is a
230 * predefined object. All properties defined in the source object are
231 * automatically inherited by the resulting object, including future
234 * @param {Object} source The source object to be used as the prototype for
236 * @returns {Object} The resulting copy.
238 prototypedCopy: function( source ) {
239 var copy = function() {};
240 copy.prototype = source;
245 * Makes fast (shallow) copy of an object.
246 * This method is faster than {@link #clone} which does
247 * a deep copy of an object (including arrays).
250 * @param {Object} source The object to be copied.
251 * @returns {Object} Copy of `source`.
253 copy: function( source ) {
257 for ( name in source )
258 obj[ name ] = source[ name ];
264 * Checks if an object is an Array.
266 * alert( CKEDITOR.tools.isArray( [] ) ); // true
267 * alert( CKEDITOR.tools.isArray( ' Test
' ) ); // false
269 * @param {Object} object The object to be checked.
270 * @returns {Boolean} `true` if the object is an Array, otherwise `false`.
272 isArray: function( object ) {
273 return Object.prototype.toString.call( object ) == ' [ object Array
] ';
277 * Whether the object contains no properties of its own.
282 isEmpty: function( object ) {
283 for ( var i in object ) {
284 if ( object.hasOwnProperty( i ) )
291 * Generates an object or a string containing vendor-specific and vendor-free CSS properties.
293 * CKEDITOR.tools.cssVendorPrefix( ' border
- radius
', ' 0 ', true );
294 * // On Firefox: ' - moz
- border
- radius : 0 ; border
- radius : 0 '
295 * // On Chrome: ' - webkit
- border
- radius : 0 ; border
- radius : 0 '
297 * @param {String} property The CSS property name.
298 * @param {String} value The CSS value.
299 * @param {Boolean} [asString=false] If `true`, then the returned value will be a CSS string.
300 * @returns {Object/String} The object containing CSS properties or its stringified version.
302 cssVendorPrefix: function( property, value, asString ) {
304 return cssVendorPrefix + property + ' : ' + value + ' ; ' + property + ' : ' + value;
307 ret[ property ] = value;
308 ret[ cssVendorPrefix + property ] = value;
314 * Transforms a CSS property name to its relative DOM style name.
316 * alert( CKEDITOR.tools.cssStyleToDomStyle( ' background
- color
' ) ); // ' backgroundColor
'
317 * alert( CKEDITOR.tools.cssStyleToDomStyle( ' float ' ) ); // ' cssFloat
'
320 * @param {String} cssName The CSS property name.
321 * @returns {String} The transformed name.
323 cssStyleToDomStyle: ( function() {
324 var test = document.createElement( ' div
' ).style;
326 var cssFloat = ( typeof test.cssFloat != ' undefined ' ) ? ' cssFloat
' : ( typeof test.styleFloat != ' undefined ' ) ? ' styleFloat
' : ' float ';
328 return function( cssName ) {
329 if ( cssName == ' float ' )
332 return cssName.replace( /-./g, function( match ) {
333 return match.substr( 1 ).toUpperCase();
340 * Builds a HTML snippet from a set of `<style>/<link>`.
342 * @param {String/Array} css Each of which are URLs (absolute) of a CSS file or
343 * a trunk of style text.
346 buildStyleHtml: function( css ) {
347 css = [].concat( css );
350 for ( var i = 0; i < css.length; i++ ) {
351 if ( ( item = css[ i ] ) ) {
352 // Is CSS style text ?
353 if ( /@import|[{}]/.test( item ) )
354 retval.push( ' < style
> ' + item + ' </ style
> ' );
356 retval.push( ' < link type
= "text/css" rel
= stylesheet href
= "' + item + '" > ' );
359 return retval.join( ' ' );
363 * Replaces special HTML characters in a string with their relative HTML
366 * alert( CKEDITOR.tools.htmlEncode( ' A
> B
& C
< D
' ) ); // ' A
& gt
; B
& amp
; C
& lt
; D
'
368 * @param {String} text The string to be encoded.
369 * @returns {String} The encoded string.
371 htmlEncode: function( text ) {
372 // Backwards compatibility - accept also non-string values (casting is done below).
373 // Since 4.4.8 we return empty string for null and undefined because these values make no sense.
374 if ( text === undefined || text === null ) {
378 return String( text ).replace( ampRegex, ' & amp
; ' ).replace( gtRegex, ' & gt
; ' ).replace( ltRegex, ' & lt
; ' );
382 * Decodes HTML entities that browsers tend to encode when used in text nodes.
384 * alert( CKEDITOR.tools.htmlDecode( ' & lt
; a
& amp
; b
& gt
; ' ) ); // ' < a
& b
> '
386 * Read more about chosen entities in the [research](http://dev.ckeditor.com/ticket/13105#comment:8).
388 * @param {String} The string to be decoded.
389 * @returns {String} The decoded string.
391 htmlDecode: function( text ) {
393 // * http://dev.ckeditor.com/ticket/13105#comment:8 and comment:9,
394 // * http://jsperf.com/wth-is-going-on-with-jsperf JSPerf has some serious problems, but you can observe
395 // that combined regexp tends to be quicker (except on V8). It will also not be prone to fail on ' & amp
; lt
; '
396 // (see http://dev.ckeditor.com/ticket/13105#DXWTF:CKEDITOR.tools.htmlEnDecodeAttr).
397 return text.replace( allEscRegex, allEscDecode );
401 * Replaces special HTML characters in HTMLElement attribute with their relative HTML entity values.
403 * alert( CKEDITOR.tools.htmlEncodeAttr( ' < a
" b >' ) ); // '<a " b >'
405 * @param {String} The attribute value to be encoded.
406 * @returns {String} The encoded value.
408 htmlEncodeAttr: function( text ) {
409 return CKEDITOR.tools.htmlEncode( text ).replace( quoteRegex, '"' );
413 * Decodes HTML entities that browsers tend to encode when used in attributes.
415 * alert( CKEDITOR.tools.htmlDecodeAttr( '<a " b>' ) ); // '<a " b
> '
417 * Since CKEditor 4.5 this method simply executes {@link #htmlDecode} which covers
418 * all necessary entities.
420 * @param {String} text The text to be decoded.
421 * @returns {String} The decoded text.
423 htmlDecodeAttr: function( text ) {
424 return CKEDITOR.tools.htmlDecode( text );
428 * Transforms text to valid HTML: creates paragraphs, replaces tabs with non-breaking spaces etc.
431 * @param {String} text Text to transform.
432 * @param {Number} enterMode Editor {@link CKEDITOR.config#enterMode Enter mode}.
433 * @returns {String} HTML generated from the text.
435 transformPlainTextToHtml: function( text, enterMode ) {
436 var isEnterBrMode = enterMode == CKEDITOR.ENTER_BR,
438 html = this.htmlEncode( text.replace( / \r\n /g, ' \n ' ) );
441 html = html.replace( / \t /g, ' & nbsp
;& nbsp
; & nbsp
; ' );
443 var paragraphTag = enterMode == CKEDITOR.ENTER_P ? ' p
' : ' div
';
445 // Two line-breaks create one paragraphing block.
446 if ( !isEnterBrMode ) {
447 var duoLF = / \n {2}/g;
448 if ( duoLF.test( html ) ) {
449 var openTag = ' < ' + paragraphTag + ' > ', endTag = ' </ ' + paragraphTag + ' > ';
450 html = openTag + html.replace( duoLF, function() {
451 return endTag + openTag;
456 // One <br> per line-break.
457 html = html.replace( / \n /g, ' < br
> ' );
459 // Compensate padding <br> at the end of block, avoid loosing them during insertion.
460 if ( !isEnterBrMode ) {
461 html = html.replace( new RegExp( ' < br
>(?=</ ' + paragraphTag + ' >) ' ), function( match ) {
462 return CKEDITOR.tools.repeat( match, 2 );
466 // Preserve spaces at the ends, so they won' t be lost after
insertion ( merged
with adjacent ones
).
467 html
= html
. replace ( /^ | $/ g
, ' ' );
469 // Finally, preserve whitespaces that are to be lost.
470 html
= html
. replace ( /(>|\s) /g , function ( match
, before
) {
471 return before
+ ' ' ;
472 } ). replace ( / (?=<)/ g
, ' ' );
478 * Gets a unique number for this CKEDITOR execution session. It returns
479 * consecutive numbers starting from 1.
481 * alert( CKEDITOR.tools.getNextNumber() ); // (e.g.) 1
482 * alert( CKEDITOR.tools.getNextNumber() ); // 2
485 * @returns {Number} A unique number.
487 getNextNumber : ( function () {
495 * Gets a unique ID for CKEditor interface elements. It returns a
496 * string with the "cke_" prefix and a consecutive number.
498 * alert( CKEDITOR.tools.getNextId() ); // (e.g.) 'cke_1'
499 * alert( CKEDITOR.tools.getNextId() ); // 'cke_2'
501 * @returns {String} A unique ID.
503 getNextId : function () {
504 return 'cke_' + this . getNextNumber ();
508 * Gets a universally unique ID. It returns a random string
509 * compliant with ISO/IEC 11578:1996, without dashes, with the "e" prefix to
510 * make sure that the ID does not start with a number.
512 * @returns {String} A global unique ID.
514 getUniqueId : function () {
515 var uuid
= 'e' ; // Make sure that id does not start with number.
516 for ( var i
= 0 ; i
< 8 ; i
++ ) {
517 uuid
+= Math
. floor ( ( 1 + Math
. random () ) * 0x10000 ). toString ( 16 ). substring ( 1 );
523 * Creates a function override.
526 * myFunction: function( name ) {
527 * alert( 'Name: ' + name );
531 * obj.myFunction = CKEDITOR.tools.override( obj.myFunction, function( myFunctionOriginal ) {
532 * return function( name ) {
533 * alert( 'Overriden name: ' + name );
534 * myFunctionOriginal.call( this, name );
538 * @param {Function} originalFunction The function to be overridden.
539 * @param {Function} functionBuilder A function that returns the new
540 * function. The original function reference will be passed to this function.
541 * @returns {Function} The new function.
543 override : function ( originalFunction
, functionBuilder
) {
544 var newFn
= functionBuilder ( originalFunction
);
545 newFn
. prototype = originalFunction
. prototype ;
550 * Executes a function after a specified delay.
552 * CKEDITOR.tools.setTimeout( function() {
553 * alert( 'Executed after 2 seconds' );
556 * @param {Function} func The function to be executed.
557 * @param {Number} [milliseconds=0] The amount of time (in milliseconds) to wait
558 * to fire the function execution.
559 * @param {Object} [scope=window] The object to store the function execution scope
560 * (the `this` object).
561 * @param {Object/Array} [args] A single object, or an array of objects, to
562 * pass as argument to the function.
563 * @param {Object} [ownerWindow=window] The window that will be used to set the
565 * @returns {Object} A value that can be used to cancel the function execution.
567 setTimeout : function ( func
, milliseconds
, scope
, args
, ownerWindow
) {
569 ownerWindow
= window
;
574 return ownerWindow
. setTimeout ( function () {
576 func
. apply ( scope
, []. concat ( args
) );
579 }, milliseconds
|| 0 );
583 * Removes spaces from the start and the end of a string. The following
584 * characters are removed: space, tab, line break, line feed.
586 * alert( CKEDITOR.tools.trim( ' example ' ); // 'example'
589 * @param {String} str The text from which the spaces will be removed.
590 * @returns {String} The modified string without the boundary spaces.
593 // We are not using \s because we don't want "non-breaking spaces" to be caught.
594 var trimRegex
= /(?:^[ \t\n\r ]+)|(?:[ \t\n\r ]+$)/ g
;
595 return function ( str
) {
596 return str
. replace ( trimRegex
, '' );
601 * Removes spaces from the start (left) of a string. The following
602 * characters are removed: space, tab, line break, line feed.
604 * alert( CKEDITOR.tools.ltrim( ' example ' ); // 'example '
607 * @param {String} str The text from which the spaces will be removed.
608 * @returns {String} The modified string excluding the removed spaces.
610 ltrim : ( function () {
611 // We are not using \s because we don't want "non-breaking spaces" to be caught.
612 var trimRegex
= /^[ \t\n\r ]+/ g
;
613 return function ( str
) {
614 return str
. replace ( trimRegex
, '' );
619 * Removes spaces from the end (right) of a string. The following
620 * characters are removed: space, tab, line break, line feed.
622 * alert( CKEDITOR.tools.ltrim( ' example ' ); // ' example'
625 * @param {String} str The text from which spaces will be removed.
626 * @returns {String} The modified string excluding the removed spaces.
628 rtrim : ( function () {
629 // We are not using \s because we don't want "non-breaking spaces" to be caught.
630 var trimRegex
= /[ \t\n\r ]+$/ g
;
631 return function ( str
) {
632 return str
. replace ( trimRegex
, '' );
637 * Returns the index of an element in an array.
639 * var letters = [ 'a', 'b', 0, 'c', false ];
640 * alert( CKEDITOR.tools.indexOf( letters, '0' ) ); // -1 because 0 !== '0'
641 * alert( CKEDITOR.tools.indexOf( letters, false ) ); // 4 because 0 !== false
643 * @param {Array} array The array to be searched.
644 * @param {Object/Function} value The element to be found. This can be an
645 * evaluation function which receives a single parameter call for
646 * each entry in the array, returning `true` if the entry matches.
647 * @returns {Number} The (zero-based) index of the first entry that matches
648 * the entry, or `-1` if not found.
650 indexOf : function ( array
, value
) {
651 if ( typeof value
== 'function' ) {
652 for ( var i
= 0 , len
= array
. length
; i
< len
; i
++ ) {
653 if ( value ( array
[ i
] ) )
656 } else if ( array
. indexOf
)
657 return array
. indexOf ( value
);
659 for ( i
= 0 , len
= array
. length
; i
< len
; i
++ ) {
660 if ( array
[ i
] === value
)
668 * Returns the index of an element in an array.
670 * var obj = { prop: true };
671 * var letters = [ 'a', 'b', 0, obj, false ];
673 * alert( CKEDITOR.tools.indexOf( letters, '0' ) ); // null
674 * alert( CKEDITOR.tools.indexOf( letters, function( value ) {
675 * // Return true when passed value has property 'prop'.
676 * return value && 'prop' in value;
679 * @param {Array} array The array to be searched.
680 * @param {Object/Function} value The element to be found. Can be an
681 * evaluation function which receives a single parameter call for
682 * each entry in the array, returning `true` if the entry matches.
683 * @returns Object The value that was found in an array.
685 search : function ( array
, value
) {
686 var index
= CKEDITOR
. tools
. indexOf ( array
, value
);
687 return index
>= 0 ? array
[ index
] : null ;
691 * Creates a function that will always execute in the context of a
694 * var obj = { text: 'My Object' };
696 * function alertText() {
697 * alert( this.text );
700 * var newFunc = CKEDITOR.tools.bind( alertText, obj );
701 * newFunc(); // Alerts 'My Object'.
703 * @param {Function} func The function to be executed.
704 * @param {Object} obj The object to which the execution context will be bound.
705 * @returns {Function} The function that can be used to execute the
706 * `func` function in the context of `obj`.
708 bind : function ( func
, obj
) {
710 return func
. apply ( obj
, arguments
);
715 * Class creation based on prototype inheritance which supports of the
716 * following features:
720 * * Public (prototype) fields
721 * * Chainable base class constructor
723 * @param {Object} definition The class definition object.
724 * @returns {Function} A class-like JavaScript function.
726 createClass : function ( definition
) {
727 var $ = definition
.$,
728 baseClass
= definition
. base
,
729 privates
= definition
. privates
|| definition
. _
,
730 proto
= definition
. proto
,
731 statics
= definition
. statics
;
733 // Create the constructor, if not present in the definition.
734 !$ && ( $ = function () {
735 baseClass
&& this . base
. apply ( this , arguments
);
739 var originalConstructor
= $;
741 // Create (and get) the private namespace.
742 var _
= this . _
|| ( this . _
= {} );
744 // Make some magic so "this" will refer to the main
745 // instance when coding private functions.
746 for ( var privateName
in privates
) {
747 var priv
= privates
[ privateName
];
749 _
[ privateName
] = ( typeof priv
== 'function' ) ? CKEDITOR
. tools
. bind ( priv
, this ) : priv
;
752 originalConstructor
. apply ( this , arguments
);
757 $. prototype = this . prototypedCopy ( baseClass
. prototype );
758 $. prototype . constructor = $;
761 $. baseProto
= baseClass
. prototype ;
762 // Super constructor.
763 $. prototype . base = function () {
764 this . base
= baseClass
. prototype . base
;
765 baseClass
. apply ( this , arguments
);
766 this . base
= arguments
. callee
;
771 this . extend ( $. prototype , proto
, true );
774 this . extend ( $, statics
, true );
780 * Creates a function reference that can be called later using
781 * {@link #callFunction}. This approach is especially useful to
782 * make DOM attribute function calls to JavaScript-defined functions.
784 * var ref = CKEDITOR.tools.addFunction( function() {
787 * CKEDITOR.tools.callFunction( ref ); // 'Hello!'
789 * @param {Function} fn The function to be executed on call.
790 * @param {Object} [scope] The object to have the context on `fn` execution.
791 * @returns {Number} A unique reference to be used in conjuction with
792 * {@link #callFunction}.
794 addFunction : function ( fn
, scope
) {
795 return functions
. push ( function () {
796 return fn
. apply ( scope
|| this , arguments
);
801 * Removes the function reference created with {@link #addFunction}.
803 * @param {Number} ref The function reference created with
804 * {@link #addFunction}.
806 removeFunction : function ( ref
) {
807 functions
[ ref
] = null ;
811 * Executes a function based on the reference created with {@link #addFunction}.
813 * var ref = CKEDITOR.tools.addFunction( function() {
816 * CKEDITOR.tools.callFunction( ref ); // 'Hello!'
818 * @param {Number} ref The function reference created with {@link #addFunction}.
819 * @param {Mixed} params Any number of parameters to be passed to the executed function.
820 * @returns {Mixed} The return value of the function.
822 callFunction : function ( ref
) {
823 var fn
= functions
[ ref
];
824 return fn
&& fn
. apply ( window
, Array
. prototype . slice
. call ( arguments
, 1 ) );
828 * Appends the `px` length unit to the size value if it is missing.
830 * var cssLength = CKEDITOR.tools.cssLength;
831 * cssLength( 42 ); // '42px'
832 * cssLength( '42' ); // '42px'
833 * cssLength( '42px' ); // '42px'
834 * cssLength( '42%' ); // '42%'
835 * cssLength( 'bold' ); // 'bold'
836 * cssLength( false ); // ''
837 * cssLength( NaN ); // ''
840 * @param {Number/String/Boolean} length
842 cssLength : ( function () {
843 var pixelRegex
= /^-?\d+\.?\d*px$/ ,
846 return function ( length
) {
847 lengthTrimmed
= CKEDITOR
. tools
. trim ( length
+ '' ) + 'px' ;
849 if ( pixelRegex
. test ( lengthTrimmed
) )
850 return lengthTrimmed
;
857 * Converts the specified CSS length value to the calculated pixel length inside this page.
859 * **Note:** Percentage-based value is left intact.
862 * @param {String} cssLength CSS length value.
864 convertToPx : ( function () {
867 return function ( cssLength
) {
869 calculator
= CKEDITOR
. dom
. element
. createFromHtml ( '<div style="position:absolute;left:-9999px;' +
870 'top:-9999px;margin:0px;padding:0px;border:0px;"' +
871 '></div>' , CKEDITOR
. document
);
872 CKEDITOR
. document
. getBody (). append ( calculator
);
875 if ( !( /%$/ ). test ( cssLength
) ) {
876 calculator
. setStyle ( 'width' , cssLength
);
877 return calculator
.$. clientWidth
;
885 * String specified by `str` repeats `times` times.
887 * @param {String} str
888 * @param {Number} times
891 repeat : function ( str
, times
) {
892 return new Array ( times
+ 1 ). join ( str
);
896 * Returns the first successfully executed return value of a function that
897 * does not throw any exception.
899 * @param {Function...} fn
902 tryThese : function () {
904 for ( var i
= 0 , length
= arguments
. length
; i
< length
; i
++ ) {
905 var lambda
= arguments
[ i
];
907 returnValue
= lambda ();
915 * Generates a combined key from a series of params.
917 * var key = CKEDITOR.tools.genKey( 'key1', 'key2', 'key3' );
918 * alert( key ); // 'key1-key2-key3'.
920 * @param {String} subKey One or more strings used as subkeys.
924 return Array
. prototype . slice
. call ( arguments
). join ( '-' );
928 * Creates a "deferred" function which will not run immediately,
929 * but rather runs as soon as the interpreter’s call stack is empty.
930 * Behaves much like `window.setTimeout` with a delay.
932 * **Note:** The return value of the original function will be lost.
934 * @param {Function} fn The callee function.
935 * @returns {Function} The new deferred function.
937 defer : function ( fn
) {
939 var args
= arguments
,
941 window
. setTimeout ( function () {
942 fn
. apply ( self
, args
);
948 * Normalizes CSS data in order to avoid differences in the style attribute.
950 * @param {String} styleText The style data to be normalized.
951 * @param {Boolean} [nativeNormalize=false] Parse the data using the browser.
952 * @returns {String} The normalized value.
954 normalizeCssText : function ( styleText
, nativeNormalize
) {
957 parsedProps
= CKEDITOR
. tools
. parseCssText ( styleText
, true , nativeNormalize
);
959 for ( name
in parsedProps
)
960 props
. push ( name
+ ':' + parsedProps
[ name
] );
964 return props
. length
? ( props
. join ( ';' ) + ';' ) : '' ;
968 * Finds and converts `rgb(x,x,x)` color definition to hexadecimal notation.
970 * @param {String} styleText The style data (or just a string containing RGB colors) to be converted.
971 * @returns {String} The style data with RGB colors converted to hexadecimal equivalents.
973 convertRgbToHex : function ( styleText
) {
974 return styleText
. replace ( /(?:rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\))/gi , function ( match
, red
, green
, blue
) {
975 var color
= [ red
, green
, blue
];
976 // Add padding zeros if the hex value is less than 0x10.
977 for ( var i
= 0 ; i
< 3 ; i
++ )
978 color
[ i
] = ( '0' + parseInt ( color
[ i
], 10 ). toString ( 16 ) ). slice ( - 2 );
979 return '#' + color
. join ( '' );
984 * Normalizes hexadecimal notation so that the color string is always 6 characters long and lowercase.
986 * @param {String} styleText The style data (or just a string containing hex colors) to be converted.
987 * @returns {String} The style data with hex colors normalized.
989 normalizeHex : function ( styleText
) {
990 return styleText
. replace ( /#(([0-9a-f]{3}){1,2})($|;|\s+)/gi , function ( match
, hexColor
, hexColorPart
, separator
) {
991 var normalizedHexColor
= hexColor
. toLowerCase ();
992 if ( normalizedHexColor
. length
== 3 ) {
993 var parts
= normalizedHexColor
. split ( '' );
994 normalizedHexColor
= [ parts
[ 0 ], parts
[ 0 ], parts
[ 1 ], parts
[ 1 ], parts
[ 2 ], parts
[ 2 ] ]. join ( '' );
996 return '#' + normalizedHexColor
+ separator
;
1001 * Turns inline style text properties into one hash.
1003 * @param {String} styleText The style data to be parsed.
1004 * @param {Boolean} [normalize=false] Normalize properties and values
1005 * (e.g. trim spaces, convert to lower case).
1006 * @param {Boolean} [nativeNormalize=false] Parse the data using the browser.
1007 * @returns {Object} The object containing parsed properties.
1009 parseCssText : function ( styleText
, normalize
, nativeNormalize
) {
1012 if ( nativeNormalize
) {
1013 // Injects the style in a temporary span object, so the browser parses it,
1014 // retrieving its final format.
1015 var temp
= new CKEDITOR
. dom
. element ( 'span' );
1016 styleText
= temp
. setAttribute ( 'style' , styleText
). getAttribute ( 'style' ) || '' ;
1019 // Normalize colors.
1021 styleText
= CKEDITOR
. tools
. normalizeHex ( CKEDITOR
. tools
. convertRgbToHex ( styleText
) );
1024 // IE will leave a single semicolon when failed to parse the style text. (http://dev.ckeditor.com/ticket/3891)
1025 if ( ! styleText
|| styleText
== ';' )
1028 styleText
. replace ( /"/g , '"' ). replace ( /\s*([^:;\s]+)\s*:\s*([^;]+)\s*(?=;|$)/g , function ( match
, name
, value
) {
1030 name
= name
. toLowerCase ();
1031 // Drop extra whitespacing from font-family.
1032 if ( name
== 'font-family' )
1033 value
= value
. replace ( /\s*,\s*/g , ',' );
1034 value
= CKEDITOR
. tools
. trim ( value
);
1037 retval
[ name
] = value
;
1043 * Serializes the `style name => value` hash to a style text.
1045 * var styleObj = CKEDITOR.tools.parseCssText( 'color: red; border: none' );
1046 * console.log( styleObj.color ); // -> 'red'
1047 * CKEDITOR.tools.writeCssText( styleObj ); // -> 'color:red; border:none'
1048 * CKEDITOR.tools.writeCssText( styleObj, true ); // -> 'border:none; color:red'
1051 * @param {Object} styles The object contaning style properties.
1052 * @param {Boolean} [sort] Whether to sort CSS properties.
1053 * @returns {String} The serialized style text.
1055 writeCssText : function ( styles
, sort
) {
1059 for ( name
in styles
)
1060 stylesArr
. push ( name
+ ':' + styles
[ name
] );
1065 return stylesArr
. join ( '; ' );
1069 * Compares two objects.
1071 * **Note:** This method performs shallow, non-strict comparison.
1074 * @param {Object} left
1075 * @param {Object} right
1076 * @param {Boolean} [onlyLeft] Check only the properties that are present in the `left` object.
1077 * @returns {Boolean} Whether objects are identical.
1079 objectCompare : function ( left
, right
, onlyLeft
) {
1082 if ( ! left
&& ! right
)
1084 if ( ! left
|| ! right
)
1087 for ( name
in left
) {
1088 if ( left
[ name
] != right
[ name
] )
1094 for ( name
in right
) {
1095 if ( left
[ name
] != right
[ name
] )
1104 * Returns an array of passed object's keys.
1106 * console.log( CKEDITOR.tools.objectKeys( { foo: 1, bar: false } );
1107 * // -> [ 'foo', 'bar' ]
1110 * @param {Object} obj
1111 * @returns {Array} Object's keys.
1113 objectKeys : function ( obj
) {
1115 for ( var i
in obj
)
1122 * Converts an array to an object by rewriting array items
1123 * to object properties.
1125 * var arr = [ 'foo', 'bar', 'foo' ];
1126 * console.log( CKEDITOR.tools.convertArrayToObject( arr ) );
1127 * // -> { foo: true, bar: true }
1128 * console.log( CKEDITOR.tools.convertArrayToObject( arr, 1 ) );
1129 * // -> { foo: 1, bar: 1 }
1132 * @param {Array} arr The array to be converted to an object.
1133 * @param [fillWith=true] Set each property of an object to `fillWith` value.
1135 convertArrayToObject : function ( arr
, fillWith
) {
1138 if ( arguments
. length
== 1 )
1141 for ( var i
= 0 , l
= arr
. length
; i
< l
; ++ i
)
1142 obj
[ arr
[ i
] ] = fillWith
;
1148 * Tries to fix the `document.domain` of the current document to match the
1149 * parent window domain, avoiding "Same Origin" policy issues.
1150 * This is an Internet Explorer only requirement.
1153 * @returns {Boolean} `true` if the current domain is already good or if
1154 * it has been fixed successfully.
1156 fixDomain : function () {
1161 // Try to access the parent document. It throws
1162 // "access denied" if restricted by the "Same Origin" policy.
1163 domain
= window
. parent
. document
. domain
;
1166 // Calculate the value to set to document.domain.
1169 // If it is not the first pass, strip one part of the
1170 // name. E.g. "test.example.com" => "example.com"
1171 domain
. replace ( /.+?(?:\.|$)/ , '' ) :
1173 // In the first pass, we'll handle the
1174 // "document.domain = document.domain" case.
1177 // Stop here if there is no more domain parts available.
1181 document
. domain
= domain
;
1189 * Buffers `input` events (or any `input` calls)
1190 * and triggers `output` not more often than once per `minInterval`.
1192 * var buffer = CKEDITOR.tools.eventsBuffer( 200, function() {
1193 * console.log( 'foo!' );
1197 * // 'foo!' logged immediately.
1199 * // Nothing logged.
1201 * // Nothing logged.
1202 * // ... after 200ms a single 'foo!' will be logged.
1204 * Can be easily used with events:
1206 * var buffer = CKEDITOR.tools.eventsBuffer( 200, function() {
1207 * console.log( 'foo!' );
1210 * editor.on( 'key', buffer.input );
1211 * // Note: There is no need to bind buffer as a context.
1214 * @param {Number} minInterval Minimum interval between `output` calls in milliseconds.
1215 * @param {Function} output Function that will be executed as `output`.
1216 * @param {Object} [scopeObj] The object used to scope the listener call (the `this` object).
1218 * @returns {Function} return.input Buffer's input method.
1219 * @returns {Function} return.reset Resets buffered events — `output` will not be executed
1220 * until next `input` is triggered.
1222 eventsBuffer : function ( minInterval
, output
, scopeObj
) {
1226 function triggerOutput () {
1227 lastOutput
= ( new Date () ). getTime ();
1230 output
. call ( scopeObj
);
1241 var diff
= ( new Date () ). getTime () - lastOutput
;
1243 // If less than minInterval passed after last check,
1244 // schedule next for minInterval after previous one.
1245 if ( diff
< minInterval
)
1246 scheduled
= setTimeout ( triggerOutput
, minInterval
- diff
);
1253 clearTimeout ( scheduled
);
1255 scheduled
= lastOutput
= 0 ;
1261 * Enables HTML5 elements for older browsers (IE8) in the passed document.
1263 * In IE8 this method can also be executed on a document fragment.
1265 * **Note:** This method has to be used in the `<head>` section of the document.
1268 * @param {Object} doc Native `Document` or `DocumentFragment` in which the elements will be enabled.
1269 * @param {Boolean} [withAppend] Whether to append created elements to the `doc`.
1271 enableHtml5Elements : function ( doc
, withAppend
) {
1272 var els
= 'abbr,article,aside,audio,bdi,canvas,data,datalist,details,figcaption,figure,footer,header,hgroup,main,mark,meter,nav,output,progress,section,summary,time,video' . split ( ',' ),
1277 el
= doc
. createElement ( els
[ i
] );
1279 doc
. appendChild ( el
);
1284 * Checks if any of the `arr` items match the provided regular expression.
1286 * @param {Array} arr The array whose items will be checked.
1287 * @param {RegExp} regexp The regular expression.
1288 * @returns {Boolean} Returns `true` for the first occurrence of the search pattern.
1291 checkIfAnyArrayItemMatches : function ( arr
, regexp
) {
1292 for ( var i
= 0 , l
= arr
. length
; i
< l
; ++ i
) {
1293 if ( arr
[ i
]. match ( regexp
) )
1300 * Checks if any of the `obj` properties match the provided regular expression.
1302 * @param obj The object whose properties will be checked.
1303 * @param {RegExp} regexp The regular expression.
1304 * @returns {Boolean} Returns `true` for the first occurrence of the search pattern.
1307 checkIfAnyObjectPropertyMatches : function ( obj
, regexp
) {
1308 for ( var i
in obj
) {
1309 if ( i
. match ( regexp
) )
1316 * Converts a keystroke to its string representation. Returns an object with two fields:
1318 * * `display` – A string that should be used for visible labels.
1319 * For Mac devices it uses `⌥` for `ALT`, `⇧` for `SHIFT` and `⌘` for `COMMAND`.
1320 * * `aria` – A string that should be used for ARIA descriptions.
1321 * It does not use special characters such as `⌥`, `⇧` or `⌘`.
1323 * var lang = editor.lang.common.keyboard;
1324 * var shortcut = CKEDITOR.tools.keystrokeToString( lang, CKEDITOR.CTRL + 88 );
1325 * console.log( shortcut.display ); // 'CTRL + X', on Mac '⌘ + X'.
1326 * console.log( shortcut.aria ); // 'CTRL + X', on Mac 'COMMAND + X'.
1329 * @param {Object} lang A language object with the key name translation.
1330 * @param {Number} keystroke The keystroke to convert.
1331 * @returns {{display: String, aria: String}}
1333 keystrokeToString : function ( lang
, keystroke
) {
1334 var special
= keystroke
& 0xFF0000 ,
1335 key
= keystroke
& 0x00FFFF ,
1336 isMac
= CKEDITOR
. env
. mac
,
1345 if ( special
& CKEDITOR
. CTRL
) {
1346 display
. push ( isMac
? '⌘' : lang
[ CTRL
] );
1347 aria
. push ( isMac
? lang
[ CMD
] : lang
[ CTRL
] );
1350 if ( special
& CKEDITOR
. ALT
) {
1351 display
. push ( isMac
? '⌥' : lang
[ ALT
] );
1352 aria
. push ( lang
[ ALT
] );
1355 if ( special
& CKEDITOR
. SHIFT
) {
1356 display
. push ( isMac
? '⇧' : lang
[ SHIFT
] );
1357 aria
. push ( lang
[ SHIFT
] );
1361 if ( lang
[ key
] ) {
1362 display
. push ( lang
[ key
] );
1363 aria
. push ( lang
[ key
] );
1365 display
. push ( String
. fromCharCode ( key
) );
1366 aria
. push ( String
. fromCharCode ( key
) );
1371 display : display
. join ( '+' ),
1372 aria : aria
. join ( '+' )
1377 * The data URI of a transparent image. May be used e.g. in HTML as an image source or in CSS in `url()`.
1382 transparentImageData : 'data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==' ,
1386 * Returns the value of the cookie with a given name or `null` if the cookie is not found.
1389 * @param {String} name
1392 getCookie : function ( name
) {
1393 name
= name
. toLowerCase ();
1394 var parts
= document
. cookie
. split ( ';' );
1397 for ( var i
= 0 ; i
< parts
. length
; i
++ ) {
1398 pair
= parts
[ i
]. split ( '=' );
1399 key
= decodeURIComponent ( CKEDITOR
. tools
. trim ( pair
[ 0 ] ). toLowerCase () );
1401 if ( key
=== name
) {
1402 return decodeURIComponent ( pair
. length
> 1 ? pair
[ 1 ] : '' );
1410 * Sets the value of the cookie with a given name.
1413 * @param {String} name
1414 * @param {String} value
1416 setCookie : function ( name
, value
) {
1417 document
. cookie
= encodeURIComponent ( name
) + '=' + encodeURIComponent ( value
) + ';path=/' ;
1421 * Returns the CSRF token value. The value is a hash stored in `document.cookie`
1422 * under the `ckCsrfToken` key. The CSRF token can be used to secure the communication
1423 * between the web browser and the server, i.e. for the file upload feature in the editor.
1428 getCsrfToken : function () {
1429 var token
= CKEDITOR
. tools
. getCookie ( TOKEN_COOKIE_NAME
);
1431 if ( ! token
|| token
. length
!= TOKEN_LENGTH
) {
1432 token
= generateToken ( TOKEN_LENGTH
);
1433 CKEDITOR
. tools
. setCookie ( TOKEN_COOKIE_NAME
, token
);
1440 * Returns an escaped CSS selector. `CSS.escape()` is used if defined, leading digit is escaped otherwise.
1443 * @param {String} selector A CSS selector to escape.
1444 * @returns {String} An escaped selector.
1446 escapeCss : function ( selector
) {
1452 // CSS.escape() can be used.
1453 if ( window
. CSS
&& CSS
. escape
) {
1454 return CSS
. escape ( selector
);
1457 // Simple leading digit escape.
1458 if ( ! isNaN ( parseInt ( selector
. charAt ( 0 ), 10 ) ) ) {
1459 return ' \\ 3' + selector
. charAt ( 0 ) + ' ' + selector
. substring ( 1 , selector
. length
);
1466 * Detects which mouse button generated a given DOM event.
1469 * @param {CKEDITOR.dom.event} evt DOM event.
1470 * @returns {Number|Boolean} Returns a number indicating the mouse button or `false`
1471 * if the mouse button cannot be determined.
1473 getMouseButton : function ( evt
) {
1474 var evtData
= evt
. data
,
1475 domEvent
= evtData
&& evtData
.$;
1477 if ( !( evtData
&& domEvent
) ) {
1478 // Added in case when there's no data available. That's the case in some unit test in built version which
1479 // mock event but doesn't put data object.
1483 if ( CKEDITOR
. env
. ie
&& CKEDITOR
. env
. version
< 9 ) {
1484 if ( domEvent
. button
=== 4 ) {
1485 return CKEDITOR
. MOUSE_BUTTON_MIDDLE
;
1486 } else if ( domEvent
. button
=== 1 ) {
1487 return CKEDITOR
. MOUSE_BUTTON_LEFT
;
1489 return CKEDITOR
. MOUSE_BUTTON_RIGHT
;
1493 return domEvent
. button
;
1497 * A set of functions for operations on styles.
1499 * @property {CKEDITOR.tools.style}
1503 * Methods to parse miscellaneous CSS properties.
1505 * @property {CKEDITOR.tools.style.parse}
1506 * @member CKEDITOR.tools.style
1509 // Color list based on https://www.w3.org/TR/css-color-4/#named-colors.
1511 aliceblue : '#F0F8FF' ,
1512 antiquewhite : '#FAEBD7' ,
1514 aquamarine : '#7FFFD4' ,
1519 blanchedalmond : '#FFEBCD' ,
1521 blueviolet : '#8A2BE2' ,
1523 burlywood : '#DEB887' ,
1524 cadetblue : '#5F9EA0' ,
1525 chartreuse : '#7FFF00' ,
1526 chocolate : '#D2691E' ,
1528 cornflowerblue : '#6495ED' ,
1529 cornsilk : '#FFF8DC' ,
1532 darkblue : '#00008B' ,
1533 darkcyan : '#008B8B' ,
1534 darkgoldenrod : '#B8860B' ,
1535 darkgray : '#A9A9A9' ,
1536 darkgreen : '#006400' ,
1537 darkgrey : '#A9A9A9' ,
1538 darkkhaki : '#BDB76B' ,
1539 darkmagenta : '#8B008B' ,
1540 darkolivegreen : '#556B2F' ,
1541 darkorange : '#FF8C00' ,
1542 darkorchid : '#9932CC' ,
1544 darksalmon : '#E9967A' ,
1545 darkseagreen : '#8FBC8F' ,
1546 darkslateblue : '#483D8B' ,
1547 darkslategray : '#2F4F4F' ,
1548 darkslategrey : '#2F4F4F' ,
1549 darkturquoise : '#00CED1' ,
1550 darkviolet : '#9400D3' ,
1551 deeppink : '#FF1493' ,
1552 deepskyblue : '#00BFFF' ,
1555 dodgerblue : '#1E90FF' ,
1556 firebrick : '#B22222' ,
1557 floralwhite : '#FFFAF0' ,
1558 forestgreen : '#228B22' ,
1560 gainsboro : '#DCDCDC' ,
1561 ghostwhite : '#F8F8FF' ,
1563 goldenrod : '#DAA520' ,
1566 greenyellow : '#ADFF2F' ,
1568 honeydew : '#F0FFF0' ,
1570 indianred : '#CD5C5C' ,
1574 lavender : '#E6E6FA' ,
1575 lavenderblush : '#FFF0F5' ,
1576 lawngreen : '#7CFC00' ,
1577 lemonchiffon : '#FFFACD' ,
1578 lightblue : '#ADD8E6' ,
1579 lightcoral : '#F08080' ,
1580 lightcyan : '#E0FFFF' ,
1581 lightgoldenrodyellow : '#FAFAD2' ,
1582 lightgray : '#D3D3D3' ,
1583 lightgreen : '#90EE90' ,
1584 lightgrey : '#D3D3D3' ,
1585 lightpink : '#FFB6C1' ,
1586 lightsalmon : '#FFA07A' ,
1587 lightseagreen : '#20B2AA' ,
1588 lightskyblue : '#87CEFA' ,
1589 lightslategray : '#778899' ,
1590 lightslategrey : '#778899' ,
1591 lightsteelblue : '#B0C4DE' ,
1592 lightyellow : '#FFFFE0' ,
1594 limegreen : '#32CD32' ,
1598 mediumaquamarine : '#66CDAA' ,
1599 mediumblue : '#0000CD' ,
1600 mediumorchid : '#BA55D3' ,
1601 mediumpurple : '#9370DB' ,
1602 mediumseagreen : '#3CB371' ,
1603 mediumslateblue : '#7B68EE' ,
1604 mediumspringgreen : '#00FA9A' ,
1605 mediumturquoise : '#48D1CC' ,
1606 mediumvioletred : '#C71585' ,
1607 midnightblue : '#191970' ,
1608 mintcream : '#F5FFFA' ,
1609 mistyrose : '#FFE4E1' ,
1610 moccasin : '#FFE4B5' ,
1611 navajowhite : '#FFDEAD' ,
1615 olivedrab : '#6B8E23' ,
1617 orangered : '#FF4500' ,
1619 palegoldenrod : '#EEE8AA' ,
1620 palegreen : '#98FB98' ,
1621 paleturquoise : '#AFEEEE' ,
1622 palevioletred : '#DB7093' ,
1623 papayawhip : '#FFEFD5' ,
1624 peachpuff : '#FFDAB9' ,
1628 powderblue : '#B0E0E6' ,
1630 rebeccapurple : '#663399' ,
1632 rosybrown : '#BC8F8F' ,
1633 royalblue : '#4169E1' ,
1634 saddlebrown : '#8B4513' ,
1636 sandybrown : '#F4A460' ,
1637 seagreen : '#2E8B57' ,
1638 seashell : '#FFF5EE' ,
1642 slateblue : '#6A5ACD' ,
1643 slategray : '#708090' ,
1644 slategrey : '#708090' ,
1646 springgreen : '#00FF7F' ,
1647 steelblue : '#4682B4' ,
1652 turquoise : '#40E0D0' ,
1656 whitesmoke : '#F5F5F5' ,
1658 yellowgreen : '#9ACD32'
1674 _widthRegExp : /^(thin|medium|thick|[\+-]?\d+(\.\d+)?[a-z%]+|[\+-]?0+(\.0+)?|\.\d+[a-z%]+)$/ ,
1676 _rgbaRegExp : /rgba?\(\s*\d+%?\s*,\s*\d+%?\s*,\s*\d+%?\s*(?:,\s*[0-9.]+\s*)?\)/gi ,
1678 _hslaRegExp : /hsla?\(\s*[0-9.]+\s*,\s*\d+%\s*,\s*\d+%\s*(?:,\s*[0-9.]+\s*)?\)/gi ,
1681 * Parses the `value` used as a `background` property shorthand and returns information as an object.
1683 * **Note:** Currently only the `color` property is extracted. Any other parts will go into the `unprocessed` property.
1685 * var background = CKEDITOR.tools.style.parse.background( '#0C0 url(foo.png)' );
1686 * console.log( background );
1687 * // Logs: { color: '#0C0', unprocessed: 'url(foo.png)' }
1689 * @param {String} value The value of the `background` property.
1690 * @returns {Object} An object with information extracted from the background.
1691 * @returns {String} return.color The **first** color value found. The color format remains the same as in input.
1692 * @returns {String} return.unprocessed The remaining part of the `value` that has not been processed.
1693 * @member CKEDITOR.tools.style.parse
1695 background : function ( value
) {
1697 colors
= this . _findColor ( value
);
1699 if ( colors
. length
) {
1700 ret
. color
= colors
[ 0 ];
1702 CKEDITOR
. tools
. array
. forEach ( colors
, function ( colorToken
) {
1703 value
= value
. replace ( colorToken
, '' );
1707 value
= CKEDITOR
. tools
. trim ( value
);
1710 // If anything was left unprocessed include it as unprocessed part.
1711 ret
. unprocessed
= value
;
1718 * Parses the `margin` CSS property shorthand format.
1720 * console.log( CKEDITOR.tools.parse.margin( '3px 0 2' ) );
1721 * // Logs: { top: "3px", right: "0", bottom: "2", left: "0" }
1723 * @param {String} value The `margin` property value.
1725 * @returns {Number} return.top Top margin.
1726 * @returns {Number} return.right Right margin.
1727 * @returns {Number} return.bottom Bottom margin.
1728 * @returns {Number} return.left Left margin.
1729 * @member CKEDITOR.tools.style.parse
1731 margin : function ( value
) {
1734 var widths
= value
. match ( /(?:\-?[\.\d]+(?:%|\w*)|auto|inherit|initial|unset)/g ) || [ '0px' ];
1736 switch ( widths
. length
) {
1738 mapStyles ( [ 0 , 0 , 0 , 0 ] );
1741 mapStyles ( [ 0 , 1 , 0 , 1 ] );
1744 mapStyles ( [ 0 , 1 , 2 , 1 ] );
1747 mapStyles ( [ 0 , 1 , 2 , 3 ] );
1751 function mapStyles ( map
) {
1752 ret
. top
= widths
[ map
[ 0 ] ];
1753 ret
. right
= widths
[ map
[ 1 ] ];
1754 ret
. bottom
= widths
[ map
[ 2 ] ];
1755 ret
. left
= widths
[ map
[ 3 ] ];
1762 * Parses the `border` CSS property shorthand format.
1763 * This CSS property does not support inheritance (https://www.w3.org/TR/css3-background/#the-border-shorthands).
1765 * console.log( CKEDITOR.tools.style.parse.border( '3px solid #ffeedd' ) );
1766 * // Logs: { width: "3px", style: "solid", color: "#ffeedd" }
1768 * @param {String} value The `border` property value.
1770 * @returns {String} return.width The border-width attribute.
1771 * @returns {String} return.style The border-style attribute.
1772 * @returns {String} return.color The border-color attribute.
1773 * @member CKEDITOR.tools.style.parse
1775 border : function ( value
) {
1777 input
= value
. split ( /\s+/ );
1779 CKEDITOR
. tools
. array
. forEach ( input
, function ( val
) {
1781 var parseColor
= CKEDITOR
. tools
. style
. parse
. _findColor ( val
);
1782 if ( parseColor
. length
) {
1783 ret
. color
= parseColor
[ 0 ];
1789 if ( CKEDITOR
. tools
. indexOf ( CKEDITOR
. tools
. style
. parse
. _borderStyle
, val
) !== - 1 ) {
1796 if ( CKEDITOR
. tools
. style
. parse
. _widthRegExp
. test ( val
) ) {
1807 * Searches the `value` for any CSS color occurrences and returns it.
1810 * @param {String} value
1811 * @returns {String[]} An array of matched results.
1812 * @member CKEDITOR.tools.style.parse
1814 _findColor : function ( value
) {
1816 arrayTools
= CKEDITOR
. tools
. array
;
1819 // Check for rgb(a).
1820 ret
= ret
. concat ( value
. match ( this . _rgbaRegExp
) || [] );
1822 // Check for hsl(a).
1823 ret
= ret
. concat ( value
. match ( this . _hslaRegExp
) || [] );
1825 ret
= ret
. concat ( arrayTools
. filter ( value
. split ( /\s+/ ), function ( colorEntry
) {
1826 // Check for hex format.
1827 if ( colorEntry
. match ( /^\#[a-f0-9]{3}(?:[a-f0-9]{3})?$/gi ) ) {
1831 // Check for preset names.
1832 return colorEntry
. toLowerCase () in CKEDITOR
. tools
. style
. parse
. _colors
;
1841 * A set of array helpers.
1843 * @property {CKEDITOR.tools.array}
1844 * @member CKEDITOR.tools
1848 * Returns a copy of `array` filtered using the `fn` function. Any elements that the `fn` will return `false` for
1849 * will get removed from the returned array.
1851 * var filtered = this.array.filter( [ 0, 1, 2, 3 ], function( value ) {
1852 * // Leave only values equal or greater than 2.
1853 * return value >= 2;
1855 * console.log( filtered );
1858 * @param {Array} array
1859 * @param {Function} fn A function that gets called with each `array` item. Any item that `fn`
1860 * returned a `false`-alike value for will be filtered out of the `array`.
1861 * @param {Mixed} fn.value The currently iterated array value.
1862 * @param {Number} fn.index The index of the currently iterated value in an array.
1863 * @param {Array} fn.array The original array passed as the `array` variable.
1864 * @param {Mixed} [thisArg=undefined] A context object for `fn`.
1865 * @returns {Array} The filtered array.
1866 * @member CKEDITOR.tools.array
1868 filter : function ( array
, fn
, thisArg
) {
1871 this . forEach ( array
, function ( val
, i
) {
1872 if ( fn
. call ( thisArg
, val
, i
, array
) ) {
1881 * Iterates over every element in the `array`.
1883 * @param {Array} array An array to be iterated over.
1884 * @param {Function} fn The function called for every `array` element.
1885 * @param {Mixed} fn.value The currently iterated array value.
1886 * @param {Number} fn.index The index of the currently iterated value in an array.
1887 * @param {Array} fn.array The original array passed as an `array` variable.
1888 * @param {Mixed} [thisArg=undefined] The context object for `fn`.
1889 * @member CKEDITOR.tools.array
1891 forEach : function ( array
, fn
, thisArg
) {
1892 var len
= array
. length
,
1895 for ( i
= 0 ; i
< len
; i
++ ) {
1896 fn
. call ( thisArg
, array
[ i
], i
, array
);
1901 * Applies a function to each element of an array and returns the array of results in the same order.
1902 * Note the order of the parameters.
1904 * @param {Array} array An array of elements that `fn` is applied on.
1905 * @param {Function} fn A function with the signature `a -> b`.
1906 * @param {Mixed} [thisArg=undefined] The context object for `fn`.
1907 * @returns {Array} An array of mapped elements.
1908 * @member CKEDITOR.tools.array
1911 map : function ( array
, fn
, thisArg
) {
1913 for ( var i
= 0 ; i
< array
. length
; i
++ ) {
1914 result
. push ( fn
. call ( thisArg
, array
[ i
], i
, array
) );
1920 * Applies a function against each value in an array storing the result in an accumulator passed to the next iteration.
1921 * Note the order of the parameters.
1923 * @param {Array} array An array of elements that `fn` is applied on.
1924 * @param {Function} fn A function with the signature `(accumulator, a, index, array) -> b`.
1925 * @param {Mixed} initial Initial value of the accumulator.
1926 * @param {Mixed} [thisArg=undefined] The context object for `fn`.
1927 * @returns {Mixed} The final value of the accumulator.
1928 * @member CKEDITOR.tools.array
1931 reduce : function ( array
, fn
, initial
, thisArg
) {
1933 for ( var i
= 0 ; i
< array
. length
; i
++ ) {
1934 acc
= fn
. call ( thisArg
, acc
, array
[ i
], i
, array
);
1941 * A set of object helpers.
1943 * @property {CKEDITOR.tools.object}
1944 * @member CKEDITOR.tools
1948 * Returns the first key from `obj` which has a given `value`.
1950 * @param {Object} obj An object whose `key` is looked for.
1951 * @param {Mixed} value An object's `value` to be looked for.
1952 * @returns {String/null} Matched `key` or `null` if not found.
1953 * @member CKEDITOR.tools.object
1956 findKey : function ( obj
, value
) {
1957 if ( typeof obj
!== 'object' ) {
1963 for ( key
in obj
) {
1964 if ( obj
[ key
] === value
) {
1974 // Generates a CSRF token with a given length.
1977 // @param {Number} length
1978 // @returns {string}
1979 function generateToken ( length
) {
1980 var randValues
= [];
1983 if ( window
. crypto
&& window
. crypto
. getRandomValues
) {
1984 randValues
= new Uint8Array ( length
);
1985 window
. crypto
. getRandomValues ( randValues
);
1987 for ( var i
= 0 ; i
< length
; i
++ ) {
1988 randValues
. push ( Math
. floor ( Math
. random () * 256 ) );
1992 for ( var j
= 0 ; j
< randValues
. length
; j
++ ) {
1993 var character
= tokenCharset
. charAt ( randValues
[ j
] % tokenCharset
. length
);
1994 result
+= Math
. random () > 0.5 ? character
. toUpperCase () : character
;
2001 * @member CKEDITOR.tools.array
2003 * @inheritdoc CKEDITOR.tools#indexOf
2005 CKEDITOR
. tools
. array
. indexOf
= CKEDITOR
. tools
. indexOf
;
2008 * @member CKEDITOR.tools.array
2010 * @inheritdoc CKEDITOR.tools#isArray
2012 CKEDITOR
. tools
. array
. isArray
= CKEDITOR
. tools
. isArray
;
2015 * Left mouse button.
2019 * @property {Number} [=0]
2022 CKEDITOR
. MOUSE_BUTTON_LEFT
= 0 ;
2025 * Middle mouse button.
2029 * @property {Number} [=1]
2032 CKEDITOR
. MOUSE_BUTTON_MIDDLE
= 1 ;
2035 * Right mouse button.
2039 * @property {Number} [=2]
2042 CKEDITOR
. MOUSE_BUTTON_RIGHT
= 2 ;
2045 * The namespace containing functions to work on CSS properties.
2048 * @class CKEDITOR.tools.style
2052 * The namespace with helper functions to parse some common CSS properties.
2055 * @class CKEDITOR.tools.style.parse
2059 * The namespace with helper functions and polyfills for arrays.
2062 * @class CKEDITOR.tools.array
2066 * The namespace with helper functions and polyfills for objects.
2069 * @class CKEDITOR.tools.object
2073 // PACKAGER_RENAME( CKEDITOR.tools )