Compare commits

..

1 Commits

Author SHA1 Message Date
Kevin Jahns
3bac7362c2 v13.0.0-57 -- distribution files 2018-05-02 18:43:14 +02:00
20 changed files with 20191 additions and 6260 deletions

View File

@@ -70,6 +70,7 @@ 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-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-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-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-map@10/dist/y-map.js"></script>
<script src="https://cdn.jsdelivr.net/npm/y-text@9/dist/y-text.js"></script> <script src="https://cdn.jsdelivr.net/npm/y-text@9/dist/y-text.js"></script>
// .. // ..
@@ -88,6 +89,7 @@ var Y = require('yjs')
require('y-array')(Y) // add the y-array type to Yjs require('y-array')(Y) // add the y-array type to Yjs
require('y-websockets-client')(Y) require('y-websockets-client')(Y)
require('y-memory')(Y) require('y-memory')(Y)
require('y-array')(Y)
require('y-map')(Y) require('y-map')(Y)
require('y-text')(Y) require('y-text')(Y)
// .. // ..
@@ -100,6 +102,7 @@ import Y from 'yjs'
import yArray from 'y-array' import yArray from 'y-array'
import yWebsocketsClient from 'y-webrtc' import yWebsocketsClient from 'y-webrtc'
import yMemory from 'y-memory' import yMemory from 'y-memory'
import yArray from 'y-array'
import yMap from 'y-map' import yMap from 'y-map'
import yText from 'y-text' import yText from 'y-text'
// .. // ..

View File

