Compare commits

..

2 Commits

Author SHA1 Message Date
Kevin Jahns
783cbd63fc 13.0.0-31 2017-11-14 20:44:12 -08:00
Kevin Jahns
41be80e751 fix y-xml server environment 2017-11-14 20:43:30 -08:00
12 changed files with 94 additions and 25012 deletions

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "yjs", "name": "yjs",
"version": "13.0.0-30", "version": "13.0.0-31",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "yjs", "name": "yjs",
"version": "13.0.0-30", "version": "13.0.0-31",
"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",

View File

@@ -5,7 +5,7 @@ import YMap from '../YMap.js'
import YXmlFragment from './YXmlFragment.js' import YXmlFragment from './YXmlFragment.js'
export default class YXmlElement extends YXmlFragment { export default class YXmlElement extends YXmlFragment {
constructor (arg1, arg2) { constructor (arg1, arg2, _document) {
super() super()
this.nodeName = null this.nodeName = null
this._scrollElement = null this._scrollElement = null
@@ -13,7 +13,7 @@ export default class YXmlElement extends YXmlFragment {
this.nodeName = arg1.toUpperCase() this.nodeName = arg1.toUpperCase()
} else if (arg1 != null && arg1.nodeType != null && arg1.nodeType === arg1.ELEMENT_NODE) { } else if (arg1 != null && arg1.nodeType != null && arg1.nodeType === arg1.ELEMENT_NODE) {
this.nodeName = arg1.nodeName this.nodeName = arg1.nodeName
this._setDom(arg1) this._setDom(arg1, _document)
} else { } else {
this.nodeName = 'UNDEFINED' this.nodeName = 'UNDEFINED'
} }
@@ -26,14 +26,12 @@ export default class YXmlElement extends YXmlFragment {
struct.nodeName = this.nodeName struct.nodeName = this.nodeName
return struct return struct
} }
_setDom (dom) { _setDom (dom, _document) {
if (this._dom != null) { if (this._dom != null) {
throw new Error('Only call this method if you know what you are doing ;)') throw new Error('Only call this method if you know what you are doing ;)')
} else if (dom._yxml != null) { // TODO do i need to check this? - no.. but for dev purps.. } else if (dom._yxml != null) { // TODO do i need to check this? - no.. but for dev purps..
throw new Error('Already bound to an YXml type') throw new Error('Already bound to an YXml type')
} else { } else {
this._dom = dom
dom._yxml = this
// tag is already set in constructor // tag is already set in constructor
// set attributes // set attributes
let attrNames = [] let attrNames = []
@@ -46,8 +44,8 @@ export default class YXmlElement extends YXmlFragment {
let attrValue = dom.getAttribute(attrName) let attrValue = dom.getAttribute(attrName)
this.setAttribute(attrName, attrValue) this.setAttribute(attrName, attrValue)
} }
this.insertDomElements(0, Array.prototype.slice.call(dom.childNodes)) this.insertDomElements(0, Array.prototype.slice.call(dom.childNodes), _document)
this._bindToDom(dom) this._bindToDom(dom, _document)
return dom return dom
} }
} }
@@ -115,7 +113,6 @@ export default class YXmlElement extends YXmlFragment {
let dom = this._dom let dom = this._dom
if (dom == null) { if (dom == null) {
dom = _document.createElement(this.nodeName) dom = _document.createElement(this.nodeName)
this._dom = dom
dom._yxml = this dom._yxml = this
let attrs = this.getAttributes() let attrs = this.getAttributes()
for (let key in attrs) { for (let key in attrs) {
@@ -124,7 +121,7 @@ export default class YXmlElement extends YXmlFragment {
this.forEach(yxml => { this.forEach(yxml => {
dom.appendChild(yxml.getDom(_document)) dom.appendChild(yxml.getDom(_document))
}) })
this._bindToDom(dom) this._bindToDom(dom, _document)
} }
return dom return dom
} }

View File

@@ -9,7 +9,7 @@ import YXmlEvent from './YXmlEvent.js'
import { logID } from '../../MessageHandler/messageToString.js' import { logID } from '../../MessageHandler/messageToString.js'
import diff from 'fast-diff' import diff from 'fast-diff'
function domToYXml (parent, doms) { function domToYXml (parent, doms, _document) {
const types = [] const types = []
doms.forEach(d => { doms.forEach(d => {
if (d._yxml != null && d._yxml !== false) { if (d._yxml != null && d._yxml !== false) {
@@ -20,7 +20,7 @@ function domToYXml (parent, doms) {
if (d.nodeType === d.TEXT_NODE) { if (d.nodeType === d.TEXT_NODE) {
type = new YXmlText(d) type = new YXmlText(d)
} else if (d.nodeType === d.ELEMENT_NODE) { } else if (d.nodeType === d.ELEMENT_NODE) {
type = new YXmlFragment._YXmlElement(d, parent._domFilter) type = new YXmlFragment._YXmlElement(d, parent._domFilter, _document)
} else { } else {
throw new Error('Unsupported node!') throw new Error('Unsupported node!')
} }
@@ -98,7 +98,9 @@ export default class YXmlFragment extends YArray {
} catch (e) { } catch (e) {
console.error(e) console.error(e)
} }
this._domObserver.takeRecords() if (this._domObserver !== null) {
this._domObserver.takeRecords()
}
token = true token = true
} }
} }
@@ -162,113 +164,116 @@ export default class YXmlFragment extends YArray {
this._dom = null this._dom = null
} }
} }
insertDomElementsAfter (prev, doms) { insertDomElementsAfter (prev, doms, _document) {
const types = domToYXml(this, doms) const types = domToYXml(this, doms, _document)
this.insertAfter(prev, types) this.insertAfter(prev, types)
return types return types
} }
insertDomElements (pos, doms) { insertDomElements (pos, doms, _document) {
const types = domToYXml(this, doms) const types = domToYXml(this, doms, _document)
this.insert(pos, types) this.insert(pos, types)
return types return types
} }
getDom () { getDom () {
return this._dom return this._dom
} }
bindToDom (dom) { bindToDom (dom, _document) {
if (this._dom != null) { if (this._dom != null) {
this._unbindFromDom() this._unbindFromDom()
} }
if (dom._yxml != null) { if (dom._yxml != null) {
dom._yxml._unbindFromDom() dom._yxml._unbindFromDom()
} }
if (MutationObserver == null) {
throw new Error('Not able to bind to a DOM element, because MutationObserver is not available!')
}
dom.innerHTML = '' dom.innerHTML = ''
this._dom = dom
dom._yxml = this
this.forEach(t => { this.forEach(t => {
dom.insertBefore(t.getDom(), null) dom.insertBefore(t.getDom(_document), null)
}) })
this._bindToDom(dom) this._bindToDom(dom, _document)
} }
// binds to a dom element // binds to a dom element
// Only call if dom and YXml are isomorph // Only call if dom and YXml are isomorph
_bindToDom (dom) { _bindToDom (dom, _document) {
if (this._parent === null || this._parent._dom != null || typeof MutationObserver === 'undefined') { _document = _document || document
// only bind if parent did not already bind this._dom = dom
dom._yxml = this
// TODO: refine this..
if ((this.constructor !== YXmlFragment && this._parent !== this._y) || this._parent === null) {
// TODO: only top level YXmlFragment can bind. Also allow YXmlElements..
return return
} }
this._y.on('beforeTransaction', () => {
this._domObserverListener(this._domObserver.takeRecords())
})
this._y.on('beforeTransaction', beforeTransactionSelectionFixer) this._y.on('beforeTransaction', beforeTransactionSelectionFixer)
this._y.on('afterTransaction', afterTransactionSelectionFixer) this._y.on('afterTransaction', afterTransactionSelectionFixer)
// Apply Y.Xml events to dom // Apply Y.Xml events to dom
this.observeDeep(reflectChangesOnDom.bind(this)) this.observeDeep(events => {
reflectChangesOnDom.call(this, events, _document)
})
// Apply Dom changes on Y.Xml // Apply Dom changes on Y.Xml
this._domObserverListener = mutations => { if (typeof MutationObserver !== 'undefined') {
this._mutualExclude(() => { this._y.on('beforeTransaction', () => {
this._y.transact(() => { this._domObserverListener(this._domObserver.takeRecords())
let diffChildren = new Set() })
mutations.forEach(mutation => { this._domObserverListener = mutations => {
const dom = mutation.target this._mutualExclude(() => {
const yxml = dom._yxml this._y.transact(() => {
if (yxml == null) { let diffChildren = new Set()
// dom element is filtered mutations.forEach(mutation => {
return const dom = mutation.target
} const yxml = dom._yxml
switch (mutation.type) { if (yxml == null) {
case 'characterData': // dom element is filtered
var diffs = diff(yxml.toString(), dom.nodeValue) return
var pos = 0 }
for (var i = 0; i < diffs.length; i++) { switch (mutation.type) {
var d = diffs[i] case 'characterData':
if (d[0] === 0) { // EQUAL var diffs = diff(yxml.toString(), dom.nodeValue)
pos += d[1].length var pos = 0
} else if (d[0] === -1) { // DELETE for (var i = 0; i < diffs.length; i++) {
yxml.delete(pos, d[1].length) var d = diffs[i]
} else { // INSERT if (d[0] === 0) { // EQUAL
yxml.insert(pos, d[1]) pos += d[1].length
pos += d[1].length } else if (d[0] === -1) { // DELETE
} yxml.delete(pos, d[1].length)
} } else { // INSERT
break yxml.insert(pos, d[1])
case 'attributes': pos += d[1].length
let name = mutation.attributeName
// check if filter accepts attribute
if (this._domFilter(dom, [name]).length > 0 && this.constructor !== YXmlFragment) {
var val = dom.getAttribute(name)
if (yxml.getAttribute(name) !== val) {
if (val == null) {
yxml.removeAttribute(name)
} else {
yxml.setAttribute(name, val)
} }
} }
} break
break case 'attributes':
case 'childList': let name = mutation.attributeName
diffChildren.add(mutation.target) // check if filter accepts attribute
break if (this._domFilter(dom, [name]).length > 0 && this.constructor !== YXmlFragment) {
var val = dom.getAttribute(name)
if (yxml.getAttribute(name) !== val) {
if (val == null) {
yxml.removeAttribute(name)
} else {
yxml.setAttribute(name, val)
}
}
}
break
case 'childList':
diffChildren.add(mutation.target)
break
}
})
for (let dom of diffChildren) {
if (dom._yxml != null && dom._yxml !== false) {
applyChangesFromDom(dom)
}
} }
}) })
for (let dom of diffChildren) {
if (dom._yxml != null && dom._yxml !== false) {
applyChangesFromDom(dom)
}
}
}) })
}
this._domObserver = new MutationObserver(this._domObserverListener)
this._domObserver.observe(dom, {
childList: true,
attributes: true,
characterData: true,
subtree: true
}) })
} }
this._domObserver = new MutationObserver(this._domObserverListener)
this._domObserver.observe(dom, {
childList: true,
attributes: true,
characterData: true,
subtree: true
})
return dom return dom
} }
_logString () { _logString () {

View File

@@ -135,7 +135,7 @@ export function applyChangesFromDom (dom) {
} }
} }
export function reflectChangesOnDom (events) { export function reflectChangesOnDom (events, _document) {
// Make sure that no filtered attributes are applied to the structure // Make sure that no filtered attributes are applied to the structure
// if they were, delete them // if they were, delete them
/* /*
@@ -183,9 +183,9 @@ export function reflectChangesOnDom (events) {
}) })
if (event.childListChanged) { if (event.childListChanged) {
// create fragment of undeleted nodes // create fragment of undeleted nodes
const fragment = document.createDocumentFragment() const fragment = _document.createDocumentFragment()
yxml.forEach(function (t) { yxml.forEach(function (t) {
fragment.append(t.getDom()) fragment.appendChild(t.getDom(_document))
}) })
// remove remainding nodes // remove remainding nodes
let lastChild = dom.lastChild let lastChild = dom.lastChild
@@ -194,7 +194,7 @@ export function reflectChangesOnDom (events) {
lastChild = dom.lastChild lastChild = dom.lastChild
} }
// insert fragment of undeleted nodes // insert fragment of undeleted nodes
dom.append(fragment) dom.appendChild(fragment)
} }
} }
/* TODO: smartscrolling /* TODO: smartscrolling

View File

@@ -153,7 +153,7 @@ export async function initArrays (t, opts) {
result['array' + i] = y.define('array', Y.Array) result['array' + i] = y.define('array', Y.Array)
result['map' + i] = y.define('map', Y.Map) result['map' + i] = y.define('map', Y.Map)
result['xml' + i] = y.define('xml', Y.XmlElement) result['xml' + i] = y.define('xml', Y.XmlElement)
y.get('xml', Y.Xml).setDomFilter(function (d, attrs) { y.get('xml').setDomFilter(function (d, attrs) {
if (d.nodeName === 'HIDDEN') { if (d.nodeName === 'HIDDEN') {
return null return null
} else { } else {

9
y.js

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

5574
y.node.js

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

19334
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