Initial
This commit is contained in:
8
resources/app/node_modules/prosemirror-collab/.tern-project
generated
vendored
Normal file
8
resources/app/node_modules/prosemirror-collab/.tern-project
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"libs": ["browser"],
|
||||
"plugins": {
|
||||
"node": {},
|
||||
"complete_strings": {},
|
||||
"es_modules": {}
|
||||
}
|
||||
}
|
||||
104
resources/app/node_modules/prosemirror-collab/CONTRIBUTING.md
generated
vendored
Normal file
104
resources/app/node_modules/prosemirror-collab/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
# How to contribute
|
||||
|
||||
- [Getting help](#getting-help)
|
||||
- [Submitting bug reports](#submitting-bug-reports)
|
||||
- [Contributing code](#contributing-code)
|
||||
|
||||
## Getting help
|
||||
|
||||
Community discussion, questions, and informal bug reporting is done on the
|
||||
[discuss.ProseMirror forum](http://discuss.prosemirror.net).
|
||||
|
||||
## Submitting bug reports
|
||||
|
||||
Report bugs on the
|
||||
[GitHub issue tracker](http://github.com/prosemirror/prosemirror/issues).
|
||||
Before reporting a bug, please read these pointers.
|
||||
|
||||
- The issue tracker is for *bugs*, not requests for help. Questions
|
||||
should be asked on the [forum](http://discuss.prosemirror.net).
|
||||
|
||||
- Include information about the version of the code that exhibits the
|
||||
problem. For browser-related issues, include the browser and browser
|
||||
version on which the problem occurred.
|
||||
|
||||
- Mention very precisely what went wrong. "X is broken" is not a good
|
||||
bug report. What did you expect to happen? What happened instead?
|
||||
Describe the exact steps a maintainer has to take to make the
|
||||
problem occur. A screencast can be useful, but is no substitute for
|
||||
a textual description.
|
||||
|
||||
- A great way to make it easy to reproduce your problem, if it can not
|
||||
be trivially reproduced on the website demos, is to submit a script
|
||||
that triggers the issue.
|
||||
|
||||
## Contributing code
|
||||
|
||||
If you want to make a change that involves a significant overhaul of
|
||||
the code or introduces a user-visible new feature, create an
|
||||
[RFC](https://github.com/ProseMirror/rfcs/) first with your proposal.
|
||||
|
||||
- Make sure you have a [GitHub Account](https://github.com/signup/free)
|
||||
|
||||
- Fork the relevant repository
|
||||
([how to fork a repo](https://help.github.com/articles/fork-a-repo))
|
||||
|
||||
- Create a local checkout of the code. You can use the
|
||||
[main repository](https://github.com/prosemirror/prosemirror) to
|
||||
easily check out all core modules.
|
||||
|
||||
- Make your changes, and commit them
|
||||
|
||||
- Follow the code style of the rest of the project (see below). Run
|
||||
`npm run lint` (in the main repository checkout) to make sure that
|
||||
the linter is happy.
|
||||
|
||||
- If your changes are easy to test or likely to regress, add tests in
|
||||
the relevant `test/` directory. Either put them in an existing
|
||||
`test-*.js` file, if they fit there, or add a new file.
|
||||
|
||||
- Make sure all tests pass. Run `npm run test` to verify tests pass
|
||||
(you will need Node.js v6+).
|
||||
|
||||
- Submit a pull request ([how to create a pull request](https://help.github.com/articles/fork-a-repo)).
|
||||
Don't put more than one feature/fix in a single pull request.
|
||||
|
||||
By contributing code to ProseMirror you
|
||||
|
||||
- Agree to license the contributed code under the project's [MIT
|
||||
license](https://github.com/ProseMirror/prosemirror/blob/master/LICENSE).
|
||||
|
||||
- Confirm that you have the right to contribute and license the code
|
||||
in question. (Either you hold all rights on the code, or the rights
|
||||
holder has explicitly granted the right to use it like this,
|
||||
through a compatible open source license or through a direct
|
||||
agreement with you.)
|
||||
|
||||
### Coding standards
|
||||
|
||||
- ES6 syntax, targeting an ES5 runtime (i.e. don't use library
|
||||
elements added by ES6, don't use ES7/ES.next syntax).
|
||||
|
||||
- 2 spaces per indentation level, no tabs.
|
||||
|
||||
- No semicolons except when necessary.
|
||||
|
||||
- Follow the surrounding code when it comes to spacing, brace
|
||||
placement, etc.
|
||||
|
||||
- Brace-less single-statement bodies are encouraged (whenever they
|
||||
don't impact readability).
|
||||
|
||||
- [getdocs](https://github.com/marijnh/getdocs)-style doc comments
|
||||
above items that are part of the public API.
|
||||
|
||||
- When documenting non-public items, you can put the type after a
|
||||
single colon, so that getdocs doesn't pick it up and add it to the
|
||||
API reference.
|
||||
|
||||
- The linter (`npm run lint`) complains about unused variables and
|
||||
functions. Prefix their names with an underscore to muffle it.
|
||||
|
||||
- ProseMirror does *not* follow JSHint or JSLint prescribed style.
|
||||
Patches that try to 'fix' code to pass one of these linters will not
|
||||
be accepted.
|
||||
19
resources/app/node_modules/prosemirror-collab/LICENSE
generated
vendored
Normal file
19
resources/app/node_modules/prosemirror-collab/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (C) 2015-2017 by Marijn Haverbeke <marijn@haverbeke.berlin> and others
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
155
resources/app/node_modules/prosemirror-collab/dist/index.cjs
generated
vendored
Normal file
155
resources/app/node_modules/prosemirror-collab/dist/index.cjs
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
'use strict';
|
||||
|
||||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
||||
|
||||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
Object.defineProperty(exports, '__esModule', {
|
||||
value: true
|
||||
});
|
||||
|
||||
var prosemirrorState = require('prosemirror-state');
|
||||
|
||||
var Rebaseable = _createClass(function Rebaseable(step, inverted, origin) {
|
||||
_classCallCheck(this, Rebaseable);
|
||||
|
||||
this.step = step;
|
||||
this.inverted = inverted;
|
||||
this.origin = origin;
|
||||
});
|
||||
|
||||
function rebaseSteps(steps, over, transform) {
|
||||
for (var i = steps.length - 1; i >= 0; i--) {
|
||||
transform.step(steps[i].inverted);
|
||||
}
|
||||
|
||||
for (var _i = 0; _i < over.length; _i++) {
|
||||
transform.step(over[_i]);
|
||||
}
|
||||
|
||||
var result = [];
|
||||
|
||||
for (var _i2 = 0, mapFrom = steps.length; _i2 < steps.length; _i2++) {
|
||||
var mapped = steps[_i2].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[_i2].origin));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var CollabState = _createClass(function CollabState(version, unconfirmed) {
|
||||
_classCallCheck(this, CollabState);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
var collabKey = new prosemirrorState.PluginKey("collab");
|
||||
|
||||
function collab() {
|
||||
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
||||
var conf = {
|
||||
version: config.version || 0,
|
||||
clientID: config.clientID == null ? Math.floor(Math.random() * 0xFFFFFFFF) : config.clientID
|
||||
};
|
||||
return new prosemirrorState.Plugin({
|
||||
key: collabKey,
|
||||
state: {
|
||||
init: function init() {
|
||||
return new CollabState(conf.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: conf,
|
||||
historyPreserveItems: true
|
||||
});
|
||||
}
|
||||
|
||||
function receiveTransaction(state, steps, clientIDs) {
|
||||
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
||||
var collabState = collabKey.getState(state);
|
||||
var version = collabState.version + steps.length;
|
||||
var ourID = collabKey.get(state).spec.config.clientID;
|
||||
var ours = 0;
|
||||
|
||||
while (ours < clientIDs.length && clientIDs[ours] == ourID) {
|
||||
++ours;
|
||||
}
|
||||
|
||||
var unconfirmed = collabState.unconfirmed.slice(ours);
|
||||
steps = ours ? steps.slice(ours) : steps;
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}));
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
function getVersion(state) {
|
||||
return collabKey.getState(state).version;
|
||||
}
|
||||
|
||||
exports.collab = collab;
|
||||
exports.getVersion = getVersion;
|
||||
exports.rebaseSteps = rebaseSteps;
|
||||
exports.receiveTransaction = receiveTransaction;
|
||||
exports.sendableSteps = sendableSteps;
|
||||
60
resources/app/node_modules/prosemirror-collab/dist/index.d.cts
generated
vendored
Normal file
60
resources/app/node_modules/prosemirror-collab/dist/index.d.cts
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
import { Plugin, EditorState, Transaction } from 'prosemirror-state';
|
||||
import { Step } from 'prosemirror-transform';
|
||||
|
||||
declare type CollabConfig = {
|
||||
/**
|
||||
The starting version number of the collaborative editing.
|
||||
Defaults to 0.
|
||||
*/
|
||||
version?: number;
|
||||
/**
|
||||
This client's ID, used to distinguish its changes from those of
|
||||
other clients. Defaults to a random 32-bit number.
|
||||
*/
|
||||
clientID?: number | string;
|
||||
};
|
||||
/**
|
||||
Creates a plugin that enables the collaborative editing framework
|
||||
for the editor.
|
||||
*/
|
||||
declare function collab(config?: CollabConfig): Plugin;
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
declare function receiveTransaction(state: EditorState, steps: readonly Step[], clientIDs: readonly (string | number)[], options?: {
|
||||
/**
|
||||
When enabled (the default is `false`), if the current
|
||||
selection is a [text selection](https://prosemirror.net/docs/ref/#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.
|
||||
*/
|
||||
mapSelectionBackward?: boolean;
|
||||
}): 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.
|
||||
*/
|
||||
declare function sendableSteps(state: EditorState): {
|
||||
version: number;
|
||||
steps: readonly Step[];
|
||||
clientID: number | string;
|
||||
origins: readonly Transaction[];
|
||||
} | null;
|
||||
/**
|
||||
Get the version up to which the collab plugin has synced with the
|
||||
central authority.
|
||||
*/
|
||||
declare function getVersion(state: EditorState): number;
|
||||
|
||||
export { collab, getVersion, receiveTransaction, sendableSteps };
|
||||
156
resources/app/node_modules/prosemirror-collab/dist/index.js
generated
vendored
Normal file
156
resources/app/node_modules/prosemirror-collab/dist/index.js
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
import { PluginKey, Plugin, TextSelection } from 'prosemirror-state';
|
||||
|
||||
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 (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;
|
||||
}
|
||||
// This state field accumulates changes that have to be sent to the
|
||||
// central authority in the collaborating group and makes it possible
|
||||
// to integrate changes made by peers into our local document. It is
|
||||
// defined by the plugin, and will be available as the `collab` field
|
||||
// in the resulting editor state.
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
},
|
||||
config: conf,
|
||||
// This is used to notify the history plugin to not merge steps,
|
||||
// so that the history can be rebased.
|
||||
historyPreserveItems: true
|
||||
});
|
||||
}
|
||||
/**
|
||||
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.
|
||||
|
||||
`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) {
|
||||
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));
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
Get the version up to which the collab plugin has synced with the
|
||||
central authority.
|
||||
*/
|
||||
function getVersion(state) {
|
||||
return collabKey.getState(state).version;
|
||||
}
|
||||
|
||||
export { collab, getVersion, rebaseSteps, receiveTransaction, sendableSteps };
|
||||
36
resources/app/node_modules/prosemirror-collab/package.json
generated
vendored
Normal file
36
resources/app/node_modules/prosemirror-collab/package.json
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "prosemirror-collab",
|
||||
"version": "1.3.1",
|
||||
"description": "Collaborative editing for ProseMirror",
|
||||
"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",
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "Marijn Haverbeke",
|
||||
"email": "marijn@haverbeke.berlin",
|
||||
"web": "http://marijnhaverbeke.nl"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/prosemirror/prosemirror-collab.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@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"
|
||||
}
|
||||
}
|
||||
11
resources/app/node_modules/prosemirror-collab/src/README.md
generated
vendored
Normal file
11
resources/app/node_modules/prosemirror-collab/src/README.md
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
This module implements an API into which a communication channel for
|
||||
collaborative editing can be hooked. See
|
||||
[the guide](/docs/guide/#collab) for more details and an example.
|
||||
|
||||
@collab
|
||||
|
||||
@getVersion
|
||||
|
||||
@receiveTransaction
|
||||
|
||||
@sendableSteps
|
||||
184
resources/app/node_modules/prosemirror-collab/src/collab.ts
generated
vendored
Normal file
184
resources/app/node_modules/prosemirror-collab/src/collab.ts
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
import {Plugin, PluginKey, TextSelection, EditorState, Transaction} from "prosemirror-state"
|
||||
import {Step, Transform} from "prosemirror-transform"
|
||||
|
||||
class Rebaseable {
|
||||
constructor(
|
||||
readonly step: Step,
|
||||
readonly inverted: Step,
|
||||
readonly origin: Transform
|
||||
) {}
|
||||
}
|
||||
|
||||
/// Undo a given set of steps, apply a set of other steps, and then
|
||||
/// redo them @internal
|
||||
export function rebaseSteps(steps: readonly Rebaseable[], over: readonly Step[], transform: Transform) {
|
||||
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
|
||||
}
|
||||
|
||||
// This state field accumulates changes that have to be sent to the
|
||||
// central authority in the collaborating group and makes it possible
|
||||
// to integrate changes made by peers into our local document. It is
|
||||
// defined by the plugin, and will be available as the `collab` field
|
||||
// in the resulting editor state.
|
||||
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.
|
||||
readonly version: number,
|
||||
// The local steps that havent been successfully sent to the
|
||||
// server yet.
|
||||
readonly unconfirmed: readonly Rebaseable[]
|
||||
) {}
|
||||
}
|
||||
|
||||
function unconfirmedFrom(transform: Transform) {
|
||||
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
|
||||
}
|
||||
|
||||
const collabKey = new PluginKey("collab")
|
||||
|
||||
type CollabConfig = {
|
||||
/// The starting version number of the collaborative editing.
|
||||
/// Defaults to 0.
|
||||
version?: number
|
||||
|
||||
/// This client's ID, used to distinguish its changes from those of
|
||||
/// other clients. Defaults to a random 32-bit number.
|
||||
clientID?: number | string
|
||||
}
|
||||
|
||||
/// Creates a plugin that enables the collaborative editing framework
|
||||
/// for the editor.
|
||||
export function collab(config: CollabConfig = {}): Plugin {
|
||||
let conf: Required<CollabConfig> = {
|
||||
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
|
||||
}
|
||||
},
|
||||
|
||||
config: conf,
|
||||
|
||||
// This is used to notify the history plugin to not merge steps,
|
||||
// so that the history can be rebased.
|
||||
historyPreserveItems: true
|
||||
})
|
||||
}
|
||||
|
||||
/// 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.
|
||||
export function receiveTransaction(
|
||||
state: EditorState,
|
||||
steps: readonly Step[],
|
||||
clientIDs: readonly (string | number)[],
|
||||
options: {
|
||||
/// 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.
|
||||
mapSelectionBackward?: boolean
|
||||
} = {}
|
||||
) {
|
||||
// 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: string | number = (collabKey.get(state)!.spec as any).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 as any).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.
|
||||
///
|
||||
/// `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.
|
||||
export function sendableSteps(state: EditorState): {
|
||||
version: number,
|
||||
steps: readonly Step[],
|
||||
clientID: number | string,
|
||||
origins: readonly Transaction[]
|
||||
} | null {
|
||||
let collabState = collabKey.getState(state) as CollabState
|
||||
if (collabState.unconfirmed.length == 0) return null
|
||||
return {
|
||||
version: collabState.version,
|
||||
steps: collabState.unconfirmed.map(s => s.step),
|
||||
clientID: (collabKey.get(state)!.spec as any).config.clientID,
|
||||
get origins() {
|
||||
return (this as any)._origins || ((this as any)._origins = collabState.unconfirmed.map(s => s.origin))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the version up to which the collab plugin has synced with the
|
||||
/// central authority.
|
||||
export function getVersion(state: EditorState): number {
|
||||
return collabKey.getState(state).version
|
||||
}
|
||||
Reference in New Issue
Block a user