@@ -1,7 +1,7 @@
/* global Y */ /* global Y */
window.onload = function () { window.onload = function () {
window.domBinding = new Y.DomBinding(window.yXmlType, document.body, { scrollingElement: document.scrollingElement }) window.domBinding = new Y.DomBinding(window.yXmlType, document.body)
} }
let y = new Y('htmleditor', { let y = new Y('htmleditor', {

28
package-lock.json generated
View File

@@ -1,21 +1,9 @@
{ {
"name": "yjs", "name": "yjs",
"version": "13.0.0-61", "version": "13.0.0-57",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "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": { "abab": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
@@ -1510,7 +1498,6 @@
"version": "2.6.8", "version": "2.6.8",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
"integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
"dev": true,
"requires": { "requires": {
"ms": "2.0.0" "ms": "2.0.0"
} }
@@ -4819,8 +4806,7 @@
"ms": { "ms": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
"dev": true
}, },
"mute-stream": { "mute-stream": {
"version": "0.0.5", "version": "0.0.5",
@@ -5643,16 +5629,6 @@
"glob": "7.1.2" "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": { "rollup-plugin-babel": {
"version": "2.7.1", "version": "2.7.1",
"resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-2.7.1.tgz", "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-2.7.1.tgz",

View File

@@ -1,6 +1,6 @@
{ {
"name": "yjs", "name": "yjs",
"version": "13.0.0-61", "version": "13.0.0-57",
"description": "A framework for real-time p2p shared editing on any data", "description": "A framework for real-time p2p shared editing on any data",
"main": "./y.node.js", "main": "./y.node.js",
"browser": "./y.js", "browser": "./y.js",
@@ -61,7 +61,6 @@
"esdoc-standard-plugin": "^1.0.0", "esdoc-standard-plugin": "^1.0.0",
"quill": "^1.3.5", "quill": "^1.3.5",
"quill-cursors": "^1.0.2", "quill-cursors": "^1.0.2",
"rollup": "^0.58.2",
"rollup-plugin-babel": "^2.7.1", "rollup-plugin-babel": "^2.7.1",
"rollup-plugin-commonjs": "^8.0.2", "rollup-plugin-commonjs": "^8.0.2",
"rollup-plugin-inject": "^2.0.0", "rollup-plugin-inject": "^2.0.0",
@@ -72,5 +71,8 @@
"rollup-watch": "^3.2.2", "rollup-watch": "^3.2.2",
"standard": "^10.0.2", "standard": "^10.0.2",
"tag-dist-files": "^0.1.6" "tag-dist-files": "^0.1.6"
},
"dependencies": {
"debug": "^2.6.8"
} }
} }

View File

@@ -33,7 +33,6 @@ export default class DomBinding extends Binding {
this.opts = opts this.opts = opts
opts.document = opts.document || document opts.document = opts.document || document
opts.hooks = opts.hooks || {} opts.hooks = opts.hooks || {}
this.scrollingElement = opts.scrollingElement || null
/** /**
* Maps each DOM element to the type that it is associated with. * Maps each DOM element to the type that it is associated with.
* @type {Map} * @type {Map}
@@ -106,6 +105,17 @@ export default class DomBinding extends Binding {
createAssociation(this, target, type) 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! * NOTE: currently does not apply filter to existing elements!
* @param {FilterFunction} filter The filter function to use from now on. * @param {FilterFunction} filter The filter function to use from now on.
@@ -121,11 +131,12 @@ export default class DomBinding extends Binding {
destroy () { destroy () {
this.domToType = null this.domToType = null
this.typeToDom = null this.typeToDom = null
this.type.unobserveDeep(this._typeObserver) this.type.unobserve(this._typeObserver)
this._mutationObserver.disconnect() this._mutationObserver.disconnect()
const y = this.type._y const y = this.type._y
y.off('beforeTransaction', this._beforeTransactionHandler) y.off('beforeTransaction', this._beforeTransactionHandler)
y.off('beforeObserverCalls', this._beforeObserverCallsHandler) y.off('beforeObserverCalls', this._beforeObserverCallsHandler)
y.off('afterObserverCalls', this._afterObserverCallsHandler)
y.off('afterTransaction', this._afterTransactionHandler) y.off('afterTransaction', this._afterTransactionHandler)
super.destroy() super.destroy()
} }

View File

@@ -60,8 +60,8 @@ function applyChangesFromDom (binding, dom, yxml, _document) {
removeAssociation(binding, childNode, childType) removeAssociation(binding, childNode, childType)
} else { } else {
// child was moved to a different position. // child was moved to a different position.
removeAssociation(binding, childNode, childType)
childType._delete(y) childType._delete(y)
removeAssociation(binding, childNode, childType)
} }
prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding) prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding)
} else { } else {
@@ -90,19 +90,8 @@ export default function domObserver (mutations, _document) {
mutations.forEach(mutation => { mutations.forEach(mutation => {
const dom = mutation.target const dom = mutation.target
const yxml = this.domToType.get(dom) const yxml = this.domToType.get(dom)
if (yxml === undefined) { // In case yxml is undefined, we double check if we forgot to bind the dom if (yxml === false || yxml === undefined || yxml.constructor === YXmlHook) {
let parent = dom // dom element is filtered
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 return
} }
switch (mutation.type) { switch (mutation.type) {
@@ -136,6 +125,9 @@ export default function domObserver (mutations, _document) {
} }
}) })
for (let dom of diffChildren) { for (let dom of diffChildren) {
if (dom.yOnChildrenChanged !== undefined) {
dom.yOnChildrenChanged()
}
const yxml = this.domToType.get(dom) const yxml = this.domToType.get(dom)
applyChangesFromDom(this, dom, yxml, _document) applyChangesFromDom(this, dom, yxml, _document)
} }

View File

@@ -1,7 +1,5 @@
import YXmlText from '../../Types/YXml/YXmlText.js' import { YXmlText, YXmlElement, YXmlHook } from '../../Types/YXml/YXml.js'
import YXmlHook from '../../Types/YXml/YXmlHook.js'
import YXmlElement from '../../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'

View File

@@ -1,55 +1,20 @@
/* global getSelection */
import YXmlText from '../../Types/YXml/YXmlText.js' import YXmlText from '../../Types/YXml/YXmlText.js'
import YXmlHook from '../../Types/YXml/YXmlHook.js' import YXmlHook from '../../Types/YXml/YXmlHook.js'
import { removeDomChildrenUntilElementFound } from './util.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 * @private
*/ */
export default function typeObserver (events) { export default function typeObserver (events) {
this._mutualExclude(() => { this._mutualExclude(() => {
const scrollRef = findScrollReference(this.scrollingElement)
events.forEach(event => { events.forEach(event => {
const yxml = event.target const yxml = event.target
const dom = this.typeToDom.get(yxml) const dom = this.typeToDom.get(yxml)
if (dom !== undefined && dom !== false) { if (dom !== undefined && dom !== false) {
if (yxml.constructor === YXmlText) { if (yxml.constructor === YXmlText) {
dom.nodeValue = yxml.toString() dom.nodeValue = yxml.toString()
// TODO: use hasOwnProperty instead of === undefined check
} else if (event.attributesChanged !== undefined) { } else if (event.attributesChanged !== undefined) {
// update attributes // update attributes
event.attributesChanged.forEach(attributeName => { event.attributesChanged.forEach(attributeName => {
@@ -94,6 +59,5 @@ export default function typeObserver (events) {
} }
} }
}) })
fixScroll(this.scrollingElement, scrollRef)
}) })
} }

View File

@@ -61,5 +61,5 @@ export function logID (id) {
export function logItemHelper (name, item, append) { export function logItemHelper (name, item, append) {
const left = item._left !== null ? item._left._lastId : null const left = item._left !== null ? item._left._lastId : null
const origin = item._origin !== null ? item._origin._lastId : null const origin = item._origin !== null ? item._origin._lastId : null
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 : ''})` 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 : ''})`
} }

View File

@@ -155,7 +155,7 @@ function insertAttributes (y, parent, left, right, attributes, currentAttributes
*/ */
function insertText (y, text, parent, left, right, currentAttributes, attributes) { function insertText (y, text, parent, left, right, currentAttributes, attributes) {
for (let [key] of currentAttributes) { for (let [key] of currentAttributes) {
if (attributes[key] === undefined) { if (attributes.hasOwnProperty(key) === false) {
attributes[key] = null attributes[key] = null
} }
} }
@@ -189,9 +189,8 @@ function formatText (y, length, parent, left, right, currentAttributes, attribut
if (right._deleted === false) { if (right._deleted === false) {
switch (right.constructor) { switch (right.constructor) {
case ItemFormat: case ItemFormat:
const attr = attributes[right.key] if (attributes.hasOwnProperty(right.key)) {
if (attr !== undefined) { if (attributes[right.key] === right.value) {
if (attr === right.value) {
negatedAttributes.delete(right.key) negatedAttributes.delete(right.key)
} else { } else {
negatedAttributes.set(right.key, right.value) negatedAttributes.set(right.key, right.value)
@@ -406,9 +405,8 @@ class YTextEvent extends YArrayEvent {
} }
} else if (item._deleted === false) { } else if (item._deleted === false) {
oldAttributes.set(item.key, item.value) oldAttributes.set(item.key, item.value)
const attr = attributes[item.key] if (attributes.hasOwnProperty(item.key)) {
if (attr !== undefined) { if (attributes[item.key] !== item.value) {
if (attr !== item.value) {
if (action === 'retain') { if (action === 'retain') {
addOp() addOp()
} }
@@ -435,7 +433,7 @@ class YTextEvent extends YArrayEvent {
addOp() addOp()
while (this._delta.length > 0) { while (this._delta.length > 0) {
let lastOp = this._delta[this._delta.length - 1] let lastOp = this._delta[this._delta.length - 1]
if (lastOp.retain !== undefined && lastOp.attributes === undefined) { if (lastOp.hasOwnProperty('retain') && !lastOp.hasOwnProperty('attributes')) {
// retain delta's if they don't assign attributes // retain delta's if they don't assign attributes
this._delta.pop() this._delta.pop()
} else { } else {
@@ -507,11 +505,11 @@ export default class YText extends YArray {
const currentAttributes = new Map() const currentAttributes = new Map()
for (let i = 0; i < delta.length; i++) { for (let i = 0; i < delta.length; i++) {
let op = delta[i] let op = delta[i]
if (op.insert !== undefined) { if (op.hasOwnProperty('insert')) {
;[left, right] = insertText(y, op.insert, this, left, right, currentAttributes, op.attributes || {}) ;[left, right] = insertText(y, op.insert, this, left, right, currentAttributes, op.attributes || {})
} else if (op.retain !== undefined) { } else if (op.hasOwnProperty('retain')) {
;[left, right] = formatText(y, op.retain, this, left, right, currentAttributes, op.attributes || {}) ;[left, right] = formatText(y, op.retain, this, left, right, currentAttributes, op.attributes || {})
} else if (op.delete !== undefined) { } else if (op.hasOwnProperty('delete')) {
;[left, right] = deleteText(y, op.delete, this, left, right, currentAttributes) ;[left, right] = deleteText(y, op.delete, this, left, right, currentAttributes)
} }
} }

12
src/Types/YXml/YXml.js Normal file
View File

@@ -0,0 +1,12 @@
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

View File

@@ -1,5 +1,5 @@
import YMap from '../YMap/YMap.js' import YMap from '../YMap/YMap.js'
import YXmlFragment from './YXmlFragment.js' import { YXmlFragment } from './YXml.js'
import { createAssociation } from '../../Bindings/DomBinding/util.js' import { createAssociation } from '../../Bindings/DomBinding/util.js'
/** /**
@@ -186,5 +186,3 @@ export default class YXmlElement extends YXmlFragment {
return dom return dom
} }
} }
YXmlFragment._YXmlElement = YXmlElement

View File

@@ -1,10 +1,7 @@
import YArray from '../Types/YArray/YArray.js' import YArray from '../Types/YArray/YArray.js'
import YMap from '../Types/YMap/YMap.js' import YMap from '../Types/YMap/YMap.js'
import YText from '../Types/YText/YText.js' import YText from '../Types/YText/YText.js'
import YXmlText from '../Types/YXml/YXmlText.js' import { YXmlFragment, YXmlElement, YXmlText, YXmlHook } from '../Types/YXml/YXml.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 Delete from '../Struct/Delete.js'
import ItemJSON from '../Struct/ItemJSON.js' import ItemJSON from '../Struct/ItemJSON.js'

View File

@@ -10,10 +10,7 @@ import Persistence from './Persistence.js'
import YArray from './Types/YArray/YArray.js' import YArray from './Types/YArray/YArray.js'
import YMap from './Types/YMap/YMap.js' import YMap from './Types/YMap/YMap.js'
import YText from './Types/YText/YText.js' import YText from './Types/YText/YText.js'
import YXmlText from './Types/YXml/YXmlText.js' import { YXmlFragment, YXmlElement, YXmlText, YXmlHook } from './Types/YXml/YXml.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 BinaryDecoder from './Util/Binary/Decoder.js'
import { getRelativePosition, fromRelativePosition } from './Util/relativePosition.js' import { getRelativePosition, fromRelativePosition } from './Util/relativePosition.js'
import { registerStruct } from './Util/structReferences.js' import { registerStruct } from './Util/structReferences.js'

8
y.js

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

847
y.node.js

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

25426
y.test.js

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long