New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

scribe-editor

Package Overview
Dependencies
Maintainers
9
Versions
68
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

scribe-editor - npm Package Compare versions

Comparing version 1.2.11 to 1.3.0

examples/shared-undo-manager.html

4

CHANGELOG.md

@@ -0,1 +1,5 @@

# 1.3.0
Introduces a new time-based undo manager and improvements to allow multiple Scribe instances to share or have a separate undo manager. Thanks to [Abdulrahman Alsaleh](https://github.com/aaalsaleh) for providing the code and spending a lot of time working with us on the tests.
# 1.2.11

@@ -2,0 +6,0 @@

2

package.json
{
"name": "scribe-editor",
"version": "1.2.11",
"version": "1.3.0",
"main": "src/scribe.js",

@@ -5,0 +5,0 @@ "dependencies": {

@@ -10,12 +10,7 @@ define(function () {

redoCommand.execute = function () {
var historyItem = scribe.undoManager.redo();
if (typeof historyItem !== 'undefined') {
scribe.restoreFromHistory(historyItem);
}
scribe.undoManager.redo();
};
redoCommand.queryEnabled = function () {
return scribe.undoManager.position < scribe.undoManager.stack.length - 1;
return scribe.undoManager.position > 0;
};

@@ -22,0 +17,0 @@

@@ -10,11 +10,7 @@ define(function () {

undoCommand.execute = function () {
var historyItem = scribe.undoManager.undo();
if (typeof historyItem !== 'undefined') {
scribe.restoreFromHistory(historyItem);
}
scribe.undoManager.undo();
};
undoCommand.queryEnabled = function () {
return scribe.undoManager.position > 1;
return scribe.undoManager.position < scribe.undoManager.length;
};

@@ -21,0 +17,0 @@

@@ -14,16 +14,2 @@ define([

/**
* Push the first history item when the editor is focused.
*/
var pushHistoryOnFocus = function () {
// Tabbing into the editor doesn't create a range immediately, so we
// have to wait until the next event loop.
setTimeout(function () {
scribe.pushHistory();
}.bind(scribe), 0);
scribe.el.removeEventListener('focus', pushHistoryOnFocus);
}.bind(scribe);
scribe.el.addEventListener('focus', pushHistoryOnFocus);
/**
* Firefox: Giving focus to a `contenteditable` will place the caret

@@ -95,15 +81,10 @@ * outside of any block elements. Chrome behaves correctly by placing the

// happens on the first `focus` event).
if (isEditorActive) {
if (scribe.undoManager) {
// Discard the last history item, as we're going to be adding
// a new clean history item next.
scribe.undoManager.undo();
}
// Pass content through formatters, place caret back
scribe.transactionManager.run(runFormatters);
} else {
runFormatters();
}
// The previous check is no longer needed, and the above comments are no longer valid.
// Now `scribe.setContent` updates the content manually, and `scribe.pushHistory`
// will not detect any changes, and nothing will be push into the history.
// Any mutations made without `scribe.getContent` will be pushed into the history normally.
// Pass content through formatters, place caret back
scribe.transactionManager.run(runFormatters);
}

@@ -110,0 +91,0 @@

@@ -41,5 +41,5 @@ define([], function () {

* and recorded the faulty content as an item in the
* UndoManager. We interfere with the undoManager
* here to discard that history item, and let the next
* transaction run produce a clean one instead.
* UndoManager. We interfere with the undoManager
* by force merging that transaction with the next
* transaction which produce a clean one instead.
*

@@ -51,5 +51,2 @@ * FIXME: ideally we would not trigger a

*/
if (scribe.undoManager) {
scribe.undoManager.undo();
}

@@ -86,3 +83,3 @@ scribe.transactionManager.run(function () {

selection.selectMarkers();
});
}, true);
}

@@ -89,0 +86,0 @@ }

@@ -32,3 +32,3 @@ define([

buildTransactionManager,
buildUndoManager,
UndoManager,
EventEmitter,

@@ -51,3 +51,8 @@ elementHelpers,

debug: false,
undo: { enabled: true },
undo: {
manager: false,
enabled: true,
limit: 100,
interval: 250
},
defaultCommandPatches: [

@@ -80,6 +85,16 @@ 'bold',

if (this.options.undo.enabled) {
var UndoManager = buildUndoManager(this);
this.undoManager = new UndoManager();
if (this.options.undo.manager) {
this.undoManager = this.options.undo.manager;
}
else {
this.undoManager = new UndoManager(this.options.undo.limit, this.el);
}
this._merge = false;
this._forceMerge = false;
this._mergeTimer = 0;
this._lastItem = {content: ''};
}
this.setHTML(this.getHTML());
this.el.setAttribute('contenteditable', true);

@@ -163,2 +178,4 @@

Scribe.prototype.setHTML = function (html, skipFormatters) {
this._lastItem.content = html;
if (skipFormatters) {

@@ -187,31 +204,55 @@ this._skipFormatters = true;

Scribe.prototype.pushHistory = function () {
if (this.options.undo.enabled) {
var previousUndoItem = this.undoManager.stack[this.undoManager.position];
var previousContent = previousUndoItem && previousUndoItem
/**
* Chrome and Firefox: If we did push to the history, this would break
* browser magic around `Document.queryCommandState` (http://jsbin.com/eDOxacI/1/edit?js,console,output).
* This happens when doing any DOM manipulation.
*/
var scribe = this;
if (scribe.options.undo.enabled) {
// Get scribe previous content, and strip markers.
var lastContentNoMarkers = scribe._lastItem.content
.replace(/<em class="scribe-marker">/g, '').replace(/<\/em>/g, '');
/**
* Chrome and Firefox: If we did push to the history, this would break
* browser magic around `Document.queryCommandState` (http://jsbin.com/eDOxacI/1/edit?js,console,output).
* This happens when doing any DOM manipulation.
*/
// We only want to push the history if the content actually changed.
if (! previousUndoItem || (previousUndoItem && this.getHTML() !== previousContent)) {
var selection = new this.api.Selection();
if (scribe.getHTML() !== lastContentNoMarkers) {
var selection = new scribe.api.Selection();
selection.placeMarkers();
var html = this.getHTML();
var content = scribe.getHTML();
selection.removeMarkers();
this.undoManager.push(html);
// Checking if there is a need to merge, and that the previous history item
// is the last history item of the same scribe instance.
// It is possible the last transaction is not for the same instance, or
// even not a scribe transaction (e.g. when using a shared undo manager).
var previousItem = scribe.undoManager.item(scribe.undoManager.position);
if ((scribe._merge || scribe._forceMerge) && previousItem && scribe._lastItem == previousItem[0]) {
// If so, merge manually with the last item to save more memory space.
scribe._lastItem.content = content;
}
else {
// Otherwise, create a new history item, and register it as a new transaction
scribe._lastItem = {
previousItem: scribe._lastItem,
content: content,
scribe: scribe,
execute: function () { },
undo: function () { this.scribe.restoreFromHistory(this.previousItem); },
redo: function () { this.scribe.restoreFromHistory(this); }
};
scribe.undoManager.transact(scribe._lastItem, false);
}
// Merge next transaction if it happens before the interval option, otherwise don't merge.
clearTimeout(scribe._mergeTimer);
scribe._merge = true;
scribe._mergeTimer = setTimeout(function() { scribe._merge = false; }, scribe.options.undo.interval);
return true;
} else {
return false;
}
} else {
return false;
}
return false;
};

@@ -224,4 +265,6 @@

Scribe.prototype.restoreFromHistory = function (historyItem) {
this.setHTML(historyItem, true);
this._lastItem = historyItem;
this.setHTML(historyItem.content, true);
// Restore the selection

@@ -228,0 +271,0 @@ var selection = new this.api.Selection();

@@ -24,3 +24,3 @@ define(['lodash-amd/modern/objects/assign'], function (assign) {

run: function (transaction) {
run: function (transaction, forceMerge) {
this.start();

@@ -33,3 +33,5 @@ // If there is an error, don't prevent the transaction from ending.

} finally {
scribe._forceMerge = forceMerge === true;
this.end();
scribe._forceMerge = false;
}

@@ -36,0 +38,0 @@ }

define(function () {
'use strict';
return function (scribe) {
function UndoManager(limit, undoScopeHost) {
this._stack = [];
this._limit = limit;
this._fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
this._ush = undoScopeHost;
function UndoManager() {
this.position = -1;
this.stack = [];
this.debug = scribe.isDebugModeEnabled();
this.position = 0;
this.length = 0;
}
UndoManager.prototype.transact = function (transaction, merge) {
if (arguments.length < 2) {
throw new TypeError('Not enough arguments to UndoManager.transact.');
}
UndoManager.prototype.maxStackSize = 100;
transaction.execute();
UndoManager.prototype.push = function (item) {
if (this.debug) {
console.log('UndoManager.push: %s', item);
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._ush.dispatchEvent(new CustomEvent('DOMTransaction', {detail: {transactions: this._stack[0].slice()}, bubbles: true, cancelable: false}));
}
};
UndoManager.prototype.undo = function () {
if (this.position < this.length) {
for (var i = this._stack[this.position].length - 1; i >= 0; i--) {
this._stack[this.position][i].undo();
}
this.stack.length = ++this.position;
this.stack.push(item);
this.position++;
while (this.stack.length > this.maxStackSize) {
this.stack.shift();
--this.position;
if (this._fireEvent) {
this._ush.dispatchEvent(new CustomEvent('undo', {detail: {transactions: this._stack[this.position - 1].slice()}, bubbles: true, cancelable: false}));
}
};
}
};
UndoManager.prototype.undo = function () {
if (this.position > 0) {
return this.stack[--this.position];
UndoManager.prototype.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--;
UndoManager.prototype.redo = function () {
if (this.position < (this.stack.length - 1)) {
return this.stack[++this.position];
if (this._fireEvent) {
this._ush.dispatchEvent(new CustomEvent('redo', {detail: {transactions: this._stack[this.position].slice()}, bubbles: true, cancelable: false}));
}
};
}
};
return UndoManager;
UndoManager.prototype.item = function (index) {
if (index >= 0 && index < this.length) {
return this._stack[index].slice();
}
return null;
};
UndoManager.prototype.clearUndo = function () {
this._stack.length = this.length = this.position;
};
UndoManager.prototype.clearRedo = function () {
this._stack.splice(0, this.position);
this.position = 0;
this.length = this._stack.length;
};
return UndoManager;
});

@@ -27,2 +27,10 @@ var chai = require('chai');

});
// Undo manager merge interval set to 0ms (default is 1000ms).
// This will avoid merging instant typing transactions as performed by these automated tests.
beforeEach(function () {
return driver.executeScript(function () {
window.scribe.options.undo.interval = 0;
});
});

@@ -29,0 +37,0 @@ givenContentOf('<p>|1</p>', function () {

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc