X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=_source%2Fplugins%2Fundo%2Fplugin.js;h=fde581f07014eb0e599f49a164c0a4d6e0722a5c;hb=8665a7c6c60586526e32e8941fe2896739b6ebfb;hp=e013a9ddb42af6b9cb8dfc0baf743ba6cac7355a;hpb=ea7e3453c7b0f023b050aca6d9f83ab372860d91;p=ckeditor.git diff --git a/_source/plugins/undo/plugin.js b/_source/plugins/undo/plugin.js index e013a9d..fde581f 100644 --- a/_source/plugins/undo/plugin.js +++ b/_source/plugins/undo/plugin.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -114,27 +114,69 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // Create the first image. editor.fire( 'saveSnapshot' ); }; + + /** + * Update the undo stacks with any subsequent DOM changes after this call. + * @name CKEDITOR.editor#updateUndo + * @example + * function() + * { + * editor.fire( 'updateSnapshot' ); + * ... + * // Ask to include subsequent (in this call stack) DOM changes to be + * // considered as part of the first snapshot. + * editor.fire( 'updateSnapshot' ); + * editor.document.body.append(...); + * ... + * } + */ + editor.on( 'updateSnapshot', function() + { + if ( undoManager.currentImage && new Image( editor ).equals( undoManager.currentImage ) ) + setTimeout( function () { undoManager.update(); }, 0 ); + }); } }); - // Gets a snapshot image which represent the current document status. - function Image( editor ) + CKEDITOR.plugins.undo = {}; + + /** + * Undo snapshot which represents the current document status. + * @name CKEDITOR.plugins.undo.Image + * @param editor The editor instance on which the image is created. + */ + var Image = CKEDITOR.plugins.undo.Image = function( editor ) { - var selection = editor.getSelection(); + this.editor = editor; + var contents = editor.getSnapshot(), + selection = contents && editor.getSelection(); + + // In IE, we need to remove the expando attributes. + CKEDITOR.env.ie && contents && ( contents = contents.replace( /\s+_cke_expando=".*?"/g, '' ) ); - this.contents = editor.getSnapshot(); + this.contents = contents; this.bookmarks = selection && selection.createBookmarks2( true ); + }; - // In IE, we need to remove the expando attributes. - if ( CKEDITOR.env.ie ) - this.contents = this.contents.replace( /\s+_cke_expando=".*?"/g, '' ); - } + // Attributes that browser may changing them when setting via innerHTML. + var protectedAttrs = /\b(?:href|src|name)="[^"]*?"/gi; Image.prototype = { equals : function( otherImage, contentOnly ) { - if ( this.contents != otherImage.contents ) + + var thisContents = this.contents, + otherContents = otherImage.contents; + + // For IE6/7 : Comparing only the protected attribute values but not the original ones.(#4522) + if ( CKEDITOR.env.ie && ( CKEDITOR.env.ie7Compat || CKEDITOR.env.ie6Compat ) ) + { + thisContents = thisContents.replace( protectedAttrs, '' ); + otherContents = otherContents.replace( protectedAttrs, '' ); + } + + if ( thisContents != otherContents ) return false; if ( contentOnly ) @@ -179,6 +221,11 @@ For licensing, see LICENSE.html or http://ckeditor.com/license this.reset(); } + + var editingKeyCodes = { /*Backspace*/ 8:1, /*Delete*/ 46:1 }, + modifierKeyCodes = { /*Shift*/ 16:1, /*Ctrl*/ 17:1, /*Alt*/ 18:1 }, + navigationKeyCodes = { 37:1, 38:1, 39:1, 40:1 }; // Arrows: L, T, R, B + UndoManager.prototype = { /** @@ -187,32 +234,26 @@ For licensing, see LICENSE.html or http://ckeditor.com/license */ type : function( event ) { - var keystroke = event && event.data.getKeystroke(), - - // Backspace, Delete - modifierCodes = { 8:1, 46:1 }, - // Keystrokes which will modify the contents. - isModifier = keystroke in modifierCodes, - wasModifier = this.lastKeystroke in modifierCodes, - lastWasSameModifier = isModifier && keystroke == this.lastKeystroke, - - // Arrows: L, T, R, B - resetTypingCodes = { 37:1, 38:1, 39:1, 40:1 }, + var keystroke = event && event.data.getKey(), + isModifierKey = keystroke in modifierKeyCodes, + isEditingKey = keystroke in editingKeyCodes, + wasEditingKey = this.lastKeystroke in editingKeyCodes, + sameAsLastEditingKey = isEditingKey && keystroke == this.lastKeystroke, // Keystrokes which navigation through contents. - isReset = keystroke in resetTypingCodes, - wasReset = this.lastKeystroke in resetTypingCodes, + isReset = keystroke in navigationKeyCodes, + wasReset = this.lastKeystroke in navigationKeyCodes, // Keystrokes which just introduce new contents. - isContent = ( !isModifier && !isReset ), + isContent = ( !isEditingKey && !isReset ), // Create undo snap for every different modifier key. - modifierSnapshot = ( isModifier && !lastWasSameModifier ), + modifierSnapshot = ( isEditingKey && !sameAsLastEditingKey ), // Create undo snap on the following cases: - // 1. Just start to type. + // 1. Just start to type . // 2. Typing some content after a modifier. // 3. Typing some content after make a visible selection. - startedTyping = !this.typing - || ( isContent && ( wasModifier || wasReset ) ); + startedTyping = !( isModifierKey || this.typing ) + || ( isContent && ( wasEditingKey || wasReset ) ); if ( startedTyping || modifierSnapshot ) { @@ -230,6 +271,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license if ( beforeTypeImage.contents != currentSnapshot ) { + // It's safe to now indicate typing state. + this.typing = true; + // This's a special save, with specified snapshot // and without auto 'fireChange'. if ( !this.save( false, beforeTypeImage, false ) ) @@ -250,15 +294,16 @@ For licensing, see LICENSE.html or http://ckeditor.com/license } this.lastKeystroke = keystroke; + // Create undo snap after typed too much (over 25 times). - if ( isModifier ) + if ( isEditingKey ) { this.typesCount = 0; this.modifiersCount++; if ( this.modifiersCount > 25 ) { - this.save(); + this.save( false, null, false ); this.modifiersCount = 1; } } @@ -269,12 +314,11 @@ For licensing, see LICENSE.html or http://ckeditor.com/license if ( this.typesCount > 25 ) { - this.save(); + this.save( false, null, false ); this.typesCount = 1; } } - this.typing = true; }, reset : function() // Reset the undo stack. @@ -336,6 +380,10 @@ For licensing, see LICENSE.html or http://ckeditor.com/license if ( !image ) image = new Image( this.editor ); + // Do nothing if it was not possible to retrieve an image. + if ( image.contents === false ) + return false; + // Check if this is a duplicate. In such case, do nothing. if ( this.currentImage && image.equals( this.currentImage, onContentOnly ) ) return false; @@ -375,8 +423,10 @@ For licensing, see LICENSE.html or http://ckeditor.com/license this.index = image.index; - this.currentImage = image; - + // Update current image with the actual editor + // content, since actualy content may differ from + // the original snapshot due to dom change. (#4622) + this.update(); this.fireChange(); }, @@ -475,6 +525,14 @@ For licensing, see LICENSE.html or http://ckeditor.com/license } return false; + }, + + /** + * Update the last snapshot of the undo stack with the current editor content. + */ + update : function() + { + this.snapshots.splice( this.index, 1, ( this.currentImage = new Image( this.editor ) ) ); } }; })(); @@ -488,3 +546,10 @@ For licensing, see LICENSE.html or http://ckeditor.com/license * config.undoStackSize = 50; */ CKEDITOR.config.undoStackSize = 20; + +/** + * Fired when the editor is about to save an undo snapshot. This event can be + * fired by plugins and customizations to make the editor saving undo snapshots. + * @name CKEDITOR.editor#saveSnapshot + * @event + */