From 407c2438392f10ac3d7c4e97669f7ed467b21506 Mon Sep 17 00:00:00 2001 From: Kevin Jahns Date: Thu, 14 May 2020 15:31:27 +0200 Subject: [PATCH] add utility setMeta function --- src/lib.js | 32 ++++++++++++++++++++++++++++++++ src/plugins/cursor-plugin.js | 20 ++++++++++---------- src/y-prosemirror.js | 2 +- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/src/lib.js b/src/lib.js index 285fcc7..7054d79 100644 --- a/src/lib.js +++ b/src/lib.js @@ -1,7 +1,39 @@ import { ProsemirrorMapping } from './plugins/sync-plugin.js' // eslint-disable-line import * as Y from 'yjs' +// eslint-disable-next-line +import { EditorView } from 'prosemirror-view' import * as error from 'lib0/error.js' +import * as map from 'lib0/map.js' +import * as eventloop from 'lib0/eventloop.js' + +/** + * Is null if no timeout is in progress. + * Is defined if a timeout is in progress. + * Maps from view + * @type {Map>|null} + */ +let viewsToUpdate = null + +const updateMetas = () => { + const ups = /** @type {Map>} */ (viewsToUpdate) + viewsToUpdate = null + ups.forEach((metas, view) => { + const tr = view.state.tr + metas.forEach((val, key) => { + tr.setMeta(key, val) + }) + view.dispatch(tr) + }) +} + +export const setMeta = (view, key, value) => { + if (!viewsToUpdate) { + viewsToUpdate = new Map() + eventloop.timeout(0, updateMetas) + } + map.setIfUndefined(viewsToUpdate, view, map.create).set(key, value) +} /** * Transforms a Prosemirror based absolute position to a Yjs Cursor (relative position in the Yjs model). diff --git a/src/plugins/cursor-plugin.js b/src/plugins/cursor-plugin.js index c2e3529..049af19 100644 --- a/src/plugins/cursor-plugin.js +++ b/src/plugins/cursor-plugin.js @@ -4,7 +4,7 @@ import { Decoration, DecorationSet } from 'prosemirror-view' // eslint-disable-l import { Plugin, PluginKey } from 'prosemirror-state' // eslint-disable-line import { Awareness } from 'y-protocols/awareness.js' // eslint-disable-line import { ySyncPluginKey } from './sync-plugin.js' -import { absolutePositionToRelativePosition, relativePositionToAbsolutePosition } from '../lib.js' +import { absolutePositionToRelativePosition, relativePositionToAbsolutePosition, setMeta } from '../lib.js' import * as math from 'lib0/math.js' @@ -81,9 +81,10 @@ export const createDecorations = (state, awareness, createCursor) => { * @param {Awareness} awareness * @param {object} [opts] * @param {function(any):HTMLElement} [opts.cursorBuilder] + * @param {function(any):any} [opts.getSelection] * @return {any} */ -export const yCursorPlugin = (awareness, { cursorBuilder = defaultCursorBuilder } = {}) => new Plugin({ +export const yCursorPlugin = (awareness, { cursorBuilder = defaultCursorBuilder, getSelection = state => state.selection } = {}) => new Plugin({ key: yCursorPluginKey, state: { init (_, state) { @@ -105,26 +106,25 @@ export const yCursorPlugin = (awareness, { cursorBuilder = defaultCursorBuilder }, view: view => { const awarenessListener = () => { - setTimeout(() => { - // @ts-ignore - if (view.docView) { - view.dispatch(view.state.tr.setMeta(yCursorPluginKey, { awarenessUpdated: true })) - } - }) + // @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 (view.hasFocus() && ystate.binding !== null) { + const selection = getSelection(view.state) /** * @type {Y.RelativePosition} */ - const anchor = absolutePositionToRelativePosition(view.state.selection.anchor, ystate.type, ystate.binding.mapping) + const anchor = absolutePositionToRelativePosition(selection.anchor, ystate.type, ystate.binding.mapping) /** * @type {Y.RelativePosition} */ - const head = absolutePositionToRelativePosition(view.state.selection.head, ystate.type, ystate.binding.mapping) + 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('cursor', { anchor, head diff --git a/src/y-prosemirror.js b/src/y-prosemirror.js index de63dfb..05fc662 100644 --- a/src/y-prosemirror.js +++ b/src/y-prosemirror.js @@ -1,4 +1,4 @@ export * from './plugins/cursor-plugin.js' export * from './plugins/sync-plugin.js' export * from './plugins/undo-plugin.js' -export { absolutePositionToRelativePosition, relativePositionToAbsolutePosition } from './lib.js' +export { absolutePositionToRelativePosition, relativePositionToAbsolutePosition, setMeta } from './lib.js'