}
};
})();
-/**
- * Originally based of this code... - refactored for Roo...
- * https://github.com/aaalsaleh/undo-manager
-
- * undo-manager.js
- * @author Abdulrahman Alsaleh
- * @copyright 2015 Abdulrahman Alsaleh
- * @license MIT License (c)
- *
- * Hackily modifyed by alan@roojs.com
- *
- *
- *
- *
- * TOTALLY UNTESTED...
- *
- * Documentation to be done....
- */
-
-
-/**
-* @class Roo.lib.UndoManager
-* An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
-* Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
-
- * Usage:
- * <pre><code>
-
-
-editor.undoManager = new Roo.lib.UndoManager(1000, editor);
-
-</code></pre>
-
-* For more information see this blog post with examples:
-* <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
- - Create Elements using DOM, HTML fragments and Templates</a>.
-* @constructor
-* @param {Number} limit how far back to go ... use 1000?
-* @param {Object} scope usually use document..
-*/
-
-Roo.lib.UndoManager = function (limit, undoScopeHost)
-{
- this.stack = [];
- this.limit = limit;
- this.scope = undoScopeHost;
- this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
- if (this.fireEvent) {
- this.bindEvents();
- }
- this.reset();
-
-};
-
-Roo.lib.UndoManager.prototype = {
-
- limit : false,
- stack : false,
- scope : false,
- fireEvent : false,
- position : 0,
- length : 0,
-
-
- /**
- * To push and execute a transaction, the method undoManager.transact
- * must be called by passing a transaction object as the first argument, and a merge
- * flag as the second argument. A transaction object has the following properties:
- *
- * Usage:
-<pre><code>
-undoManager.transact({
- label: 'Typing',
- execute: function() { ... },
- undo: function() { ... },
- // redo same as execute
- redo: function() { this.execute(); }
-}, false);
-
-// merge transaction
-undoManager.transact({
- label: 'Typing',
- execute: function() { ... }, // this will be run...
- undo: function() { ... }, // what to do when undo is run.
- // redo same as execute
- redo: function() { this.execute(); }
-}, true);
-</code></pre>
- *
- *
- * @param {Object} transaction The transaction to add to the stack.
- * @return {String} The HTML fragment
- */
-
-
- transact : function (transaction, merge)
- {
- if (arguments.length < 2) {
- throw new TypeError('Not enough arguments to UndoManager.transact.');
- }
-
- transaction.execute();
-
- this.stack.splice(0, this.position);
- if (merge && this.length) {
- this.stack[0].push(transaction);
- } else {
- this.stack.unshift([transaction]);
- }
-
- this.position = 0;
-
- if (this.limit && this.stack.length > this.limit) {
- this.length = this.stack.length = this.limit;
- } else {
- this.length = this.stack.length;
- }
-
- if (this.fireEvent) {
- this.scope.dispatchEvent(
- new CustomEvent('DOMTransaction', {
- detail: {
- transactions: this.stack[0].slice()
- },
- bubbles: true,
- cancelable: false
- })
- );
- }
-
- //Roo.log("transaction: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
-
-
- },
-
- undo : function ()
- {
- //Roo.log("undo: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
-
- if (this.position < this.length) {
- for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
- this.stack[this.position][i].undo();
- }
- this.position++;
-
- if (this.fireEvent) {
- this.scope.dispatchEvent(
- new CustomEvent('undo', {
- detail: {
- transactions: this.stack[this.position - 1].slice()
- },
- bubbles: true,
- cancelable: false
- })
- );
- }
- }
- },
-
- redo : function ()
- {
- if (this.position > 0) {
- for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
- this.stack[this.position - 1][i].redo();
- }
- this.position--;
-
- if (this.fireEvent) {
- this.scope.dispatchEvent(
- new CustomEvent('redo', {
- detail: {
- transactions: this.stack[this.position].slice()
- },
- bubbles: true,
- cancelable: false
- })
- );
- }
- }
- },
-
- item : function (index)
- {
- if (index >= 0 && index < this.length) {
- return this.stack[index].slice();
- }
- return null;
- },
-
- clearUndo : function () {
- this.stack.length = this.length = this.position;
- },
-
- clearRedo : function () {
- this.stack.splice(0, this.position);
- this.position = 0;
- this.length = this.stack.length;
- },
- /**
- * Reset the undo - probaly done on load to clear all history.
- */
- reset : function()
- {
- this.stack = [];
- this.position = 0;
- this.length = 0;
- this.current_html = this.scope.innerHTML;
- if (this.timer !== false) {
- clearTimeout(this.timer);
- }
- this.timer = false;
- this.merge = false;
- this.addEvent();
-
- },
- current_html : '',
- timer : false,
- merge : false,
-
-
- // this will handle the undo/redo on the element.?
- bindEvents : function()
- {
- var el = this.scope;
- el.undoManager = this;
-
-
- this.scope.addEventListener('keydown', function(e) {
- if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
- if (e.shiftKey) {
- el.undoManager.redo(); // Ctrl/Command + Shift + Z
- } else {
- el.undoManager.undo(); // Ctrl/Command + Z
- }
-
- e.preventDefault();
- }
- });
- /// ignore keyup..
- this.scope.addEventListener('keyup', function(e) {
- if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
- e.preventDefault();
- }
- });
-
-
-
- var t = this;
-
- el.addEventListener('input', function(e) {
- if(el.innerHTML == t.current_html) {
- return;
- }
- // only record events every second.
- if (t.timer !== false) {
- clearTimeout(t.timer);
- t.timer = false;
- }
- t.timer = setTimeout(function() { t.merge = false; }, 1000);
-
- t.addEvent(t.merge);
- t.merge = true; // ignore changes happening every second..
- });
- },
- /**
- * Manually add an event.
- * Normall called without arguements - and it will just get added to the stack.
- *
- */
-
- addEvent : function(merge)
- {
- //Roo.log("undomanager +" + (merge ? 'Y':'n'));
- // not sure if this should clear the timer
- merge = typeof(merge) == 'undefined' ? false : merge;
-
- this.scope.undoManager.transact({
- scope : this.scope,
- oldHTML: this.current_html,
- newHTML: this.scope.innerHTML,
- // nothing to execute (content already changed when input is fired)
- execute: function() { },
- undo: function() {
- this.scope.innerHTML = this.current_html = this.oldHTML;
- },
- redo: function() {
- this.scope.innerHTML = this.current_html = this.newHTML;
- }
- }, false); //merge);
-
- this.merge = merge;
-
- this.current_html = this.scope.innerHTML;
- }
-
-
-
-
-
-
-};
-/**
- * @class Roo.lib.Range
- * @constructor
- * This is a toolkit, normally used to copy features into a Dom Range element
- * Roo.lib.Range.wrap(x);
- *
- *
- *
- */
-Roo.lib.Range = function() { };
-
-/**
- * Wrap a Dom Range object, to give it new features...
- * @static
- * @param {Range} the range to wrap
- */
-Roo.lib.Range.wrap = function(r) {
- return Roo.apply(r, Roo.lib.Range.prototype);
-};
-/**
- * find a parent node eg. LI / OL
- * @param {string|Array} node name or array of nodenames
- * @return {DomElement|false}
- */
-Roo.apply(Roo.lib.Range.prototype,
-{
-
- closest : function(str)
- {
- if (typeof(str) != 'string') {
- // assume it's a array.
- for(var i = 0;i < str.length;i++) {
- var r = this.closest(str[i]);
- if (r !== false) {
- return r;
- }
-
- }
- return false;
- }
- str = str.toLowerCase();
- var n = this.commonAncestorContainer; // might not be a node
- while (n.nodeType != 1) {
- n = n.parentNode;
- }
-
- if (n.nodeName.toLowerCase() == str ) {
- return n;
- }
- if (n.nodeName.toLowerCase() == 'body') {
- return false;
- }
-
- return n.closest(str) || false;
-
- },
- cloneRange : function()
- {
- return Roo.lib.Range.wrap(Range.prototype.cloneRange.call(this));
- }
-});/**
- * @class Roo.lib.Selection
- * @constructor
- * This is a toolkit, normally used to copy features into a Dom Selection element
- * Roo.lib.Selection.wrap(x);
- *
- *
- *
- */
-Roo.lib.Selection = function() { };
-
-/**
- * Wrap a Dom Range object, to give it new features...
- * @static
- * @param {Range} the range to wrap
- */
-Roo.lib.Selection.wrap = function(r, doc) {
- Roo.apply(r, Roo.lib.Selection.prototype);
- r.ownerDocument = doc; // usefull so we dont have to keep referening to it.
- return r;
-};
-/**
- * find a parent node eg. LI / OL
- * @param {string|Array} node name or array of nodenames
- * @return {DomElement|false}
- */
-Roo.apply(Roo.lib.Selection.prototype,
-{
- /**
- * the owner document
- */
- ownerDocument : false,
-
- getRangeAt : function(n)
- {
- return Roo.lib.Range.wrap(Selection.prototype.getRangeAt.call(this,n));
- },
-
- /**
- * insert node at selection
- * @param {DomElement|string} node
- * @param {string} cursor (after|in|none) where to place the cursor after inserting.
- */
- insertNode: function(node, cursor)
- {
- if (typeof(node) == 'string') {
- node = this.ownerDocument.createElement(node);
- if (cursor == 'in') {
- node.innerHTML = ' ';
- }
- }
-
- var range = this.getRangeAt(0);
-
- if (this.type != 'Caret') {
- range.deleteContents();
- }
- var sn = node.childNodes[0]; // select the contents.
-
-
-
- range.insertNode(node);
- if (cursor == 'after') {
- node.insertAdjacentHTML('afterend', ' ');
- sn = node.nextSibling;
- }
-
- if (cursor == 'none') {
- return;
- }
-
- this.cursorText(sn);
- },
-
- cursorText : function(n)
- {
-
- //var range = this.getRangeAt(0);
- range = Roo.lib.Range.wrap(new Range());
- //range.selectNode(n);
-
- var ix = Array.from(n.parentNode.childNodes).indexOf(n);
- range.setStart(n.parentNode,ix);
- range.setEnd(n.parentNode,ix+1);
- //range.collapse(false);
-
- this.removeAllRanges();
- this.addRange(range);
-
- Roo.log([n, range, this,this.baseOffset,this.extentOffset, this.type]);
- },
- cursorAfter : function(n)
- {
- if (!n.nextSibling || n.nextSibling.nodeValue != ' ') {
- n.insertAdjacentHTML('afterend', ' ');
- }
- this.cursorText (n.nextSibling);
- }
-
-
-});/*
+/*
* Based on:
* Ext JS Library 1.1.1
* Copyright(c) 2006-2007, Ext JS, LLC.