Compare commits
27 Commits
v13-doc
...
v13.0.0-61
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d50d408cdd | ||
|
|
db5312443e | ||
|
|
dbda07424b | ||
|
|
684d38d6c8 | ||
|
|
44fa064eb2 | ||
|
|
9b6fffd880 | ||
|
|
e9993b2643 | ||
|
|
762e9e8a3a | ||
|
|
6ddeb788c7 | ||
|
|
b9245f323c | ||
|
|
c0e630b635 | ||
|
|
e56457a0ef | ||
|
|
ca13849828 | ||
|
|
92c2fbd6d3 | ||
|
|
65b8921f05 | ||
|
|
1ace7f4b73 | ||
|
|
6336064516 | ||
|
|
49d2e42b41 | ||
|
|
c098e8e745 | ||
|
|
38558a7fad | ||
|
|
bdb3782f8f | ||
|
|
bc32f7348e | ||
|
|
09a94f053e | ||
|
|
0df0079fa3 | ||
|
|
ed2273e2ed | ||
|
|
941a22b257 | ||
|
|
4aa41b98a9 |
@@ -70,7 +70,6 @@ missing modules.
|
||||
<script src="https://cdn.jsdelivr.net/npm/y-array@10/dist/y-array.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/y-websockets-client@8/dist/y-websockets-client.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/y-memory@8/dist/y-memory.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/y-array@10/dist/y-array.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/y-map@10/dist/y-map.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/y-text@9/dist/y-text.js"></script>
|
||||
// ..
|
||||
@@ -89,7 +88,6 @@ var Y = require('yjs')
|
||||
require('y-array')(Y) // add the y-array type to Yjs
|
||||
require('y-websockets-client')(Y)
|
||||
require('y-memory')(Y)
|
||||
require('y-array')(Y)
|
||||
require('y-map')(Y)
|
||||
require('y-text')(Y)
|
||||
// ..
|
||||
@@ -102,7 +100,6 @@ import Y from 'yjs'
|
||||
import yArray from 'y-array'
|
||||
import yWebsocketsClient from 'y-webrtc'
|
||||
import yMemory from 'y-memory'
|
||||
import yArray from 'y-array'
|
||||
import yMap from 'y-map'
|
||||
import yText from 'y-text'
|
||||
// ..
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* global Y */
|
||||
|
||||
window.onload = function () {
|
||||
window.domBinding = new Y.DomBinding(window.yXmlType, document.body)
|
||||
window.domBinding = new Y.DomBinding(window.yXmlType, document.body, { scrollingElement: document.scrollingElement })
|
||||
}
|
||||
|
||||
let y = new Y('htmleditor', {
|
||||
|
||||
28
package-lock.json
generated
28
package-lock.json
generated
@@ -1,9 +1,21 @@
|
||||
{
|
||||
"name": "yjs",
|
||||
"version": "13.0.0-54",
|
||||
"version": "13.0.0-61",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@types/estree": {
|
||||
"version": "0.0.38",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.38.tgz",
|
||||
"integrity": "sha512-F/v7t1LwS4vnXuPooJQGBRKRGIoxWUTmA4VHfqjOccFsNDThD5bfUNpITive6s352O7o384wcpEaDV8rHCehDA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "6.0.110",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.110.tgz",
|
||||
"integrity": "sha512-LiaH3mF+OAqR+9Wo1OTJDbZDtCewAVjTbMhF1ZgUJ3fc8xqOJq6VqbpBh9dJVCVzByGmYIg2fREbuXNX0TKiJA==",
|
||||
"dev": true
|
||||
},
|
||||
"abab": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
|
||||
@@ -1498,6 +1510,7 @@
|
||||
"version": "2.6.8",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
|
||||
"integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
@@ -4806,7 +4819,8 @@
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
||||
"dev": true
|
||||
},
|
||||
"mute-stream": {
|
||||
"version": "0.0.5",
|
||||
@@ -5629,6 +5643,16 @@
|
||||
"glob": "7.1.2"
|
||||
}
|
||||
},
|
||||
"rollup": {
|
||||
"version": "0.58.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-0.58.2.tgz",
|
||||
"integrity": "sha512-RZVvCWm9BHOYloaE6LLiE/ibpjv1CmI8F8k0B0Cp+q1eezo3cswszJH1DN0djgzSlo0hjuuCmyeI+1XOYLl4wg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/estree": "0.0.38",
|
||||
"@types/node": "6.0.110"
|
||||
}
|
||||
},
|
||||
"rollup-plugin-babel": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-2.7.1.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "yjs",
|
||||
"version": "13.0.0-54",
|
||||
"version": "13.0.0-61",
|
||||
"description": "A framework for real-time p2p shared editing on any data",
|
||||
"main": "./y.node.js",
|
||||
"browser": "./y.js",
|
||||
@@ -61,6 +61,7 @@
|
||||
"esdoc-standard-plugin": "^1.0.0",
|
||||
"quill": "^1.3.5",
|
||||
"quill-cursors": "^1.0.2",
|
||||
"rollup": "^0.58.2",
|
||||
"rollup-plugin-babel": "^2.7.1",
|
||||
"rollup-plugin-commonjs": "^8.0.2",
|
||||
"rollup-plugin-inject": "^2.0.0",
|
||||
@@ -71,8 +72,5 @@
|
||||
"rollup-watch": "^3.2.2",
|
||||
"standard": "^10.0.2",
|
||||
"tag-dist-files": "^0.1.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": "^2.6.8"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ export default class DomBinding extends Binding {
|
||||
this.opts = opts
|
||||
opts.document = opts.document || document
|
||||
opts.hooks = opts.hooks || {}
|
||||
this.scrollingElement = opts.scrollingElement || null
|
||||
/**
|
||||
* Maps each DOM element to the type that it is associated with.
|
||||
* @type {Map}
|
||||
@@ -105,17 +106,6 @@ export default class DomBinding extends Binding {
|
||||
createAssociation(this, target, type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the smart scrolling functionality for a Dom Binding.
|
||||
* This is useful when YXml is bound to a shared editor. When activated,
|
||||
* the viewport will be changed to accommodate remote changes.
|
||||
*
|
||||
* @param {Element} scrollElement The node that is
|
||||
*/
|
||||
enableSmartScrolling (scrollElement) {
|
||||
// @TODO: implement smart scrolling
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: currently does not apply filter to existing elements!
|
||||
* @param {FilterFunction} filter The filter function to use from now on.
|
||||
@@ -131,12 +121,11 @@ export default class DomBinding extends Binding {
|
||||
destroy () {
|
||||
this.domToType = null
|
||||
this.typeToDom = null
|
||||
this.type.unobserve(this._typeObserver)
|
||||
this.type.unobserveDeep(this._typeObserver)
|
||||
this._mutationObserver.disconnect()
|
||||
const y = this.type._y
|
||||
y.off('beforeTransaction', this._beforeTransactionHandler)
|
||||
y.off('beforeObserverCalls', this._beforeObserverCallsHandler)
|
||||
y.off('afterObserverCalls', this._afterObserverCallsHandler)
|
||||
y.off('afterTransaction', this._afterTransactionHandler)
|
||||
super.destroy()
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ function applyChangesFromDom (binding, dom, yxml, _document) {
|
||||
removeAssociation(binding, childNode, childType)
|
||||
} else {
|
||||
// child was moved to a different position.
|
||||
childType._delete(y)
|
||||
removeAssociation(binding, childNode, childType)
|
||||
childType._delete(y)
|
||||
}
|
||||
prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding)
|
||||
} else {
|
||||
@@ -90,8 +90,19 @@ export default function domObserver (mutations, _document) {
|
||||
mutations.forEach(mutation => {
|
||||
const dom = mutation.target
|
||||
const yxml = this.domToType.get(dom)
|
||||
if (yxml === false || yxml === undefined || yxml.constructor === YXmlHook) {
|
||||
// dom element is filtered
|
||||
if (yxml === undefined) { // In case yxml is undefined, we double check if we forgot to bind the dom
|
||||
let parent = dom
|
||||
let yParent
|
||||
do {
|
||||
parent = parent.parentElement
|
||||
yParent = this.domToType.get(parent)
|
||||
} while (yParent === undefined && parent !== null)
|
||||
if (yParent !== false && yParent !== undefined && yParent.constructor !== YXmlHook) {
|
||||
diffChildren.add(parent)
|
||||
}
|
||||
return
|
||||
} else if (yxml === false || yxml.constructor === YXmlHook) {
|
||||
// dom element is filtered / a dom hook
|
||||
return
|
||||
}
|
||||
switch (mutation.type) {
|
||||
@@ -125,9 +136,6 @@ export default function domObserver (mutations, _document) {
|
||||
}
|
||||
})
|
||||
for (let dom of diffChildren) {
|
||||
if (dom.yOnChildrenChanged !== undefined) {
|
||||
dom.yOnChildrenChanged()
|
||||
}
|
||||
const yxml = this.domToType.get(dom)
|
||||
applyChangesFromDom(this, dom, yxml, _document)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
|
||||
import { YXmlText, YXmlElement, YXmlHook } from '../../Types/YXml/YXml.js'
|
||||
import YXmlText from '../../Types/YXml/YXmlText.js'
|
||||
import YXmlHook from '../../Types/YXml/YXmlHook.js'
|
||||
import YXmlElement from '../../Types/YXml/YXmlElement.js'
|
||||
import { createAssociation, domsToTypes } from './util.js'
|
||||
import { filterDomAttributes, defaultFilter } from './filter.js'
|
||||
|
||||
|
||||
@@ -1,20 +1,55 @@
|
||||
/* global getSelection */
|
||||
|
||||
import YXmlText from '../../Types/YXml/YXmlText.js'
|
||||
import YXmlHook from '../../Types/YXml/YXmlHook.js'
|
||||
import { removeDomChildrenUntilElementFound } from './util.js'
|
||||
|
||||
function findScrollReference (scrollingElement) {
|
||||
if (scrollingElement !== null) {
|
||||
let anchor = getSelection().anchorNode
|
||||
if (anchor == null) {
|
||||
let children = scrollingElement.children // only iterate through non-text nodes
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const elem = children[i]
|
||||
const rect = elem.getBoundingClientRect()
|
||||
if (rect.top >= 0) {
|
||||
return { elem, top: rect.top }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (anchor.nodeType === document.TEXT_NODE) {
|
||||
anchor = anchor.parentElement
|
||||
}
|
||||
const top = anchor.getBoundingClientRect().top
|
||||
return { elem: anchor, top: top }
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function fixScroll (scrollingElement, ref) {
|
||||
if (ref !== null) {
|
||||
const { elem, top } = ref
|
||||
const currentTop = elem.getBoundingClientRect().top
|
||||
const newScroll = scrollingElement.scrollTop + currentTop - top
|
||||
if (newScroll >= 0) {
|
||||
scrollingElement.scrollTop = newScroll
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export default function typeObserver (events) {
|
||||
this._mutualExclude(() => {
|
||||
const scrollRef = findScrollReference(this.scrollingElement)
|
||||
events.forEach(event => {
|
||||
const yxml = event.target
|
||||
const dom = this.typeToDom.get(yxml)
|
||||
if (dom !== undefined && dom !== false) {
|
||||
if (yxml.constructor === YXmlText) {
|
||||
dom.nodeValue = yxml.toString()
|
||||
// TODO: use hasOwnProperty instead of === undefined check
|
||||
} else if (event.attributesChanged !== undefined) {
|
||||
// update attributes
|
||||
event.attributesChanged.forEach(attributeName => {
|
||||
@@ -59,5 +94,6 @@ export default function typeObserver (events) {
|
||||
}
|
||||
}
|
||||
})
|
||||
fixScroll(this.scrollingElement, scrollRef)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ function _integrateRemoteStructHelper (y, struct) {
|
||||
if (y.ss.getState(id.user) > id.clock) {
|
||||
return
|
||||
}
|
||||
if (struct.constructor === GC || (struct._parent.constructor !== GC && struct._parent._deleted === false)) {
|
||||
if (!y.gcEnabled || struct.constructor === GC || (struct._parent.constructor !== GC && struct._parent._deleted === false)) {
|
||||
// Is either a GC or Item with an undeleted parent
|
||||
// save to integrate
|
||||
struct._integrate(y)
|
||||
|
||||
@@ -61,5 +61,5 @@ export function logID (id) {
|
||||
export function logItemHelper (name, item, append) {
|
||||
const left = item._left !== null ? item._left._lastId : null
|
||||
const origin = item._origin !== null ? item._origin._lastId : null
|
||||
return `${name}(id:${logID(item._id)},start:${logID(item._start)},left:${logID(left)},origin:${logID(origin)},right:${logID(item._right)},parent:${logID(item._parent)},parentSub:${item._parentSub}${append !== undefined ? ' - ' + append : ''})`
|
||||
return `${name}(id:${logID(item._id)},left:${logID(left)},origin:${logID(origin)},right:${logID(item._right)},parent:${logID(item._parent)},parentSub:${item._parentSub}${append !== undefined ? ' - ' + append : ''})`
|
||||
}
|
||||
|
||||
@@ -217,8 +217,8 @@ export default class Type extends Item {
|
||||
* collect the children of this type.
|
||||
*/
|
||||
_delete (y, createDelete, gcChildren) {
|
||||
if (gcChildren === undefined) {
|
||||
gcChildren = y._hasUndoManager === false
|
||||
if (gcChildren === undefined || !y.gcEnabled) {
|
||||
gcChildren = y._hasUndoManager === false && y.gcEnabled
|
||||
}
|
||||
super._delete(y, createDelete, gcChildren)
|
||||
y._transaction.changedTypes.delete(this)
|
||||
|
||||
@@ -155,7 +155,7 @@ function insertAttributes (y, parent, left, right, attributes, currentAttributes
|
||||
*/
|
||||
function insertText (y, text, parent, left, right, currentAttributes, attributes) {
|
||||
for (let [key] of currentAttributes) {
|
||||
if (attributes.hasOwnProperty(key) === false) {
|
||||
if (attributes[key] === undefined) {
|
||||
attributes[key] = null
|
||||
}
|
||||
}
|
||||
@@ -189,8 +189,9 @@ function formatText (y, length, parent, left, right, currentAttributes, attribut
|
||||
if (right._deleted === false) {
|
||||
switch (right.constructor) {
|
||||
case ItemFormat:
|
||||
if (attributes.hasOwnProperty(right.key)) {
|
||||
if (attributes[right.key] === right.value) {
|
||||
const attr = attributes[right.key]
|
||||
if (attr !== undefined) {
|
||||
if (attr === right.value) {
|
||||
negatedAttributes.delete(right.key)
|
||||
} else {
|
||||
negatedAttributes.set(right.key, right.value)
|
||||
@@ -405,8 +406,9 @@ class YTextEvent extends YArrayEvent {
|
||||
}
|
||||
} else if (item._deleted === false) {
|
||||
oldAttributes.set(item.key, item.value)
|
||||
if (attributes.hasOwnProperty(item.key)) {
|
||||
if (attributes[item.key] !== item.value) {
|
||||
const attr = attributes[item.key]
|
||||
if (attr !== undefined) {
|
||||
if (attr !== item.value) {
|
||||
if (action === 'retain') {
|
||||
addOp()
|
||||
}
|
||||
@@ -433,7 +435,7 @@ class YTextEvent extends YArrayEvent {
|
||||
addOp()
|
||||
while (this._delta.length > 0) {
|
||||
let lastOp = this._delta[this._delta.length - 1]
|
||||
if (lastOp.hasOwnProperty('retain') && !lastOp.hasOwnProperty('attributes')) {
|
||||
if (lastOp.retain !== undefined && lastOp.attributes === undefined) {
|
||||
// retain delta's if they don't assign attributes
|
||||
this._delta.pop()
|
||||
} else {
|
||||
@@ -505,11 +507,11 @@ export default class YText extends YArray {
|
||||
const currentAttributes = new Map()
|
||||
for (let i = 0; i < delta.length; i++) {
|
||||
let op = delta[i]
|
||||
if (op.hasOwnProperty('insert')) {
|
||||
if (op.insert !== undefined) {
|
||||
;[left, right] = insertText(y, op.insert, this, left, right, currentAttributes, op.attributes || {})
|
||||
} else if (op.hasOwnProperty('retain')) {
|
||||
} else if (op.retain !== undefined) {
|
||||
;[left, right] = formatText(y, op.retain, this, left, right, currentAttributes, op.attributes || {})
|
||||
} else if (op.hasOwnProperty('delete')) {
|
||||
} else if (op.delete !== undefined) {
|
||||
;[left, right] = deleteText(y, op.delete, this, left, right, currentAttributes)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
import YXmlFragment from './YXmlFragment.js'
|
||||
import YXmlElement from './YXmlElement.js'
|
||||
import YXmlHook from './YXmlHook.js'
|
||||
|
||||
export { default as YXmlFragment } from './YXmlFragment.js'
|
||||
export { default as YXmlElement } from './YXmlElement.js'
|
||||
export { default as YXmlText } from './YXmlText.js'
|
||||
export { default as YXmlHook } from './YXmlHook.js'
|
||||
|
||||
YXmlFragment._YXmlElement = YXmlElement
|
||||
YXmlFragment._YXmlHook = YXmlHook
|
||||
@@ -1,5 +1,5 @@
|
||||
import YMap from '../YMap/YMap.js'
|
||||
import { YXmlFragment } from './YXml.js'
|
||||
import YXmlFragment from './YXmlFragment.js'
|
||||
import { createAssociation } from '../../Bindings/DomBinding/util.js'
|
||||
|
||||
/**
|
||||
@@ -186,3 +186,5 @@ export default class YXmlElement extends YXmlFragment {
|
||||
return dom
|
||||
}
|
||||
}
|
||||
|
||||
YXmlFragment._YXmlElement = YXmlElement
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import YArray from '../Types/YArray/YArray.js'
|
||||
import YMap from '../Types/YMap/YMap.js'
|
||||
import YText from '../Types/YText/YText.js'
|
||||
import { YXmlFragment, YXmlElement, YXmlText, YXmlHook } from '../Types/YXml/YXml.js'
|
||||
import YXmlText from '../Types/YXml/YXmlText.js'
|
||||
import YXmlHook from '../Types/YXml/YXmlHook.js'
|
||||
import YXmlFragment from '../Types/YXml/YXmlFragment.js'
|
||||
import YXmlElement from '../Types/YXml/YXmlElement.js'
|
||||
|
||||
import Delete from '../Struct/Delete.js'
|
||||
import ItemJSON from '../Struct/ItemJSON.js'
|
||||
|
||||
@@ -10,7 +10,10 @@ import Persistence from './Persistence.js'
|
||||
import YArray from './Types/YArray/YArray.js'
|
||||
import YMap from './Types/YMap/YMap.js'
|
||||
import YText from './Types/YText/YText.js'
|
||||
import { YXmlFragment, YXmlElement, YXmlText, YXmlHook } from './Types/YXml/YXml.js'
|
||||
import YXmlText from './Types/YXml/YXmlText.js'
|
||||
import YXmlHook from './Types/YXml/YXmlHook.js'
|
||||
import YXmlFragment from './Types/YXml/YXmlFragment.js'
|
||||
import YXmlElement from './Types/YXml/YXmlElement.js'
|
||||
import BinaryDecoder from './Util/Binary/Decoder.js'
|
||||
import { getRelativePosition, fromRelativePosition } from './Util/relativePosition.js'
|
||||
import { registerStruct } from './Util/structReferences.js'
|
||||
|
||||
3
src/Y.js
3
src/Y.js
@@ -28,8 +28,9 @@ export { default as DomBinding } from './Bindings/DomBinding/DomBinding.js'
|
||||
* @param {AbstractPersistence} persistence Persistence adapter instance
|
||||
*/
|
||||
export default class Y extends NamedEventHandler {
|
||||
constructor (room, opts, persistence) {
|
||||
constructor (room, opts, persistence, conf = {}) {
|
||||
super()
|
||||
this.gcEnabled = conf.gc || false
|
||||
/**
|
||||
* The room name that this Yjs instance connects to.
|
||||
* @type {String}
|
||||
|
||||
1
y.node.js.map
Normal file
1
y.node.js.map
Normal file
File diff suppressed because one or more lines are too long
1
y.test.js.map
Normal file
1
y.test.js.map
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user