source: trunk/phpgwapi/js/ckeditor/_source/core/tools.js @ 2862

Revision 2862, 20.0 KB checked in by rodsouza, 14 years ago (diff)

Ticket #663 - Atualizando e centralizando o CKEditor (v. 3.2.1)

Line 
1/*
2Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.html or http://ckeditor.com/license
4*/
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.tools} object, which contains
8 *              utility functions.
9 */
10
11(function()
12{
13        var functions = [];
14
15        /**
16         * Utility functions.
17         * @namespace
18         * @example
19         */
20        CKEDITOR.tools =
21        {
22                /**
23                 * Compare the elements of two arrays.
24                 * @param {Array} arrayA An array to be compared.
25                 * @param {Array} arrayB The other array to be compared.
26                 * @returns {Boolean} "true" is the arrays have the same lenght and
27                 *              their elements match.
28                 * @example
29                 * var a = [ 1, 'a', 3 ];
30                 * var b = [ 1, 3, 'a' ];
31                 * var c = [ 1, 'a', 3 ];
32                 * var d = [ 1, 'a', 3, 4 ];
33                 *
34                 * alert( CKEDITOR.tools.arrayCompare( a, b ) );  // false
35                 * alert( CKEDITOR.tools.arrayCompare( a, c ) );  // true
36                 * alert( CKEDITOR.tools.arrayCompare( a, d ) );  // false
37                 */
38                arrayCompare : function( arrayA, arrayB )
39                {
40                        if ( !arrayA && !arrayB )
41                                return true;
42
43                        if ( !arrayA || !arrayB || arrayA.length != arrayB.length )
44                                return false;
45
46                        for ( var i = 0 ; i < arrayA.length ; i++ )
47                        {
48                                if ( arrayA[ i ] != arrayB[ i ] )
49                                        return false;
50                        }
51
52                        return true;
53                },
54
55                /**
56                 * Creates a deep copy of an object.
57                 * Attention: there is no support for recursive references.
58                 * @param {Object} object The object to be cloned.
59                 * @returns {Object} The object clone.
60                 * @example
61                 * var obj =
62                 *     {
63                 *         name : 'John',
64                 *         cars :
65                 *             {
66                 *                 Mercedes : { color : 'blue' },
67                 *                 Porsche : { color : 'red' }
68                 *             }
69                 *     };
70                 * var clone = CKEDITOR.tools.clone( obj );
71                 * clone.name = 'Paul';
72                 * clone.cars.Porsche.color = 'silver';
73                 * alert( obj.name );   // John
74                 * alert( clone.name ); // Paul
75                 * alert( obj.cars.Porsche.color );     // red
76                 * alert( clone.cars.Porsche.color );   // silver
77                 */
78                clone : function( obj )
79                {
80                        var clone;
81
82                        // Array.
83                        if ( obj && ( obj instanceof Array ) )
84                        {
85                                clone = [];
86
87                                for ( var i = 0 ; i < obj.length ; i++ )
88                                        clone[ i ] = this.clone( obj[ i ] );
89
90                                return clone;
91                        }
92
93                        // "Static" types.
94                        if ( obj === null
95                                || ( typeof( obj ) != 'object' )
96                                || ( obj instanceof String )
97                                || ( obj instanceof Number )
98                                || ( obj instanceof Boolean )
99                                || ( obj instanceof Date )
100                                || ( obj instanceof RegExp) )
101                        {
102                                return obj;
103                        }
104
105                        // Objects.
106                        clone = new obj.constructor();
107
108                        for ( var propertyName in obj )
109                                if ( ! ( propertyName in Object.prototype ) )
110                                {
111                                        var property = obj[ propertyName ];
112                                        clone[ propertyName ] = this.clone( property );
113                                }
114
115                        return clone;
116                },
117
118                /**
119                 * Turn the first letter of string to upper-case.
120                 * @param {String} str
121                 */
122                capitalize: function( str )
123                {
124                        return str.charAt( 0 ).toUpperCase() + str.substring( 1 ).toLowerCase();
125                },
126
127                /**
128                 * Copy the properties from one object to another. By default, properties
129                 * already present in the target object <strong>are not</strong> overwritten.
130                 * @param {Object} target The object to be extended.
131                 * @param {Object} source[,souce(n)] The objects from which copy
132                 *              properties. Any number of objects can be passed to this function.
133                 * @param {Boolean} [overwrite] If 'true' is specified it indicates that
134                 *            properties already present in the target object could be
135                 *            overwritten by subsequent objects.
136                 * @param {Object} [properties] Only properties within the specified names
137                 *            list will be received from the source object.
138                 * @returns {Object} the extended object (target).
139                 * @example
140                 * // Create the sample object.
141                 * var myObject =
142                 * {
143                 *     prop1 : true
144                 * };
145                 *
146                 * // Extend the above object with two properties.
147                 * CKEDITOR.tools.extend( myObject,
148                 *     {
149                 *         prop2 : true,
150                 *         prop3 : true
151                 *     } );
152                 *
153                 * // Alert "prop1", "prop2" and "prop3".
154                 * for ( var p in myObject )
155                 *     alert( p );
156                 */
157                extend : function( target )
158                {
159                        var argsLength = arguments.length,
160                                overwrite, propertiesList;
161
162                        if ( typeof ( overwrite = arguments[ argsLength - 1 ] ) == 'boolean')
163                                argsLength--;
164                        else if ( typeof ( overwrite = arguments[ argsLength - 2 ] ) == 'boolean' )
165                        {
166                                propertiesList = arguments [ argsLength -1 ];
167                                argsLength-=2;
168                        }
169                        for ( var i = 1 ; i < argsLength ; i++ )
170                        {
171                                var source = arguments[ i ];
172                                for ( var propertyName in source )
173                                        if ( ! ( propertyName in Object.prototype ) )
174                                        {
175                                                // Only copy existed fields if in overwrite mode.
176                                                if ( overwrite === true || target[ propertyName ] == undefined )
177                                                {
178                                                        // Only copy  specified fields if list is provided.
179                                                        if ( !propertiesList || ( propertyName in propertiesList ) )
180                                                                target[ propertyName ] = source[ propertyName ];
181
182                                                }
183                                        }
184                        }
185
186                        return target;
187                },
188
189                /**
190                 * Creates an object which is an instance of a class which prototype is a
191                 * predefined object. All properties defined in the source object are
192                 * automatically inherited by the resulting object, including future
193                 * changes to it.
194                 * @param {Object} source The source object to be used as the prototype for
195                 *              the final object.
196                 * @returns {Object} The resulting copy.
197                 */
198                prototypedCopy : function( source )
199                {
200                        var copy = function()
201                        {};
202                        copy.prototype = source;
203                        return new copy();
204                },
205
206                /**
207                 * Checks if an object is an Array.
208                 * @param {Object} object The object to be checked.
209                 * @type Boolean
210                 * @returns <i>true</i> if the object is an Array, otherwise <i>false</i>.
211                 * @example
212                 * alert( CKEDITOR.tools.isArray( [] ) );      // "true"
213                 * alert( CKEDITOR.tools.isArray( 'Test' ) );  // "false"
214                 */
215                isArray : function( object )
216                {
217                        return ( !!object && object instanceof Array );
218                },
219
220                isEmpty : function ( object )
221                {
222                        for ( var i in object )
223                                if ( ! ( i in Object.prototype ) )
224                                {
225                                        if ( object.hasOwnProperty( i ) )
226                                                return false;
227                                }
228                        return true;
229                },
230                /**
231                 * Transforms a CSS property name to its relative DOM style name.
232                 * @param {String} cssName The CSS property name.
233                 * @returns {String} The transformed name.
234                 * @example
235                 * alert( CKEDITOR.tools.cssStyleToDomStyle( 'background-color' ) );  // "backgroundColor"
236                 * alert( CKEDITOR.tools.cssStyleToDomStyle( 'float' ) );             // "cssFloat"
237                 */
238                cssStyleToDomStyle : ( function()
239                {
240                        var test = document.createElement( 'div' ).style;
241
242                        var cssFloat = ( typeof test.cssFloat != 'undefined' ) ? 'cssFloat'
243                                : ( typeof test.styleFloat != 'undefined' ) ? 'styleFloat'
244                                : 'float';
245
246                        return function( cssName )
247                        {
248                                if ( cssName == 'float' )
249                                        return cssFloat;
250                                else
251                                {
252                                        return cssName.replace( /-./g, function( match )
253                                                {
254                                                        return match.substr( 1 ).toUpperCase();
255                                                });
256                                }
257                        };
258                } )(),
259
260                /**
261                 * Build the HTML snippet of a set of <style>/<link>.
262                 * @param css {String|Array} Each of which are url (absolute) of a CSS file or
263                 * a trunk of style text.
264                 */
265                buildStyleHtml : function ( css )
266                {
267                        css = [].concat( css );
268                        var item, retval = [];
269                        for ( var i = 0; i < css.length; i++ )
270                        {
271                                item = css[ i ];
272                                // Is CSS style text ?
273                                if ( /@import|[{}]/.test(item) )
274                                        retval.push('<style>' + item + '</style>');
275                                else
276                                        retval.push('<link type="text/css" rel=stylesheet href="' + item + '">');
277                        }
278                        return retval.join( '' );
279                },
280
281                /**
282                 * Replace special HTML characters in a string with their relative HTML
283                 * entity values.
284                 * @param {String} text The string to be encoded.
285                 * @returns {String} The encode string.
286                 * @example
287                 * alert( CKEDITOR.tools.htmlEncode( 'A > B & C < D' ) );  // "A &amp;gt; B &amp;amp; C &amp;lt; D"
288                 */
289                htmlEncode : function( text )
290                {
291                        var standard = function( text )
292                        {
293                                var span = new CKEDITOR.dom.element( 'span' );
294                                span.setText( text );
295                                return span.getHtml();
296                        };
297
298                        var fix1 = ( standard( '\n' ).toLowerCase() == '<br>' ) ?
299                                function( text )
300                                {
301                                        // #3874 IE and Safari encode line-break into <br>
302                                        return standard( text ).replace( /<br>/gi, '\n' );
303                                } :
304                                standard;
305
306                        var fix2 = ( standard( '>' ) == '>' ) ?
307                                function( text )
308                                {
309                                        // WebKit does't encode the ">" character, which makes sense, but
310                                        // it's different than other browsers.
311                                        return fix1( text ).replace( />/g, '&gt;' );
312                                } :
313                                fix1;
314
315                        var fix3 = ( standard( '  ' ) == '&nbsp; ' ) ?
316                                function( text )
317                                {
318                                        // #3785 IE8 changes spaces (>= 2) to &nbsp;
319                                        return fix2( text ).replace( /&nbsp;/g, ' ' );
320                                } :
321                                fix2;
322
323                        this.htmlEncode = fix3;
324
325                        return this.htmlEncode( text );
326                },
327
328                /**
329                 * Replace special HTML characters in HTMLElement's attribute with their relative HTML entity values.
330                 * @param {String} The attribute's value to be encoded.
331                 * @returns {String} The encode value.
332                 * @example
333                 * element.setAttribute( 'title', '<a " b >' );
334                 * alert( CKEDITOR.tools.htmlEncodeAttr( element.getAttribute( 'title' ) );  // "&gt;a &quot; b &lt;"
335                 */
336                htmlEncodeAttr : function( text )
337                {
338                        return text.replace( /"/g, '&quot;' ).replace( /</g, '&lt;' ).replace( />/, '&gt;' );
339                },
340
341                /**
342                 * Replace characters can't be represented through CSS Selectors string
343                 * by CSS Escape Notation where the character escape sequence consists
344                 * of a backslash character (\) followed by the orginal characters.
345                 * Ref: http://www.w3.org/TR/css3-selectors/#grammar
346                 * @param cssSelectText
347                 * @return the escaped selector text.
348                 */
349                escapeCssSelector : function( cssSelectText )
350                {
351                        return cssSelectText.replace( /[\s#:.,$*^\[\]()~=+>]/g, '\\$&' );
352                },
353
354                /**
355                 * Gets a unique number for this CKEDITOR execution session. It returns
356                 * progressive numbers starting at 1.
357                 * @function
358                 * @returns {Number} A unique number.
359                 * @example
360                 * alert( CKEDITOR.tools.<b>getNextNumber()</b> );  // "1" (e.g.)
361                 * alert( CKEDITOR.tools.<b>getNextNumber()</b> );  // "2"
362                 */
363                getNextNumber : (function()
364                {
365                        var last = 0;
366                        return function()
367                        {
368                                return ++last;
369                        };
370                })(),
371
372                /**
373                 * Creates a function override.
374                 * @param {Function} originalFunction The function to be overridden.
375                 * @param {Function} functionBuilder A function that returns the new
376                 *              function. The original function reference will be passed to this
377                 *              function.
378                 * @returns {Function} The new function.
379                 * @example
380                 * var example =
381                 * {
382                 *     myFunction : function( name )
383                 *     {
384                 *         alert( 'Name: ' + name );
385                 *     }
386                 * };
387                 *
388                 * example.myFunction = CKEDITOR.tools.override( example.myFunction, function( myFunctionOriginal )
389                 *     {
390                 *         return function( name )
391                 *             {
392                 *                 alert( 'Override Name: ' + name );
393                 *                 myFunctionOriginal.call( this, name );
394                 *             };
395                 *     });
396                 */
397                override : function( originalFunction, functionBuilder )
398                {
399                        return functionBuilder( originalFunction );
400                },
401
402                /**
403                 * Executes a function after specified delay.
404                 * @param {Function} func The function to be executed.
405                 * @param {Number} [milliseconds] The amount of time (millisecods) to wait
406                 *              to fire the function execution. Defaults to zero.
407                 * @param {Object} [scope] The object to hold the function execution scope
408                 *              (the "this" object). By default the "window" object.
409                 * @param {Object|Array} [args] A single object, or an array of objects, to
410                 *              pass as arguments to the function.
411                 * @param {Object} [ownerWindow] The window that will be used to set the
412                 *              timeout. By default the current "window".
413                 * @returns {Object} A value that can be used to cancel the function execution.
414                 * @example
415                 * CKEDITOR.tools.<b>setTimeout(
416                 *     function()
417                 *     {
418                 *         alert( 'Executed after 2 seconds' );
419                 *     },
420                 *     2000 )</b>;
421                 */
422                setTimeout : function( func, milliseconds, scope, args, ownerWindow )
423                {
424                        if ( !ownerWindow )
425                                ownerWindow = window;
426
427                        if ( !scope )
428                                scope = ownerWindow;
429
430                        return ownerWindow.setTimeout(
431                                function()
432                                {
433                                        if ( args )
434                                                func.apply( scope, [].concat( args ) ) ;
435                                        else
436                                                func.apply( scope ) ;
437                                },
438                                milliseconds || 0 );
439                },
440
441                /**
442                 * Remove spaces from the start and the end of a string. The following
443                 * characters are removed: space, tab, line break, line feed.
444                 * @function
445                 * @param {String} str The text from which remove the spaces.
446                 * @returns {String} The modified string without the boundary spaces.
447                 * @example
448                 * alert( CKEDITOR.tools.trim( '  example ' );  // "example"
449                 */
450                trim : (function()
451                {
452                        // We are not using \s because we don't want "non-breaking spaces" to be caught.
453                        var trimRegex = /(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g;
454                        return function( str )
455                        {
456                                return str.replace( trimRegex, '' ) ;
457                        };
458                })(),
459
460                /**
461                 * Remove spaces from the start (left) of a string. The following
462                 * characters are removed: space, tab, line break, line feed.
463                 * @function
464                 * @param {String} str The text from which remove the spaces.
465                 * @returns {String} The modified string excluding the removed spaces.
466                 * @example
467                 * alert( CKEDITOR.tools.ltrim( '  example ' );  // "example "
468                 */
469                ltrim : (function()
470                {
471                        // We are not using \s because we don't want "non-breaking spaces" to be caught.
472                        var trimRegex = /^[ \t\n\r]+/g;
473                        return function( str )
474                        {
475                                return str.replace( trimRegex, '' ) ;
476                        };
477                })(),
478
479                /**
480                 * Remove spaces from the end (right) of a string. The following
481                 * characters are removed: space, tab, line break, line feed.
482                 * @function
483                 * @param {String} str The text from which remove the spaces.
484                 * @returns {String} The modified string excluding the removed spaces.
485                 * @example
486                 * alert( CKEDITOR.tools.ltrim( '  example ' );  // "  example"
487                 */
488                rtrim : (function()
489                {
490                        // We are not using \s because we don't want "non-breaking spaces" to be caught.
491                        var trimRegex = /[ \t\n\r]+$/g;
492                        return function( str )
493                        {
494                                return str.replace( trimRegex, '' ) ;
495                        };
496                })(),
497
498                /**
499                 * Returns the index of an element in an array.
500                 * @param {Array} array The array to be searched.
501                 * @param {Object} entry The element to be found.
502                 * @returns {Number} The (zero based) index of the first entry that matches
503                 *              the entry, or -1 if not found.
504                 * @example
505                 * var letters = [ 'a', 'b', 0, 'c', false ];
506                 * alert( CKEDITOR.tools.indexOf( letters, '0' ) );  "-1" because 0 !== '0'
507                 * alert( CKEDITOR.tools.indexOf( letters, false ) );  "4" because 0 !== false
508                 */
509                indexOf :
510                        // #2514: We should try to use Array.indexOf if it does exist.
511                        ( Array.prototype.indexOf ) ?
512                                function( array, entry )
513                                        {
514                                                return array.indexOf( entry );
515                                        }
516                        :
517                                function( array, entry )
518                                {
519                                        for ( var i = 0, len = array.length ; i < len ; i++ )
520                                        {
521                                                if ( array[ i ] === entry )
522                                                        return i;
523                                        }
524                                        return -1;
525                                },
526
527                /**
528                 * Creates a function that will always execute in the context of a
529                 * specified object.
530                 * @param {Function} func The function to be executed.
531                 * @param {Object} obj The object to which bind the execution context.
532                 * @returns {Function} The function that can be used to execute the
533                 *              "func" function in the context of "obj".
534                 * @example
535                 * var obj = { text : 'My Object' };
536                 *
537                 * function alertText()
538                 * {
539                 *     alert( this.text );
540                 * }
541                 *
542                 * var newFunc = <b>CKEDITOR.tools.bind( alertText, obj )</b>;
543                 * newFunc();  // Alerts "My Object".
544                 */
545                bind : function( func, obj )
546                {
547                        return function() { return func.apply( obj, arguments ); };
548                },
549
550                /**
551                 * Class creation based on prototype inheritance, with supports of the
552                 * following features:
553                 * <ul>
554                 * <li> Static fields </li>
555                 * <li> Private fields </li>
556                 * <li> Public (prototype) fields </li>
557                 * <li> Chainable base class constructor </li>
558                 * </ul>
559                 * @param {Object} definition The class definition object.
560                 * @returns {Function} A class-like JavaScript function.
561                 */
562                createClass : function( definition )
563                {
564                        var $ = definition.$,
565                                baseClass = definition.base,
566                                privates = definition.privates || definition._,
567                                proto = definition.proto,
568                                statics = definition.statics;
569
570                        if ( privates )
571                        {
572                                var originalConstructor = $;
573                                $ = function()
574                                {
575                                        // Create (and get) the private namespace.
576                                        var _ = this._ || ( this._ = {} );
577
578                                        // Make some magic so "this" will refer to the main
579                                        // instance when coding private functions.
580                                        for ( var privateName in privates )
581                                                if ( ! ( privateName in Object.prototype ) )
582                                                {
583                                                        var priv = privates[ privateName ];
584
585                                                        _[ privateName ] =
586                                                                ( typeof priv == 'function' ) ? CKEDITOR.tools.bind( priv, this ) : priv;
587                                                }
588
589                                        originalConstructor.apply( this, arguments );
590                                };
591                        }
592
593                        if ( baseClass )
594                        {
595                                $.prototype = this.prototypedCopy( baseClass.prototype );
596                                $.prototype.constructor = $;
597                                $.prototype.base = function()
598                                {
599                                        this.base = baseClass.prototype.base;
600                                        baseClass.apply( this, arguments );
601                                        this.base = arguments.callee;
602                                };
603                        }
604
605                        if ( proto )
606                                this.extend( $.prototype, proto, true );
607
608                        if ( statics )
609                                this.extend( $, statics, true );
610
611                        return $;
612                },
613
614                /**
615                 * Creates a function reference that can be called later using
616                 * CKEDITOR.tools.callFunction. This approach is specially useful to
617                 * make DOM attribute function calls to JavaScript defined functions.
618                 * @param {Function} fn The function to be executed on call.
619                 * @param {Object} [scope] The object to have the context on "fn" execution.
620                 * @returns {Number} A unique reference to be used in conjuction with
621                 *              CKEDITOR.tools.callFunction.
622                 * @example
623                 * var ref = <b>CKEDITOR.tools.addFunction</b>(
624                 *     function()
625                 *     {
626                 *         alert( 'Hello!');
627                 *     });
628                 * CKEDITOR.tools.callFunction( ref );  // Hello!
629                 */
630                addFunction : function( fn, scope )
631                {
632                        return functions.push( function()
633                                {
634                                        fn.apply( scope || this, arguments );
635                                }) - 1;
636                },
637
638                /**
639                 * Removes the function reference created with {@see CKEDITOR.tools.addFunction}.
640                 * @param {Number} ref The function reference created with
641                 *              CKEDITOR.tools.addFunction.
642                 */
643                removeFunction : function( ref )
644                {
645                        functions[ ref ] = null;
646                },
647
648                /**
649                 * Executes a function based on the reference created with
650                 * CKEDITOR.tools.addFunction.
651                 * @param {Number} ref The function reference created with
652                 *              CKEDITOR.tools.addFunction.
653                 * @param {[Any,[Any,...]} params Any number of parameters to be passed
654                 *              to the executed function.
655                 * @returns {Any} The return value of the function.
656                 * @example
657                 * var ref = CKEDITOR.tools.addFunction(
658                 *     function()
659                 *     {
660                 *         alert( 'Hello!');
661                 *     });
662                 * <b>CKEDITOR.tools.callFunction( ref )</b>;  // Hello!
663                 */
664                callFunction : function( ref )
665                {
666                        var fn = functions[ ref ];
667                        return fn && fn.apply( window, Array.prototype.slice.call( arguments, 1 ) );
668                },
669
670                cssLength : (function()
671                {
672                        var decimalRegex = /^\d+(?:\.\d+)?$/;
673                        return function( length )
674                        {
675                                return length + ( decimalRegex.test( length ) ? 'px' : '' );
676                        };
677                })(),
678
679                repeat : function( str, times )
680                {
681                        return new Array( times + 1 ).join( str );
682                },
683
684                tryThese : function()
685                {
686                        var returnValue;
687                        for ( var i = 0, length = arguments.length; i < length; i++ )
688                        {
689                                var lambda = arguments[i];
690                                try
691                                {
692                                        returnValue = lambda();
693                                        break;
694                                }
695                                catch (e) {}
696                        }
697                        return returnValue;
698                }
699        };
700})();
701
702// PACKAGER_RENAME( CKEDITOR.tools )
Note: See TracBrowser for help on using the repository browser.