You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 7-8.RSVP
Socket
Socket
Sign inDemoInstall

y-prosemirror

Package Overview
Dependencies
Maintainers
1
Versions
68
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.1.1 to 0.1.2

131

dist/y-prosemirror.js

@@ -13,4 +13,6 @@ 'use strict';

var object = require('lib0/dist/object.js');
var set = require('lib0/dist/set.js');
var diff_js = require('lib0/dist/diff.js');
var error = require('lib0/dist/error.js');
var random = require('lib0/dist/random.js');

@@ -150,31 +152,2 @@ /**

/*
class PermanentUserData {
/**
* @param {Y.Doc} doc
* @param {string} userid
*
constructor (doc, userid) {
const users = doc.getMap('users')
this.doc = doc
this.users = users
let user = users.get(userid)
if (!user) {
user = new Y.Map()
const ids = new Y.Array()
const ds = new Y.Array()
ids.push([userid])
user.set('ids', ids)
user.set('ds', ds)
users.set(userid, user)
}
users.observe(event => {
event.changes.added.forEach(item => {
item.content.type
})
})
}
}
*/
/**

@@ -203,2 +176,39 @@ * @module bindings/prosemirror

/**
* @typedef {Object} ColorDef
* @property {string} ColorDef.light
* @property {string} ColorDef.dark
*/
/**
* @typedef {Object} YSyncOpts
* @property {Array<ColorDef>} [YSyncOpts.colors]
* @property {Map<string,ColorDef>} [YSyncOpts.colorMapping]
* @property {Y.PermanentUserData|null} [YSyncOpts.permanentUserData]
*/
/**
* @type {Array<ColorDef>}
*/
const defaultColors = [{ light: '#ecd44433', dark: '#ecd444' }];
/**
* @param {Map<string,ColorDef>} colorMapping
* @param {Array<ColorDef>} colors
* @param {string} user
* @return {ColorDef}
*/
const getUserColor = (colorMapping, colors, user) => {
// @todo do not hit the same color twice if possible
if (!colorMapping.has(user)) {
if (colorMapping.size < colors.length) {
const usedColors = set.create();
colorMapping.forEach(color => usedColors.add(color));
colors = colors.filter(color => !usedColors.has(color));
}
colorMapping.set(user, random.oneOf(colors));
}
return /** @type {ColorDef} */ (colorMapping.get(user))
};
/**
* This plugin listens to changes in prosemirror view and keeps yXmlState and view in sync.

@@ -208,5 +218,6 @@ *

* @param {Y.XmlFragment} yXmlFragment
* @param {YSyncOpts} opts
* @return {Plugin} Returns a prosemirror plugin that binds to this type
*/
const ySyncPlugin = yXmlFragment => {
const ySyncPlugin = (yXmlFragment, { colors = defaultColors, colorMapping = new Map(), permanentUserData = null } = {}) => {
let changedInitialContent = false;

@@ -226,3 +237,6 @@ const plugin = new prosemirrorState.Plugin({

prevSnapshot: null,
isChangeOrigin: false
isChangeOrigin: false,
colors,
colorMapping,
permanentUserData
}

@@ -245,5 +259,5 @@ },

if (change.restore == null) {
pluginState.binding._renderSnapshot(change.snapshot, change.prevSnapshot);
pluginState.binding._renderSnapshot(change.snapshot, change.prevSnapshot, pluginState);
} else {
pluginState.binding._renderSnapshot(change.snapshot, change.snapshot);
pluginState.binding._renderSnapshot(change.snapshot, change.snapshot, pluginState);
// reset to current prosemirror state

@@ -370,10 +384,30 @@ delete pluginState.restore;

* @param {Y.Snapshot} prevSnapshot
* @param {Object} pluginState
*/
_renderSnapshot (snapshot, prevSnapshot) {
_renderSnapshot (snapshot, prevSnapshot, pluginState) {
// clear mapping because we are going to rerender
this.mapping = new Map();
this.mux(() => {
const fragmentContent = Y.typeListToArraySnapshot(this.type, new Y.Snapshot(prevSnapshot.ds, snapshot.sv)).map(t => createNodeFromYElement(t, this.prosemirrorView.state.schema, new Map(), snapshot, prevSnapshot)).filter(n => n !== null);
const tr = this.prosemirrorView.state.tr.replace(0, this.prosemirrorView.state.doc.content.size, new PModel.Slice(new PModel.Fragment(fragmentContent), 0, 0));
this.prosemirrorView.dispatch(tr);
this.doc.transact(transaction => {
// before rendering, we are going to sanitize ops and split deleted ops
// if they were deleted by seperate users.
const pud = pluginState.permanentUserData;
if (pud) {
pud.dss.forEach(ds => {
Y.iterateDeletedStructs(transaction, ds, item => {});
});
}
const computeYChange = (type, id) => {
const user = type === 'added' ? pud.getUserByClientId(id.client) : pud.getUserByDeletedId(id);
return {
user,
type,
color: getUserColor(pluginState.colorMapping, pluginState.colors, user)
}
};
// Create document fragment and render
const fragmentContent = Y.typeListToArraySnapshot(this.type, new Y.Snapshot(prevSnapshot.ds, snapshot.sv)).map(t => createNodeFromYElement(t, this.prosemirrorView.state.schema, new Map(), snapshot, prevSnapshot, computeYChange)).filter(n => n !== null);
const tr = this.prosemirrorView.state.tr.replace(0, this.prosemirrorView.state.doc.content.size, new PModel.Slice(new PModel.Fragment(fragmentContent), 0, 0));
this.prosemirrorView.dispatch(tr);
});
});

@@ -396,3 +430,3 @@ }

const delType = (_, type) => this.mapping.delete(type);
Y.iterateDeletedStructs(transaction, transaction.deleteSet, this.doc.store, struct => struct.constructor === Y.Item && this.mapping.delete(/** @type {Y.ContentType} */ (/** @type {Y.Item} */ (struct).content).type));
Y.iterateDeletedStructs(transaction, transaction.deleteSet, struct => struct.constructor === Y.Item && this.mapping.delete(/** @type {Y.ContentType} */ (/** @type {Y.Item} */ (struct).content).type));
transaction.changed.forEach(delType);

@@ -430,9 +464,10 @@ transaction.changedParentTypes.forEach(delType);

* @param {Y.Snapshot} [prevSnapshot]
* @param {function('removed' | 'added', Y.ID):any} [computeYChange]
* @return {PModel.Node | null}
*/
const createNodeIfNotExists = (el, schema, mapping, snapshot, prevSnapshot) => {
const createNodeIfNotExists = (el, schema, mapping, snapshot, prevSnapshot, computeYChange) => {
const node = /** @type {PModel.Node} */ (mapping.get(el));
if (node === undefined) {
if (el instanceof Y.XmlElement) {
return createNodeFromYElement(el, schema, mapping, snapshot, prevSnapshot)
return createNodeFromYElement(el, schema, mapping, snapshot, prevSnapshot, computeYChange)
} else {

@@ -452,5 +487,6 @@ throw error.methodUnimplemented() // we are currently not handling hooks

* @param {Y.Snapshot} [prevSnapshot]
* @param {function('removed' | 'added', Y.ID):any} [computeYChange]
* @return {PModel.Node | null} Returns node if node could be created. Otherwise it deletes the yjs type and returns null
*/
const createNodeFromYElement = (el, schema, mapping, snapshot, prevSnapshot) => {
const createNodeFromYElement = (el, schema, mapping, snapshot, prevSnapshot, computeYChange) => {
let _snapshot = snapshot;

@@ -470,3 +506,3 @@ let _prevSnapshot = prevSnapshot;

if (type.constructor === Y.XmlElement) {
const n = createNodeIfNotExists(type, schema, mapping, _snapshot, _prevSnapshot);
const n = createNodeIfNotExists(type, schema, mapping, _snapshot, _prevSnapshot, computeYChange);
if (n !== null) {

@@ -476,3 +512,3 @@ children.push(n);

} else {
const ns = createTextNodesFromYText(type, schema, mapping, _snapshot, _prevSnapshot);
const ns = createTextNodesFromYText(type, schema, mapping, _snapshot, _prevSnapshot, computeYChange);
if (ns !== null) {

@@ -496,5 +532,5 @@ ns.forEach(textchild => {

if (!isVisible(/** @type {Y.Item} */ (el._item), snapshot)) {
attrs.ychange = { user: /** @type {Y.Item} */ (el._item).id.client, state: 'removed' };
attrs.ychange = computeYChange ? computeYChange('removed', /** @type {Y.Item} */ (el._item).id) : { type: 'removed' };
} else if (!isVisible(/** @type {Y.Item} */ (el._item), prevSnapshot)) {
attrs.ychange = { user: /** @type {Y.Item} */ (el._item).id.client, state: 'added' };
attrs.ychange = computeYChange ? computeYChange('added', /** @type {Y.Item} */ (el._item).id) : { type: 'added' };
}

@@ -522,7 +558,8 @@ }

* @param {Y.Snapshot} [prevSnapshot]
* @param {function('removed' | 'added', Y.ID):any} [computeYChange]
* @return {Array<PModel.Node>|null}
*/
const createTextNodesFromYText = (text, schema, mapping, snapshot, prevSnapshot) => {
const createTextNodesFromYText = (text, schema, mapping, snapshot, prevSnapshot, computeYChange) => {
const nodes = [];
const deltas = text.toDelta(snapshot, prevSnapshot);
const deltas = text.toDelta(snapshot, prevSnapshot, computeYChange);
try {

@@ -529,0 +566,0 @@ for (let i = 0; i < deltas.length; i++) {

{
"name": "y-prosemirror",
"version": "0.1.1",
"version": "0.1.2",
"description": "Prosemirror bindings for Yjs",

@@ -41,6 +41,6 @@ "main": "./dist/y-prosemirror.js",

"dependencies": {
"lib0": "^0.1.0"
"lib0": "^0.1.1"
},
"peerDependencies": {
"yjs": ">=13.0.0-97",
"yjs": ">=13.0.0-98",
"y-protocols": "^0.1.0",

@@ -64,4 +64,4 @@ "prosemirror-model": "^1.7.0",

"y-protocols": "^0.1.0",
"yjs": "13.0.0-97"
"yjs": "13.0.0-98"
}
}

@@ -139,30 +139,1 @@ import { ProsemirrorMapping } from './plugins/sync-plugin.js' // eslint-disable-line

}
/*
class PermanentUserData {
/**
* @param {Y.Doc} doc
* @param {string} userid
*
constructor (doc, userid) {
const users = doc.getMap('users')
this.doc = doc
this.users = users
let user = users.get(userid)
if (!user) {
user = new Y.Map()
const ids = new Y.Array()
const ds = new Y.Array()
ids.push([userid])
user.set('ids', ids)
user.set('ds', ds)
users.set(userid, user)
}
users.observe(event => {
event.changes.added.forEach(item => {
item.content.type
})
})
}
}
*/

@@ -11,2 +11,3 @@ /**

import * as object from 'lib0/object.js'
import * as set from 'lib0/set.js'
import { simpleDiff } from 'lib0/diff.js'

@@ -16,2 +17,3 @@ import * as error from 'lib0/error.js'

import { absolutePositionToRelativePosition, relativePositionToAbsolutePosition } from '../lib.js'
import * as random from 'lib0/random.js'

@@ -37,2 +39,39 @@ /**

/**
* @typedef {Object} ColorDef
* @property {string} ColorDef.light
* @property {string} ColorDef.dark
*/
/**
* @typedef {Object} YSyncOpts
* @property {Array<ColorDef>} [YSyncOpts.colors]
* @property {Map<string,ColorDef>} [YSyncOpts.colorMapping]
* @property {Y.PermanentUserData|null} [YSyncOpts.permanentUserData]
*/
/**
* @type {Array<ColorDef>}
*/
const defaultColors = [{ light: '#ecd44433', dark: '#ecd444' }]
/**
* @param {Map<string,ColorDef>} colorMapping
* @param {Array<ColorDef>} colors
* @param {string} user
* @return {ColorDef}
*/
const getUserColor = (colorMapping, colors, user) => {
// @todo do not hit the same color twice if possible
if (!colorMapping.has(user)) {
if (colorMapping.size < colors.length) {
const usedColors = set.create()
colorMapping.forEach(color => usedColors.add(color))
colors = colors.filter(color => !usedColors.has(color))
}
colorMapping.set(user, random.oneOf(colors))
}
return /** @type {ColorDef} */ (colorMapping.get(user))
}
/**
* This plugin listens to changes in prosemirror view and keeps yXmlState and view in sync.

@@ -42,5 +81,6 @@ *

* @param {Y.XmlFragment} yXmlFragment
* @param {YSyncOpts} opts
* @return {Plugin} Returns a prosemirror plugin that binds to this type
*/
export const ySyncPlugin = yXmlFragment => {
export const ySyncPlugin = (yXmlFragment, { colors = defaultColors, colorMapping = new Map(), permanentUserData = null } = {}) => {
let changedInitialContent = false

@@ -60,3 +100,6 @@ const plugin = new Plugin({

prevSnapshot: null,
isChangeOrigin: false
isChangeOrigin: false,
colors,
colorMapping,
permanentUserData
}

@@ -79,5 +122,5 @@ },

if (change.restore == null) {
pluginState.binding._renderSnapshot(change.snapshot, change.prevSnapshot)
pluginState.binding._renderSnapshot(change.snapshot, change.prevSnapshot, pluginState)
} else {
pluginState.binding._renderSnapshot(change.snapshot, change.snapshot)
pluginState.binding._renderSnapshot(change.snapshot, change.snapshot, pluginState)
// reset to current prosemirror state

@@ -204,10 +247,30 @@ delete pluginState.restore

* @param {Y.Snapshot} prevSnapshot
* @param {Object} pluginState
*/
_renderSnapshot (snapshot, prevSnapshot) {
_renderSnapshot (snapshot, prevSnapshot, pluginState) {
// clear mapping because we are going to rerender
this.mapping = new Map()
this.mux(() => {
const fragmentContent = Y.typeListToArraySnapshot(this.type, new Y.Snapshot(prevSnapshot.ds, snapshot.sv)).map(t => createNodeFromYElement(t, this.prosemirrorView.state.schema, new Map(), snapshot, prevSnapshot)).filter(n => n !== null)
const tr = this.prosemirrorView.state.tr.replace(0, this.prosemirrorView.state.doc.content.size, new PModel.Slice(new PModel.Fragment(fragmentContent), 0, 0))
this.prosemirrorView.dispatch(tr)
this.doc.transact(transaction => {
// before rendering, we are going to sanitize ops and split deleted ops
// if they were deleted by seperate users.
const pud = pluginState.permanentUserData
if (pud) {
pud.dss.forEach(ds => {
Y.iterateDeletedStructs(transaction, ds, item => {})
})
}
const computeYChange = (type, id) => {
const user = type === 'added' ? pud.getUserByClientId(id.client) : pud.getUserByDeletedId(id)
return {
user,
type,
color: getUserColor(pluginState.colorMapping, pluginState.colors, user)
}
}
// Create document fragment and render
const fragmentContent = Y.typeListToArraySnapshot(this.type, new Y.Snapshot(prevSnapshot.ds, snapshot.sv)).map(t => createNodeFromYElement(t, this.prosemirrorView.state.schema, new Map(), snapshot, prevSnapshot, computeYChange)).filter(n => n !== null)
const tr = this.prosemirrorView.state.tr.replace(0, this.prosemirrorView.state.doc.content.size, new PModel.Slice(new PModel.Fragment(fragmentContent), 0, 0))
this.prosemirrorView.dispatch(tr)
})
})

@@ -230,3 +293,3 @@ }

const delType = (_, type) => this.mapping.delete(type)
Y.iterateDeletedStructs(transaction, transaction.deleteSet, this.doc.store, struct => struct.constructor === Y.Item && this.mapping.delete(/** @type {Y.ContentType} */ (/** @type {Y.Item} */ (struct).content).type))
Y.iterateDeletedStructs(transaction, transaction.deleteSet, struct => struct.constructor === Y.Item && this.mapping.delete(/** @type {Y.ContentType} */ (/** @type {Y.Item} */ (struct).content).type))
transaction.changed.forEach(delType)

@@ -264,9 +327,10 @@ transaction.changedParentTypes.forEach(delType)

* @param {Y.Snapshot} [prevSnapshot]
* @param {function('removed' | 'added', Y.ID):any} [computeYChange]
* @return {PModel.Node | null}
*/
export const createNodeIfNotExists = (el, schema, mapping, snapshot, prevSnapshot) => {
export const createNodeIfNotExists = (el, schema, mapping, snapshot, prevSnapshot, computeYChange) => {
const node = /** @type {PModel.Node} */ (mapping.get(el))
if (node === undefined) {
if (el instanceof Y.XmlElement) {
return createNodeFromYElement(el, schema, mapping, snapshot, prevSnapshot)
return createNodeFromYElement(el, schema, mapping, snapshot, prevSnapshot, computeYChange)
} else {

@@ -286,5 +350,6 @@ throw error.methodUnimplemented() // we are currently not handling hooks

* @param {Y.Snapshot} [prevSnapshot]
* @param {function('removed' | 'added', Y.ID):any} [computeYChange]
* @return {PModel.Node | null} Returns node if node could be created. Otherwise it deletes the yjs type and returns null
*/
export const createNodeFromYElement = (el, schema, mapping, snapshot, prevSnapshot) => {
export const createNodeFromYElement = (el, schema, mapping, snapshot, prevSnapshot, computeYChange) => {
let _snapshot = snapshot

@@ -304,3 +369,3 @@ let _prevSnapshot = prevSnapshot

if (type.constructor === Y.XmlElement) {
const n = createNodeIfNotExists(type, schema, mapping, _snapshot, _prevSnapshot)
const n = createNodeIfNotExists(type, schema, mapping, _snapshot, _prevSnapshot, computeYChange)
if (n !== null) {

@@ -310,3 +375,3 @@ children.push(n)

} else {
const ns = createTextNodesFromYText(type, schema, mapping, _snapshot, _prevSnapshot)
const ns = createTextNodesFromYText(type, schema, mapping, _snapshot, _prevSnapshot, computeYChange)
if (ns !== null) {

@@ -330,5 +395,5 @@ ns.forEach(textchild => {

if (!isVisible(/** @type {Y.Item} */ (el._item), snapshot)) {
attrs.ychange = { user: /** @type {Y.Item} */ (el._item).id.client, state: 'removed' }
attrs.ychange = computeYChange ? computeYChange('removed', /** @type {Y.Item} */ (el._item).id) : { type: 'removed' }
} else if (!isVisible(/** @type {Y.Item} */ (el._item), prevSnapshot)) {
attrs.ychange = { user: /** @type {Y.Item} */ (el._item).id.client, state: 'added' }
attrs.ychange = computeYChange ? computeYChange('added', /** @type {Y.Item} */ (el._item).id) : { type: 'added' }
}

@@ -356,7 +421,8 @@ }

* @param {Y.Snapshot} [prevSnapshot]
* @param {function('removed' | 'added', Y.ID):any} [computeYChange]
* @return {Array<PModel.Node>|null}
*/
export const createTextNodesFromYText = (text, schema, mapping, snapshot, prevSnapshot) => {
export const createTextNodesFromYText = (text, schema, mapping, snapshot, prevSnapshot, computeYChange) => {
const nodes = []
const deltas = text.toDelta(snapshot, prevSnapshot)
const deltas = text.toDelta(snapshot, prevSnapshot, computeYChange)
try {

@@ -363,0 +429,0 @@ for (let i = 0; i < deltas.length; i++) {

Sorry, the diff of this file is too big to display

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc