Skip to content

Instantly share code, notes, and snippets.

@emanuele45
Last active August 1, 2017 00:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save emanuele45/157db026b083f08360d762cf396cd997 to your computer and use it in GitHub Desktop.
Save emanuele45/157db026b083f08360d762cf396cd997 to your computer and use it in GitHub Desktop.
(function ($) {
'use strict';
$.sceditor.plugins.undo = function () {
var base = this;
var editor;
var charChangedCount = 0;
var previousValue;
var undoLimit = 50;
var cursorPosition = -1;
var undoStates = [];
var ignoreNextValueChanged = false;
/**
* Sets the editor to the specified state.
*
* @param {Object} state
* @private
*/
var applyState = function (state) {
ignoreNextValueChanged = true;
previousValue = state.value;
editor.sourceMode(state.sourceMode);
editor.val(state.value, false);
editor.focus();
if (state.sourceMode) {
editor.sourceEditorCaret(state.caret);
} else {
editor.getRangeHelper().restoreRange();
}
ignoreNextValueChanged = false;
};
/**
* Caluclates the number of characters that have changed
* between two strings.
*
* @param {String} strA
* @param {String} strB
* @return {String}
* @private
*/
var simpleDiff = function (strA, strB) {
var start, end, aLenDiff, bLenDiff,
aLength = strA.length,
bLength = strB.length,
length = Math.max(aLength, bLength);
// Calculate the start
for (start = 0; start < length; start++) {
if (strA.charAt(start) !== strB.charAt(start)) {
break;
}
}
// Calculate the end
aLenDiff = aLength < bLength ? bLength - aLength : 0;
bLenDiff = bLength < aLength ? aLength - bLength : 0;
for (end = length - 1; end >= 0; end--) {
if (strA.charAt(end - aLenDiff) !==
strB.charAt(end - bLenDiff)) {
break;
}
}
return (end - start) + 1;
};
var addState = function (state, position) {
while (position < undoStates.length - 1) {
undoStates.pop();
}
undoStates.push(state);
cursorPosition = position + 1;
};
base.init = function () {
// The this variable will be set to the instance of the editor
// calling it, hence why the plugins "this" is saved to the base
// variable.
editor = this;
undoLimit = editor.undoLimit || undoLimit;
// addShortcut is the easiest way to add handlers to specific
// shortcuts
editor.addShortcut('ctrl+z', base.undo);
editor.addShortcut('ctrl+shift+z', base.redo);
editor.addShortcut('ctrl+y', base.redo);
};
base.undo = function () {
var rawEditorValue = editor.val(null, false);
if (cursorPosition == -1) {
return false;
}
if (cursorPosition == undoStates.length - 1) {
addState({
'caret': editor.sourceEditorCaret(),
'sourceMode': editor.sourceMode(),
'value': rawEditorValue
}, cursorPosition);
cursorPosition = cursorPosition - 1;
}
cursorPosition = cursorPosition - 1;
applyState(undoStates[cursorPosition]);
return false;
};
base.redo = function () {
if (cursorPosition == undoStates.length - 1) {
return false;
}
cursorPosition = cursorPosition + 1;
applyState(undoStates[cursorPosition]);
return false;
};
base.signalReady = function () {
var rawValue = editor.val(null, false);
// Store the initial value as the last value
previousValue = rawValue;
addState({
'caret': this.sourceEditorCaret(),
'sourceMode': this.sourceMode(),
'value': rawValue
}, cursorPosition);
};
/**
* Handle the valueChanged signal.
*
* e.rawValue will either be the raw HTML from the WYSIWYG editor with
* the rangeHelper range markers inserted, or it will be the raw value
* of the source editor (BBCode or HTML depening on plugins).
* @return {void}
*/
base.signalValuechangedEvent = function (e) {
var rawValue = e.rawValue;
if (undoLimit > 0 && undoStates.length > undoLimit) {
undoStates.shift();
}
// If the editor hasn't fully loaded yet,
// then the previous value won't be set.
if (ignoreNextValueChanged || !previousValue ||
previousValue === rawValue) {
return;
}
// Value has changed so remove all redo states
charChangedCount += simpleDiff(previousValue, rawValue);
if (charChangedCount < 20) {
return;
// ??
} else if (charChangedCount < 50 && !/\s$/g.test(e.rawValue)) {
return;
}
addState({
'caret': editor.sourceEditorCaret(),
'sourceMode': editor.sourceMode(),
'value': rawValue
}, cursorPosition);
charChangedCount = 0;
previousValue = rawValue;
};
};
}(jQuery));
@Spuds
Copy link

Spuds commented Jul 30, 2017

Update base.signalReady as below, it prevents the page jump when the editor gets focus to check caret position. It would still jump if the editor has content, but then the named link would not be in play.

		base.signalReady = function () {
			var rawValue = editor.val(null, false),
				caret;

			// Save a call, and a page jump, when the editor is empty
			if (rawValue === '') {
				caret = {end: 0, start: 0};
			} else {
				caret = this.sourceEditorCaret();
			}

			// Store the initial value as the last value
			previousValue = rawValue;

			addState({
				'caret': caret,
				'sourceMode': this.sourceMode(),
				'value': rawValue
			}, cursorPosition);
		};

@emanuele45
Copy link
Author

@Spuds if I got it right, the version is the branch Elk_Branch_1.5.3 of your fork, right?
If I send you a PR you can minify it and push it to elk repo?
Or... actually, I can I just use the file you uploaded at elk.net, right? 😀

@Spuds
Copy link

Spuds commented Aug 1, 2017

I'll push your changes to that elk branch repo so we don't loose track (again lol, the undo in that branch is missing this change but its on my local, go figure)

The version on the site is what went through the :offical: Grunt build process, as such it went through all the syntax, format checking etc etc So that minimized file is good to use in the Elkatre 1.1 repo

The open issue on the new editor is the bug reported on our site with IE/Edge. I opened the issue we SCE but you just don't know when Sam will be around to look at it. I'll try to debug but can't start on it until next week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment