[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 YUI.add('moodle-atto_undo-button', function (Y, NAME) { 2 3 // This file is part of Moodle - http://moodle.org/ 4 // 5 // Moodle is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // Moodle is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 17 18 /** 19 * @component atto_undo 20 * @copyright 2014 Jerome Mouneyrac 21 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 */ 23 24 /** 25 * @module moodle-atto_undo-button 26 */ 27 28 /** 29 * Atto text editor undo plugin. 30 * 31 * @namespace M.atto_undo 32 * @class button 33 * @extends M.editor_atto.EditorPlugin 34 */ 35 36 Y.namespace('M.atto_undo').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { 37 /** 38 * The maximum saved number of undo steps. 39 * 40 * @property _maxUndos 41 * @type {Number} The maximum number of saved undos. 42 * @default 40 43 * @private 44 */ 45 _maxUndos: 40, 46 47 /** 48 * History of edits. 49 * 50 * @property _undoStack 51 * @type {Array} The elements of the array are the html strings that make a snapshot 52 * @private 53 */ 54 _undoStack: null, 55 56 /** 57 * History of edits. 58 * 59 * @property _redoStack 60 * @type {Array} The elements of the array are the html strings that make a snapshot 61 * @private 62 */ 63 _redoStack: null, 64 65 /** 66 * Add the buttons to the toolbar 67 * 68 * @method initializer 69 */ 70 initializer: function() { 71 // Initialise the undo and redo stacks. 72 this._undoStack = []; 73 this._redoStack = []; 74 75 this.addButton({ 76 title: 'undo', 77 icon: 'e/undo', 78 callback: this._undoHandler, 79 buttonName: 'undo', 80 keys: 90 81 }); 82 83 this.addButton({ 84 title: 'redo', 85 icon: 'e/redo', 86 callback: this._redoHandler, 87 buttonName: 'redo', 88 keys: 89 89 }); 90 91 // Enable the undo once everything has loaded. 92 this.get('host').on('pluginsloaded', function() { 93 // Adds the current value to the stack. 94 this._addToUndo(this._getHTML()); 95 this.get('host').on('atto:selectionchanged', this._changeListener, this); 96 }, this); 97 98 this._updateButtonsStates(); 99 }, 100 101 /** 102 * Adds an element to the redo stack. 103 * 104 * @method _addToRedo 105 * @private 106 * @param {String} html The HTML content to save. 107 */ 108 _addToRedo: function(html) { 109 this._redoStack.push(html); 110 }, 111 112 /** 113 * Adds an element to the undo stack. 114 * 115 * @method _addToUndo 116 * @private 117 * @param {String} html The HTML content to save. 118 * @param {Boolean} [clearRedo=false] Whether or not we should clear the redo stack. 119 */ 120 _addToUndo: function(html, clearRedo) { 121 var last = this._undoStack[this._undoStack.length - 1]; 122 123 if (typeof clearRedo === 'undefined') { 124 clearRedo = false; 125 } 126 127 if (last !== html) { 128 this._undoStack.push(html); 129 if (clearRedo) { 130 this._redoStack = []; 131 } 132 } 133 134 while (this._undoStack.length > this._maxUndos) { 135 this._undoStack.shift(); 136 } 137 }, 138 139 /** 140 * Get the editor HTML. 141 * 142 * @method _getHTML 143 * @private 144 * @return {String} The HTML. 145 */ 146 _getHTML: function() { 147 return this.get('host').getCleanHTML(); 148 }, 149 150 /** 151 * Get an element on the redo stack. 152 * 153 * @method _getRedo 154 * @private 155 * @return {String} The HTML to restore, or undefined. 156 */ 157 _getRedo: function() { 158 return this._redoStack.pop(); 159 }, 160 161 /** 162 * Get an element on the undo stack. 163 * 164 * @method _getUndo 165 * @private 166 * @param {String} current The current HTML. 167 * @return {String} The HTML to restore. 168 */ 169 _getUndo: function(current) { 170 if (this._undoStack.length === 1) { 171 return this._undoStack[0]; 172 } 173 174 var last = this._undoStack.pop(); 175 if (last === current) { 176 // Oops, the latest undo step is the current content, we should unstack once more. 177 // There is no need to do that in a loop as the same stack should never contain duplicates. 178 last = this._undoStack.pop(); 179 } 180 181 // We always need to keep the first element of the stack. 182 if (this._undoStack.length === 0) { 183 this._addToUndo(last); 184 } 185 186 return last; 187 }, 188 189 /** 190 * Restore a value from a stack. 191 * 192 * @method _restoreValue 193 * @private 194 * @param {String} html The HTML to restore in the editor. 195 */ 196 _restoreValue: function(html) { 197 this.editor.setHTML(html); 198 // We always add the restored value to the stack, otherwise an event could think that 199 // the content has changed and clear the redo stack. 200 this._addToUndo(html); 201 }, 202 203 /** 204 * Update the states of the buttons. 205 * 206 * @method _updateButtonsStates 207 * @private 208 */ 209 _updateButtonsStates: function() { 210 if (this._undoStack.length > 1) { 211 this.enableButtons('undo'); 212 } else { 213 this.disableButtons('undo'); 214 } 215 216 if (this._redoStack.length > 0) { 217 this.enableButtons('redo'); 218 } else { 219 this.disableButtons('redo'); 220 } 221 }, 222 223 /** 224 * Handle a click on undo 225 * 226 * @method _undoHandler 227 * @param {Event} The click event 228 * @private 229 */ 230 _undoHandler: function(e) { 231 e.preventDefault(); 232 var html = this._getHTML(), 233 undo = this._getUndo(html); 234 235 // Edge case, but that could happen. We do nothing when the content equals the undo step. 236 if (html === undo) { 237 this._updateButtonsStates(); 238 return; 239 } 240 241 // Restore the value. 242 this._restoreValue(undo); 243 244 // Add to the redo stack. 245 this._addToRedo(html); 246 247 // Update the button states. 248 this._updateButtonsStates(); 249 }, 250 251 /** 252 * Handle a click on redo 253 * 254 * @method _redoHandler 255 * @param {Event} The click event 256 * @private 257 */ 258 _redoHandler: function(e) { 259 e.preventDefault(); 260 var html = this._getHTML(), 261 redo = this._getRedo(); 262 263 // Edge case, but that could happen. We do nothing when the content equals the redo step. 264 if (html === redo) { 265 this._updateButtonsStates(); 266 return; 267 } 268 // Restore the value. 269 this._restoreValue(redo); 270 271 // Update the button states. 272 this._updateButtonsStates(); 273 }, 274 275 /** 276 * If we are significantly different from the last saved version, save a new version. 277 * 278 * @method _changeListener 279 * @param {EventFacade} The click event 280 * @private 281 */ 282 _changeListener: function(e) { 283 if (e.event && e.event.type.indexOf('key') !== -1) { 284 // These are the 4 arrow keys. 285 if ((e.event.keyCode !== 39) && 286 (e.event.keyCode !== 37) && 287 (e.event.keyCode !== 40) && 288 (e.event.keyCode !== 38)) { 289 // Skip this event type. We only want focus/mouse/arrow events. 290 return; 291 } 292 } 293 294 this._addToUndo(this._getHTML(), true); 295 this._updateButtonsStates(); 296 } 297 }); 298 299 300 }, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |