added prosemirror binding
This commit is contained in:
		
							parent
							
								
									e8060de914
								
							
						
					
					
						commit
						32b8fac37f
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -2,7 +2,7 @@ node_modules
 | 
				
			|||||||
bower_components
 | 
					bower_components
 | 
				
			||||||
docs
 | 
					docs
 | 
				
			||||||
/y.*
 | 
					/y.*
 | 
				
			||||||
/examples/yjs-dist.js*
 | 
					/examples/*/index.dist.*
 | 
				
			||||||
.vscode
 | 
					.vscode
 | 
				
			||||||
.yjsPersisted
 | 
					.yjsPersisted
 | 
				
			||||||
build
 | 
					build
 | 
				
			||||||
							
								
								
									
										67
									
								
								bindings/BindMapping.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								bindings/BindMapping.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,67 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Type that maps from Yjs type to Target type.
 | 
				
			||||||
 | 
					 * Used to implement double bindings.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @template Y
 | 
				
			||||||
 | 
					 * @template T
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export default class BindMapping {
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  constructor () {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @type Map<Y, T>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    this.yt = new Map()
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @type Map<T, Y>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    this.ty = new Map()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Map y to t. Removes all existing bindings from y and t
 | 
				
			||||||
 | 
					   * @param {Y} y
 | 
				
			||||||
 | 
					   * @param {T} t
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  bind (y, t) {
 | 
				
			||||||
 | 
					    const existingT = this.yt.get(y)
 | 
				
			||||||
 | 
					    if (existingT !== undefined) {
 | 
				
			||||||
 | 
					      this.ty.delete(existingT)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const existingY = this.ty.get(t)
 | 
				
			||||||
 | 
					    if (existingY !== undefined) {
 | 
				
			||||||
 | 
					      this.yt.delete(existingY)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.yt.set(y, t)
 | 
				
			||||||
 | 
					    this.ty.set(t, y)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * @param {Y} y
 | 
				
			||||||
 | 
					   * @return {boolean}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  hasY (y) {
 | 
				
			||||||
 | 
					    return this.yt.has(y)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * @param {T} t
 | 
				
			||||||
 | 
					   * @return {boolean}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  hasT (t) {
 | 
				
			||||||
 | 
					    return this.ty.has(t)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * @param {Y} y
 | 
				
			||||||
 | 
					   * @return {T}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  getY (y) {
 | 
				
			||||||
 | 
					    return this.yt.get(y)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * @param {T} t
 | 
				
			||||||
 | 
					   * @return {Y}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  getT (t) {
 | 
				
			||||||
 | 
					    return this.ty.get(t)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
/* eslint-env browser */
 | 
					/* eslint-env browser */
 | 
				
			||||||
import YXmlText from '../../Types/YXml/YXmlText.js'
 | 
					import YXmlText from '../../src/Types/YXml/YXmlText.js'
 | 
				
			||||||
import YXmlHook from '../../Types/YXml/YXmlHook.js'
 | 
					import YXmlHook from '../../src/Types/YXml/YXmlHook.js'
 | 
				
			||||||
import YXmlElement from '../../Types/YXml/YXmlElement.js'
 | 
					import YXmlElement from '../../src/Types/YXml/YXmlElement.js'
 | 
				
			||||||
import { createAssociation, domsToTypes } from './util.js'
 | 
					import { createAssociation, domsToTypes } from './util.js'
 | 
				
			||||||
import { filterDomAttributes, defaultFilter } from './filter.js'
 | 
					import { filterDomAttributes, defaultFilter } from './filter.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
import isParentOf from '../../Util/isParentOf.js'
 | 
					import isParentOf from '../../src/Util/isParentOf.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @callback DomFilter
 | 
					 * @callback DomFilter
 | 
				
			||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
/* globals getSelection */
 | 
					/* globals getSelection */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { getRelativePosition } from '../../Util/relativePosition.js'
 | 
					import { getRelativePosition } from '../../src/Util/relativePosition.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let relativeSelection = null
 | 
					let relativeSelection = null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
/* eslint-env browser */
 | 
					/* eslint-env browser */
 | 
				
			||||||
/* global getSelection */
 | 
					/* global getSelection */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import YXmlText from '../../Types/YXml/YXmlText.js'
 | 
					import YXmlText from '../../src/Types/YXml/YXmlText.js'
 | 
				
			||||||
import YXmlHook from '../../Types/YXml/YXmlHook.js'
 | 
					import YXmlHook from '../../src/Types/YXml/YXmlHook.js'
 | 
				
			||||||
import { removeDomChildrenUntilElementFound } from './util.js'
 | 
					import { removeDomChildrenUntilElementFound } from './util.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function findScrollReference (scrollingElement) {
 | 
					function findScrollReference (scrollingElement) {
 | 
				
			||||||
@ -2,9 +2,9 @@
 | 
				
			|||||||
import domToType from './domToType.js'
 | 
					import domToType from './domToType.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @typedef {import('../../Types/YXml/YXmlText.js').default} YXmlText
 | 
					 * @typedef {import('../../src/Types/YXml/YXmlText.js').default} YXmlText
 | 
				
			||||||
 * @typedef {import('../../Types/YXml/YXmlElement.js').default} YXmlElement
 | 
					 * @typedef {import('../../src/Types/YXml/YXmlElement.js').default} YXmlElement
 | 
				
			||||||
 * @typedef {import('../../Types/YXml/YXmlHook.js').default} YXmlHook
 | 
					 * @typedef {import('../../src/Types/YXml/YXmlHook.js').default} YXmlHook
 | 
				
			||||||
 * @typedef {import('./DomBinding.js').default} DomBinding
 | 
					 * @typedef {import('./DomBinding.js').default} DomBinding
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										190
									
								
								bindings/ProsemirrorBinding/ProsemirrorBinding.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								bindings/ProsemirrorBinding/ProsemirrorBinding.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,190 @@
 | 
				
			|||||||
 | 
					import BindMapping from '../BindMapping.js'
 | 
				
			||||||
 | 
					import * as PModel from 'prosemirror-model'
 | 
				
			||||||
 | 
					import * as Y from '../../src/index.js'
 | 
				
			||||||
 | 
					import { createMutex } from '../../lib/mutex.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @typedef {import('prosemirror-view').EditorView} EditorView
 | 
				
			||||||
 | 
					 * @typedef {import('prosemirror-state').EditorState} EditorState
 | 
				
			||||||
 | 
					 * @typedef {BindMapping<Y.Text | Y.XmlElement, PModel.Node>} ProsemirrorMapping
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class ProsemirrorBinding {
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * @param {Y.XmlFragment} yDomFragment The bind source
 | 
				
			||||||
 | 
					   * @param {EditorView} prosemirror The target binding
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  constructor (yDomFragment, prosemirror) {
 | 
				
			||||||
 | 
					    this.type = yDomFragment
 | 
				
			||||||
 | 
					    this.prosemirror = prosemirror
 | 
				
			||||||
 | 
					    const mux = createMutex()
 | 
				
			||||||
 | 
					    this.mux = mux
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @type {ProsemirrorMapping}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    const mapping = new BindMapping()
 | 
				
			||||||
 | 
					    this.mapping = mapping
 | 
				
			||||||
 | 
					    const oldDispatch = prosemirror.props.dispatchTransaction || null
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @type {any}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    const updatedProps = {
 | 
				
			||||||
 | 
					      dispatchTransaction: function (tr) {
 | 
				
			||||||
 | 
					        // TODO: remove
 | 
				
			||||||
 | 
					        const time = performance.now()
 | 
				
			||||||
 | 
					        const newState = prosemirror.state.apply(tr)
 | 
				
			||||||
 | 
					        mux(() => {
 | 
				
			||||||
 | 
					          updateYFragment(yDomFragment, newState, mapping)
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        if (oldDispatch !== null) {
 | 
				
			||||||
 | 
					          oldDispatch.call(this, tr)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          prosemirror.updateState(newState)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        console.info('time for Yjs update: ', performance.now() - time)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    prosemirror.setProps(updatedProps)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    yDomFragment.observeDeep(events => {
 | 
				
			||||||
 | 
					      if (events.length === 0) {
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      mux(() => {
 | 
				
			||||||
 | 
					        events.forEach(event => {
 | 
				
			||||||
 | 
					          // recompute node for each parent
 | 
				
			||||||
 | 
					          // except main node, compute main node in the end
 | 
				
			||||||
 | 
					          let target = event.target
 | 
				
			||||||
 | 
					          if (target !== yDomFragment) {
 | 
				
			||||||
 | 
					            do {
 | 
				
			||||||
 | 
					              if (target.constructor === Y.XmlElement) {
 | 
				
			||||||
 | 
					                createNodeFromYElement(target, prosemirror.state.schema, mapping)
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              target = target._parent
 | 
				
			||||||
 | 
					            } while (target._parent !== yDomFragment)
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        const fragmentContent = yDomFragment.toArray().map(t => createNodeIfNotExists(t, prosemirror.state.schema, mapping))
 | 
				
			||||||
 | 
					        const tr = prosemirror.state.tr.replace(0, prosemirror.state.doc.content.size, new PModel.Slice(new PModel.Fragment(fragmentContent), 0, 0))
 | 
				
			||||||
 | 
					        const newState = prosemirror.updateState(prosemirror.state.apply(tr))
 | 
				
			||||||
 | 
					        console.log('state updated', newState, tr)
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {Y.XmlElement} el
 | 
				
			||||||
 | 
					 * @param {PModel.Schema} schema
 | 
				
			||||||
 | 
					 * @param {ProsemirrorMapping} mapping
 | 
				
			||||||
 | 
					 * @return {PModel.Node}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const createNodeIfNotExists = (el, schema, mapping) => {
 | 
				
			||||||
 | 
					  const node = mapping.getY(el)
 | 
				
			||||||
 | 
					  if (node === undefined) {
 | 
				
			||||||
 | 
					    return createNodeFromYElement(el, schema, mapping)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return node
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {Y.XmlElement} el
 | 
				
			||||||
 | 
					 * @param {PModel.Schema} schema
 | 
				
			||||||
 | 
					 * @param {ProsemirrorMapping} mapping
 | 
				
			||||||
 | 
					 * @return {PModel.Node}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const createNodeFromYElement = (el, schema, mapping) => {
 | 
				
			||||||
 | 
					  const children = []
 | 
				
			||||||
 | 
					  el.toArray().forEach(type => {
 | 
				
			||||||
 | 
					    if (type.constructor === Y.XmlElement) {
 | 
				
			||||||
 | 
					      children.push(createNodeIfNotExists(type, schema, mapping))
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      children.concat(createTextNodesFromYText(type, schema, mapping)).forEach(textchild => children.push(textchild))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					  const node = schema.node(el.nodeName.toLowerCase(), el.getAttributes(), el.toArray().map(t => createNodeIfNotExists(t, schema, mapping)))
 | 
				
			||||||
 | 
					  mapping.bind(el, node)
 | 
				
			||||||
 | 
					  return node
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {Y.Text} text
 | 
				
			||||||
 | 
					 * @param {PModel.Schema} schema
 | 
				
			||||||
 | 
					 * @param {ProsemirrorMapping} mapping
 | 
				
			||||||
 | 
					 * @return {Array<PModel.Node>}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const createTextNodesFromYText = (text, schema, mapping) => {
 | 
				
			||||||
 | 
					  const nodes = []
 | 
				
			||||||
 | 
					  const deltas = text.toDelta()
 | 
				
			||||||
 | 
					  for (let i = 0; i < deltas.length; i++) {
 | 
				
			||||||
 | 
					    const delta = deltas[i]
 | 
				
			||||||
 | 
					    const marks = []
 | 
				
			||||||
 | 
					    for (let markName in delta.attributes) {
 | 
				
			||||||
 | 
					      marks.push(schema.mark(markName, delta.attributes[markName]))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    nodes.push(schema.text(delta.insert, marks))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (nodes.length > 0) {
 | 
				
			||||||
 | 
					    mapping.bind(text, nodes[0]) // only map to first child, all following children are also considered bound to this type
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return nodes
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {PModel.Node} node
 | 
				
			||||||
 | 
					 * @param {ProsemirrorMapping} mapping
 | 
				
			||||||
 | 
					 * @return {Y.XmlElement | Y.Text}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const createTypeFromNode = (node, mapping) => {
 | 
				
			||||||
 | 
					  let type
 | 
				
			||||||
 | 
					  if (node.isText) {
 | 
				
			||||||
 | 
					    type = new Y.Text()
 | 
				
			||||||
 | 
					    const attrs = {}
 | 
				
			||||||
 | 
					    node.marks.forEach(mark => { attrs[mark.type.name] = mark.attrs })
 | 
				
			||||||
 | 
					    type.insert(0, node.text, attrs)
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    type = new Y.XmlElement(node.type.name)
 | 
				
			||||||
 | 
					    for (let key in node.attrs) {
 | 
				
			||||||
 | 
					      type.setAttribute(key, node.attrs[key])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    type.insert(0, node.content.content.map(node => createTypeFromNode(node, mapping)))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  mapping.bind(type, node)
 | 
				
			||||||
 | 
					  return type
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {Y.XmlFragment} yDomFragment
 | 
				
			||||||
 | 
					 * @param {EditorState} state
 | 
				
			||||||
 | 
					 * @param {BindMapping} mapping
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const updateYFragment = (yDomFragment, state, mapping) => {
 | 
				
			||||||
 | 
					  const pChildCnt = state.doc.content.childCount
 | 
				
			||||||
 | 
					  const yChildren = yDomFragment.toArray()
 | 
				
			||||||
 | 
					  const yChildCnt = yChildren.length
 | 
				
			||||||
 | 
					  const minCnt = pChildCnt < yChildCnt ? pChildCnt : yChildCnt
 | 
				
			||||||
 | 
					  let left = 0
 | 
				
			||||||
 | 
					  let right = 0
 | 
				
			||||||
 | 
					  // find number of matching elements from left
 | 
				
			||||||
 | 
					  for (;left < minCnt; left++) {
 | 
				
			||||||
 | 
					    if (state.doc.content.child(left) !== mapping.getY(yChildren[left])) {
 | 
				
			||||||
 | 
					      break
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // find number of matching elements from right
 | 
				
			||||||
 | 
					  for (;right < minCnt; right++) {
 | 
				
			||||||
 | 
					    if (state.doc.content.child(pChildCnt - right - 1) !== mapping.getY(yChildren[yChildCnt - right - 1])) {
 | 
				
			||||||
 | 
					      break
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (left + right > pChildCnt) {
 | 
				
			||||||
 | 
					    // nothing changed
 | 
				
			||||||
 | 
					    return
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  yDomFragment._y.transact(() => {
 | 
				
			||||||
 | 
					    // now update y to match editor state
 | 
				
			||||||
 | 
					    yDomFragment.delete(left, yChildCnt - left - right)
 | 
				
			||||||
 | 
					    yDomFragment.insert(left, state.doc.content.content.slice(left, pChildCnt - right).map(node => createTypeFromNode(node, mapping)))
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					  console.log(yDomFragment.toDomString())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import Binding from '../Binding.js'
 | 
					import Binding from '../Binding.js'
 | 
				
			||||||
import simpleDiff from '../../../lib/simpleDiff.js'
 | 
					import simpleDiff from '../../lib/simpleDiff.js'
 | 
				
			||||||
import { getRelativePosition, fromRelativePosition } from '../../Util/relativePosition.js'
 | 
					import { getRelativePosition, fromRelativePosition } from '../../src/Util/relativePosition.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function typeObserver () {
 | 
					function typeObserver () {
 | 
				
			||||||
  this._mutualExclude(() => {
 | 
					  this._mutualExclude(() => {
 | 
				
			||||||
@ -1,19 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "name": "yjs-examples",
 | 
					 | 
				
			||||||
  "version": "0.0.0",
 | 
					 | 
				
			||||||
  "homepage": "y-js.org",
 | 
					 | 
				
			||||||
  "authors": [
 | 
					 | 
				
			||||||
    "Kevin Jahns <kevin.jahns@rwth-aachen.de>"
 | 
					 | 
				
			||||||
  ],
 | 
					 | 
				
			||||||
  "description": "Examples for Yjs",
 | 
					 | 
				
			||||||
  "license": "MIT",
 | 
					 | 
				
			||||||
  "ignore": [],
 | 
					 | 
				
			||||||
  "dependencies": {
 | 
					 | 
				
			||||||
    "quill": "^1.0.0-rc.2",
 | 
					 | 
				
			||||||
    "ace": "~1.2.3",
 | 
					 | 
				
			||||||
    "ace-builds": "~1.2.3",
 | 
					 | 
				
			||||||
    "jquery": "~2.2.2",
 | 
					 | 
				
			||||||
    "d3": "^3.5.16",
 | 
					 | 
				
			||||||
    "codemirror": "^5.25.0"
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import YWebsocketsConnector from '../../src/Connectors/WebsocketsConnector/WebsocketsConnector.js'
 | 
					import YWebsocketsConnector from '../../src/Connectors/WebsocketsConnector/WebsocketsConnector.js'
 | 
				
			||||||
import Y from '../../src/Y.js'
 | 
					import Y from '../../src/Y.js'
 | 
				
			||||||
import DomBinding from '../../src/Bindings/DomBinding/DomBinding.js'
 | 
					import DomBinding from '../../bindings/DomBinding/DomBinding.js'
 | 
				
			||||||
import UndoManager from '../../src/Util/UndoManager.js'
 | 
					import UndoManager from '../../src/Util/UndoManager.js'
 | 
				
			||||||
import YXmlFragment from '../../src/Types/YXml/YXmlFragment.js'
 | 
					import YXmlFragment from '../../src/Types/YXml/YXmlFragment.js'
 | 
				
			||||||
import YXmlText from '../../src/Types/YXml/YXmlText.js'
 | 
					import YXmlText from '../../src/Types/YXml/YXmlText.js'
 | 
				
			||||||
 | 
				
			|||||||
@ -1,55 +0,0 @@
 | 
				
			|||||||
<!DOCTYPE html>
 | 
					 | 
				
			||||||
<html>
 | 
					 | 
				
			||||||
<body>
 | 
					 | 
				
			||||||
  <style>
 | 
					 | 
				
			||||||
    .wrapper {
 | 
					 | 
				
			||||||
      display: grid;
 | 
					 | 
				
			||||||
      grid-template-columns: repeat(3, 1fr);
 | 
					 | 
				
			||||||
      grid-gap: 7px;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    .one {
 | 
					 | 
				
			||||||
      grid-column: 1 ;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    .two {
 | 
					 | 
				
			||||||
      grid-column: 2;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    .three {
 | 
					 | 
				
			||||||
      grid-column: 3;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    textarea {
 | 
					 | 
				
			||||||
      width: calc(100% - 10px)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    .editor-container {
 | 
					 | 
				
			||||||
      background-color: #4caf50;
 | 
					 | 
				
			||||||
      padding: 4px 5px 10px 5px;
 | 
					 | 
				
			||||||
      border-radius: 11px;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    .editor-container[disconnected] {
 | 
					 | 
				
			||||||
      background-color: red;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    .disconnected-info {
 | 
					 | 
				
			||||||
      display: none;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    .editor-container[disconnected] .disconnected-info {
 | 
					 | 
				
			||||||
      display: inline;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  </style>
 | 
					 | 
				
			||||||
  <div class="wrapper">
 | 
					 | 
				
			||||||
    <div id="container1" class="one editor-container">
 | 
					 | 
				
			||||||
      <h1>Server 1 <span class="disconnected-info">(disconnected)</span></h1>
 | 
					 | 
				
			||||||
      <textarea id="textarea1" rows=40 autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
    <div id="container2" class="two editor-container">
 | 
					 | 
				
			||||||
      <h1>Server 2 <span class="disconnected-info">(disconnected)</span></h1>
 | 
					 | 
				
			||||||
      <textarea id="textarea2" rows=40 autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
    <div id="container3" class="three editor-container">
 | 
					 | 
				
			||||||
      <h1>Server 3 <span class="disconnected-info">(disconnected)</span></h1>
 | 
					 | 
				
			||||||
      <textarea id="textarea3" rows=40 autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
  <script src="../../y.js"></script>
 | 
					 | 
				
			||||||
  <script src='../../../y-websockets-client/y-websockets-client.js'></script>
 | 
					 | 
				
			||||||
  <script src="./index.js"></script>
 | 
					 | 
				
			||||||
</body>
 | 
					 | 
				
			||||||
</html>
 | 
					 | 
				
			||||||
@ -1,38 +0,0 @@
 | 
				
			|||||||
/* global Y */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function bindYjsInstance (y, suffix) {
 | 
					 | 
				
			||||||
  y.define('textarea', Y.Text).bind(document.getElementById('textarea' + suffix))
 | 
					 | 
				
			||||||
  y.connector.socket.on('connection', function () {
 | 
					 | 
				
			||||||
    document.getElementById('container' + suffix).removeAttribute('disconnected')
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
  y.connector.socket.on('disconnect', function () {
 | 
					 | 
				
			||||||
    document.getElementById('container' + suffix).setAttribute('disconnected', true)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let y1 = new Y('infinite-example', {
 | 
					 | 
				
			||||||
  connector: {
 | 
					 | 
				
			||||||
    name: 'websockets-client',
 | 
					 | 
				
			||||||
    url: 'http://127.0.0.1:1234'
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
window.y1 = y1
 | 
					 | 
				
			||||||
bindYjsInstance(y1, '1')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let y2 = new Y('infinite-example', {
 | 
					 | 
				
			||||||
  connector: {
 | 
					 | 
				
			||||||
    name: 'websockets-client',
 | 
					 | 
				
			||||||
    url: 'http://127.0.0.1:1234'
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
window.y2 = y2
 | 
					 | 
				
			||||||
bindYjsInstance(y2, '2')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let y3 = new Y('infinite-example', {
 | 
					 | 
				
			||||||
  connector: {
 | 
					 | 
				
			||||||
    name: 'websockets-client',
 | 
					 | 
				
			||||||
    url: 'http://127.0.0.1:1234'
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
window.y3 = y3
 | 
					 | 
				
			||||||
bindYjsInstance(y1, '3')
 | 
					 | 
				
			||||||
@ -3,7 +3,7 @@
 | 
				
			|||||||
import { createYdbClient } from '../../YdbClient/index.js'
 | 
					import { createYdbClient } from '../../YdbClient/index.js'
 | 
				
			||||||
import Y from '../../src/Y.dist.js'
 | 
					import Y from '../../src/Y.dist.js'
 | 
				
			||||||
import * as ydb from '../../YdbClient/YdbClient.js'
 | 
					import * as ydb from '../../YdbClient/YdbClient.js'
 | 
				
			||||||
import DomBinding from '../../src/Bindings/DomBinding/DomBinding.js'
 | 
					import DomBinding from '../../bindings/DomBinding/DomBinding.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const uuidv4 = () => 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
 | 
					const uuidv4 = () => 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
 | 
				
			||||||
  const r = Math.random() * 16 | 0
 | 
					  const r = Math.random() * 16 | 0
 | 
				
			||||||
 | 
				
			|||||||
@ -1,23 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "name": "examples",
 | 
					 | 
				
			||||||
  "version": "0.0.0",
 | 
					 | 
				
			||||||
  "description": "",
 | 
					 | 
				
			||||||
  "scripts": {
 | 
					 | 
				
			||||||
    "dist": "rollup -c",
 | 
					 | 
				
			||||||
    "watch": "rollup -cw"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "author": "Kevin Jahns",
 | 
					 | 
				
			||||||
  "license": "MIT",
 | 
					 | 
				
			||||||
  "dependencies": {
 | 
					 | 
				
			||||||
    "monaco-editor": "^0.8.3",
 | 
					 | 
				
			||||||
    "rollup": "^0.52.3"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "devDependencies": {
 | 
					 | 
				
			||||||
    "standard": "^10.0.2"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "standard": {
 | 
					 | 
				
			||||||
    "ignore": [
 | 
					 | 
				
			||||||
      "bower_components"
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										29
									
								
								examples/prosemirror/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								examples/prosemirror/index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					  <head>
 | 
				
			||||||
 | 
					      <script type="module" src="./index.dist.js"></script>
 | 
				
			||||||
 | 
					      <link rel=stylesheet href="https://prosemirror.net/css/editor.css">
 | 
				
			||||||
 | 
					      <style>
 | 
				
			||||||
 | 
					        placeholder {
 | 
				
			||||||
 | 
					          display: inline;
 | 
				
			||||||
 | 
					          border: 1px solid #ccc;
 | 
				
			||||||
 | 
					          color: #ccc;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        placeholder:after {
 | 
				
			||||||
 | 
					          content: "☁";
 | 
				
			||||||
 | 
					          font-size: 200%;
 | 
				
			||||||
 | 
					          line-height: 0.1;
 | 
				
			||||||
 | 
					          font-weight: bold;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .ProseMirror img { max-width: 100px }
 | 
				
			||||||
 | 
					      </style>
 | 
				
			||||||
 | 
					  </head>
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					  <div id="editor" style="margin-bottom: 23px"></div>
 | 
				
			||||||
 | 
					  <div style="display: none" id="content">
 | 
				
			||||||
 | 
					    <h3>Hello User</h3>
 | 
				
			||||||
 | 
					    <p>type something ...</p>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					  <div>Insert image: <input type=file id=image-upload></div>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										112
									
								
								examples/prosemirror/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								examples/prosemirror/index.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,112 @@
 | 
				
			|||||||
 | 
					/* eslint-env browser */
 | 
				
			||||||
 | 
					import * as Y from '../../src/index.js'
 | 
				
			||||||
 | 
					import ProsemirrorBinding from '../../bindings/ProsemirrorBinding/ProsemirrorBinding.js'
 | 
				
			||||||
 | 
					import WebsocketProvider from '../../provider/websocket/WebSocketProvider.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import {EditorState} from 'prosemirror-state'
 | 
				
			||||||
 | 
					import {EditorView} from 'prosemirror-view'
 | 
				
			||||||
 | 
					import {Schema, DOMParser, Mark, Fragment, Node, Slice} from 'prosemirror-model'
 | 
				
			||||||
 | 
					import {schema} from 'prosemirror-schema-basic'
 | 
				
			||||||
 | 
					import {exampleSetup} from 'prosemirror-example-setup'
 | 
				
			||||||
 | 
					import {Plugin} from 'prosemirror-state'
 | 
				
			||||||
 | 
					import {Decoration, DecorationSet} from 'prosemirror-view'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let placeholderPlugin = new Plugin({
 | 
				
			||||||
 | 
					  state: {
 | 
				
			||||||
 | 
					    init() { return DecorationSet.empty },
 | 
				
			||||||
 | 
					    apply(tr, set) {
 | 
				
			||||||
 | 
					      // Adjust decoration positions to changes made by the transaction
 | 
				
			||||||
 | 
					      set = set.map(tr.mapping, tr.doc)
 | 
				
			||||||
 | 
					      // See if the transaction adds or removes any placeholders
 | 
				
			||||||
 | 
					      let action = tr.getMeta(this)
 | 
				
			||||||
 | 
					      if (action && action.add) {
 | 
				
			||||||
 | 
					        let widget = document.createElement("placeholder")
 | 
				
			||||||
 | 
					        let deco = Decoration.widget(action.add.pos, widget, {id: action.add.id})
 | 
				
			||||||
 | 
					        set = set.add(tr.doc, [deco])
 | 
				
			||||||
 | 
					      } else if (action && action.remove) {
 | 
				
			||||||
 | 
					        set = set.remove(set.find(null, null,
 | 
				
			||||||
 | 
					                                  spec => spec.id == action.remove.id))
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return set
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  props: {
 | 
				
			||||||
 | 
					    decorations(state) { return this.getState(state) }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function findPlaceholder(state, id) {
 | 
				
			||||||
 | 
					  let decos = placeholderPlugin.getState(state)
 | 
				
			||||||
 | 
					  let found = decos.find(null, null, spec => spec.id == id)
 | 
				
			||||||
 | 
					  return found.length ? found[0].from : null
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.querySelector("#image-upload").addEventListener("change", e => {
 | 
				
			||||||
 | 
					  if (view.state.selection.$from.parent.inlineContent && e.target.files.length)
 | 
				
			||||||
 | 
					    startImageUpload(view, e.target.files[0])
 | 
				
			||||||
 | 
					  view.focus()
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function startImageUpload(view, file) {
 | 
				
			||||||
 | 
					  // A fresh object to act as the ID for this upload
 | 
				
			||||||
 | 
					  let id = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Replace the selection with a placeholder
 | 
				
			||||||
 | 
					  let tr = view.state.tr
 | 
				
			||||||
 | 
					  if (!tr.selection.empty) tr.deleteSelection()
 | 
				
			||||||
 | 
					  tr.setMeta(placeholderPlugin, {add: {id, pos: tr.selection.from}})
 | 
				
			||||||
 | 
					  view.dispatch(tr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uploadFile(file).then(url => {
 | 
				
			||||||
 | 
					    let pos = findPlaceholder(view.state, id)
 | 
				
			||||||
 | 
					    // If the content around the placeholder has been deleted, drop
 | 
				
			||||||
 | 
					    // the image
 | 
				
			||||||
 | 
					    if (pos == null) return
 | 
				
			||||||
 | 
					    // Otherwise, insert it at the placeholder's position, and remove
 | 
				
			||||||
 | 
					    // the placeholder
 | 
				
			||||||
 | 
					    view.dispatch(view.state.tr
 | 
				
			||||||
 | 
					                  .replaceWith(pos, pos, schema.nodes.image.create({src: url}))
 | 
				
			||||||
 | 
					                  .setMeta(placeholderPlugin, {remove: {id}}))
 | 
				
			||||||
 | 
					  }, () => {
 | 
				
			||||||
 | 
					    // On failure, just clean up the placeholder
 | 
				
			||||||
 | 
					    view.dispatch(tr.setMeta(placeholderPlugin, {remove: {id}}))
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This is just a dummy that loads the file and creates a data URL.
 | 
				
			||||||
 | 
					// You could swap it out with a function that does an actual upload
 | 
				
			||||||
 | 
					// and returns a regular URL for the uploaded file.
 | 
				
			||||||
 | 
					function uploadFile (file) {
 | 
				
			||||||
 | 
					  let reader = new FileReader()
 | 
				
			||||||
 | 
					  return new Promise((accept, fail) => {
 | 
				
			||||||
 | 
					    reader.onload = () => accept(reader.result)
 | 
				
			||||||
 | 
					    reader.onerror = () => fail(reader.error)
 | 
				
			||||||
 | 
					    // Some extra delay to make the asynchronicity visible
 | 
				
			||||||
 | 
					    setTimeout(() => reader.readAsDataURL(file), 1500)
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const view = new EditorView(document.querySelector('#editor'), {
 | 
				
			||||||
 | 
					  state: EditorState.create({
 | 
				
			||||||
 | 
					    doc: DOMParser.fromSchema(schema).parse(document.querySelector('#content')),
 | 
				
			||||||
 | 
					    plugins: exampleSetup({schema}).concat(placeholderPlugin)
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const provider = new WebsocketProvider('ws://localhost:1234/')
 | 
				
			||||||
 | 
					const ydocument = provider.get('prosemirror')
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @type {any}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const type = ydocument.define('prosemirror', Y.XmlFragment)
 | 
				
			||||||
 | 
					const prosemirrorBinding = new ProsemirrorBinding(type, view)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					window.view = view
 | 
				
			||||||
 | 
					window.EditorState = EditorState
 | 
				
			||||||
 | 
					window.EditorView = EditorView
 | 
				
			||||||
 | 
					window.Mark = Mark
 | 
				
			||||||
 | 
					window.Fragment = Fragment
 | 
				
			||||||
 | 
					window.Node = Node
 | 
				
			||||||
 | 
					window.Schema = Schema
 | 
				
			||||||
 | 
					window.Slice = Slice
 | 
				
			||||||
 | 
					window.prosemirrorBinding = prosemirrorBinding
 | 
				
			||||||
							
								
								
									
										20
									
								
								examples/prosemirror/rollup.browser.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								examples/prosemirror/rollup.browser.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					import nodeResolve from 'rollup-plugin-node-resolve'
 | 
				
			||||||
 | 
					import commonjs from 'rollup-plugin-commonjs'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  input: './index.js',
 | 
				
			||||||
 | 
					  output: {
 | 
				
			||||||
 | 
					    name: 'index',
 | 
				
			||||||
 | 
					    file: 'index.dist.js',
 | 
				
			||||||
 | 
					    format: 'umd',
 | 
				
			||||||
 | 
					    sourcemap: true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  plugins: [
 | 
				
			||||||
 | 
					    nodeResolve({
 | 
				
			||||||
 | 
					      main: true,
 | 
				
			||||||
 | 
					      module: true,
 | 
				
			||||||
 | 
					      browser: true
 | 
				
			||||||
 | 
					    }),
 | 
				
			||||||
 | 
					    commonjs()
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,29 +0,0 @@
 | 
				
			|||||||
import nodeResolve from 'rollup-plugin-node-resolve'
 | 
					 | 
				
			||||||
import commonjs from 'rollup-plugin-commonjs'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var pkg = require('./package.json')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default {
 | 
					 | 
				
			||||||
  input: 'yjs-dist.js',
 | 
					 | 
				
			||||||
  name: 'Y',
 | 
					 | 
				
			||||||
  output: {
 | 
					 | 
				
			||||||
    file: 'yjs-dist.js',
 | 
					 | 
				
			||||||
    format: 'umd'
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  plugins: [
 | 
					 | 
				
			||||||
    nodeResolve({
 | 
					 | 
				
			||||||
      main: true,
 | 
					 | 
				
			||||||
      module: true,
 | 
					 | 
				
			||||||
      browser: true
 | 
					 | 
				
			||||||
    }),
 | 
					 | 
				
			||||||
    commonjs()
 | 
					 | 
				
			||||||
  ],
 | 
					 | 
				
			||||||
  sourcemap: true,
 | 
					 | 
				
			||||||
  banner: `
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ${pkg.name} - ${pkg.description}
 | 
					 | 
				
			||||||
 * @version v${pkg.version}
 | 
					 | 
				
			||||||
 * @license ${pkg.license}
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										176
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										176
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -2012,6 +2012,12 @@
 | 
				
			|||||||
      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
 | 
					      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "crel": {
 | 
				
			||||||
 | 
					      "version": "3.1.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/crel/-/crel-3.1.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-VIGY44ERxx8lXVkOEfcB0A49OkjxkQNK+j+fHvoLy7GsGX1KKgAaQ+p9N0YgvQXu+X+ryUWGDeLx/fSI+w7+eg==",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "cross-spawn": {
 | 
					    "cross-spawn": {
 | 
				
			||||||
      "version": "5.1.0",
 | 
					      "version": "5.1.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
 | 
				
			||||||
@ -5363,6 +5369,12 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "orderedmap": {
 | 
				
			||||||
 | 
					      "version": "1.0.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-1.0.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-2Q/Cuh7QhRkJB9YB3sbmpT+NQbo=",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "os-homedir": {
 | 
					    "os-homedir": {
 | 
				
			||||||
      "version": "1.0.2",
 | 
					      "version": "1.0.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
 | 
				
			||||||
@ -5656,6 +5668,158 @@
 | 
				
			|||||||
        "object-assign": "^4.1.1"
 | 
					        "object-assign": "^4.1.1"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "prosemirror-commands": {
 | 
				
			||||||
 | 
					      "version": "1.0.7",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.0.7.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-IR8yMSdw7XlKuF68tydAak1J9P/lLD5ohsrL7pzoLsJAJAQU7mVPDXtGbQrrm0mesddFjcc1zNo/cJQN3lRYnA==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "prosemirror-model": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-state": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-transform": "^1.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "prosemirror-dropcursor": {
 | 
				
			||||||
 | 
					      "version": "1.1.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.1.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-GeUyMO/tOEf8MXrP7Xb7UIMrfK86OGh0fnyBrHfhav4VjY9cw65mNoqHy87CklE5711AhCP5Qzfp8RL/hVKusg==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "prosemirror-state": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-transform": "^1.1.0",
 | 
				
			||||||
 | 
					        "prosemirror-view": "^1.1.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "prosemirror-example-setup": {
 | 
				
			||||||
 | 
					      "version": "1.0.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/prosemirror-example-setup/-/prosemirror-example-setup-1.0.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-4NKWpdmm75Zzgq/dIrypRnkBNPx+ONKyoGF42a9g3VIVv0TWglf1CBNxt5kzCgli9xdfut/xE5B42F9DR6BLHw==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "prosemirror-commands": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-dropcursor": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-gapcursor": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-history": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-inputrules": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-keymap": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-menu": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-schema-list": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-state": "^1.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "prosemirror-gapcursor": {
 | 
				
			||||||
 | 
					      "version": "1.0.3",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.0.3.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-X+hJhr42PcHWiSWL+lI5f/UeOhXCxlBFb8M6O8aG1hssmaRrW7sS2/Fjg5jFV+pTdS1REFkmm1occh01FMdDIQ==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "prosemirror-keymap": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-model": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-state": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-view": "^1.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "prosemirror-history": {
 | 
				
			||||||
 | 
					      "version": "1.0.3",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.0.3.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-IfFGbhafSx+R3aq7nLJGkXeu2iaUiP8mkU3aRu2uQcIIjU8Fq7RJfuvhIOJ2RNUoSyqF/ANkdTjnZ74F5eHs1Q==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "prosemirror-state": "^1.2.2",
 | 
				
			||||||
 | 
					        "prosemirror-transform": "^1.0.0",
 | 
				
			||||||
 | 
					        "rope-sequence": "^1.2.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "prosemirror-inputrules": {
 | 
				
			||||||
 | 
					      "version": "1.0.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.0.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-UHy22NmwxS5WIMQYkzraDttQAF8mpP82FfbJsmKFfx6jwkR/SZa+ZhbkLY0zKQ5fBdJN7euj36JG/B5iAlrpxA==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "prosemirror-state": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-transform": "^1.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "prosemirror-keymap": {
 | 
				
			||||||
 | 
					      "version": "1.0.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.0.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-e79ApE7PXXZMFtPz7WbjycjAFd1NPjgY1MkecVz98tqwlBSggXWXYQnWFk6x7UkmnBYRHHbXHkR/RXmu2wyBJg==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "prosemirror-state": "^1.0.0",
 | 
				
			||||||
 | 
					        "w3c-keyname": "^1.1.8"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "prosemirror-menu": {
 | 
				
			||||||
 | 
					      "version": "1.0.5",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.0.5.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-9Vrn7CC191v7FA4QrAkL8W1SrR73V3CRIYCDuk94R8oFVk4VxSFdoKVLHuvGzxZ8b5LCu3DMJfh86YW9uL4RkQ==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "crel": "^3.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-commands": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-history": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-state": "^1.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "prosemirror-model": {
 | 
				
			||||||
 | 
					      "version": "1.6.3",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.6.3.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-iqIml664X9MUVGLz2nzK4xfAofX8+o7gs2mi2/k+pVD0qZ7th1Jm5eG3AsqWoEUIZuWeaOWCKpBl/dPnhIIWew==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "orderedmap": "^1.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "prosemirror-schema-basic": {
 | 
				
			||||||
 | 
					      "version": "1.0.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.0.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-xTFjtuLZgcRS4MoDbUyI9NSk/k/ACLGKZQcDXH18ctM9BOmP4z5rGZcA014fCF2FnMFOU+lKwusL0JjVrEectQ==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "prosemirror-model": "^1.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "prosemirror-schema-list": {
 | 
				
			||||||
 | 
					      "version": "1.0.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.0.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-AiLIX6qm6PEeDtMCKZLcSLi55WXo1ls7DnRK+4hSkoi0IIzNdxGsRlecCd3MzEu//DVz3nAEh+zEmslyW+uk8g==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "prosemirror-model": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-transform": "^1.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "prosemirror-state": {
 | 
				
			||||||
 | 
					      "version": "1.2.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.2.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-j8aC/kf9BJSCQau485I/9pj39XQoce+TqH5xzekT7WWFARTsRYFLJtiXBcCKakv1VSeev+sC3bJP0pLfz7Ft8g==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "prosemirror-model": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-transform": "^1.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "prosemirror-transform": {
 | 
				
			||||||
 | 
					      "version": "1.1.3",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.1.3.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-1O6Di5lOL1mp4nuCnQNkHY7l2roIW5y8RH4ZG3hMYmkmDEWzTaFFnxxAAHsE5ipGLBSRcTlP7SsDhYBIdSuLpQ==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "prosemirror-model": "^1.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "prosemirror-view": {
 | 
				
			||||||
 | 
					      "version": "1.6.5",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.6.5.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-brg8fExNrmklbLs8VJ7uvmo/Lh93EHErH47alI55hkJ12EF73K+t2+IyrlkJF84tt5wFBJ20LeSxF8HlJHXiYg==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "prosemirror-model": "^1.1.0",
 | 
				
			||||||
 | 
					        "prosemirror-state": "^1.0.0",
 | 
				
			||||||
 | 
					        "prosemirror-transform": "^1.1.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "pseudomap": {
 | 
					    "pseudomap": {
 | 
				
			||||||
      "version": "1.0.2",
 | 
					      "version": "1.0.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
 | 
				
			||||||
@ -6252,6 +6416,12 @@
 | 
				
			|||||||
        "require-relative": "0.8.7"
 | 
					        "require-relative": "0.8.7"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "rope-sequence": {
 | 
				
			||||||
 | 
					      "version": "1.2.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.2.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-ScTlwvVKSOmQsFCSZ3HihxvLMc4=",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "run-async": {
 | 
					    "run-async": {
 | 
				
			||||||
      "version": "2.3.0",
 | 
					      "version": "2.3.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
 | 
				
			||||||
@ -6950,6 +7120,12 @@
 | 
				
			|||||||
      "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==",
 | 
					      "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "w3c-keyname": {
 | 
				
			||||||
 | 
					      "version": "1.1.8",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-1.1.8.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-2HAdug8GTiu3b4NYhssdtY8PXRue3ICnh1IlxvZYl+hiINRq0GfNWei3XOPDg8L0PsxbmYjWVLuLj6BMRR/9vA==",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "webidl-conversions": {
 | 
					    "webidl-conversions": {
 | 
				
			||||||
      "version": "2.0.1",
 | 
					      "version": "2.0.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-2.0.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-2.0.1.tgz",
 | 
				
			||||||
 | 
				
			|||||||
@ -57,6 +57,10 @@
 | 
				
			|||||||
    "cutest": "^0.1.9",
 | 
					    "cutest": "^0.1.9",
 | 
				
			||||||
    "esdoc": "^1.1.0",
 | 
					    "esdoc": "^1.1.0",
 | 
				
			||||||
    "esdoc-standard-plugin": "^1.0.0",
 | 
					    "esdoc-standard-plugin": "^1.0.0",
 | 
				
			||||||
 | 
					    "prosemirror-example-setup": "^1.0.1",
 | 
				
			||||||
 | 
					    "prosemirror-schema-basic": "^1.0.0",
 | 
				
			||||||
 | 
					    "prosemirror-state": "^1.2.2",
 | 
				
			||||||
 | 
					    "prosemirror-view": "^1.6.5",
 | 
				
			||||||
    "quill": "^1.3.6",
 | 
					    "quill": "^1.3.6",
 | 
				
			||||||
    "quill-cursors": "^1.0.3",
 | 
					    "quill-cursors": "^1.0.3",
 | 
				
			||||||
    "rollup": "^0.58.2",
 | 
					    "rollup": "^0.58.2",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,56 +0,0 @@
 | 
				
			|||||||
 | 
					 | 
				
			||||||
import Binding from '../Binding.js'
 | 
					 | 
				
			||||||
import simpleDiff from '../../Util/simpleDiff.js'
 | 
					 | 
				
			||||||
import { getRelativePosition, fromRelativePosition } from '../../Util/relativePosition.js'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function typeObserver () {
 | 
					 | 
				
			||||||
  this._mutualExclude(() => {
 | 
					 | 
				
			||||||
    const textarea = this.target
 | 
					 | 
				
			||||||
    const textType = this.type
 | 
					 | 
				
			||||||
    const relativeStart = getRelativePosition(textType, textarea.selectionStart)
 | 
					 | 
				
			||||||
    const relativeEnd = getRelativePosition(textType, textarea.selectionEnd)
 | 
					 | 
				
			||||||
    textarea.value = textType.toString()
 | 
					 | 
				
			||||||
    const start = fromRelativePosition(textType._y, relativeStart)
 | 
					 | 
				
			||||||
    const end = fromRelativePosition(textType._y, relativeEnd)
 | 
					 | 
				
			||||||
    textarea.setSelectionRange(start, end)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function domObserver () {
 | 
					 | 
				
			||||||
  this._mutualExclude(() => {
 | 
					 | 
				
			||||||
    let diff = simpleDiff(this.type.toString(), this.target.value)
 | 
					 | 
				
			||||||
    this.type.delete(diff.pos, diff.remove)
 | 
					 | 
				
			||||||
    this.type.insert(diff.pos, diff.insert)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * A binding that binds a YText to a dom textarea.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This binding is automatically destroyed when its parent is deleted.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @example
 | 
					 | 
				
			||||||
 *   const textare = document.createElement('textarea')
 | 
					 | 
				
			||||||
 *   const type = y.define('textarea', Y.Text)
 | 
					 | 
				
			||||||
 *   const binding = new Y.QuillBinding(type, textarea)
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
export default class TextareaBinding extends Binding {
 | 
					 | 
				
			||||||
  constructor (textType, domTextarea) {
 | 
					 | 
				
			||||||
    // Binding handles textType as this.type and domTextarea as this.target
 | 
					 | 
				
			||||||
    super(textType, domTextarea)
 | 
					 | 
				
			||||||
    // set initial value
 | 
					 | 
				
			||||||
    domTextarea.value = textType.toString()
 | 
					 | 
				
			||||||
    // Observers are handled by this class
 | 
					 | 
				
			||||||
    this._typeObserver = typeObserver.bind(this)
 | 
					 | 
				
			||||||
    this._domObserver = domObserver.bind(this)
 | 
					 | 
				
			||||||
    textType.observe(this._typeObserver)
 | 
					 | 
				
			||||||
    domTextarea.addEventListener('input', this._domObserver)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  destroy () {
 | 
					 | 
				
			||||||
    // Remove everything that is handled by this class
 | 
					 | 
				
			||||||
    this.type.unobserve(this._typeObserver)
 | 
					 | 
				
			||||||
    this.target.unobserve(this._domObserver)
 | 
					 | 
				
			||||||
    super.destroy()
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -499,6 +499,39 @@ export default class YText extends YArray {
 | 
				
			|||||||
    return str
 | 
					    return str
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  toDomString () {
 | 
				
			||||||
 | 
					    return this.toDelta().map(delta => {
 | 
				
			||||||
 | 
					      const nestedNodes = []
 | 
				
			||||||
 | 
					      for (let nodeName in delta.attributes) {
 | 
				
			||||||
 | 
					        const attrs = []
 | 
				
			||||||
 | 
					        for (let key in delta.attributes[nodeName]) {
 | 
				
			||||||
 | 
					          attrs.push({key, value: delta.attributes[nodeName][key]})
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // sort attributes to get a unique order
 | 
				
			||||||
 | 
					        attrs.sort((a, b) => a.key < b.key ? -1 : 1)
 | 
				
			||||||
 | 
					        nestedNodes.push({ nodeName, attrs })
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // sort node order to get a unique order
 | 
				
			||||||
 | 
					      nestedNodes.sort((a, b) => a.nodeName < b.nodeName ? -1 : 1)
 | 
				
			||||||
 | 
					      // now convert to dom string
 | 
				
			||||||
 | 
					      let str = ''
 | 
				
			||||||
 | 
					      for (let i = 0; i < nestedNodes.length; i++) {
 | 
				
			||||||
 | 
					        const node = nestedNodes[i]
 | 
				
			||||||
 | 
					        str += `<${node.nodeName}`
 | 
				
			||||||
 | 
					        for (let j = 0; j < node.attrs.length; j++) {
 | 
				
			||||||
 | 
					          const attr = node.attrs[i]
 | 
				
			||||||
 | 
					          str += ` ${attr.key}="${attr.value}"`
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        str += '>'
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      str += delta.insert
 | 
				
			||||||
 | 
					      for (let i = nestedNodes.length - 1; i >= 0; i--) {
 | 
				
			||||||
 | 
					        str += `</${nestedNodes[i].nodeName}>`
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return str
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Apply a {@link Delta} on this shared YText type.
 | 
					   * Apply a {@link Delta} on this shared YText type.
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import YMap from '../YMap/YMap.js'
 | 
					import YMap from '../YMap/YMap.js'
 | 
				
			||||||
import YXmlFragment from './YXmlFragment.js'
 | 
					import YXmlFragment from './YXmlFragment.js'
 | 
				
			||||||
import { createAssociation } from '../../Bindings/DomBinding/util.js'
 | 
					import { createAssociation } from '../../../bindings/DomBinding/util.js'
 | 
				
			||||||
import * as encoding from '../../../lib/encoding.js'
 | 
					import * as encoding from '../../../lib/encoding.js'
 | 
				
			||||||
import * as decoding from '../../../lib/decoding.js'
 | 
					import * as decoding from '../../../lib/decoding.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -82,6 +82,10 @@ export default class YXmlElement extends YXmlFragment {
 | 
				
			|||||||
    super._integrate(y)
 | 
					    super._integrate(y)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  toString () {
 | 
				
			||||||
 | 
					    return this.toDomString()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Returns the string representation of this YXmlElement.
 | 
					   * Returns the string representation of this YXmlElement.
 | 
				
			||||||
   * The attributes are ordered by attribute-name, so you can easily use this
 | 
					   * The attributes are ordered by attribute-name, so you can easily use this
 | 
				
			||||||
@ -91,7 +95,7 @@ export default class YXmlElement extends YXmlFragment {
 | 
				
			|||||||
   *
 | 
					   *
 | 
				
			||||||
   * @public
 | 
					   * @public
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  toString () {
 | 
					  toDomString () {
 | 
				
			||||||
    const attrs = this.getAttributes()
 | 
					    const attrs = this.getAttributes()
 | 
				
			||||||
    const stringBuilder = []
 | 
					    const stringBuilder = []
 | 
				
			||||||
    const keys = []
 | 
					    const keys = []
 | 
				
			||||||
@ -106,7 +110,7 @@ export default class YXmlElement extends YXmlFragment {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    const nodeName = this.nodeName.toLocaleLowerCase()
 | 
					    const nodeName = this.nodeName.toLocaleLowerCase()
 | 
				
			||||||
    const attrsString = stringBuilder.length > 0 ? ' ' + stringBuilder.join(' ') : ''
 | 
					    const attrsString = stringBuilder.length > 0 ? ' ' + stringBuilder.join(' ') : ''
 | 
				
			||||||
    return `<${nodeName}${attrsString}>${super.toString()}</${nodeName}>`
 | 
					    return `<${nodeName}${attrsString}>${super.toDomString()}</${nodeName}>`
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
@ -170,7 +174,7 @@ export default class YXmlElement extends YXmlFragment {
 | 
				
			|||||||
   *                                        nodejs)
 | 
					   *                                        nodejs)
 | 
				
			||||||
   * @param {Object<string, any>} [hooks={}] Optional property to customize how hooks
 | 
					   * @param {Object<string, any>} [hooks={}] Optional property to customize how hooks
 | 
				
			||||||
   *                                             are presented in the DOM
 | 
					   *                                             are presented in the DOM
 | 
				
			||||||
   * @param {import('../../Bindings/DomBinding/DomBinding.js').default} [binding] You should not set this property. This is
 | 
					   * @param {import('../../../bindings/DomBinding/DomBinding.js').default} [binding] You should not set this property. This is
 | 
				
			||||||
   *                               used if DomBinding wants to create a
 | 
					   *                               used if DomBinding wants to create a
 | 
				
			||||||
   *                               association to the created DOM type.
 | 
					   *                               association to the created DOM type.
 | 
				
			||||||
   * @return {Element} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
 | 
					   * @return {Element} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
import { createAssociation } from '../../Bindings/DomBinding/util.js'
 | 
					import { createAssociation } from '../../../bindings/DomBinding/util.js'
 | 
				
			||||||
import YXmlTreeWalker from './YXmlTreeWalker.js'
 | 
					import YXmlTreeWalker from './YXmlTreeWalker.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import YArray from '../YArray/YArray.js'
 | 
					import YArray from '../YArray/YArray.js'
 | 
				
			||||||
@ -7,7 +7,7 @@ import { logItemHelper } from '../../message.js'
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @typedef {import('./YXmlElement.js').default} YXmlElement
 | 
					 * @typedef {import('./YXmlElement.js').default} YXmlElement
 | 
				
			||||||
 * @typedef {import('../../Bindings/DomBinding/DomBinding.js').default} DomBinding
 | 
					 * @typedef {import('../../../bindings/DomBinding/DomBinding.js').default} DomBinding
 | 
				
			||||||
 * @typedef {import('../../Y.js').default} Y
 | 
					 * @typedef {import('../../Y.js').default} Y
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -113,13 +113,17 @@ export default class YXmlFragment extends YArray {
 | 
				
			|||||||
    this._callEventHandler(transaction, new YXmlEvent(this, parentSubs, remote, transaction))
 | 
					    this._callEventHandler(transaction, new YXmlEvent(this, parentSubs, remote, transaction))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  toString () {
 | 
				
			||||||
 | 
					    return this.toDomString()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Get the string representation of all the children of this YXmlFragment.
 | 
					   * Get the string representation of all the children of this YXmlFragment.
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
   * @return {string} The string representation of all children.
 | 
					   * @return {string} The string representation of all children.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  toString () {
 | 
					  toDomString () {
 | 
				
			||||||
    return this.map(xml => xml.toString()).join('')
 | 
					    return this.map(xml => xml.toDomString()).join('')
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,10 @@
 | 
				
			|||||||
import YMap from '../YMap/YMap.js'
 | 
					import YMap from '../YMap/YMap.js'
 | 
				
			||||||
import { createAssociation } from '../../Bindings/DomBinding/util.js'
 | 
					import { createAssociation } from '../../../bindings/DomBinding/util.js'
 | 
				
			||||||
import * as encoding from '../../../lib/encoding.js'
 | 
					import * as encoding from '../../../lib/encoding.js'
 | 
				
			||||||
import * as decoding from '../../../lib/decoding.js'
 | 
					import * as decoding from '../../../lib/decoding.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @typedef {import('../../Bindings/DomBinding/DomBinding.js').default} DomBinding
 | 
					 * @typedef {import('../../../bindings/DomBinding/DomBinding.js').default} DomBinding
 | 
				
			||||||
 * @typedef {import('../../Y.js').default} Y
 | 
					 * @typedef {import('../../Y.js').default} Y
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
import YText from '../YText/YText.js'
 | 
					import YText from '../YText/YText.js'
 | 
				
			||||||
import { createAssociation } from '../../Bindings/DomBinding/util.js'
 | 
					import { createAssociation } from '../../../bindings/DomBinding/util.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @typedef {import('../../Bindings/DomBinding/DomBinding.js').default} DomBinding
 | 
					 * @typedef {import('../../../bindings/DomBinding/DomBinding.js').default} DomBinding
 | 
				
			||||||
 * @typedef {import('../../index.js').Y} Y
 | 
					 * @typedef {import('../../index.js').Y} Y
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -30,12 +30,6 @@ export { default as XmlElement } from './Types/YXml/YXmlElement.js'
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export { getRelativePosition, fromRelativePosition } from './Util/relativePosition.js'
 | 
					export { getRelativePosition, fromRelativePosition } from './Util/relativePosition.js'
 | 
				
			||||||
export { registerStruct as registerType } from './Util/structReferences.js'
 | 
					export { registerStruct as registerType } from './Util/structReferences.js'
 | 
				
			||||||
export { default as TextareaBinding } from './Bindings/TextareaBinding/TextareaBinding.js'
 | 
					 | 
				
			||||||
export { default as QuillBinding } from './Bindings/QuillBinding/QuillBinding.js'
 | 
					 | 
				
			||||||
export { default as DomBinding } from './Bindings/DomBinding/DomBinding.js'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export { default as domToType } from './Bindings/DomBinding/domToType.js'
 | 
					 | 
				
			||||||
export { domsToTypes, switchAssociation } from './Bindings/DomBinding/util.js'
 | 
					 | 
				
			||||||
export * from './message.js'
 | 
					export * from './message.js'
 | 
				
			||||||
export * from '../lib/encoding.js'
 | 
					export * from '../lib/encoding.js'
 | 
				
			||||||
export * from '../lib/decoding.js'
 | 
					export * from '../lib/decoding.js'
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user