Ticket #2763: 2763_7.patch

File 2763_7.patch, 16.7 KB (added by Frederico Caldeira Knabben, 11 years ago)
  • _source/core/command.js

     
    99
    1010        this.exec = function()
    1111        {
    12                 commandDefinition.exec.call( this, editor );
     12                if ( this.state == CKEDITOR.TRISTATE_DISABLED )
     13                        return false;
     14
     15                return ( commandDefinition.exec.call( this, editor ) !== false );
    1316        };
    1417
    1518        CKEDITOR.tools.extend( this, commandDefinition );
  • _source/core/commanddefinition.js

     
    2424 * @function
    2525 * @param {CKEDITOR.editor} editor The editor within which run the command.
    2626 * @param {Object} [data] Additional data to be used to execute the command.
     27 * @returns {Boolean} Whether the command has been successfully executed.
     28 *              Defaults to "true", if nothing is returned.
    2729 * @example
    2830 * editorInstance.addCommand( 'sample',
    2931 * {
     
    3335 *     }
    3436 * });
    3537 */
     38
     39/**
     40 * Whether the command need to be hooked into the redo/undo system.
     41 * @name  CKEDITOR.commandDefinition.canUndo
     42 * @type {Boolean} If not defined or 'true' both hook into undo system, set it
     43 *              to 'false' explicitly  keep it out.
     44 * @field
     45 * @example
     46 * editorInstance.addCommand( 'alertName',
     47 * {
     48 *     exec : function( editor )
     49 *     {
     50 *         alert( editor.name );
     51 *     },
     52 *     canUndo : false    // No support for undo/redo
     53 * });
     54 */
  • _source/core/config.js

     
    147147         * config.plugins = 'basicstyles,button,htmldataprocessor,toolbar,wysiwygarea';
    148148         */
    149149
    150         plugins : 'basicstyles,blockquote,button,elementspath,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,newpage,pagebreak,preview,print,removeformat,smiley,sourcearea,table,specialchar,tab,toolbar,wysiwygarea',
     150        plugins : 'basicstyles,blockquote,button,elementspath,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,newpage,pagebreak,preview,print,removeformat,smiley,sourcearea,table,specialchar,tab,toolbar,undo,wysiwygarea',
    151151
    152152        /**
    153153         * The theme to be used to build the UI.
  • _source/core/dom/domobject.js

     
    6464                        // set to the event.
    6565
    6666                        // Get the listeners holder object.
    67                         var nativeListeners = this.getCustomData( '_cke_nativeListeners' ) || this.setCustomData( '_cke_nativeListeners', {} );
     67                        var nativeListeners = this.getCustomData( '_cke_nativeListeners' );
    6868
     69                        if ( !nativeListeners )
     70                        {
     71                                nativeListeners = {};
     72                                this.setCustomData( '_cke_nativeListeners', nativeListeners );
     73                        }
     74
    6975                        // Check if we have a listener for that event.
    7076                        if ( !nativeListeners[ eventName ] )
    7177                        {
  • _source/core/editor.js

     
    386386                execCommand : function( commandName, data )
    387387                {
    388388                        var command = this.getCommand( commandName );
     389
     390                        var eventData =
     391                        {
     392                                name: commandName,
     393                                commandData: data,
     394                                command: command
     395                        };
     396
    389397                        if ( command && command.state != CKEDITOR.TRISTATE_DISABLED )
    390                                 return command.exec( this, data );
     398                        {
     399                                if ( this.fire( 'beforeCommandExec', eventData ) !== false )
     400                                {
     401                                        eventData.returnValue = command.exec( this, eventData.commandData );
    391402
     403                                        if ( this.fire( 'afterCommandExec', eventData ) !== false )
     404                                                return eventData.returnValue;
     405                                }
     406                        }
     407
    392408                        // throw 'Unknown command name "' + commandName + '"';
    393409                        return false;
    394410                },
     
    454470                        return data;
    455471                },
    456472
     473                loadSnapshot : function( snapshot )
     474                {
     475                        this.fire( 'loadSnapshot', snapshot );
     476                },
     477
    457478                /**
    458479                 * Sets the editor data. The data must be provided in raw format.
    459480                 * @param {String} data HTML code to replace the curent content in the editor.
  • _source/core/tools.js

     
    1515 */
    1616CKEDITOR.tools =
    1717{
     18        arrayCompare : function( arrayA, arrayB )
     19        {
     20                if ( !arrayA && !arrayB )
     21                        return true;
     22
     23                if ( !arrayA || !arrayB || arrayA.length != arrayB.length )
     24                        return false;
     25
     26                for ( var i = 0 ; i < arrayA.length ; i++ )
     27                {
     28                        if ( arrayA[ i ] != arrayB[ i ] )
     29                                return false;
     30                }
     31
     32                return true;
     33        },
     34
    1835        /**
    1936         * Copy the properties from one object to another. By default, properties
    2037         * already present in the target object <strong>are not</strong> overwritten.
  • _source/lang/en.js

     
    4343        horizontalrule  : 'Insert Horizontal Line',
    4444        pagebreak               : 'Insert Page Break',
    4545        unlink                  : 'Unlink',
     46        undo                    : 'Undo',
     47        redo                    : 'Redo',
    4648
    4749        // Common messages and labels.
    4850        common :
  • _source/plugins/editingblock/plugin.js

     
    7070                                        if ( editor.mode )
    7171                                                event.data = getMode( editor ).getSnapshotData();
    7272                                });
     73
     74                        editor.on( 'loadSnapshot', function( event )
     75                                {
     76                                        if ( editor.mode )
     77                                                getMode( editor ).loadSnapshotData( event.data );
     78                                });
    7379                }
    7480        });
    7581
  • _source/plugins/selection/plugin.js

     
    633633                        return retval;
    634634                },
    635635
     636                createBookmarks2 : function( normalized )
     637                {
     638                        var bookmarks = [],
     639                                ranges = this.getRanges();
     640
     641                        for ( var i = 0 ; i < ranges.length ; i++ )
     642                                bookmarks.push( ranges[i].createBookmark2( normalized ) );
     643                       
     644                        return bookmarks;
     645                },
     646
    636647                selectBookmarks : function( bookmarks )
    637648                {
    638649                        var ranges = [];
  • _source/plugins/toolbar/plugin.js

     
    213213                'Outdent', 'Indent', 'Blockquote', '-',
    214214                'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-',
    215215                'Subscript', 'Superscript', '-',
     216                'Undo', 'Redo', '-',
    216217                'SelectAll', 'RemoveFormat', '-',
    217218                'Link', 'Unlink', 'Anchor', '-',
    218219                'Image', '-',
  • _source/plugins/undo/plugin.js

     
     1/*
     2Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
     3For licensing, see LICENSE.html or http://ckeditor.com/license
     4*/
     5
     6/**
     7 * @fileOverview Undo/Redo system for saving shapshot for document modification
     8 *              and other recordable changes.
     9 */
     10
     11(function()
     12{
     13        CKEDITOR.plugins.add( 'undo',
     14        {
     15                requires : [ 'selection', 'wysiwygarea' ],
     16
     17                init : function( editor )
     18                {
     19                        var undoManager = new UndoManager( editor );
     20
     21                        var undoCommand = editor.addCommand( 'undo',
     22                                {
     23                                        exec : function()
     24                                        {
     25                                                if ( undoManager.undo() )
     26                                                {
     27                                                        editor.selectionChange();
     28                                                        this.fire( 'afterUndo' );
     29                                                }
     30                                        },
     31                                        state : CKEDITOR.TRISTATE_DISABLED,
     32                                        canUndo : false
     33                                });
     34
     35                        var redoCommand = editor.addCommand( 'redo',
     36                                {
     37                                        exec : function()
     38                                        {
     39                                                if ( undoManager.redo() )
     40                                                {
     41                                                        editor.selectionChange();
     42                                                        this.fire( 'afterRedo' );
     43                                                }
     44                                        },
     45                                        state : CKEDITOR.TRISTATE_DISABLED,
     46                                        canUndo : false
     47                                });
     48
     49                        undoManager.onChange = function()
     50                        {
     51                                undoCommand.setState( undoManager.undoable() ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED );
     52                                redoCommand.setState( undoManager.redoable() ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED );
     53                        };
     54
     55                        function recordCommand( event )
     56                        {
     57                                // If the command hasn't been marked to not support undo.
     58                                if ( undoManager.enabled && event.data.command.canUndo !== false )
     59                                        undoManager.save();
     60                        }
     61
     62                        // We'll save snapshots before and after executing a command.
     63                        editor.on( 'beforeCommandExec', recordCommand );
     64                        editor.on( 'afterCommandExec', recordCommand );
     65
     66                        // Make the undo manager available only in wysiwyg mode.
     67                        editor.on( 'mode', function()
     68                                {
     69                                        if ( !undoManager.enabled && editor.mode == 'wysiwyg' )
     70                                        {
     71                                                undoManager.enabled = true;
     72
     73                                                editor.document.on( 'keydown', function( event )
     74                                                        {
     75                                                                // Do not capture CTRL hotkeys.
     76                                                                if ( !event.data.$.ctrlKey && !event.data.$.metaKey )
     77                                                                        undoManager.type();
     78                                                        });
     79
     80                                                // Being this the first call, let's get an undo snapshot.
     81                                                if ( undoManager.index == -1 )
     82                                                        undoManager.save();
     83                                        }
     84
     85                                        undoManager.onChange();
     86                                });
     87
     88                        editor.ui.addButton( 'Undo',
     89                                {
     90                                        label : editor.lang.undo,
     91                                        command : 'undo'
     92                                });
     93
     94                        editor.ui.addButton( 'Redo',
     95                                {
     96                                        label : editor.lang.redo,
     97                                        command : 'redo'
     98                                });
     99                }
     100        });
     101
     102        // Gets a snapshot image which represent the current document status.
     103        function Image( editor )
     104        {
     105                var selection = editor.getSelection();
     106
     107                this.contents   = editor.getSnapshot();
     108                this.bookmarks  = selection && selection.createBookmarks2( true );
     109               
     110                // In IE, we need to remove the expando attributes.
     111                if ( CKEDITOR.env.ie )
     112                        this.contents = this.contents.replace( /\s+_cke_expando=".*?"/g, '' );
     113        }
     114
     115        Image.prototype =
     116        {
     117                equals : function( otherImage, contentOnly )
     118                {
     119                        if ( this.contents != otherImage.contents )
     120                                return false;
     121
     122                        if ( contentOnly )
     123                                return true;
     124
     125                        var bookmarksA = this.bookmarks,
     126                                bookmarksB = otherImage.bookmarks;
     127
     128                        if ( bookmarksA || bookmarksB )
     129                        {
     130                                if ( !bookmarksA || !bookmarksB || bookmarksA.length != bookmarksB.length )
     131                                        return false;
     132
     133                                for ( var i = 0 ; i < bookmarksA.length ; i++ )
     134                                {
     135                                        var bookmarkA = bookmarksA[ i ],
     136                                                bookmarkB = bookmarksB[ i ];
     137
     138                                        if (
     139                                                bookmarkA.startOffset != bookmarkB.startOffset ||
     140                                                bookmarkA.endOffset != bookmarkB.endOffset ||
     141                                                !CKEDITOR.tools.arrayCompare( bookmarkA.start, bookmarkB.start ) ||
     142                                                !CKEDITOR.tools.arrayCompare( bookmarkA.end, bookmarkB.end ) )
     143                                        {
     144                                                return false;
     145                                        }
     146                                }
     147                        }
     148
     149                        return true;
     150                }
     151        };
     152
     153        /**
     154         * @constructor Main logic for Redo/Undo feature.
     155         */
     156        function UndoManager( editor )
     157        {
     158                this.typesCount = 0;
     159
     160                this.editor = editor;
     161
     162                /**
     163                 * Stack for all the undo and redo snapshots, they're always created/removed
     164                 * in consistency.
     165                 */
     166                this.snapshots = [];
     167
     168                /**
     169                 * Current snapshot history index.
     170                 */
     171                this.index = -1;
     172
     173                this.limit = editor.config.undoStackSize;
     174        }
     175
     176        UndoManager.prototype =
     177        {
     178                type : function()
     179                {
     180                        if ( !this.typing )
     181                        {
     182                                var beforeTypeImage = new Image( this.editor );
     183
     184                                // Use setTimeout, so we give the necessary time to the
     185                                // browser to insert the character into the DOM.
     186                                CKEDITOR.tools.setTimeout( function()
     187                                        {
     188                                                var currentSnapshot = this.editor.getSnapshot();
     189                                               
     190                                                // In IE, we need to remove the expando attributes.
     191                                                if ( CKEDITOR.env.ie )
     192                                                        currentSnapshot = currentSnapshot.replace( /\s+_cke_expando=".*?"/g, '' );
     193                                               
     194                                                if ( beforeTypeImage.contents != currentSnapshot )
     195                                                {
     196                                                        if ( !this.save( false, beforeTypeImage ) )
     197                                                        {
     198                                                                // Drop future snapshots.
     199                                                                this.snapshots.splice( this.index + 1, this.snapshots.length - this.index - 1 );
     200                                                        }
     201
     202                                                        this.hasUndo = true;
     203                                                        this.hasRedo = false;
     204
     205                                                        this.typesCount = 1;
     206                                                        this.typing = true;
     207
     208                                                        this.onChange();
     209                                                }
     210                                        },
     211                                        0, this );
     212                       
     213                                return;
     214                        }
     215
     216                        this.typesCount++;
     217
     218                        if ( this.typesCount > 25 )
     219                        {
     220                                this.save();
     221                                this.typesCount = 1;
     222                        }
     223
     224                        this.typing = true;
     225                },
     226
     227                fireChange : function()
     228                {
     229                        this.hasUndo = !!this.getNextImage( true );
     230                        this.hasRedo = !!this.getNextImage( false );
     231
     232                        this.typing = false;
     233                        this.typesCount = 0;
     234
     235                        this.onChange();
     236                },
     237
     238                /**
     239                 * Save a snapshot of document image for later retrieve.
     240                 */
     241                save : function( onContentOnly, image )
     242                {
     243                        var snapshots = this.snapshots;
     244
     245                        // Get a content image.
     246                        if ( !image )
     247                                image = new Image( this.editor );
     248
     249                        // Check if this is a duplicate. In such case, do nothing.
     250                        if ( this.currentImage && image.equals( this.currentImage, onContentOnly ) )
     251                                return false;
     252
     253                        // Drop future snapshots.
     254                        snapshots.splice( this.index + 1, snapshots.length - this.index - 1 );
     255
     256                        // If we have reached the limit, remove the oldest one.
     257                        if ( snapshots.length == this.limit )
     258                                snapshots.shift();
     259
     260                        // Add the new image, updating the current index.
     261                        this.index = snapshots.push( image ) - 1;
     262
     263                        this.currentImage = image;
     264
     265                        this.fireChange();
     266
     267                        return true;
     268                },
     269
     270                restoreImage : function( image )
     271                {
     272                        this.editor.loadSnapshot( image.contents );
     273                       
     274                        if ( image.bookmarks )
     275                                this.editor.getSelection().selectBookmarks( image.bookmarks );
     276
     277                        this.index = image.index;
     278
     279                        this.currentImage = image;
     280
     281                        this.fireChange();
     282                },
     283
     284                // Get the closest available image.
     285                getNextImage : function( isUndo )
     286                {
     287                        var snapshots = this.snapshots,
     288                                currentImage = this.currentImage,
     289                                image, i;
     290
     291                        if ( currentImage )
     292                        {
     293                                if ( isUndo )
     294                                {
     295                                        for ( i = this.index - 1 ; i >= 0 ; i-- )
     296                                        {
     297                                                image = snapshots[ i ];
     298                                                if ( !currentImage.equals( image, true ) )
     299                                                {
     300                                                        image.index = i;
     301                                                        return image;
     302                                                }
     303                                        }
     304                                }
     305                                else
     306                                {
     307                                        for ( i = this.index + 1 ; i < snapshots.length ; i++ )
     308                                        {
     309                                                image = snapshots[ i ];
     310                                                if ( !currentImage.equals( image, true ) )
     311                                                {
     312                                                        image.index = i;
     313                                                        return image;
     314                                                }
     315                                        }
     316                                }
     317                        }
     318
     319                        return null;
     320                },
     321
     322                /**
     323                 * Check the current redo state.
     324                 * @return {Boolean} Whether the document has previous state to
     325                 *              retrieve.
     326                 */
     327                redoable : function()
     328                {
     329                        return this.enabled && this.hasRedo;
     330                },
     331
     332                /**
     333                 * Check the current undo state.
     334                 * @return {Boolean} Whether the document has future state to restore.
     335                 */
     336                undoable : function()
     337                {
     338                        return this.enabled && this.hasUndo;
     339                },
     340
     341                /**
     342                 * Perform undo on current index.
     343                 */
     344                undo : function()
     345                {
     346                        if ( this.undoable() )
     347                        {
     348                                this.save( true );
     349
     350                                var image = this.getNextImage( true );
     351                                if ( image )
     352                                        return this.restoreImage( image ), true;
     353                        }
     354
     355                        return false;
     356                },
     357
     358                /**
     359                 * Perform redo on current index.
     360                 */
     361                redo : function()
     362                {
     363                        if ( this.redoable() )
     364                        {
     365                                // Try to save. If no changes have been made, the redo stack
     366                                // will not change, so it will still be redoable.
     367                                this.save( true );
     368
     369                                // If instead we had changes, we can't redo anymore.
     370                                if ( this.redoable() )
     371                                {
     372                                        var image = this.getNextImage( false );
     373                                        if ( image )
     374                                                return this.restoreImage( image ), true;
     375                                }
     376                        }
     377
     378                        return false;
     379                }
     380        };
     381})();
     382
     383CKEDITOR.config.undoStackSize = 20;
  • _source/skins/default/toolbar.css

     
    310310{
    311311        background-position: 0 -880px;
    312312}
    313 
     313.cke_skin_default a.cke_button_undo .cke_icon
     314{
     315        background-position: 0 -208px;
     316}
     317.cke_skin_default a.cke_button_redo .cke_icon
     318{
     319        background-position: 0 -224px;
     320}
    314321.cke_skin_default a.cke_button_numberedlist .cke_icon
    315322{
    316323        background-position: 0 -400px;
© 2003 – 2019 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy