Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

prosemirror-collab

Package Overview
Dependencies
Maintainers
1
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

prosemirror-collab - npm Package Compare versions

Comparing version 1.2.2 to 1.3.0-beta.1

dist/index.cjs

10

CHANGELOG.md

@@ -47,3 +47,3 @@ ## 1.2.2 (2019-11-20)

[`sendableSteps`](http://prosemirror.net/docs/ref/version/0.18.0.html#collab.sendableSteps) now also returns information about the original transactions that produced the steps.
[`sendableSteps`](https://prosemirror.net/docs/ref/version/0.18.0.html#collab.sendableSteps) now also returns information about the original transactions that produced the steps.

@@ -56,4 +56,4 @@ ## 0.11.0 (2016-09-21)

Interface [adjusted](http://prosemirror.net/docs/ref/version/0.11.0.html#collab) to work with the new
[plugin](http://prosemirror.net/docs/ref/version/0.11.0.html#state.Plugin) system.
Interface [adjusted](https://prosemirror.net/docs/ref/version/0.11.0.html#collab) to work with the new
[plugin](https://prosemirror.net/docs/ref/version/0.11.0.html#state.Plugin) system.

@@ -63,6 +63,6 @@ ### New features

When receiving changes, the module now
[generates](http://prosemirror.net/docs/ref/version/0.11.0.html#collab.receiveAction) a regular
[transform action](http://prosemirror.net/docs/ref/version/0.11.0.html#state.TransformAction) instead of hard-setting
[generates](https://prosemirror.net/docs/ref/version/0.11.0.html#collab.receiveAction) a regular
[transform action](https://prosemirror.net/docs/ref/version/0.11.0.html#state.TransformAction) instead of hard-setting
the editor's document. This solves problematic corner cases for code
keeping track of the document by listening to transform actions.

@@ -1,31 +0,30 @@

'use strict';
import { PluginKey, Plugin, TextSelection } from 'prosemirror-state';
Object.defineProperty(exports, '__esModule', { value: true });
var prosemirrorState = require('prosemirror-state');
var Rebaseable = function Rebaseable(step, inverted, origin) {
this.step = step;
this.inverted = inverted;
this.origin = origin;
};
// : ([Rebaseable], [Step], Transform) → [Rebaseable]
// Undo a given set of steps, apply a set of other steps, and then
// redo them.
class Rebaseable {
constructor(step, inverted, origin) {
this.step = step;
this.inverted = inverted;
this.origin = origin;
}
}
/**
Undo a given set of steps, apply a set of other steps, and then
redo them @internal
*/
function rebaseSteps(steps, over, transform) {
for (var i = steps.length - 1; i >= 0; i--) { transform.step(steps[i].inverted); }
for (var i$1 = 0; i$1 < over.length; i$1++) { transform.step(over[i$1]); }
var result = [];
for (var i$2 = 0, mapFrom = steps.length; i$2 < steps.length; i$2++) {
var mapped = steps[i$2].step.map(transform.mapping.slice(mapFrom));
mapFrom--;
if (mapped && !transform.maybeStep(mapped).failed) {
transform.mapping.setMirror(mapFrom, transform.steps.length - 1);
result.push(new Rebaseable(mapped, mapped.invert(transform.docs[transform.docs.length - 1]), steps[i$2].origin));
for (let i = steps.length - 1; i >= 0; i--)
transform.step(steps[i].inverted);
for (let i = 0; i < over.length; i++)
transform.step(over[i]);
let result = [];
for (let i = 0, mapFrom = steps.length; i < steps.length; i++) {
let mapped = steps[i].step.map(transform.mapping.slice(mapFrom));
mapFrom--;
if (mapped && !transform.maybeStep(mapped).failed) {
transform.mapping.setMirror(mapFrom, transform.steps.length - 1);
result.push(new Rebaseable(mapped, mapped.invert(transform.docs[transform.docs.length - 1]), steps[i].origin));
}
}
}
return result
return result;
}
// This state field accumulates changes that have to be sent to the

@@ -36,154 +35,124 @@ // central authority in the collaborating group and makes it possible

// in the resulting editor state.
var CollabState = function CollabState(version, unconfirmed) {
// : number
// The version number of the last update received from the central
// authority. Starts at 0 or the value of the `version` property
// in the option object, for the editor's value when the option
// was enabled.
this.version = version;
// : [Rebaseable]
// The local steps that havent been successfully sent to the
// server yet.
this.unconfirmed = unconfirmed;
};
class CollabState {
constructor(
// The version number of the last update received from the central
// authority. Starts at 0 or the value of the `version` property
// in the option object, for the editor's value when the option
// was enabled.
version,
// The local steps that havent been successfully sent to the
// server yet.
unconfirmed) {
this.version = version;
this.unconfirmed = unconfirmed;
}
}
function unconfirmedFrom(transform) {
var result = [];
for (var i = 0; i < transform.steps.length; i++)
{ result.push(new Rebaseable(transform.steps[i],
transform.steps[i].invert(transform.docs[i]),
transform)); }
return result
let result = [];
for (let i = 0; i < transform.steps.length; i++)
result.push(new Rebaseable(transform.steps[i], transform.steps[i].invert(transform.docs[i]), transform));
return result;
}
var collabKey = new prosemirrorState.PluginKey("collab");
// :: (?Object) → Plugin
//
// Creates a plugin that enables the collaborative editing framework
// for the editor.
//
// config::- An optional set of options
//
// version:: ?number
// The starting version number of the collaborative editing.
// Defaults to 0.
//
// clientID:: ?union<number, string>
// This client's ID, used to distinguish its changes from those of
// other clients. Defaults to a random 32-bit number.
function collab(config) {
if ( config === void 0 ) config = {};
config = {version: config.version || 0,
clientID: config.clientID == null ? Math.floor(Math.random() * 0xFFFFFFFF) : config.clientID};
return new prosemirrorState.Plugin({
key: collabKey,
state: {
init: function () { return new CollabState(config.version, []); },
apply: function apply(tr, collab) {
var newState = tr.getMeta(collabKey);
if (newState)
{ return newState }
if (tr.docChanged)
{ return new CollabState(collab.version, collab.unconfirmed.concat(unconfirmedFrom(tr))) }
return collab
}
},
config: config,
// This is used to notify the history plugin to not merge steps,
// so that the history can be rebased.
historyPreserveItems: true
})
const collabKey = new PluginKey("collab");
/**
Creates a plugin that enables the collaborative editing framework
for the editor.
*/
function collab(config = {}) {
let conf = {
version: config.version || 0,
clientID: config.clientID == null ? Math.floor(Math.random() * 0xFFFFFFFF) : config.clientID
};
return new Plugin({
key: collabKey,
state: {
init: () => new CollabState(conf.version, []),
apply(tr, collab) {
let newState = tr.getMeta(collabKey);
if (newState)
return newState;
if (tr.docChanged)
return new CollabState(collab.version, collab.unconfirmed.concat(unconfirmedFrom(tr)));
return collab;
}
},
// @ts-ignore
config: conf,
// This is used to notify the history plugin to not merge steps,
// so that the history can be rebased.
historyPreserveItems: true
});
}
// :: (state: EditorState, steps: [Step], clientIDs: [union<number, string>], options: ?Object) → Transaction
// Create a transaction that represents a set of new steps received from
// the authority. Applying this transaction moves the state forward to
// adjust to the authority's view of the document.
//
// options::- Additional options.
//
// mapSelectionBackward:: ?boolean
// When enabled (the default is `false`), if the current selection
// is a [text selection](#state.TextSelection), its sides are
// mapped with a negative bias for this transaction, so that
// content inserted at the cursor ends up after the cursor. Users
// usually prefer this, but it isn't done by default for reasons
// of backwards compatibility.
function receiveTransaction(state, steps, clientIDs, options) {
// Pushes a set of steps (received from the central authority) into
// the editor state (which should have the collab plugin enabled).
// Will recognize its own changes, and confirm unconfirmed steps as
// appropriate. Remaining unconfirmed steps will be rebased over
// remote steps.
var collabState = collabKey.getState(state);
var version = collabState.version + steps.length;
var ourID = collabKey.get(state).spec.config.clientID;
// Find out which prefix of the steps originated with us
var ours = 0;
while (ours < clientIDs.length && clientIDs[ours] == ourID) { ++ours; }
var unconfirmed = collabState.unconfirmed.slice(ours);
steps = ours ? steps.slice(ours) : steps;
// If all steps originated with us, we're done.
if (!steps.length)
{ return state.tr.setMeta(collabKey, new CollabState(version, unconfirmed)) }
var nUnconfirmed = unconfirmed.length;
var tr = state.tr;
if (nUnconfirmed) {
unconfirmed = rebaseSteps(unconfirmed, steps, tr);
} else {
for (var i = 0; i < steps.length; i++) { tr.step(steps[i]); }
unconfirmed = [];
}
var newCollabState = new CollabState(version, unconfirmed);
if (options && options.mapSelectionBackward && state.selection instanceof prosemirrorState.TextSelection) {
tr.setSelection(prosemirrorState.TextSelection.between(tr.doc.resolve(tr.mapping.map(state.selection.anchor, -1)),
tr.doc.resolve(tr.mapping.map(state.selection.head, -1)), -1));
tr.updated &= ~1;
}
return tr.setMeta("rebased", nUnconfirmed).setMeta("addToHistory", false).setMeta(collabKey, newCollabState)
/**
Create a transaction that represents a set of new steps received from
the authority. Applying this transaction moves the state forward to
adjust to the authority's view of the document.
*/
function receiveTransaction(state, steps, clientIDs, options = {}) {
// Pushes a set of steps (received from the central authority) into
// the editor state (which should have the collab plugin enabled).
// Will recognize its own changes, and confirm unconfirmed steps as
// appropriate. Remaining unconfirmed steps will be rebased over
// remote steps.
let collabState = collabKey.getState(state);
let version = collabState.version + steps.length;
let ourID = collabKey.get(state).spec.config.clientID;
// Find out which prefix of the steps originated with us
let ours = 0;
while (ours < clientIDs.length && clientIDs[ours] == ourID)
++ours;
let unconfirmed = collabState.unconfirmed.slice(ours);
steps = ours ? steps.slice(ours) : steps;
// If all steps originated with us, we're done.
if (!steps.length)
return state.tr.setMeta(collabKey, new CollabState(version, unconfirmed));
let nUnconfirmed = unconfirmed.length;
let tr = state.tr;
if (nUnconfirmed) {
unconfirmed = rebaseSteps(unconfirmed, steps, tr);
}
else {
for (let i = 0; i < steps.length; i++)
tr.step(steps[i]);
unconfirmed = [];
}
let newCollabState = new CollabState(version, unconfirmed);
if (options && options.mapSelectionBackward && state.selection instanceof TextSelection) {
tr.setSelection(TextSelection.between(tr.doc.resolve(tr.mapping.map(state.selection.anchor, -1)), tr.doc.resolve(tr.mapping.map(state.selection.head, -1)), -1));
tr.updated &= ~1;
}
return tr.setMeta("rebased", nUnconfirmed).setMeta("addToHistory", false).setMeta(collabKey, newCollabState);
}
/**
Provides data describing the editor's unconfirmed steps, which need
to be sent to the central authority. Returns null when there is
nothing to send.
// :: (state: EditorState) → ?{version: number, steps: [Step], clientID: union<number, string>, origins: [Transaction]}
// Provides data describing the editor's unconfirmed steps, which need
// to be sent to the central authority. Returns null when there is
// nothing to send.
//
// `origins` holds the _original_ transactions that produced each
// steps. This can be useful for looking up time stamps and other
// metadata for the steps, but note that the steps may have been
// rebased, whereas the origin transactions are still the old,
// unchanged objects.
`origins` holds the _original_ transactions that produced each
steps. This can be useful for looking up time stamps and other
metadata for the steps, but note that the steps may have been
rebased, whereas the origin transactions are still the old,
unchanged objects.
*/
function sendableSteps(state) {
var collabState = collabKey.getState(state);
if (collabState.unconfirmed.length == 0) { return null }
return {
version: collabState.version,
steps: collabState.unconfirmed.map(function (s) { return s.step; }),
clientID: collabKey.get(state).spec.config.clientID,
get origins() { return this._origins || (this._origins = collabState.unconfirmed.map(function (s) { return s.origin; })) }
}
let collabState = collabKey.getState(state);
if (collabState.unconfirmed.length == 0)
return null;
return {
version: collabState.version,
steps: collabState.unconfirmed.map(s => s.step),
clientID: collabKey.get(state).spec.config.clientID,
get origins() {
return this._origins || (this._origins = collabState.unconfirmed.map(s => s.origin));
}
};
}
// :: (EditorState) → number
// Get the version up to which the collab plugin has synced with the
// central authority.
/**
Get the version up to which the collab plugin has synced with the
central authority.
*/
function getVersion(state) {
return collabKey.getState(state).version
return collabKey.getState(state).version;
}
exports.collab = collab;
exports.getVersion = getVersion;
exports.rebaseSteps = rebaseSteps;
exports.receiveTransaction = receiveTransaction;
exports.sendableSteps = sendableSteps;
//# sourceMappingURL=index.js.map
export { collab, getVersion, rebaseSteps, receiveTransaction, sendableSteps };
{
"name": "prosemirror-collab",
"version": "1.2.2",
"version": "1.3.0-beta.1",
"description": "Collaborative editing for ProseMirror",
"main": "dist/index.js",
"module": "dist/index.es.js",
"type": "module",
"main": "dist/index.cjs",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
"import": "./dist/index.js",
"require": "./dist/index.cjs"
},
"sideEffects": false,
"license": "MIT",

@@ -23,17 +30,12 @@ "maintainers": [

"devDependencies": {
"ist": "^1.0.0",
"mocha": "^3.0.2",
"@prosemirror/buildhelper": "^0.1.5",
"prosemirror-history": "^1.0.0",
"prosemirror-model": "^1.0.0",
"prosemirror-test-builder": "^1.0.0",
"prosemirror-transform": "^1.0.0",
"rollup": "^1.26.3",
"@rollup/plugin-buble": "^0.20.0"
"prosemirror-transform": "^1.0.0"
},
"scripts": {
"test": "mocha test/test-*.js",
"build": "rollup -c",
"watch": "rollup -c -w",
"prepare": "npm run build"
"test": "pm-runtests",
"prepare": "pm-buildhelper src/collab.ts"
}
}
# prosemirror-collab
[ [**WEBSITE**](http://prosemirror.net) | [**ISSUES**](https://github.com/prosemirror/prosemirror/issues) | [**FORUM**](https://discuss.prosemirror.net) | [**GITTER**](https://gitter.im/ProseMirror/prosemirror) | [**CHANGELOG**](https://github.com/ProseMirror/prosemirror-collab/blob/master/CHANGELOG.md) ]
[ [**WEBSITE**](https://prosemirror.net) | [**ISSUES**](https://github.com/prosemirror/prosemirror/issues) | [**FORUM**](https://discuss.prosemirror.net) | [**GITTER**](https://gitter.im/ProseMirror/prosemirror) | [**CHANGELOG**](https://github.com/ProseMirror/prosemirror-collab/blob/master/CHANGELOG.md) ]
This is a [core module](http://prosemirror.net/docs/ref/#collab) of [ProseMirror](http://prosemirror.net).
This is a [core module](https://prosemirror.net/docs/ref/#collab) of [ProseMirror](https://prosemirror.net).
ProseMirror is a well-behaved rich semantic content editor based on

@@ -10,9 +10,9 @@ contentEditable, with support for collaborative editing and custom

This [module](http://prosemirror.net/docs/ref/#collab) implements a
This [module](https://prosemirror.net/docs/ref/#collab) implements a
plugin that helps track and merge changes for
[collaborative editing](http://prosemirror\.net/docs/guide/#collab).
[collaborative editing](https://prosemirror.net/docs/guide/#collab).
The [project page](http://prosemirror.net) has more information, a
number of [examples](http://prosemirror.net/examples/) and the
[documentation](http://prosemirror.net/docs/).
The [project page](https://prosemirror.net) has more information, a
number of [examples](https://prosemirror.net/examples/) and the
[documentation](https://prosemirror.net/docs/).

@@ -19,0 +19,0 @@ This code is released under an

Sorry, the diff of this file is not supported yet

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