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 1.1.2 to 1.1.3

8

dist/src/plugins/cursor-plugin.d.ts
export function defaultCursorBuilder(user: any): HTMLElement;
export function defaultSelectionBuilder(user: any): import('prosemirror-view').DecorationAttrs;
export function createDecorations(state: any, awareness: Awareness, createCursor: any, createSelection: any): any;
export function createDecorations(state: any, awareness: Awareness, createCursor: (arg0: {
name: string;
color: string;
}) => Element, createSelection: (arg0: {
name: string;
color: string;
}) => import('prosemirror-view').DecorationAttrs): any;
export function yCursorPlugin(awareness: Awareness, { cursorBuilder, selectionBuilder, getSelection }?: {

@@ -5,0 +11,0 @@ cursorBuilder: (arg0: any) => HTMLElement;

10

package.json
{
"name": "y-prosemirror",
"version": "1.1.2",
"version": "1.1.3",
"description": "Prosemirror bindings for Yjs",

@@ -58,7 +58,7 @@ "main": "./dist/y-prosemirror.cjs",

"peerDependencies": {
"yjs": "^13.5.38",
"y-protocols": "^1.0.1",
"prosemirror-model": "^1.7.1",
"prosemirror-state": "^1.2.3",
"prosemirror-view": "^1.9.10"
"prosemirror-view": "^1.9.10",
"y-protocols": "^1.0.1",
"yjs": "^13.5.38"
},

@@ -78,3 +78,3 @@ "devDependencies": {

"rollup": "^2.59.0",
"standard": "^12.0.1",
"standard": "^17.0.0",
"typescript": "^3.9.10",

@@ -81,0 +81,0 @@ "y-protocols": "^1.0.5",

@@ -1,7 +0,10 @@

import * as Y from 'yjs'
import { Decoration, DecorationSet } from 'prosemirror-view' // eslint-disable-line
import { Plugin } from 'prosemirror-state' // eslint-disable-line
import { Awareness } from 'y-protocols/awareness' // eslint-disable-line
import { absolutePositionToRelativePosition, relativePositionToAbsolutePosition, setMeta } from '../lib.js'
import { Decoration, DecorationSet } from "prosemirror-view"; // eslint-disable-line
import { Plugin } from "prosemirror-state"; // eslint-disable-line
import { Awareness } from "y-protocols/awareness"; // eslint-disable-line
import {
absolutePositionToRelativePosition,
relativePositionToAbsolutePosition,
setMeta
} from '../lib.js'
import { yCursorPluginKey, ySyncPluginKey } from './keys.js'

@@ -17,3 +20,3 @@

*/
export const defaultCursorBuilder = user => {
export const defaultCursorBuilder = (user) => {
const cursor = document.createElement('span')

@@ -39,6 +42,6 @@ cursor.classList.add('ProseMirror-yjs-cursor')

*/
export const defaultSelectionBuilder = user => {
export const defaultSelectionBuilder = (user) => {
return {
style: `background-color: ${user.color}70`,
class: `ProseMirror-yjs-selection`
class: 'ProseMirror-yjs-selection'
}

@@ -52,9 +55,19 @@ }

* @param {Awareness} awareness
* @param {function({ name: string, color: string }):Element} createCursor
* @param {function({ name: string, color: string }):import('prosemirror-view').DecorationAttrs} createSelection
* @return {any} DecorationSet
*/
export const createDecorations = (state, awareness, createCursor, createSelection) => {
export const createDecorations = (
state,
awareness,
createCursor,
createSelection
) => {
const ystate = ySyncPluginKey.getState(state)
const y = ystate.doc
const decorations = []
if (ystate.snapshot != null || ystate.prevSnapshot != null || ystate.binding === null) {
if (
ystate.snapshot != null || ystate.prevSnapshot != null ||
ystate.binding === null
) {
// do not render cursors while snapshot is active

@@ -78,4 +91,14 @@ return DecorationSet.create(state.doc, [])

}
let anchor = relativePositionToAbsolutePosition(y, ystate.type, Y.createRelativePositionFromJSON(aw.cursor.anchor), ystate.binding.mapping)
let head = relativePositionToAbsolutePosition(y, ystate.type, Y.createRelativePositionFromJSON(aw.cursor.head), ystate.binding.mapping)
let anchor = relativePositionToAbsolutePosition(
y,
ystate.type,
Y.createRelativePositionFromJSON(aw.cursor.anchor),
ystate.binding.mapping
)
let head = relativePositionToAbsolutePosition(
y,
ystate.type,
Y.createRelativePositionFromJSON(aw.cursor.head),
ystate.binding.mapping
)
if (anchor !== null && head !== null) {

@@ -85,6 +108,16 @@ const maxsize = math.max(state.doc.content.size - 1, 0)

head = math.min(head, maxsize)
decorations.push(Decoration.widget(head, () => createCursor(user), { key: clientId + '', side: 10 }))
decorations.push(
Decoration.widget(head, () => createCursor(user), {
key: clientId + '',
side: 10
})
)
const from = math.min(anchor, head)
const to = math.max(anchor, head)
decorations.push(Decoration.inline(from, to, createSelection(user), { inclusiveEnd: true, inclusiveStart: false }))
decorations.push(
Decoration.inline(from, to, createSelection(user), {
inclusiveEnd: true,
inclusiveStart: false
})
)
}

@@ -109,69 +142,118 @@ }

*/
export const yCursorPlugin = (awareness, { cursorBuilder = defaultCursorBuilder, selectionBuilder = defaultSelectionBuilder, getSelection = state => state.selection } = {}, cursorStateField = 'cursor') => new Plugin({
key: yCursorPluginKey,
state: {
init (_, state) {
return createDecorations(state, awareness, cursorBuilder, selectionBuilder)
export const yCursorPlugin = (
awareness,
{
cursorBuilder = defaultCursorBuilder,
selectionBuilder = defaultSelectionBuilder,
getSelection = (state) => state.selection
} = {},
cursorStateField = 'cursor'
) =>
new Plugin({
key: yCursorPluginKey,
state: {
init (_, state) {
return createDecorations(
state,
awareness,
cursorBuilder,
selectionBuilder
)
},
apply (tr, prevState, _oldState, newState) {
const ystate = ySyncPluginKey.getState(newState)
const yCursorState = tr.getMeta(yCursorPluginKey)
if (
(ystate && ystate.isChangeOrigin) ||
(yCursorState && yCursorState.awarenessUpdated)
) {
return createDecorations(
newState,
awareness,
cursorBuilder,
selectionBuilder
)
}
return prevState.map(tr.mapping, tr.doc)
}
},
apply (tr, prevState, oldState, newState) {
const ystate = ySyncPluginKey.getState(newState)
const yCursorState = tr.getMeta(yCursorPluginKey)
if ((ystate && ystate.isChangeOrigin) || (yCursorState && yCursorState.awarenessUpdated)) {
return createDecorations(newState, awareness, cursorBuilder, selectionBuilder)
props: {
decorations: (state) => {
return yCursorPluginKey.getState(state)
}
return prevState.map(tr.mapping, tr.doc)
}
},
props: {
decorations: state => {
return yCursorPluginKey.getState(state)
}
},
view: view => {
const awarenessListener = () => {
// @ts-ignore
if (view.docView) {
setMeta(view, yCursorPluginKey, { awarenessUpdated: true })
},
view: (view) => {
const awarenessListener = () => {
// @ts-ignore
if (view.docView) {
setMeta(view, yCursorPluginKey, { awarenessUpdated: true })
}
}
}
const updateCursorInfo = () => {
const ystate = ySyncPluginKey.getState(view.state)
// @note We make implicit checks when checking for the cursor property
const current = awareness.getLocalState() || {}
if (ystate.binding == null) {
return
const updateCursorInfo = () => {
const ystate = ySyncPluginKey.getState(view.state)
// @note We make implicit checks when checking for the cursor property
const current = awareness.getLocalState() || {}
if (ystate.binding == null) {
return
}
if (view.hasFocus()) {
const selection = getSelection(view.state)
/**
* @type {Y.RelativePosition}
*/
const anchor = absolutePositionToRelativePosition(
selection.anchor,
ystate.type,
ystate.binding.mapping
)
/**
* @type {Y.RelativePosition}
*/
const head = absolutePositionToRelativePosition(
selection.head,
ystate.type,
ystate.binding.mapping
)
if (
current.cursor == null ||
!Y.compareRelativePositions(
Y.createRelativePositionFromJSON(current.cursor.anchor),
anchor
) ||
!Y.compareRelativePositions(
Y.createRelativePositionFromJSON(current.cursor.head),
head
)
) {
awareness.setLocalStateField(cursorStateField, {
anchor,
head
})
}
} else if (
current.cursor != null &&
relativePositionToAbsolutePosition(
ystate.doc,
ystate.type,
Y.createRelativePositionFromJSON(current.cursor.anchor),
ystate.binding.mapping
) !== null
) {
// delete cursor information if current cursor information is owned by this editor binding
awareness.setLocalStateField(cursorStateField, null)
}
}
if (view.hasFocus()) {
const selection = getSelection(view.state)
/**
* @type {Y.RelativePosition}
*/
const anchor = absolutePositionToRelativePosition(selection.anchor, ystate.type, ystate.binding.mapping)
/**
* @type {Y.RelativePosition}
*/
const head = absolutePositionToRelativePosition(selection.head, ystate.type, ystate.binding.mapping)
if (current.cursor == null || !Y.compareRelativePositions(Y.createRelativePositionFromJSON(current.cursor.anchor), anchor) || !Y.compareRelativePositions(Y.createRelativePositionFromJSON(current.cursor.head), head)) {
awareness.setLocalStateField(cursorStateField, {
anchor, head
})
awareness.on('change', awarenessListener)
view.dom.addEventListener('focusin', updateCursorInfo)
view.dom.addEventListener('focusout', updateCursorInfo)
return {
update: updateCursorInfo,
destroy: () => {
view.dom.removeEventListener('focusin', updateCursorInfo)
view.dom.removeEventListener('focusout', updateCursorInfo)
awareness.off('change', awarenessListener)
awareness.setLocalStateField(cursorStateField, null)
}
} else if (current.cursor != null && relativePositionToAbsolutePosition(ystate.doc, ystate.type, Y.createRelativePositionFromJSON(current.cursor.anchor), ystate.binding.mapping) !== null) {
// delete cursor information if current cursor information is owned by this editor binding
awareness.setLocalStateField(cursorStateField, null)
}
}
awareness.on('change', awarenessListener)
view.dom.addEventListener('focusin', updateCursorInfo)
view.dom.addEventListener('focusout', updateCursorInfo)
return {
update: updateCursorInfo,
destroy: () => {
view.dom.removeEventListener('focusin', updateCursorInfo)
view.dom.removeEventListener('focusout', updateCursorInfo)
awareness.off('change', awarenessListener)
awareness.setLocalStateField(cursorStateField, null)
}
}
}
})
})

@@ -7,3 +7,3 @@ /**

import * as PModel from 'prosemirror-model'
import { Plugin, TextSelection } from 'prosemirror-state' // eslint-disable-line
import { Plugin, TextSelection } from "prosemirror-state"; // eslint-disable-line
import * as math from 'lib0/math'

@@ -16,3 +16,6 @@ import * as object from 'lib0/object'

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

@@ -27,3 +30,8 @@ import * as environment from 'lib0/environment'

*/
export const isVisible = (item, snapshot) => snapshot === undefined ? !item.deleted : (snapshot.sv.has(item.id.client) && /** @type {number} */ (snapshot.sv.get(item.id.client)) > item.id.clock && !Y.isDeleted(snapshot.ds, item.id))
export const isVisible = (item, snapshot) =>
snapshot === undefined
? !item.deleted
: (snapshot.sv.has(item.id.client) && /** @type {number} */
(snapshot.sv.get(item.id.client)) > item.id.clock &&
!Y.isDeleted(snapshot.ds, item.id))

@@ -65,4 +73,4 @@ /**

const usedColors = set.create()
colorMapping.forEach(color => usedColors.add(color))
colors = colors.filter(color => !usedColors.has(color))
colorMapping.forEach((color) => usedColors.add(color))
colors = colors.filter((color) => !usedColors.has(color))
}

@@ -99,3 +107,3 @@ colorMapping.set(user, random.oneOf(colors))

state: {
init: (initargs, state) => {
init: (_initargs, _state) => {
return {

@@ -124,14 +132,28 @@ type: yXmlFragment,

// always set isChangeOrigin. If undefined, this is not change origin.
pluginState.isChangeOrigin = change !== undefined && !!change.isChangeOrigin
pluginState.isChangeOrigin = change !== undefined &&
!!change.isChangeOrigin
if (pluginState.binding !== null) {
if (change !== undefined && (change.snapshot != null || change.prevSnapshot != null)) {
if (
change !== undefined &&
(change.snapshot != null || change.prevSnapshot != null)
) {
// snapshot changed, rerender next
eventloop.timeout(0, () => {
if (pluginState.binding == null || pluginState.binding.isDestroyed) {
if (
pluginState.binding == null || pluginState.binding.isDestroyed
) {
return
}
if (change.restore == null) {
pluginState.binding._renderSnapshot(change.snapshot, change.prevSnapshot, pluginState)
pluginState.binding._renderSnapshot(
change.snapshot,
change.prevSnapshot,
pluginState
)
} else {
pluginState.binding._renderSnapshot(change.snapshot, change.snapshot, pluginState)
pluginState.binding._renderSnapshot(
change.snapshot,
change.snapshot,
pluginState
)
// reset to current prosemirror state

@@ -141,3 +163,7 @@ delete pluginState.restore

delete pluginState.prevSnapshot
pluginState.binding._prosemirrorChanged(pluginState.binding.prosemirrorView.state.doc)
pluginState.binding.mux(() => {
pluginState.binding._prosemirrorChanged(
pluginState.binding.prosemirrorView.state.doc
)
})
}

@@ -150,3 +176,3 @@ })

},
view: view => {
view: (view) => {
const binding = new ProsemirrorBinding(yXmlFragment, view)

@@ -165,6 +191,16 @@ if (rerenderTimeout != null) {

const pluginState = plugin.getState(view.state)
if (pluginState.snapshot == null && pluginState.prevSnapshot == null) {
if (changedInitialContent || view.state.doc.content.findDiffStart(view.state.doc.type.createAndFill().content) !== null) {
if (
pluginState.snapshot == null && pluginState.prevSnapshot == null
) {
if (
changedInitialContent ||
view.state.doc.content.findDiffStart(
view.state.doc.type.createAndFill().content
) !== null
) {
changedInitialContent = true
if (pluginState.addToHistory === false && !pluginState.isChangeOrigin) {
if (
pluginState.addToHistory === false &&
!pluginState.isChangeOrigin
) {
const yUndoPluginState = yUndoPluginKey.getState(view.state)

@@ -179,6 +215,8 @@ /**

}
pluginState.doc.transact(tr => {
tr.meta.set('addToHistory', pluginState.addToHistory)
binding._prosemirrorChanged(view.state.doc)
}, ySyncPluginKey)
binding.mux(() => {
pluginState.doc.transact((tr) => {
tr.meta.set('addToHistory', pluginState.addToHistory)
binding._prosemirrorChanged(view.state.doc)
}, ySyncPluginKey)
})
}

@@ -204,4 +242,14 @@ }

if (relSel !== null && relSel.anchor !== null && relSel.head !== null) {
const anchor = relativePositionToAbsolutePosition(binding.doc, binding.type, relSel.anchor, binding.mapping)
const head = relativePositionToAbsolutePosition(binding.doc, binding.type, relSel.head, binding.mapping)
const anchor = relativePositionToAbsolutePosition(
binding.doc,
binding.type,
relSel.anchor,
binding.mapping
)
const head = relativePositionToAbsolutePosition(
binding.doc,
binding.type,
relSel.head,
binding.mapping
)
if (anchor !== null && head !== null) {

@@ -214,4 +262,12 @@ tr = tr.setSelection(TextSelection.create(tr.doc, anchor, head))

export const getRelativeSelection = (pmbinding, state) => ({
anchor: absolutePositionToRelativePosition(state.selection.anchor, pmbinding.type, pmbinding.mapping),
head: absolutePositionToRelativePosition(state.selection.head, pmbinding.type, pmbinding.mapping)
anchor: absolutePositionToRelativePosition(
state.selection.anchor,
pmbinding.type,
pmbinding.mapping
),
head: absolutePositionToRelativePosition(
state.selection.head,
pmbinding.type,
pmbinding.mapping
)
})

@@ -250,3 +306,6 @@

if (this.beforeTransactionSelection === null) {
this.beforeTransactionSelection = getRelativeSelection(this, prosemirrorView.state)
this.beforeTransactionSelection = getRelativeSelection(
this,
prosemirrorView.state
)
}

@@ -308,3 +367,4 @@ }

return bounding.bottom >= 0 && bounding.right >= 0 &&
bounding.left <= (window.innerWidth || documentElement.clientWidth || 0) &&
bounding.left <=
(window.innerWidth || documentElement.clientWidth || 0) &&
bounding.top <= (window.innerHeight || documentElement.clientHeight || 0)

@@ -317,3 +377,5 @@ }

}
this.prosemirrorView.dispatch(this._tr.setMeta(ySyncPluginKey, { snapshot, prevSnapshot }))
this.prosemirrorView.dispatch(
this._tr.setMeta(ySyncPluginKey, { snapshot, prevSnapshot })
)
}

@@ -324,5 +386,15 @@

this.mux(() => {
const fragmentContent = this.type.toArray().map(t => createNodeFromYElement(/** @type {Y.XmlElement} */ (t), this.prosemirrorView.state.schema, this.mapping)).filter(n => n !== null)
const fragmentContent = this.type.toArray().map((t) =>
createNodeFromYElement(
/** @type {Y.XmlElement} */ (t),
this.prosemirrorView.state.schema,
this.mapping
)
).filter((n) => n !== null)
// @ts-ignore
const tr = this._tr.replace(0, this.prosemirrorView.state.doc.content.size, new PModel.Slice(new PModel.Fragment(fragmentContent), 0, 0))
const tr = this._tr.replace(
0,
this.prosemirrorView.state.doc.content.size,
new PModel.Slice(PModel.Fragment.from(fragmentContent), 0, 0)
)
tr.setMeta(ySyncPluginKey, { snapshot: null, prevSnapshot: null })

@@ -336,6 +408,18 @@ this.prosemirrorView.dispatch(tr)

this.mux(() => {
const fragmentContent = this.type.toArray().map(t => createNodeFromYElement(/** @type {Y.XmlElement} */ (t), this.prosemirrorView.state.schema, this.mapping)).filter(n => n !== null)
const fragmentContent = this.type.toArray().map((t) =>
createNodeFromYElement(
/** @type {Y.XmlElement} */ (t),
this.prosemirrorView.state.schema,
this.mapping
)
).filter((n) => n !== null)
// @ts-ignore
const tr = this._tr.replace(0, this.prosemirrorView.state.doc.content.size, new PModel.Slice(new PModel.Fragment(fragmentContent), 0, 0))
this.prosemirrorView.dispatch(tr.setMeta(ySyncPluginKey, { isChangeOrigin: true }))
const tr = this._tr.replace(
0,
this.prosemirrorView.state.doc.content.size,
new PModel.Slice(PModel.Fragment.from(fragmentContent), 0, 0)
)
this.prosemirrorView.dispatch(
tr.setMeta(ySyncPluginKey, { isChangeOrigin: true })
)
})

@@ -356,3 +440,3 @@ }

this.mux(() => {
this.doc.transact(transaction => {
this.doc.transact((transaction) => {
// before rendering, we are going to sanitize ops and split deleted ops

@@ -362,18 +446,41 @@ // if they were deleted by seperate users.

if (pud) {
pud.dss.forEach(ds => {
Y.iterateDeletedStructs(transaction, ds, item => {})
pud.dss.forEach((ds) => {
Y.iterateDeletedStructs(transaction, ds, (_item) => {})
})
}
/**
* @param {'removed'|'added'} type
* @param {Y.ID} id
*/
const computeYChange = (type, id) => {
const user = type === 'added' ? pud.getUserByClientId(id.client) : pud.getUserByDeletedId(id)
const user = type === 'added'
? pud.getUserByClientId(id.client)
: pud.getUserByDeletedId(id)
return {
user,
type,
color: getUserColor(pluginState.colorMapping, pluginState.colors, user)
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 => {
if (!t._item.deleted || isVisible(t._item, snapshot) || isVisible(t._item, prevSnapshot)) {
return createNodeFromYElement(t, this.prosemirrorView.state.schema, new Map(), snapshot, prevSnapshot, computeYChange)
const fragmentContent = Y.typeListToArraySnapshot(
this.type,
new Y.Snapshot(prevSnapshot.ds, snapshot.sv)
).map((t) => {
if (
!t._item.deleted || isVisible(t._item, snapshot) ||
isVisible(t._item, prevSnapshot)
) {
return createNodeFromYElement(
t,
this.prosemirrorView.state.schema,
new Map(),
snapshot,
prevSnapshot,
computeYChange
)
} else {

@@ -384,6 +491,12 @@ // No need to render elements that are not visible by either snapshot.

}
}).filter(n => n !== null)
}).filter((n) => n !== null)
// @ts-ignore
const tr = this._tr.replace(0, this.prosemirrorView.state.doc.content.size, new PModel.Slice(new PModel.Fragment(fragmentContent), 0, 0))
this.prosemirrorView.dispatch(tr.setMeta(ySyncPluginKey, { isChangeOrigin: true }))
const tr = this._tr.replace(
0,
this.prosemirrorView.state.doc.content.size,
new PModel.Slice(PModel.Fragment.from(fragmentContent), 0, 0)
)
this.prosemirrorView.dispatch(
tr.setMeta(ySyncPluginKey, { isChangeOrigin: true })
)
}, ySyncPluginKey)

@@ -399,3 +512,6 @@ })

const syncState = ySyncPluginKey.getState(this.prosemirrorView.state)
if (events.length === 0 || syncState.snapshot != null || syncState.prevSnapshot != null) {
if (
events.length === 0 || syncState.snapshot != null ||
syncState.prevSnapshot != null
) {
// drop out if snapshot is active

@@ -411,11 +527,32 @@ this.renderSnapshot(syncState.snapshot, syncState.prevSnapshot)

const delType = (_, type) => this.mapping.delete(type)
Y.iterateDeletedStructs(transaction, transaction.deleteSet, 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)
transaction.changedParentTypes.forEach(delType)
const fragmentContent = this.type.toArray().map(t => createNodeIfNotExists(/** @type {Y.XmlElement | Y.XmlHook} */ (t), this.prosemirrorView.state.schema, this.mapping)).filter(n => n !== null)
const fragmentContent = this.type.toArray().map((t) =>
createNodeIfNotExists(
/** @type {Y.XmlElement | Y.XmlHook} */ (t),
this.prosemirrorView.state.schema,
this.mapping
)
).filter((n) => n !== null)
// @ts-ignore
let tr = this._tr.replace(0, this.prosemirrorView.state.doc.content.size, new PModel.Slice(new PModel.Fragment(fragmentContent), 0, 0))
let tr = this._tr.replace(
0,
this.prosemirrorView.state.doc.content.size,
new PModel.Slice(PModel.Fragment.from(fragmentContent), 0, 0)
)
restoreRelativeSelection(tr, this.beforeTransactionSelection, this)
tr = tr.setMeta(ySyncPluginKey, { isChangeOrigin: true })
if (this.beforeTransactionSelection !== null && this._isLocalCursorInView()) {
if (
this.beforeTransactionSelection !== null && this._isLocalCursorInView()
) {
tr.scrollIntoView()

@@ -428,8 +565,9 @@ }

_prosemirrorChanged (doc) {
this.mux(() => {
this.doc.transact(tr => {
updateYFragment(this.doc, this.type, doc, this.mapping)
this.beforeTransactionSelection = getRelativeSelection(this, this.prosemirrorView.state)
}, ySyncPluginKey)
})
this.doc.transact((tr) => {
updateYFragment(this.doc, this.type, doc, this.mapping)
this.beforeTransactionSelection = getRelativeSelection(
this,
this.prosemirrorView.state
)
}, ySyncPluginKey)
}

@@ -455,7 +593,21 @@

*/
const createNodeIfNotExists = (el, schema, mapping, snapshot, prevSnapshot, computeYChange) => {
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, computeYChange)
return createNodeFromYElement(
el,
schema,
mapping,
snapshot,
prevSnapshot,
computeYChange
)
} else {

@@ -478,7 +630,21 @@ throw error.methodUnimplemented() // we are currently not handling hooks

*/
const createNodeFromYElement = (el, schema, mapping, snapshot, prevSnapshot, computeYChange) => {
const createNodeFromYElement = (
el,
schema,
mapping,
snapshot,
prevSnapshot,
computeYChange
) => {
const children = []
const createChildren = type => {
const createChildren = (type) => {
if (type.constructor === Y.XmlElement) {
const n = createNodeIfNotExists(type, schema, mapping, snapshot, prevSnapshot, computeYChange)
const n = createNodeIfNotExists(
type,
schema,
mapping,
snapshot,
prevSnapshot,
computeYChange
)
if (n !== null) {

@@ -488,5 +654,12 @@ children.push(n)

} else {
const ns = createTextNodesFromYText(type, schema, mapping, snapshot, prevSnapshot, computeYChange)
const ns = createTextNodesFromYText(
type,
schema,
mapping,
snapshot,
prevSnapshot,
computeYChange
)
if (ns !== null) {
ns.forEach(textchild => {
ns.forEach((textchild) => {
if (textchild !== null) {

@@ -502,3 +675,4 @@ children.push(textchild)

} else {
Y.typeListToArraySnapshot(el, new Y.Snapshot(prevSnapshot.ds, snapshot.sv)).forEach(createChildren)
Y.typeListToArraySnapshot(el, new Y.Snapshot(prevSnapshot.ds, snapshot.sv))
.forEach(createChildren)
}

@@ -509,5 +683,9 @@ try {

if (!isVisible(/** @type {Y.Item} */ (el._item), snapshot)) {
attrs.ychange = computeYChange ? computeYChange('removed', /** @type {Y.Item} */ (el._item).id) : { type: '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 = computeYChange ? computeYChange('added', /** @type {Y.Item} */ (el._item).id) : { type: 'added' }
attrs.ychange = computeYChange
? computeYChange('added', /** @type {Y.Item} */ (el._item).id)
: { type: 'added' }
}

@@ -520,3 +698,3 @@ }

// an error occured while creating the node. This is probably a result of a concurrent action.
/** @type {Y.Doc} */ (el.doc).transact(transaction => {
/** @type {Y.Doc} */ (el.doc).transact((transaction) => {
/** @type {Y.Item} */ (el._item).delete(transaction)

@@ -539,3 +717,10 @@ }, ySyncPluginKey)

*/
const createTextNodesFromYText = (text, schema, mapping, snapshot, prevSnapshot, computeYChange) => {
const createTextNodesFromYText = (
text,
schema,
mapping,
snapshot,
prevSnapshot,
computeYChange
) => {
const nodes = []

@@ -554,3 +739,3 @@ const deltas = text.toDelta(snapshot, prevSnapshot, computeYChange)

// an error occured while creating the node. This is probably a result of a concurrent action.
/** @type {Y.Doc} */ (text.doc).transact(transaction => {
/** @type {Y.Doc} */ (text.doc).transact((transaction) => {
/** @type {Y.Item} */ (text._item).delete(transaction)

@@ -572,3 +757,3 @@ }, ySyncPluginKey)

const type = new Y.XmlText()
const delta = nodes.map(node => ({
const delta = nodes.map((node) => ({
// @ts-ignore

@@ -597,3 +782,8 @@ insert: node.text,

}
type.insert(0, normalizePNodeContent(node).map(n => createTypeFromTextOrElementNode(n, mapping)))
type.insert(
0,
normalizePNodeContent(node).map((n) =>
createTypeFromTextOrElementNode(n, mapping)
)
)
mapping.set(type, node)

@@ -609,3 +799,6 @@ return type

*/
const createTypeFromTextOrElementNode = (node, mapping) => node instanceof Array ? createTypeFromTextNodes(node, mapping) : createTypeFromElementNode(node, mapping)
const createTypeFromTextOrElementNode = (node, mapping) =>
node instanceof Array
? createTypeFromTextNodes(node, mapping)
: createTypeFromElementNode(node, mapping)

@@ -615,4 +808,6 @@ const isObject = (val) => typeof val === 'object' && val !== null

const equalAttrs = (pattrs, yattrs) => {
const keys = Object.keys(pattrs).filter(key => pattrs[key] !== null)
let eq = keys.length === Object.keys(yattrs).filter(key => yattrs[key] !== null).length
const keys = Object.keys(pattrs).filter((key) => pattrs[key] !== null)
let eq =
keys.length ===
Object.keys(yattrs).filter((key) => yattrs[key] !== null).length
for (let i = 0; i < keys.length && eq; i++) {

@@ -622,3 +817,4 @@ const key = keys[i]

const r = yattrs[key]
eq = key === 'ychange' || l === r || (isObject(l) && isObject(r) && equalAttrs(l, r))
eq = key === 'ychange' || l === r ||
(isObject(l) && isObject(r) && equalAttrs(l, r))
}

@@ -636,3 +832,3 @@ return eq

*/
const normalizePNodeContent = pnode => {
const normalizePNodeContent = (pnode) => {
const c = pnode.content.content

@@ -662,3 +858,10 @@ const res = []

const delta = ytext.toDelta()
return delta.length === ptexts.length && delta.every((d, i) => d.insert === /** @type {any} */ (ptexts[i]).text && object.keys(d.attributes || {}).length === ptexts[i].marks.length && ptexts[i].marks.every(mark => equalAttrs(d.attributes[mark.type.name] || {}, mark.attrs)))
return delta.length === ptexts.length &&
delta.every((d, i) =>
d.insert === /** @type {any} */ (ptexts[i]).text &&
object.keys(d.attributes || {}).length === ptexts[i].marks.length &&
ptexts[i].marks.every((mark) =>
equalAttrs(d.attributes[mark.type.name] || {}, mark.attrs)
)
)
}

@@ -671,7 +874,15 @@

const equalYTypePNode = (ytype, pnode) => {
if (ytype instanceof Y.XmlElement && !(pnode instanceof Array) && matchNodeName(ytype, pnode)) {
if (
ytype instanceof Y.XmlElement && !(pnode instanceof Array) &&
matchNodeName(ytype, pnode)
) {
const normalizedContent = normalizePNodeContent(pnode)
return ytype._length === normalizedContent.length && equalAttrs(ytype.getAttributes(), pnode.attrs) && ytype.toArray().every((ychild, i) => equalYTypePNode(ychild, normalizedContent[i]))
return ytype._length === normalizedContent.length &&
equalAttrs(ytype.getAttributes(), pnode.attrs) &&
ytype.toArray().every((ychild, i) =>
equalYTypePNode(ychild, normalizedContent[i])
)
}
return ytype instanceof Y.XmlText && pnode instanceof Array && equalYTextPText(ytype, pnode)
return ytype instanceof Y.XmlText && pnode instanceof Array &&
equalYTextPText(ytype, pnode)
}

@@ -683,3 +894,8 @@

*/
const mappedIdentity = (mapped, pcontent) => mapped === pcontent || (mapped instanceof Array && pcontent instanceof Array && mapped.length === pcontent.length && mapped.every((a, i) => pcontent[i] === a))
const mappedIdentity = (mapped, pcontent) =>
mapped === pcontent ||
(mapped instanceof Array && pcontent instanceof Array &&
mapped.length === pcontent.length && mapped.every((a, i) =>
pcontent[i] === a
))

@@ -705,3 +921,3 @@ /**

if (mappedIdentity(mapping.get(leftY), leftP)) {
foundMappedChild = true// definite (good) match!
foundMappedChild = true // definite (good) match!
} else if (!equalYTypePNode(leftY, leftP)) {

@@ -726,3 +942,3 @@ break

const ytextTrans = ytext => {
const ytextTrans = (ytext) => {
let str = ''

@@ -760,12 +976,20 @@ /**

const { nAttrs, str } = ytextTrans(ytext)
const content = ptexts.map(p => ({ insert: /** @type {any} */ (p).text, attributes: Object.assign({}, nAttrs, marksToAttributes(p.marks)) }))
const { insert, remove, index } = simpleDiff(str, content.map(c => c.insert).join(''))
const content = ptexts.map((p) => ({
insert: /** @type {any} */ (p).text,
attributes: Object.assign({}, nAttrs, marksToAttributes(p.marks))
}))
const { insert, remove, index } = simpleDiff(
str,
content.map((c) => c.insert).join('')
)
ytext.delete(index, remove)
ytext.insert(index, insert)
ytext.applyDelta(content.map(c => ({ retain: c.insert.length, attributes: c.attributes })))
ytext.applyDelta(
content.map((c) => ({ retain: c.insert.length, attributes: c.attributes }))
)
}
const marksToAttributes = marks => {
const marksToAttributes = (marks) => {
const pattrs = {}
marks.forEach(mark => {
marks.forEach((mark) => {
if (mark.type.name !== 'ychange') {

@@ -786,3 +1010,6 @@ pattrs[mark.type.name] = mark.attrs

export const updateYFragment = (y, yDomFragment, pNode, mapping) => {
if (yDomFragment instanceof Y.XmlElement && yDomFragment.nodeName !== pNode.type.name) {
if (
yDomFragment instanceof Y.XmlElement &&
yDomFragment.nodeName !== pNode.type.name
) {
throw new Error('node name mismatch!')

@@ -820,3 +1047,3 @@ }

// find number of matching elements from left
for (;left < minCnt; left++) {
for (; left < minCnt; left++) {
const leftY = yChildren[left]

@@ -834,3 +1061,3 @@ const leftP = pChildren[left]

// find number of matching elements from right
for (;right + left + 1 < minCnt; right++) {
for (; right + left + 1 < minCnt; right++) {
const rightY = yChildren[yChildCnt - right - 1]

@@ -860,13 +1087,29 @@ const rightP = pChildren[pChildCnt - right - 1]

} else {
let updateLeft = leftY instanceof Y.XmlElement && matchNodeName(leftY, leftP)
let updateRight = rightY instanceof Y.XmlElement && matchNodeName(rightY, rightP)
let updateLeft = leftY instanceof Y.XmlElement &&
matchNodeName(leftY, leftP)
let updateRight = rightY instanceof Y.XmlElement &&
matchNodeName(rightY, rightP)
if (updateLeft && updateRight) {
// decide which which element to update
const equalityLeft = computeChildEqualityFactor(/** @type {Y.XmlElement} */ (leftY), /** @type {PModel.Node} */ (leftP), mapping)
const equalityRight = computeChildEqualityFactor(/** @type {Y.XmlElement} */ (rightY), /** @type {PModel.Node} */ (rightP), mapping)
if (equalityLeft.foundMappedChild && !equalityRight.foundMappedChild) {
const equalityLeft = computeChildEqualityFactor(
/** @type {Y.XmlElement} */ (leftY),
/** @type {PModel.Node} */ (leftP),
mapping
)
const equalityRight = computeChildEqualityFactor(
/** @type {Y.XmlElement} */ (rightY),
/** @type {PModel.Node} */ (rightP),
mapping
)
if (
equalityLeft.foundMappedChild && !equalityRight.foundMappedChild
) {
updateRight = false
} else if (!equalityLeft.foundMappedChild && equalityRight.foundMappedChild) {
} else if (
!equalityLeft.foundMappedChild && equalityRight.foundMappedChild
) {
updateLeft = false
} else if (equalityLeft.equalityFactor < equalityRight.equalityFactor) {
} else if (
equalityLeft.equalityFactor < equalityRight.equalityFactor
) {
updateLeft = false

@@ -878,10 +1121,22 @@ } else {

if (updateLeft) {
updateYFragment(y, /** @type {Y.XmlFragment} */ (leftY), /** @type {PModel.Node} */ (leftP), mapping)
updateYFragment(
y,
/** @type {Y.XmlFragment} */ (leftY),
/** @type {PModel.Node} */ (leftP),
mapping
)
left += 1
} else if (updateRight) {
updateYFragment(y, /** @type {Y.XmlFragment} */ (rightY), /** @type {PModel.Node} */ (rightP), mapping)
updateYFragment(
y,
/** @type {Y.XmlFragment} */ (rightY),
/** @type {PModel.Node} */ (rightP),
mapping
)
right += 1
} else {
yDomFragment.delete(left, 1)
yDomFragment.insert(left, [createTypeFromTextOrElementNode(leftP, mapping)])
yDomFragment.insert(left, [
createTypeFromTextOrElementNode(leftP, mapping)
])
left += 1

@@ -892,3 +1147,5 @@ }

const yDelLen = yChildCnt - left - right
if (yChildCnt === 1 && pChildCnt === 0 && yChildren[0] instanceof Y.XmlText) {
if (
yChildCnt === 1 && pChildCnt === 0 && yChildren[0] instanceof Y.XmlText
) {
// Edge case handling https://github.com/yjs/y-prosemirror/issues/108

@@ -915,2 +1172,3 @@ // Only delete the content of the Y.Text to retain remote changes on the same Y.Text object

*/
const matchNodeName = (yElement, pNode) => !(pNode instanceof Array) && yElement.nodeName === pNode.type.name
const matchNodeName = (yElement, pNode) =>
!(pNode instanceof Array) && yElement.nodeName === pNode.type.name

@@ -5,3 +5,5 @@ export * from './plugins/cursor-plugin.js'

export * from './plugins/keys.js'
export { absolutePositionToRelativePosition, relativePositionToAbsolutePosition, setMeta, prosemirrorJSONToYDoc, yDocToProsemirrorJSON, yDocToProsemirror, prosemirrorToYDoc,
prosemirrorJSONToYXmlFragment, yXmlFragmentToProsemirrorJSON, yXmlFragmentToProsemirror, prosemirrorToYXmlFragment } from './lib.js'
export {
absolutePositionToRelativePosition, relativePositionToAbsolutePosition, setMeta, prosemirrorJSONToYDoc, yDocToProsemirrorJSON, yDocToProsemirror, prosemirrorToYDoc,
prosemirrorJSONToYXmlFragment, yXmlFragmentToProsemirrorJSON, yXmlFragmentToProsemirror, prosemirrorToYXmlFragment
} from './lib.js'

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