Compare commits
1 Commits
v13.0.0-48
...
v13.0.0-37
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d30bf050bf |
@@ -24,8 +24,7 @@
|
|||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div id="aceContainer"></div>
|
<div id="aceContainer"></div>
|
||||||
<script src="../../y.js"></script>
|
<script src="../bower_components/yjs/y.js"></script>
|
||||||
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
|
|
||||||
<script src="../bower_components/ace-builds/src/ace.js"></script>
|
<script src="../bower_components/ace-builds/src/ace.js"></script>
|
||||||
|
|
||||||
<script src="./index.js"></script>
|
<script src="./index.js"></script>
|
||||||
|
|||||||
@@ -1,17 +1,24 @@
|
|||||||
/* global Y, ace */
|
/* global Y, ace */
|
||||||
|
|
||||||
let y = new Y('ace-example', {
|
Y({
|
||||||
|
db: {
|
||||||
|
name: 'memory'
|
||||||
|
},
|
||||||
connector: {
|
connector: {
|
||||||
name: 'websockets-client',
|
name: 'websockets-client',
|
||||||
url: 'http://127.0.0.1:1234'
|
room: 'ace-example'
|
||||||
|
},
|
||||||
|
sourceDir: '/bower_components',
|
||||||
|
share: {
|
||||||
|
ace: 'Text' // y.share.textarea is of type Y.Text
|
||||||
}
|
}
|
||||||
|
}).then(function (y) {
|
||||||
|
window.yAce = y
|
||||||
|
|
||||||
|
// bind the textarea to a shared text element
|
||||||
|
var editor = ace.edit('aceContainer')
|
||||||
|
editor.setTheme('ace/theme/chrome')
|
||||||
|
editor.getSession().setMode('ace/mode/javascript')
|
||||||
|
|
||||||
|
y.share.ace.bindAce(editor)
|
||||||
})
|
})
|
||||||
|
|
||||||
window.yAce = y
|
|
||||||
|
|
||||||
// bind the textarea to a shared text element
|
|
||||||
var editor = ace.edit('aceContainer')
|
|
||||||
editor.setTheme('ace/theme/chrome')
|
|
||||||
editor.getSession().setMode('ace/mode/javascript')
|
|
||||||
|
|
||||||
y.define('ace', Y.Text).bindAce(editor)
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<input type="submit" value="Send">
|
<input type="submit" value="Send">
|
||||||
</form>
|
</form>
|
||||||
<script src="../../y.js"></script>
|
<script src="../../y.js"></script>
|
||||||
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
|
<script src="../../../y-websockets-client/dist/y-websockets-client.js"></script>
|
||||||
<script src="./index.js"></script>
|
<script src="./index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
/* global Y */
|
/* global Y */
|
||||||
|
|
||||||
let y = new Y('chat-example', {
|
// initialize a shared object. This function call returns a promise!
|
||||||
|
var y = new Y({
|
||||||
connector: {
|
connector: {
|
||||||
name: 'websockets-client',
|
name: 'websockets-client',
|
||||||
url: 'http://127.0.0.1:1234'
|
room: 'chat-example'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -22,7 +23,6 @@ function appendMessage (message, position) {
|
|||||||
p.appendChild(document.createTextNode(message.message))
|
p.appendChild(document.createTextNode(message.message))
|
||||||
chatcontainer.insertBefore(p, chatcontainer.children[position] || null)
|
chatcontainer.insertBefore(p, chatcontainer.children[position] || null)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function makes sure that only 7 messages exist in the chat history.
|
// This function makes sure that only 7 messages exist in the chat history.
|
||||||
// The rest is deleted
|
// The rest is deleted
|
||||||
function cleanupChat () {
|
function cleanupChat () {
|
||||||
@@ -30,17 +30,23 @@ function cleanupChat () {
|
|||||||
chatprotocol.delete(0, chatprotocol.length - 7)
|
chatprotocol.delete(0, chatprotocol.length - 7)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cleanupChat()
|
|
||||||
|
|
||||||
// Insert the initial content
|
// Insert the initial content
|
||||||
chatprotocol.toArray().forEach(appendMessage)
|
chatprotocol.toArray().forEach(appendMessage)
|
||||||
|
cleanupChat()
|
||||||
|
|
||||||
// whenever content changes, make sure to reflect the changes in the DOM
|
// whenever content changes, make sure to reflect the changes in the DOM
|
||||||
chatprotocol.observe(function (event) {
|
chatprotocol.observe(function (event) {
|
||||||
|
if (event.type === 'insert') {
|
||||||
|
for (let i = 0; i < event.length; i++) {
|
||||||
|
appendMessage(event.values[i], event.index + i)
|
||||||
|
}
|
||||||
|
} else if (event.type === 'delete') {
|
||||||
|
for (let i = 0; i < event.length; i++) {
|
||||||
|
chatcontainer.children[event.index].remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
// concurrent insertions may result in a history > 7, so cleanup here
|
// concurrent insertions may result in a history > 7, so cleanup here
|
||||||
cleanupChat()
|
cleanupChat()
|
||||||
chatcontainer.innerHTML = ''
|
|
||||||
chatprotocol.toArray().forEach(appendMessage)
|
|
||||||
})
|
})
|
||||||
document.querySelector('#chatform').onsubmit = function (event) {
|
document.querySelector('#chatform').onsubmit = function (event) {
|
||||||
// the form is submitted
|
// the form is submitted
|
||||||
|
|||||||
@@ -5,8 +5,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<div id="codeMirrorContainer"></div>
|
<div id="codeMirrorContainer"></div>
|
||||||
|
|
||||||
<script src="../../y.js"></script>
|
<script src="../bower_components/yjs/y.js"></script>
|
||||||
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
|
|
||||||
<script src="../bower_components/codemirror/lib/codemirror.js"></script>
|
<script src="../bower_components/codemirror/lib/codemirror.js"></script>
|
||||||
<script src="../bower_components/codemirror/mode/javascript/javascript.js"></script>
|
<script src="../bower_components/codemirror/mode/javascript/javascript.js"></script>
|
||||||
<link rel="stylesheet" href="../bower_components/codemirror/lib/codemirror.css">
|
<link rel="stylesheet" href="../bower_components/codemirror/lib/codemirror.css">
|
||||||
|
|||||||
@@ -1,16 +1,24 @@
|
|||||||
/* global Y, CodeMirror */
|
/* global Y, CodeMirror */
|
||||||
|
|
||||||
let y = new Y('codemirror-example', {
|
// initialize a shared object. This function call returns a promise!
|
||||||
|
Y({
|
||||||
|
db: {
|
||||||
|
name: 'memory'
|
||||||
|
},
|
||||||
connector: {
|
connector: {
|
||||||
name: 'websockets-client',
|
name: 'websockets-client',
|
||||||
url: 'http://127.0.0.1:1234'
|
room: 'codemirror-example'
|
||||||
|
},
|
||||||
|
sourceDir: '/bower_components',
|
||||||
|
share: {
|
||||||
|
codemirror: 'Text' // y.share.codemirror is of type Y.Text
|
||||||
}
|
}
|
||||||
})
|
}).then(function (y) {
|
||||||
|
window.yCodeMirror = y
|
||||||
|
|
||||||
window.yCodeMirror = y
|
var editor = CodeMirror(document.querySelector('#codeMirrorContainer'), {
|
||||||
|
mode: 'javascript',
|
||||||
var editor = CodeMirror(document.querySelector('#codeMirrorContainer'), {
|
lineNumbers: true
|
||||||
mode: 'javascript',
|
})
|
||||||
lineNumbers: true
|
y.share.codemirror.bindCodeMirror(editor)
|
||||||
})
|
})
|
||||||
y.define('codemirror', Y.Text).bindCodeMirror(editor)
|
|
||||||
|
|||||||
@@ -13,8 +13,11 @@
|
|||||||
<button type="button" id="clearDrawingCanvas">Clear Drawing</button>
|
<button type="button" id="clearDrawingCanvas">Clear Drawing</button>
|
||||||
<svg id="drawingCanvas" viewbox="0 0 100 100" width="100%"></svg>
|
<svg id="drawingCanvas" viewbox="0 0 100 100" width="100%"></svg>
|
||||||
<script src="../../y.js"></script>
|
<script src="../../y.js"></script>
|
||||||
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
|
<script src="../../../y-array/y-array.js"></script>
|
||||||
<script src="../bower_components/d3/d3.min.js"></script>
|
<script src="../../../y-map/dist/y-map.js"></script>
|
||||||
|
<script src="../../../y-memory/y-memory.js"></script>
|
||||||
|
<script src="../../../y-websockets-client/y-websockets-client.js"></script>
|
||||||
|
<script src="../bower_components/d3/d3.js"></script>
|
||||||
<script src="./index.js"></script>
|
<script src="./index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,74 +1,84 @@
|
|||||||
/* globals Y, d3 */
|
/* globals Y, d3 */
|
||||||
|
'strict mode'
|
||||||
|
|
||||||
let y = new Y('drawing-example', {
|
Y({
|
||||||
|
db: {
|
||||||
|
name: 'memory'
|
||||||
|
},
|
||||||
connector: {
|
connector: {
|
||||||
name: 'websockets-client',
|
name: 'websockets-client',
|
||||||
url: 'http://127.0.0.1:1234'
|
room: 'drawing-example',
|
||||||
|
url: 'localhost:1234'
|
||||||
|
},
|
||||||
|
sourceDir: '/bower_components',
|
||||||
|
share: {
|
||||||
|
drawing: 'Array'
|
||||||
}
|
}
|
||||||
})
|
}).then(function (y) {
|
||||||
|
window.yDrawing = y
|
||||||
|
var drawing = y.share.drawing
|
||||||
|
var renderPath = d3.svg.line()
|
||||||
|
.x(function (d) { return d[0] })
|
||||||
|
.y(function (d) { return d[1] })
|
||||||
|
.interpolate('basis')
|
||||||
|
|
||||||
window.yDrawing = y
|
var svg = d3.select('#drawingCanvas')
|
||||||
var drawing = y.define('drawing', Y.Array)
|
.call(d3.behavior.drag()
|
||||||
var renderPath = d3.svg.line()
|
.on('dragstart', dragstart)
|
||||||
.x(function (d) { return d[0] })
|
.on('drag', drag)
|
||||||
.y(function (d) { return d[1] })
|
.on('dragend', dragend))
|
||||||
.interpolate('basic')
|
|
||||||
|
|
||||||
var svg = d3.select('#drawingCanvas')
|
// create line from a shared array object and update the line when the array changes
|
||||||
.call(d3.behavior.drag()
|
function drawLine (yarray) {
|
||||||
.on('dragstart', dragstart)
|
var line = svg.append('path').datum(yarray.toArray())
|
||||||
.on('drag', drag)
|
|
||||||
.on('dragend', dragend))
|
|
||||||
|
|
||||||
// create line from a shared array object and update the line when the array changes
|
|
||||||
function drawLine (yarray) {
|
|
||||||
var line = svg.append('path').datum(yarray.toArray())
|
|
||||||
line.attr('d', renderPath)
|
|
||||||
yarray.observe(function (event) {
|
|
||||||
line.remove()
|
|
||||||
line = svg.append('path').datum(yarray.toArray())
|
|
||||||
line.attr('d', renderPath)
|
line.attr('d', renderPath)
|
||||||
})
|
yarray.observe(function (event) {
|
||||||
}
|
// we only implement insert events that are appended to the end of the array
|
||||||
// call drawLine every time an array is appended
|
event.values.forEach(function (value) {
|
||||||
drawing.observe(function (event) {
|
line.datum().push(value)
|
||||||
event.removedElements.forEach(function () {
|
})
|
||||||
// if one is deleted, all will be deleted!!
|
line.attr('d', renderPath)
|
||||||
svg.selectAll('path').remove()
|
})
|
||||||
})
|
}
|
||||||
event.addedElements.forEach(function (path) {
|
// call drawLine every time an array is appended
|
||||||
drawLine(path)
|
y.share.drawing.observe(function (event) {
|
||||||
})
|
if (event.type === 'insert') {
|
||||||
})
|
event.values.forEach(drawLine)
|
||||||
// draw all existing content
|
} else {
|
||||||
for (var i = 0; i < drawing.length; i++) {
|
// just remove all elements (thats what we do anyway)
|
||||||
drawLine(drawing.get(i))
|
svg.selectAll('path').remove()
|
||||||
}
|
}
|
||||||
|
})
|
||||||
// clear canvas on request
|
// draw all existing content
|
||||||
document.querySelector('#clearDrawingCanvas').onclick = function () {
|
for (var i = 0; i < drawing.length; i++) {
|
||||||
drawing.delete(0, drawing.length)
|
drawLine(drawing.get(i))
|
||||||
}
|
|
||||||
|
|
||||||
var sharedLine = null
|
|
||||||
function dragstart () {
|
|
||||||
drawing.insert(drawing.length, [Y.Array])
|
|
||||||
sharedLine = drawing.get(drawing.length - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// After one dragged event is recognized, we ignore them for 33ms.
|
|
||||||
var ignoreDrag = null
|
|
||||||
function drag () {
|
|
||||||
if (sharedLine != null && ignoreDrag == null) {
|
|
||||||
ignoreDrag = window.setTimeout(function () {
|
|
||||||
ignoreDrag = null
|
|
||||||
}, 10)
|
|
||||||
sharedLine.push([d3.mouse(this)])
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function dragend () {
|
// clear canvas on request
|
||||||
sharedLine = null
|
document.querySelector('#clearDrawingCanvas').onclick = function () {
|
||||||
window.clearTimeout(ignoreDrag)
|
drawing.delete(0, drawing.length)
|
||||||
ignoreDrag = null
|
}
|
||||||
}
|
|
||||||
|
var sharedLine = null
|
||||||
|
function dragstart () {
|
||||||
|
drawing.insert(drawing.length, [Y.Array])
|
||||||
|
sharedLine = drawing.get(drawing.length - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// After one dragged event is recognized, we ignore them for 33ms.
|
||||||
|
var ignoreDrag = null
|
||||||
|
function drag () {
|
||||||
|
if (sharedLine != null && ignoreDrag == null) {
|
||||||
|
ignoreDrag = window.setTimeout(function () {
|
||||||
|
ignoreDrag = null
|
||||||
|
}, 33)
|
||||||
|
sharedLine.push([d3.mouse(this)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dragend () {
|
||||||
|
sharedLine = null
|
||||||
|
window.clearTimeout(ignoreDrag)
|
||||||
|
ignoreDrag = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
</head>
|
|
||||||
<script src="../../y.js"></script>
|
|
||||||
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
|
|
||||||
<script src="../bower_components/d3/d3.min.js"></script>
|
|
||||||
<script src="./index.js"></script>
|
|
||||||
<style>
|
|
||||||
magic-drawing .drawingCanvas path {
|
|
||||||
fill: none;
|
|
||||||
stroke: blue;
|
|
||||||
stroke-width: 2px;
|
|
||||||
stroke-linejoin: round;
|
|
||||||
stroke-linecap: round;
|
|
||||||
}
|
|
||||||
magic-drawing .drawingCanvas {
|
|
||||||
width: 500px;
|
|
||||||
height: 500px;
|
|
||||||
cursor: default;
|
|
||||||
padding:1px;
|
|
||||||
border:1px solid #021a40;
|
|
||||||
}
|
|
||||||
magic-drawing .clearDrawingButton {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
magic-drawing {
|
|
||||||
position: relative;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body contenteditable="true">
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
/* global Y, d3 */
|
|
||||||
|
|
||||||
window.onload = function () {
|
|
||||||
window.yXmlType.bindToDom(document.body)
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addMagicDrawing = function addMagicDrawing () {
|
|
||||||
let mt = document.createElement('magic-drawing')
|
|
||||||
mt.dataset.yjsHook = 'magic-drawing'
|
|
||||||
document.body.append(mt)
|
|
||||||
}
|
|
||||||
|
|
||||||
var renderPath = d3.svg.line()
|
|
||||||
.x(function (d) { return d[0] })
|
|
||||||
.y(function (d) { return d[1] })
|
|
||||||
.interpolate('basic')
|
|
||||||
|
|
||||||
function initDrawingBindings (type, dom) {
|
|
||||||
dom.contentEditable = 'false'
|
|
||||||
dom.dataset.yjsHook = 'magic-drawing'
|
|
||||||
var drawing = type.get('drawing')
|
|
||||||
if (drawing === undefined) {
|
|
||||||
drawing = type.set('drawing', new Y.Array())
|
|
||||||
}
|
|
||||||
var canvas = dom.querySelector('.drawingCanvas')
|
|
||||||
if (canvas == null) {
|
|
||||||
canvas = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
|
|
||||||
canvas.setAttribute('class', 'drawingCanvas')
|
|
||||||
canvas.setAttribute('viewbox', '0 0 100 100')
|
|
||||||
dom.insertBefore(canvas, null)
|
|
||||||
}
|
|
||||||
var clearDrawingButton = dom.querySelector('.clearDrawingButton')
|
|
||||||
if (clearDrawingButton == null) {
|
|
||||||
clearDrawingButton = document.createElement('button')
|
|
||||||
clearDrawingButton.setAttribute('type', 'button')
|
|
||||||
clearDrawingButton.setAttribute('class', 'clearDrawingButton')
|
|
||||||
clearDrawingButton.innerText = 'Clear Drawing'
|
|
||||||
dom.insertBefore(clearDrawingButton, null)
|
|
||||||
}
|
|
||||||
var svg = d3.select(canvas)
|
|
||||||
.call(d3.behavior.drag()
|
|
||||||
.on('dragstart', dragstart)
|
|
||||||
.on('drag', drag)
|
|
||||||
.on('dragend', dragend))
|
|
||||||
// create line from a shared array object and update the line when the array changes
|
|
||||||
function drawLine (yarray, svg) {
|
|
||||||
var line = svg.append('path').datum(yarray.toArray())
|
|
||||||
line.attr('d', renderPath)
|
|
||||||
yarray.observe(function (event) {
|
|
||||||
line.remove()
|
|
||||||
line = svg.append('path').datum(yarray.toArray())
|
|
||||||
line.attr('d', renderPath)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// call drawLine every time an array is appended
|
|
||||||
drawing.observe(function (event) {
|
|
||||||
event.removedElements.forEach(function () {
|
|
||||||
// if one is deleted, all will be deleted!!
|
|
||||||
svg.selectAll('path').remove()
|
|
||||||
})
|
|
||||||
event.addedElements.forEach(function (path) {
|
|
||||||
drawLine(path, svg)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
// draw all existing content
|
|
||||||
for (var i = 0; i < drawing.length; i++) {
|
|
||||||
drawLine(drawing.get(i), svg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear canvas on request
|
|
||||||
clearDrawingButton.onclick = function () {
|
|
||||||
drawing.delete(0, drawing.length)
|
|
||||||
}
|
|
||||||
|
|
||||||
var sharedLine = null
|
|
||||||
function dragstart () {
|
|
||||||
drawing.insert(drawing.length, [Y.Array])
|
|
||||||
sharedLine = drawing.get(drawing.length - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// After one dragged event is recognized, we ignore them for 33ms.
|
|
||||||
var ignoreDrag = null
|
|
||||||
function drag () {
|
|
||||||
if (sharedLine != null && ignoreDrag == null) {
|
|
||||||
ignoreDrag = window.setTimeout(function () {
|
|
||||||
ignoreDrag = null
|
|
||||||
}, 10)
|
|
||||||
sharedLine.push([d3.mouse(this)])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function dragend () {
|
|
||||||
sharedLine = null
|
|
||||||
window.clearTimeout(ignoreDrag)
|
|
||||||
ignoreDrag = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Y.XmlHook.addHook('magic-drawing', {
|
|
||||||
fillType: function (dom, type) {
|
|
||||||
initDrawingBindings(type, dom)
|
|
||||||
},
|
|
||||||
createDom: function (type) {
|
|
||||||
const dom = document.createElement('magic-drawing')
|
|
||||||
initDrawingBindings(type, dom)
|
|
||||||
return dom
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
let y = new Y('html-editor-drawing-hook-example', {
|
|
||||||
connector: {
|
|
||||||
name: 'websockets-client',
|
|
||||||
url: 'http://127.0.0.1:1234'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
window.yXml = y
|
|
||||||
window.yXmlType = y.define('xml', Y.XmlFragment)
|
|
||||||
window.undoManager = new Y.utils.UndoManager(window.yXmlType, {
|
|
||||||
captureTimeout: 500
|
|
||||||
})
|
|
||||||
|
|
||||||
document.onkeydown = function interceptUndoRedo (e) {
|
|
||||||
if (e.keyCode === 90 && e.metaKey) {
|
|
||||||
if (!e.shiftKey) {
|
|
||||||
window.undoManager.undo()
|
|
||||||
} else {
|
|
||||||
window.undoManager.redo()
|
|
||||||
}
|
|
||||||
e.preventDefault()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
</head>
|
</head>
|
||||||
<script src="../../y.js"></script>
|
<!-- jquery is not required for y-xml. It is just here for convenience, and to test batch operations. -->
|
||||||
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
|
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
|
||||||
|
<script src="../yjs-dist.js"></script>
|
||||||
|
<script src="./canvasjs.min.js"></script>
|
||||||
<script src="./index.js"></script>
|
<script src="./index.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body contenteditable="true">
|
<body contenteditable="true">
|
||||||
|
|||||||
@@ -1,17 +1,78 @@
|
|||||||
/* global Y */
|
/* global Y, HTMLElement, customElements, CanvasJS */
|
||||||
|
|
||||||
window.onload = function () {
|
window.onload = function () {
|
||||||
window.yXmlType.bindToDom(document.body)
|
window.yXmlType.bindToDom(document.body)
|
||||||
|
let mt = document.createElement('magic-table')
|
||||||
|
mt.innerHTML = '<table><tr><th>Amount</th></tr><tr><td>1</td></tr><tr><td>1</td></tr></table>'
|
||||||
|
document.body.append(mt)
|
||||||
}
|
}
|
||||||
|
|
||||||
let y = new Y('htmleditor', {
|
class MagicTable extends HTMLElement {
|
||||||
connector: {
|
constructor () {
|
||||||
name: 'websockets-client',
|
super()
|
||||||
url: 'http://127.0.0.1:1234'
|
this.createShadowRoot()
|
||||||
|
}
|
||||||
|
get _yjsHook () {
|
||||||
|
return 'magic-table'
|
||||||
|
}
|
||||||
|
showTable () {
|
||||||
|
this.shadowRoot.innerHTML = ''
|
||||||
|
this.shadowRoot.append(document.createElement('content'))
|
||||||
|
}
|
||||||
|
showDiagram () {
|
||||||
|
let dataPoints = []
|
||||||
|
this.querySelectorAll('td').forEach(td => {
|
||||||
|
let number = Number(td.textContent)
|
||||||
|
dataPoints.push({
|
||||||
|
x: (dataPoints.length + 1) * 10,
|
||||||
|
y: number,
|
||||||
|
label: '<magic-table> content'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.shadowRoot.innerHTML = ''
|
||||||
|
var chart = new CanvasJS.Chart(this.shadowRoot,
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
text: 'Bar chart'
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'bar',
|
||||||
|
|
||||||
|
dataPoints: dataPoints
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
chart.render()
|
||||||
|
|
||||||
|
// this.shadowRoot.innerHTML = '<p>dtrn</p>'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
customElements.define('magic-table', MagicTable)
|
||||||
|
|
||||||
|
Y.XmlHook.addHook('magic-table', {
|
||||||
|
fillType: function (dom, type) {
|
||||||
|
type.set('table', new Y.XmlElement(dom.querySelector('table')))
|
||||||
|
},
|
||||||
|
createDom: function (type) {
|
||||||
|
const table = type.get('table').getDom()
|
||||||
|
const dom = document.createElement('magic-table')
|
||||||
|
dom.insertBefore(table, null)
|
||||||
|
return dom
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
window.y = y
|
// initialize a shared object. This function call returns a promise!
|
||||||
|
let y = new Y({
|
||||||
|
connector: {
|
||||||
|
name: 'websockets-client',
|
||||||
|
url: 'http://127.0.0.1:1234',
|
||||||
|
room: 'html-editor-example6'
|
||||||
|
// maxBufferLength: 100
|
||||||
|
}
|
||||||
|
})
|
||||||
|
window.yXml = y
|
||||||
window.yXmlType = y.define('xml', Y.XmlFragment)
|
window.yXmlType = y.define('xml', Y.XmlFragment)
|
||||||
window.undoManager = new Y.utils.UndoManager(window.yXmlType, {
|
window.undoManager = new Y.utils.UndoManager(window.yXmlType, {
|
||||||
captureTimeout: 500
|
captureTimeout: 500
|
||||||
|
|||||||
@@ -16,9 +16,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script src="../../y.js"></script>
|
<script type="module" src="./index.js"></script>
|
||||||
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
|
|
||||||
<script src='../../../y-indexeddb/y-indexeddb.js'></script>
|
|
||||||
<script src="./index.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,19 +1,24 @@
|
|||||||
/* global Y, CodeMirror */
|
/* global Y, CodeMirror */
|
||||||
|
|
||||||
const persistence = new Y.IndexedDB()
|
// initialize a shared object. This function call returns a promise!
|
||||||
const connector = {
|
Y({
|
||||||
|
db: {
|
||||||
|
name: 'memory'
|
||||||
|
},
|
||||||
connector: {
|
connector: {
|
||||||
name: 'websockets-client',
|
name: 'websockets-client',
|
||||||
room: 'codemirror-example'
|
room: 'codemirror-example'
|
||||||
|
},
|
||||||
|
sourceDir: '/bower_components',
|
||||||
|
share: {
|
||||||
|
codemirror: 'Text' // y.share.codemirror is of type Y.Text
|
||||||
}
|
}
|
||||||
}
|
}).then(function (y) {
|
||||||
|
window.yCodeMirror = y
|
||||||
|
|
||||||
const y = new Y('codemirror-example', connector, persistence)
|
var editor = CodeMirror(document.querySelector('#codeMirrorContainer'), {
|
||||||
window.yCodeMirror = y
|
mode: 'javascript',
|
||||||
|
lineNumbers: true
|
||||||
var editor = CodeMirror(document.querySelector('#codeMirrorContainer'), {
|
})
|
||||||
mode: 'javascript',
|
y.share.codemirror.bindCodeMirror(editor)
|
||||||
lineNumbers: true
|
|
||||||
})
|
})
|
||||||
|
|
||||||
y.define('codemirror', Y.Text).bindCodeMirror(editor)
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
.one {
|
.one {
|
||||||
grid-column: 1 ;
|
grid-column: 1 ;
|
||||||
}
|
}
|
||||||
.two {
|
.two {
|
||||||
grid-column: 2;
|
grid-column: 2;
|
||||||
}
|
}
|
||||||
.three {
|
.three {
|
||||||
@@ -49,7 +49,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="../../y.js"></script>
|
<script src="../../y.js"></script>
|
||||||
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
|
<script src="../../../y-array/y-array.js"></script>
|
||||||
|
<script src="../../../y-text/dist/y-text.js"></script>
|
||||||
|
<script src="../../../y-memory/y-memory.js"></script>
|
||||||
|
<script src="../../../y-websockets-client/y-websockets-client.js"></script>
|
||||||
<script src="./index.js"></script>
|
<script src="./index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,38 +1,64 @@
|
|||||||
/* global Y */
|
/* global Y */
|
||||||
|
|
||||||
function bindYjsInstance (y, suffix) {
|
Y({
|
||||||
y.define('textarea', Y.Text).bind(document.getElementById('textarea' + suffix))
|
db: {
|
||||||
|
name: 'memory'
|
||||||
|
},
|
||||||
|
connector: {
|
||||||
|
name: 'websockets-client',
|
||||||
|
room: 'Textarea-example',
|
||||||
|
url: 'https://yjs-v13.herokuapp.com/'
|
||||||
|
},
|
||||||
|
share: {
|
||||||
|
textarea: 'Text'
|
||||||
|
}
|
||||||
|
}).then(function (y) {
|
||||||
|
window.y1 = y
|
||||||
|
y.share.textarea.bind(document.getElementById('textarea1'))
|
||||||
|
})
|
||||||
|
|
||||||
|
Y({
|
||||||
|
db: {
|
||||||
|
name: 'memory'
|
||||||
|
},
|
||||||
|
connector: {
|
||||||
|
name: 'websockets-client',
|
||||||
|
room: 'Textarea-example',
|
||||||
|
url: 'https://yjs-v13-second.herokuapp.com/'
|
||||||
|
},
|
||||||
|
share: {
|
||||||
|
textarea: 'Text'
|
||||||
|
}
|
||||||
|
}).then(function (y) {
|
||||||
|
window.y2 = y
|
||||||
|
y.share.textarea.bind(document.getElementById('textarea2'))
|
||||||
y.connector.socket.on('connection', function () {
|
y.connector.socket.on('connection', function () {
|
||||||
document.getElementById('container' + suffix).removeAttribute('disconnected')
|
document.getElementById('container2').removeAttribute('disconnected')
|
||||||
})
|
})
|
||||||
y.connector.socket.on('disconnect', function () {
|
y.connector.socket.on('disconnect', function () {
|
||||||
document.getElementById('container' + suffix).setAttribute('disconnected', true)
|
document.getElementById('container2').setAttribute('disconnected', true)
|
||||||
})
|
})
|
||||||
}
|
})
|
||||||
|
|
||||||
let y1 = new Y('infinite-example', {
|
Y({
|
||||||
|
db: {
|
||||||
|
name: 'memory'
|
||||||
|
},
|
||||||
connector: {
|
connector: {
|
||||||
name: 'websockets-client',
|
name: 'websockets-client',
|
||||||
url: 'http://127.0.0.1:1234'
|
room: 'Textarea-example',
|
||||||
|
url: 'https://yjs-v13-third.herokuapp.com/'
|
||||||
|
},
|
||||||
|
share: {
|
||||||
|
textarea: 'Text'
|
||||||
}
|
}
|
||||||
|
}).then(function (y) {
|
||||||
|
window.y3 = y
|
||||||
|
y.share.textarea.bind(document.getElementById('textarea3'))
|
||||||
|
y.connector.socket.on('connection', function () {
|
||||||
|
document.getElementById('container3').removeAttribute('disconnected')
|
||||||
|
})
|
||||||
|
y.connector.socket.on('disconnect', function () {
|
||||||
|
document.getElementById('container3').setAttribute('disconnected', true)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
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')
|
|
||||||
|
|||||||
@@ -17,7 +17,9 @@
|
|||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
<script src="../../y.js"></script>
|
<script src="../../y.js"></script>
|
||||||
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
|
<script src="../../../y-map/dist/y-map.js"></script>
|
||||||
|
<script src="../../../y-memory/y-memory.js"></script>
|
||||||
|
<script src="../../../y-websockets-client/y-websockets-client.js"></script>
|
||||||
<script src="../bower_components/d3/d3.js"></script>
|
<script src="../bower_components/d3/d3.js"></script>
|
||||||
<script src="./index.js"></script>
|
<script src="./index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,67 +1,74 @@
|
|||||||
|
/* @flow */
|
||||||
/* global Y, d3 */
|
/* global Y, d3 */
|
||||||
|
|
||||||
let y = new Y('jigsaw-example', {
|
// initialize a shared object. This function call returns a promise!
|
||||||
|
Y({
|
||||||
|
db: {
|
||||||
|
name: 'memory'
|
||||||
|
},
|
||||||
connector: {
|
connector: {
|
||||||
name: 'websockets-client',
|
name: 'websockets-client',
|
||||||
url: 'http://127.0.0.1:1234'
|
room: 'Puzzle-example',
|
||||||
|
url: 'http://localhost:1234'
|
||||||
|
},
|
||||||
|
share: {
|
||||||
|
piece1: 'Map',
|
||||||
|
piece2: 'Map',
|
||||||
|
piece3: 'Map',
|
||||||
|
piece4: 'Map'
|
||||||
}
|
}
|
||||||
})
|
}).then(function (y) {
|
||||||
|
window.yJigsaw = y
|
||||||
|
var origin // mouse start position - translation of piece
|
||||||
|
var drag = d3.behavior.drag()
|
||||||
|
.on('dragstart', function (params) {
|
||||||
|
// get the translation of the element
|
||||||
|
var translation = d3
|
||||||
|
.select(this)
|
||||||
|
.attr('transform')
|
||||||
|
.slice(10, -1)
|
||||||
|
.split(',')
|
||||||
|
.map(Number)
|
||||||
|
// mouse coordinates
|
||||||
|
var mouse = d3.mouse(this.parentNode)
|
||||||
|
origin = {
|
||||||
|
x: mouse[0] - translation[0],
|
||||||
|
y: mouse[1] - translation[1]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on('drag', function () {
|
||||||
|
var mouse = d3.mouse(this.parentNode)
|
||||||
|
var x = mouse[0] - origin.x // =^= mouse - mouse at dragstart + translation at dragstart
|
||||||
|
var y = mouse[1] - origin.y
|
||||||
|
d3.select(this).attr('transform', 'translate(' + x + ',' + y + ')')
|
||||||
|
})
|
||||||
|
.on('dragend', function (piece, i) {
|
||||||
|
// save the current translation of the puzzle piece
|
||||||
|
var mouse = d3.mouse(this.parentNode)
|
||||||
|
var x = mouse[0] - origin.x
|
||||||
|
var y = mouse[1] - origin.y
|
||||||
|
piece.set('translation', {x: x, y: y})
|
||||||
|
})
|
||||||
|
|
||||||
let jigsaw = y.define('jigsaw', Y.Map)
|
var data = [y.share.piece1, y.share.piece2, y.share.piece3, y.share.piece4]
|
||||||
window.yJigsaw = y
|
var pieces = d3.select(document.querySelector('#puzzle-example')).selectAll('path').data(data)
|
||||||
|
|
||||||
var origin // mouse start position - translation of piece
|
pieces
|
||||||
var drag = d3.behavior.drag()
|
.classed('draggable', true)
|
||||||
.on('dragstart', function (params) {
|
.attr('transform', function (piece) {
|
||||||
// get the translation of the element
|
var translation = piece.get('translation') || {x: 0, y: 0}
|
||||||
var translation = d3
|
return 'translate(' + translation.x + ',' + translation.y + ')'
|
||||||
.select(this)
|
}).call(drag)
|
||||||
.attr('transform')
|
|
||||||
.slice(10, -1)
|
|
||||||
.split(',')
|
|
||||||
.map(Number)
|
|
||||||
// mouse coordinates
|
|
||||||
var mouse = d3.mouse(this.parentNode)
|
|
||||||
origin = {
|
|
||||||
x: mouse[0] - translation[0],
|
|
||||||
y: mouse[1] - translation[1]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.on('drag', function () {
|
|
||||||
var mouse = d3.mouse(this.parentNode)
|
|
||||||
var x = mouse[0] - origin.x // =^= mouse - mouse at dragstart + translation at dragstart
|
|
||||||
var y = mouse[1] - origin.y
|
|
||||||
d3.select(this).attr('transform', 'translate(' + x + ',' + y + ')')
|
|
||||||
})
|
|
||||||
.on('dragend', function (piece, i) {
|
|
||||||
// save the current translation of the puzzle piece
|
|
||||||
var mouse = d3.mouse(this.parentNode)
|
|
||||||
var x = mouse[0] - origin.x
|
|
||||||
var y = mouse[1] - origin.y
|
|
||||||
jigsaw.set(piece, {x: x, y: y})
|
|
||||||
})
|
|
||||||
|
|
||||||
var data = ['piece1', 'piece2', 'piece3', 'piece4']
|
data.forEach(function (piece) {
|
||||||
var pieces = d3.select(document.querySelector('#puzzle-example')).selectAll('path').data(data)
|
piece.observe(function () {
|
||||||
|
// whenever a property of a piece changes, update the translation of the pieces
|
||||||
pieces
|
pieces
|
||||||
.classed('draggable', true)
|
.transition()
|
||||||
.attr('transform', function (piece) {
|
.attr('transform', function (piece) {
|
||||||
var translation = piece.get('translation') || {x: 0, y: 0}
|
var translation = piece.get('translation') || {x: 0, y: 0}
|
||||||
return 'translate(' + translation.x + ',' + translation.y + ')'
|
return 'translate(' + translation.x + ',' + translation.y + ')'
|
||||||
}).call(drag)
|
})
|
||||||
|
})
|
||||||
data.forEach(function (piece) {
|
|
||||||
jigsaw.observe(function () {
|
|
||||||
// whenever a property of a piece changes, update the translation of the pieces
|
|
||||||
pieces
|
|
||||||
.transition()
|
|
||||||
.attr('transform', function (piece) {
|
|
||||||
var translation = piece.get(piece)
|
|
||||||
if (translation == null || typeof translation.x !== 'number' || typeof translation.y !== 'number') {
|
|
||||||
translation = { x: 0, y: 0 }
|
|
||||||
}
|
|
||||||
return 'translate(' + translation.x + ',' + translation.y + ')'
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script src="../../y.js"></script>
|
<script src="../bower_components/yjs/y.js"></script>
|
||||||
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
|
<script src="../bower_components/y-websockets-client/y-websockets-client.js"></script>
|
||||||
<script src="../node_modules/monaco-editor/min/vs/loader.js"></script>
|
<script src="../node_modules/monaco-editor/min/vs/loader.js"></script>
|
||||||
<script src="./index.js"></script>
|
<script src="./index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -2,21 +2,29 @@
|
|||||||
|
|
||||||
require.config({ paths: { 'vs': '../node_modules/monaco-editor/min/vs' } })
|
require.config({ paths: { 'vs': '../node_modules/monaco-editor/min/vs' } })
|
||||||
|
|
||||||
let y = new Y('monaco-example', {
|
|
||||||
connector: {
|
|
||||||
name: 'websockets-client',
|
|
||||||
url: 'http://127.0.0.1:1234'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
require(['vs/editor/editor.main'], function () {
|
require(['vs/editor/editor.main'], function () {
|
||||||
window.yMonaco = y
|
// Initialize a shared object. This function call returns a promise!
|
||||||
|
Y({
|
||||||
|
db: {
|
||||||
|
name: 'memory'
|
||||||
|
},
|
||||||
|
connector: {
|
||||||
|
name: 'websockets-client',
|
||||||
|
room: 'monaco-example'
|
||||||
|
},
|
||||||
|
sourceDir: '/bower_components',
|
||||||
|
share: {
|
||||||
|
monaco: 'Text' // y.share.monaco is of type Y.Text
|
||||||
|
}
|
||||||
|
}).then(function (y) {
|
||||||
|
window.yMonaco = y
|
||||||
|
|
||||||
// Create Monaco editor
|
// Create Monaco editor
|
||||||
var editor = monaco.editor.create(document.getElementById('monacoContainer'), {
|
var editor = monaco.editor.create(document.getElementById('monacoContainer'), {
|
||||||
language: 'javascript'
|
language: 'javascript'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Bind to y.share.monaco
|
||||||
|
y.share.monaco.bindMonaco(editor)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Bind to y.share.monaco
|
|
||||||
y.define('monaco', Y.Text).bindMonaco(editor)
|
|
||||||
})
|
})
|
||||||
|
|||||||
663
examples/package-lock.json
generated
663
examples/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,15 +9,12 @@
|
|||||||
"author": "Kevin Jahns",
|
"author": "Kevin Jahns",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"monaco-editor": "^0.8.3",
|
"monaco-editor": "^0.8.3"
|
||||||
"rollup": "^0.52.3"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"standard": "^10.0.2"
|
"standard": "^10.0.2"
|
||||||
},
|
},
|
||||||
"standard": {
|
"standard": {
|
||||||
"ignore": [
|
"ignore": ["bower_components"]
|
||||||
"bower_components"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,10 @@
|
|||||||
<script src="../bower_components/quill/dist/quill.js"></script>
|
<script src="../bower_components/quill/dist/quill.js"></script>
|
||||||
-->
|
-->
|
||||||
<script src="../../y.js"></script>
|
<script src="../../y.js"></script>
|
||||||
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
|
<script src="../../../y-array/y-array.js"></script>
|
||||||
|
<script src="../../../y-richtext/dist/y-richtext.js"></script>
|
||||||
|
<script src="../../../y-memory/y-memory.js"></script>
|
||||||
|
<script src="../../../y-websockets-client/y-websockets-client.js"></script>
|
||||||
<script src="./index.js"></script>
|
<script src="./index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import commonjs from 'rollup-plugin-commonjs'
|
|||||||
var pkg = require('./package.json')
|
var pkg = require('./package.json')
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
input: 'yjs-dist.mjs',
|
input: 'yjs-dist.esm',
|
||||||
name: 'Y',
|
name: 'Y',
|
||||||
output: {
|
output: {
|
||||||
file: 'yjs-dist.js',
|
file: 'yjs-dist.js',
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
<textarea style="width:80%;" rows=40 autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
|
<textarea style="width:80%;" rows=40 id="textfield" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
|
||||||
<script src="../../y.js"></script>
|
<script src="../../y.js"></script>
|
||||||
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
|
<script src="../../../y-array/y-array.js"></script>
|
||||||
|
<script src="../../../y-text/y-text.js"></script>
|
||||||
|
<script src="../../../y-websockets-client/y-websockets-client.js"></script>
|
||||||
<script src="./index.js"></script>
|
<script src="./index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,15 +1,23 @@
|
|||||||
/* global Y */
|
/* global Y */
|
||||||
|
|
||||||
let y = new Y('textarea-example', {
|
// initialize a shared object. This function call returns a promise!
|
||||||
|
Y({
|
||||||
|
db: {
|
||||||
|
name: 'memory'
|
||||||
|
},
|
||||||
connector: {
|
connector: {
|
||||||
name: 'websockets-client',
|
name: 'websockets-client',
|
||||||
url: 'http://127.0.0.1:1234'
|
room: 'Textarea-example2',
|
||||||
}
|
// url: '//localhost:1234',
|
||||||
|
url: 'https://yjs-v13.herokuapp.com/'
|
||||||
|
},
|
||||||
|
share: {
|
||||||
|
textarea: 'Text'
|
||||||
|
},
|
||||||
|
timeout: 5000 // reject if no connection was established within 5 seconds
|
||||||
|
}).then(function (y) {
|
||||||
|
window.yTextarea = y
|
||||||
|
|
||||||
|
// bind the textarea to a shared text element
|
||||||
|
y.share.textarea.bind(document.getElementById('textfield'))
|
||||||
})
|
})
|
||||||
|
|
||||||
window.yTextarea = y
|
|
||||||
|
|
||||||
// bind the textarea to a shared text element
|
|
||||||
let type = y.define('textarea', Y.Text)
|
|
||||||
let textarea = document.querySelector('textarea')
|
|
||||||
window.binding = new Y.TextareaBinding(type, textarea)
|
|
||||||
|
|||||||
@@ -3,8 +3,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<!-- jquery is not required for y-xml. It is just here for convenience, and to test batch operations. -->
|
<!-- jquery is not required for y-xml. It is just here for convenience, and to test batch operations. -->
|
||||||
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
|
||||||
<script src="../../y.js"></script>
|
<script src="../yjs-dist.js"></script>
|
||||||
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
|
|
||||||
<script src="./index.js"></script>
|
<script src="./index.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -1,13 +1,23 @@
|
|||||||
/* global Y */
|
/* global Y */
|
||||||
|
|
||||||
let y = new Y('xml-example', {
|
// initialize a shared object. This function call returns a promise!
|
||||||
|
Y({
|
||||||
|
db: {
|
||||||
|
name: 'memory'
|
||||||
|
},
|
||||||
connector: {
|
connector: {
|
||||||
name: 'websockets-client',
|
name: 'websockets-client',
|
||||||
url: 'http://127.0.0.1:1234'
|
// url: 'http://127.0.0.1:1234',
|
||||||
|
url: 'http://192.168.178.81:1234',
|
||||||
|
room: 'Xml-example'
|
||||||
|
},
|
||||||
|
sourceDir: '/bower_components',
|
||||||
|
share: {
|
||||||
|
xml: 'Xml("p")' // y.share.xml is of type Y.Xml with tagname "p"
|
||||||
}
|
}
|
||||||
|
}).then(function (y) {
|
||||||
|
window.yXml = y
|
||||||
|
// bind xml type to a dom, and put it in body
|
||||||
|
window.sharedDom = y.share.xml.getDom()
|
||||||
|
document.body.appendChild(window.sharedDom)
|
||||||
})
|
})
|
||||||
|
|
||||||
window.yXml = y
|
|
||||||
// bind xml type to a dom, and put it in body
|
|
||||||
window.sharedDom = y.define('xml', Y.XmlElement).getDom()
|
|
||||||
document.body.appendChild(window.sharedDom)
|
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
|
|
||||||
import Y from '../src/Y.js'
|
import Y from '../src/Y.js'
|
||||||
import yWebsocketsClient from '../../y-websockets-client/src/y-websockets-client.js'
|
import yWebsocketsClient from '../../y-websockets-client/src/y-websockets-client.js'
|
||||||
import extendYIndexedDBPersistence from '../../y-indexeddb/src/y-indexeddb.js'
|
|
||||||
|
|
||||||
Y.extend(yWebsocketsClient)
|
Y.extend(yWebsocketsClient)
|
||||||
extendYIndexedDBPersistence(Y)
|
|
||||||
|
|
||||||
export default Y
|
export default Y
|
||||||
1150
package-lock.json
generated
1150
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "yjs",
|
"name": "yjs",
|
||||||
"version": "13.0.0-48",
|
"version": "13.0.0-37",
|
||||||
"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",
|
||||||
@@ -65,6 +65,9 @@
|
|||||||
"tag-dist-files": "^0.1.6"
|
"tag-dist-files": "^0.1.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "^2.6.8"
|
"debug": "^2.6.8",
|
||||||
|
"fast-diff": "^1.1.2",
|
||||||
|
"utf-8": "^1.0.0",
|
||||||
|
"utf8": "^2.1.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import commonjs from 'rollup-plugin-commonjs'
|
|||||||
import multiEntry from 'rollup-plugin-multi-entry'
|
import multiEntry from 'rollup-plugin-multi-entry'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
input: 'test/index.js',
|
input: 'test/y-xml.tests.js',
|
||||||
name: 'y-tests',
|
name: 'y-tests',
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
output: {
|
output: {
|
||||||
@@ -11,12 +11,12 @@ export default {
|
|||||||
format: 'umd'
|
format: 'umd'
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
multiEntry(),
|
|
||||||
nodeResolve({
|
nodeResolve({
|
||||||
main: true,
|
main: true,
|
||||||
module: true,
|
module: true,
|
||||||
browser: true
|
browser: true
|
||||||
}),
|
}),
|
||||||
commonjs()
|
commonjs(),
|
||||||
|
multiEntry()
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import utf8 from 'utf-8'
|
||||||
import ID from '../Util/ID.js'
|
import ID from '../Util/ID.js'
|
||||||
import { default as RootID, RootFakeUserID } from '../Util/RootID.js'
|
import { default as RootID, RootFakeUserID } from '../Util/RootID.js'
|
||||||
|
|
||||||
@@ -90,8 +91,7 @@ export default class BinaryDecoder {
|
|||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
bytes[i] = this.uint8arr[this.pos++]
|
bytes[i] = this.uint8arr[this.pos++]
|
||||||
}
|
}
|
||||||
let encodedString = String.fromCodePoint(...bytes)
|
return utf8.getStringFromBytes(bytes)
|
||||||
return decodeURIComponent(escape(encodedString))
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Look ahead and read varString without incrementing position
|
* Look ahead and read varString without incrementing position
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import utf8 from 'utf-8'
|
||||||
import { RootFakeUserID } from '../Util/RootID.js'
|
import { RootFakeUserID } from '../Util/RootID.js'
|
||||||
|
|
||||||
const bits7 = 0b1111111
|
const bits7 = 0b1111111
|
||||||
@@ -61,8 +62,7 @@ export default class BinaryEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
writeVarString (str) {
|
writeVarString (str) {
|
||||||
let encodedString = unescape(encodeURIComponent(str))
|
let bytes = utf8.setBytesFromString(str)
|
||||||
let bytes = encodedString.split('').map(c => c.codePointAt())
|
|
||||||
let len = bytes.length
|
let len = bytes.length
|
||||||
this.writeVarUint(len)
|
this.writeVarUint(len)
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
|
|
||||||
import { createMutualExclude } from '../Util/mutualExclude.js'
|
|
||||||
|
|
||||||
export default class Binding {
|
|
||||||
constructor (type, target) {
|
|
||||||
this.type = type
|
|
||||||
this.target = target
|
|
||||||
this._mutualExclude = createMutualExclude()
|
|
||||||
}
|
|
||||||
destroy () {
|
|
||||||
this.type = null
|
|
||||||
this.target = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -132,7 +132,6 @@ export default class AbstractConnector {
|
|||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
this.whenSyncedListeners = []
|
this.whenSyncedListeners = []
|
||||||
this.y._setContentReady()
|
|
||||||
this.y.emit('synced')
|
this.y.emit('synced')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,7 +268,7 @@ export default class AbstractConnector {
|
|||||||
if (messageType === 'sync step 2' && senderConn.auth === 'write') {
|
if (messageType === 'sync step 2' && senderConn.auth === 'write') {
|
||||||
readSyncStep2(decoder, encoder, y, senderConn, sender)
|
readSyncStep2(decoder, encoder, y, senderConn, sender)
|
||||||
} else if (messageType === 'update' && (skipAuth || senderConn.auth === 'write')) {
|
} else if (messageType === 'update' && (skipAuth || senderConn.auth === 'write')) {
|
||||||
integrateRemoteStructs(y, decoder)
|
integrateRemoteStructs(decoder, encoder, y, senderConn, sender)
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unable to receive message')
|
throw new Error('Unable to receive message')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
import { writeStructs } from './syncStep1.js'
|
|
||||||
import { integrateRemoteStructs } from './integrateRemoteStructs.js'
|
|
||||||
import { readDeleteSet, writeDeleteSet } from './deleteSet.js'
|
|
||||||
import BinaryEncoder from '../Binary/Encoder.js'
|
|
||||||
|
|
||||||
export function fromBinary (y, decoder) {
|
|
||||||
integrateRemoteStructs(y, decoder)
|
|
||||||
readDeleteSet(y, decoder)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toBinary (y) {
|
|
||||||
let encoder = new BinaryEncoder()
|
|
||||||
writeStructs(y, encoder, new Map())
|
|
||||||
writeDeleteSet(y, encoder)
|
|
||||||
return encoder
|
|
||||||
}
|
|
||||||
@@ -65,7 +65,7 @@ export function stringifyStructs (y, decoder, strBuilder) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function integrateRemoteStructs (y, decoder) {
|
export function integrateRemoteStructs (decoder, encoder, y) {
|
||||||
const len = decoder.readUint32()
|
const len = decoder.readUint32()
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
let reference = decoder.readVarUint()
|
let reference = decoder.readVarUint()
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export function sendSyncStep1 (connector, syncUser) {
|
|||||||
connector.send(syncUser, encoder.createBuffer())
|
connector.send(syncUser, encoder.createBuffer())
|
||||||
}
|
}
|
||||||
|
|
||||||
export function writeStructs (y, encoder, ss) {
|
export default function writeStructs (encoder, decoder, y, ss) {
|
||||||
const lenPos = encoder.pos
|
const lenPos = encoder.pos
|
||||||
encoder.writeUint32(0)
|
encoder.writeUint32(0)
|
||||||
let len = 0
|
let len = 0
|
||||||
@@ -60,7 +60,7 @@ export function readSyncStep1 (decoder, encoder, y, senderConn, sender) {
|
|||||||
encoder.writeVarString('sync step 2')
|
encoder.writeVarString('sync step 2')
|
||||||
encoder.writeVarString(y.connector.authInfo || '')
|
encoder.writeVarString(y.connector.authInfo || '')
|
||||||
const ss = readStateSet(decoder)
|
const ss = readStateSet(decoder)
|
||||||
writeStructs(y, encoder, ss)
|
writeStructs(encoder, decoder, y, ss)
|
||||||
writeDeleteSet(y, encoder)
|
writeDeleteSet(y, encoder)
|
||||||
y.connector.send(senderConn.uid, encoder.createBuffer())
|
y.connector.send(senderConn.uid, encoder.createBuffer())
|
||||||
senderConn.receivedSyncStep2 = true
|
senderConn.receivedSyncStep2 = true
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export function stringifySyncStep2 (y, decoder, strBuilder) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function readSyncStep2 (decoder, encoder, y, senderConn, sender) {
|
export function readSyncStep2 (decoder, encoder, y, senderConn, sender) {
|
||||||
integrateRemoteStructs(y, decoder)
|
integrateRemoteStructs(decoder, encoder, y)
|
||||||
readDeleteSet(y, decoder)
|
readDeleteSet(y, decoder)
|
||||||
y.connector._setSyncedWith(sender)
|
y.connector._setSyncedWith(sender)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,116 +1,47 @@
|
|||||||
import BinaryEncoder from './Binary/Encoder.js'
|
// import BinaryEncoder from './Binary/Encoder.js'
|
||||||
import BinaryDecoder from './Binary/Decoder.js'
|
|
||||||
import { toBinary, fromBinary } from './MessageHandler/binaryEncode.js'
|
|
||||||
import { integrateRemoteStructs } from './MessageHandler/integrateRemoteStructs.js'
|
|
||||||
import { createMutualExclude } from './Util/mutualExclude.js'
|
|
||||||
|
|
||||||
function getFreshCnf () {
|
export default function extendPersistence (Y) {
|
||||||
let buffer = new BinaryEncoder()
|
class AbstractPersistence {
|
||||||
buffer.writeUint32(0)
|
constructor (y, opts) {
|
||||||
return {
|
this.y = y
|
||||||
len: 0,
|
this.opts = opts
|
||||||
buffer
|
this.saveOperationsBuffer = []
|
||||||
}
|
this.log = Y.debug('y:persistence')
|
||||||
}
|
|
||||||
|
|
||||||
export default class AbstractPersistence {
|
|
||||||
constructor (opts) {
|
|
||||||
this.opts = opts
|
|
||||||
this.ys = new Map()
|
|
||||||
this.mutualExclude = createMutualExclude()
|
|
||||||
}
|
|
||||||
|
|
||||||
_init (y) {
|
|
||||||
let cnf = this.ys.get(y)
|
|
||||||
if (cnf === undefined) {
|
|
||||||
cnf = getFreshCnf()
|
|
||||||
this.ys.set(y, cnf)
|
|
||||||
return this.init(y).then(() => {
|
|
||||||
y.on('afterTransaction', (y, transaction) => {
|
|
||||||
let cnf = this.ys.get(y)
|
|
||||||
if (cnf.len > 0) {
|
|
||||||
cnf.buffer.setUint32(0, cnf.len)
|
|
||||||
this.saveUpdate(y, cnf.buffer.createBuffer(), transaction)
|
|
||||||
let _cnf = getFreshCnf()
|
|
||||||
for (let key in _cnf) {
|
|
||||||
cnf[key] = _cnf[key]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return this.retrieve(y)
|
|
||||||
}).then(function () {
|
|
||||||
return Promise.resolve(cnf)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return Promise.resolve(cnf)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
deinit (y) {
|
|
||||||
this.ys.delete(y)
|
|
||||||
y.persistence = null
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy () {
|
saveToMessageQueue (binary) {
|
||||||
this.ys = null
|
this.log('Room %s: Save message to message queue', this.y.options.connector.room)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
saveOperations (ops) {
|
||||||
* Remove all persisted data that belongs to a room.
|
ops = ops.map(function (op) {
|
||||||
* Automatically destroys all Yjs all Yjs instances that persist to
|
return Y.Struct[op.struct].encode(op)
|
||||||
* the room. If `destroyYjsInstances = false` the persistence functionality
|
})
|
||||||
* will be removed from the Yjs instances.
|
/*
|
||||||
*
|
const saveOperations = () => {
|
||||||
* ** Must be overwritten! **
|
if (this.saveOperationsBuffer.length > 0) {
|
||||||
*/
|
let encoder = new BinaryEncoder()
|
||||||
removePersistedData (room, destroyYjsInstances = true) {
|
encoder.writeVarString(this.opts.room)
|
||||||
this.ys.forEach((cnf, y) => {
|
encoder.writeVarString('update')
|
||||||
if (y.room === room) {
|
let ops = this.saveOperationsBuffer
|
||||||
if (destroyYjsInstances) {
|
this.saveOperationsBuffer = []
|
||||||
y.destroy()
|
let length = ops.length
|
||||||
} else {
|
encoder.writeUint32(length)
|
||||||
this.deinit(y)
|
for (var i = 0; i < length; i++) {
|
||||||
|
let op = ops[i]
|
||||||
|
Y.Struct[op.struct].binaryEncode(encoder, op)
|
||||||
|
}
|
||||||
|
this.saveToMessageQueue(encoder.createBuffer())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
*/
|
||||||
}
|
if (this.saveOperationsBuffer.length === 0) {
|
||||||
|
this.saveOperationsBuffer = ops
|
||||||
/* overwrite */
|
} else {
|
||||||
saveUpdate (buffer) {
|
this.saveOperationsBuffer = this.saveOperationsBuffer.concat(ops)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Save struct to update buffer.
|
|
||||||
* saveUpdate is called when transaction ends
|
|
||||||
*/
|
|
||||||
saveStruct (y, struct) {
|
|
||||||
let cnf = this.ys.get(y)
|
|
||||||
if (cnf !== undefined) {
|
|
||||||
this.mutualExclude(function () {
|
|
||||||
struct._toBinary(cnf.buffer)
|
|
||||||
cnf.len++
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* overwrite */
|
Y.AbstractPersistence = AbstractPersistence
|
||||||
retrieve (y, model, updates) {
|
|
||||||
this.mutualExclude(function () {
|
|
||||||
y.transact(function () {
|
|
||||||
if (model != null) {
|
|
||||||
fromBinary(y, new BinaryDecoder(new Uint8Array(model)))
|
|
||||||
}
|
|
||||||
if (updates != null) {
|
|
||||||
for (let i = 0; i < updates.length; i++) {
|
|
||||||
integrateRemoteStructs(y, new BinaryDecoder(new Uint8Array(updates[i])))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
y.emit('persistenceReady')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/* overwrite */
|
|
||||||
persist (y) {
|
|
||||||
return toBinary(y).createBuffer()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { logID } from '../MessageHandler/messageToString.js'
|
|||||||
* TODO: implement getItemCleanStartNode for better performance (only one lookup)
|
* TODO: implement getItemCleanStartNode for better performance (only one lookup)
|
||||||
*/
|
*/
|
||||||
export function deleteItemRange (y, user, clock, range) {
|
export function deleteItemRange (y, user, clock, range) {
|
||||||
const createDelete = y.connector !== null && y.connector._forwardAppliedStructs
|
const createDelete = y.connector._forwardAppliedStructs
|
||||||
let item = y.os.getItemCleanStart(new ID(user, clock))
|
let item = y.os.getItemCleanStart(new ID(user, clock))
|
||||||
if (item !== null) {
|
if (item !== null) {
|
||||||
if (!item._deleted) {
|
if (!item._deleted) {
|
||||||
@@ -70,12 +70,12 @@ export default class Delete {
|
|||||||
// from remote
|
// from remote
|
||||||
const id = this._targetID
|
const id = this._targetID
|
||||||
deleteItemRange(y, id.user, id.clock, this._length)
|
deleteItemRange(y, id.user, id.clock, this._length)
|
||||||
} else if (y.connector !== null) {
|
} else {
|
||||||
// from local
|
// from local
|
||||||
y.connector.broadcastStruct(this)
|
y.connector.broadcastStruct(this)
|
||||||
}
|
}
|
||||||
if (y.persistence !== null) {
|
if (y.persistence !== null) {
|
||||||
y.persistence.saveStruct(y, this)
|
y.persistence.saveOperations(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_logString () {
|
_logString () {
|
||||||
|
|||||||
@@ -87,18 +87,16 @@ export default class Item {
|
|||||||
return this._right
|
return this._right
|
||||||
}
|
}
|
||||||
_delete (y, createDelete = true) {
|
_delete (y, createDelete = true) {
|
||||||
if (!this._deleted) {
|
this._deleted = true
|
||||||
this._deleted = true
|
y.ds.markDeleted(this._id, this._length)
|
||||||
y.ds.markDeleted(this._id, this._length)
|
if (createDelete) {
|
||||||
if (createDelete) {
|
let del = new Delete()
|
||||||
let del = new Delete()
|
del._targetID = this._id
|
||||||
del._targetID = this._id
|
del._length = this._length
|
||||||
del._length = this._length
|
del._integrate(y, true)
|
||||||
del._integrate(y, true)
|
|
||||||
}
|
|
||||||
transactionTypeChanged(y, this._parent, this._parentSub)
|
|
||||||
y._transaction.deletedStructs.add(this)
|
|
||||||
}
|
}
|
||||||
|
transactionTypeChanged(y, this._parent, this._parentSub)
|
||||||
|
y._transaction.deletedStructs.add(this)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* This is called right before this struct receives any children.
|
* This is called right before this struct receives any children.
|
||||||
@@ -113,11 +111,9 @@ export default class Item {
|
|||||||
* - Check if this is struct deleted
|
* - Check if this is struct deleted
|
||||||
*/
|
*/
|
||||||
_integrate (y) {
|
_integrate (y) {
|
||||||
y._transaction.newTypes.add(this)
|
|
||||||
const parent = this._parent
|
const parent = this._parent
|
||||||
const selfID = this._id
|
const selfID = this._id
|
||||||
const user = selfID === null ? y.userID : selfID.user
|
const userState = selfID === null ? 0 : y.ss.getState(selfID.user)
|
||||||
const userState = y.ss.getState(user)
|
|
||||||
if (selfID === null) {
|
if (selfID === null) {
|
||||||
this._id = y.ss.getNextID(this._length)
|
this._id = y.ss.getNextID(this._length)
|
||||||
} else if (selfID.user === RootFakeUserID) {
|
} else if (selfID.user === RootFakeUserID) {
|
||||||
@@ -220,11 +216,11 @@ export default class Item {
|
|||||||
y.os.put(this)
|
y.os.put(this)
|
||||||
transactionTypeChanged(y, parent, parentSub)
|
transactionTypeChanged(y, parent, parentSub)
|
||||||
if (this._id.user !== RootFakeUserID) {
|
if (this._id.user !== RootFakeUserID) {
|
||||||
if (y.connector !== null && (y.connector._forwardAppliedStructs || this._id.user === y.userID)) {
|
if (y.connector._forwardAppliedStructs || this._id.user === y.userID) {
|
||||||
y.connector.broadcastStruct(this)
|
y.connector.broadcastStruct(this)
|
||||||
}
|
}
|
||||||
if (y.persistence !== null) {
|
if (y.persistence !== null) {
|
||||||
y.persistence.saveStruct(y, this)
|
y.persistence.saveOperations(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ export default class Type extends Item {
|
|||||||
this._deepEventHandler.removeEventListener(f)
|
this._deepEventHandler.removeEventListener(f)
|
||||||
}
|
}
|
||||||
_integrate (y) {
|
_integrate (y) {
|
||||||
|
y._transaction.newTypes.add(this)
|
||||||
super._integrate(y)
|
super._integrate(y)
|
||||||
this._y = y
|
this._y = y
|
||||||
// when integrating children we must make sure to
|
// when integrating children we must make sure to
|
||||||
|
|||||||
@@ -5,42 +5,15 @@ import { logID } from '../MessageHandler/messageToString.js'
|
|||||||
import YEvent from '../Util/YEvent.js'
|
import YEvent from '../Util/YEvent.js'
|
||||||
|
|
||||||
class YArrayEvent extends YEvent {
|
class YArrayEvent extends YEvent {
|
||||||
constructor (yarray, remote, transaction) {
|
constructor (yarray, remote) {
|
||||||
super(yarray)
|
super(yarray)
|
||||||
this.remote = remote
|
this.remote = remote
|
||||||
this._transaction = transaction
|
|
||||||
this._addedElements = null
|
|
||||||
}
|
|
||||||
get addedElements () {
|
|
||||||
if (this._addedElements === null) {
|
|
||||||
const target = this.target
|
|
||||||
const transaction = this._transaction
|
|
||||||
const addedElements = new Set()
|
|
||||||
transaction.newTypes.forEach(function (type) {
|
|
||||||
if (type._parent === target && !transaction.deletedStructs.has(type)) {
|
|
||||||
addedElements.add(type)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this._addedElements = addedElements
|
|
||||||
}
|
|
||||||
return this._addedElements
|
|
||||||
}
|
|
||||||
get removedElements () {
|
|
||||||
const target = this.target
|
|
||||||
const transaction = this._transaction
|
|
||||||
const removedElements = new Set()
|
|
||||||
transaction.deletedStructs.forEach(function (struct) {
|
|
||||||
if (struct._parent === target && !transaction.newTypes.has(struct)) {
|
|
||||||
removedElements.add(struct)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return removedElements
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class YArray extends Type {
|
export default class YArray extends Type {
|
||||||
_callObserver (transaction, parentSubs, remote) {
|
_callObserver (transaction, parentSubs, remote) {
|
||||||
this._callEventHandler(transaction, new YArrayEvent(this, remote, transaction))
|
this._callEventHandler(transaction, new YArrayEvent(this, remote))
|
||||||
}
|
}
|
||||||
get (pos) {
|
get (pos) {
|
||||||
let n = this._start
|
let n = this._start
|
||||||
@@ -211,12 +184,8 @@ export default class YArray extends Type {
|
|||||||
prevJsonIns._content.push(c)
|
prevJsonIns._content.push(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (prevJsonIns !== null) {
|
if (prevJsonIns !== null && y !== null) {
|
||||||
if (y !== null) {
|
prevJsonIns._integrate(y)
|
||||||
prevJsonIns._integrate(y)
|
|
||||||
} else if (prevJsonIns._left === null) {
|
|
||||||
this._start = prevJsonIns
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -245,17 +214,6 @@ export default class YArray extends Type {
|
|||||||
}
|
}
|
||||||
this.insertAfter(left, content)
|
this.insertAfter(left, content)
|
||||||
}
|
}
|
||||||
push (content) {
|
|
||||||
let n = this._start
|
|
||||||
let lastUndeleted = null
|
|
||||||
while (n !== null) {
|
|
||||||
if (!n._deleted) {
|
|
||||||
lastUndeleted = n
|
|
||||||
}
|
|
||||||
n = n._right
|
|
||||||
}
|
|
||||||
this.insertAfter(lastUndeleted, content)
|
|
||||||
}
|
|
||||||
_logString () {
|
_logString () {
|
||||||
const left = this._left !== null ? this._left._lastId : null
|
const left = this._left !== null ? this._left._lastId : null
|
||||||
const origin = this._origin !== null ? this._origin._lastId : null
|
const origin = this._origin !== null ? this._origin._lastId : null
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export default class YMap extends Type {
|
|||||||
this._transact(y => {
|
this._transact(y => {
|
||||||
const old = this._map.get(key) || null
|
const old = this._map.get(key) || null
|
||||||
if (old !== null) {
|
if (old !== null) {
|
||||||
if (old.constructor === ItemJSON && !old._deleted && old._content[0] === value) {
|
if (old instanceof ItemJSON && old._content[0] === value) {
|
||||||
// Trying to overwrite with same value
|
// Trying to overwrite with same value
|
||||||
// break here
|
// break here
|
||||||
return value
|
return value
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ export default class YText extends YArray {
|
|||||||
return strBuilder.join('')
|
return strBuilder.join('')
|
||||||
}
|
}
|
||||||
insert (pos, text) {
|
insert (pos, text) {
|
||||||
if (text.length <= 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this._transact(y => {
|
this._transact(y => {
|
||||||
let left = null
|
let left = null
|
||||||
let right = this._start
|
let right = this._start
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// import diff from 'fast-diff'
|
||||||
import { defaultDomFilter } from './utils.js'
|
import { defaultDomFilter } from './utils.js'
|
||||||
|
|
||||||
import YMap from '../YMap.js'
|
import YMap from '../YMap.js'
|
||||||
@@ -47,11 +48,6 @@ export default class YXmlElement extends YXmlFragment {
|
|||||||
return dom
|
return dom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_bindToDom (dom, _document) {
|
|
||||||
_document = _document || document
|
|
||||||
this._dom = dom
|
|
||||||
dom._yxml = this
|
|
||||||
}
|
|
||||||
_fromBinary (y, decoder) {
|
_fromBinary (y, decoder) {
|
||||||
const missing = super._fromBinary(y, decoder)
|
const missing = super._fromBinary(y, decoder)
|
||||||
this.nodeName = decoder.readVarString()
|
this.nodeName = decoder.readVarString()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import YArray from '../YArray.js'
|
|||||||
import YXmlEvent from './YXmlEvent.js'
|
import YXmlEvent from './YXmlEvent.js'
|
||||||
import { YXmlText, YXmlHook } from './y-xml'
|
import { YXmlText, YXmlHook } from './y-xml'
|
||||||
import { logID } from '../../MessageHandler/messageToString.js'
|
import { logID } from '../../MessageHandler/messageToString.js'
|
||||||
import diff from '../../Util/simpleDiff.js'
|
import diff from 'fast-diff'
|
||||||
|
|
||||||
function domToYXml (parent, doms, _document) {
|
function domToYXml (parent, doms, _document) {
|
||||||
const types = []
|
const types = []
|
||||||
@@ -17,7 +17,7 @@ function domToYXml (parent, doms, _document) {
|
|||||||
}
|
}
|
||||||
if (parent._domFilter(d.nodeName, new Map()) !== null) {
|
if (parent._domFilter(d.nodeName, new Map()) !== null) {
|
||||||
let type
|
let type
|
||||||
const hookName = d._yjsHook || (d.dataset != null ? d.dataset.yjsHook : undefined)
|
const hookName = d._yjsHook
|
||||||
if (hookName !== undefined) {
|
if (hookName !== undefined) {
|
||||||
type = new YXmlHook(hookName, d)
|
type = new YXmlHook(hookName, d)
|
||||||
} else if (d.nodeType === d.TEXT_NODE) {
|
} else if (d.nodeType === d.TEXT_NODE) {
|
||||||
@@ -55,7 +55,7 @@ class YXmlTreeWalker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
if (!n._deleted && (n.constructor === YXmlFragment._YXmlElement || n.constructor === YXmlFragment) && n._start !== null) {
|
if (!n._deleted && n.constructor === YXmlFragment._YXmlElement && n._start !== null) {
|
||||||
// walk down in the tree
|
// walk down in the tree
|
||||||
n = n._start
|
n = n._start
|
||||||
} else {
|
} else {
|
||||||
@@ -101,11 +101,9 @@ export default class YXmlFragment extends YArray {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
if (this._domObserver !== null) {
|
if (this._domObserver !== null) {
|
||||||
this._domObserver.takeRecords()
|
this._domObserver.takeRecords()
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
token = true
|
token = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,23 +143,6 @@ export default class YXmlFragment extends YArray {
|
|||||||
}
|
}
|
||||||
setDomFilter (f) {
|
setDomFilter (f) {
|
||||||
this._domFilter = f
|
this._domFilter = f
|
||||||
let attributes = new Map()
|
|
||||||
if (this.getAttributes !== undefined) {
|
|
||||||
let attrs = this.getAttributes()
|
|
||||||
for (let key in attrs) {
|
|
||||||
attributes.set(key, attrs[key])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let result = this._domFilter(this.nodeName, new Map(attributes))
|
|
||||||
if (result === null) {
|
|
||||||
this._delete(this._y)
|
|
||||||
} else {
|
|
||||||
attributes.forEach((value, key) => {
|
|
||||||
if (!result.has(key)) {
|
|
||||||
this.removeAttribute(key)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.forEach(xml => {
|
this.forEach(xml => {
|
||||||
xml.setDomFilter(f)
|
xml.setDomFilter(f)
|
||||||
})
|
})
|
||||||
@@ -185,9 +166,6 @@ export default class YXmlFragment extends YArray {
|
|||||||
this._dom._yxml = null
|
this._dom._yxml = null
|
||||||
this._dom = null
|
this._dom = null
|
||||||
}
|
}
|
||||||
if (this._beforeTransactionHandler !== undefined) {
|
|
||||||
this._y.off('beforeTransaction', this._beforeTransactionHandler)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
insertDomElementsAfter (prev, doms, _document) {
|
insertDomElementsAfter (prev, doms, _document) {
|
||||||
const types = domToYXml(this, doms, _document)
|
const types = domToYXml(this, doms, _document)
|
||||||
@@ -221,7 +199,9 @@ export default class YXmlFragment extends YArray {
|
|||||||
_document = _document || document
|
_document = _document || document
|
||||||
this._dom = dom
|
this._dom = dom
|
||||||
dom._yxml = this
|
dom._yxml = this
|
||||||
if (this._parent === null) {
|
// 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', beforeTransactionSelectionFixer)
|
this._y.on('beforeTransaction', beforeTransactionSelectionFixer)
|
||||||
@@ -278,10 +258,9 @@ export default class YXmlFragment extends YArray {
|
|||||||
})
|
})
|
||||||
// Apply Dom changes on Y.Xml
|
// Apply Dom changes on Y.Xml
|
||||||
if (typeof MutationObserver !== 'undefined') {
|
if (typeof MutationObserver !== 'undefined') {
|
||||||
this._beforeTransactionHandler = () => {
|
this._y.on('beforeTransaction', () => {
|
||||||
this._domObserverListener(this._domObserver.takeRecords())
|
this._domObserverListener(this._domObserver.takeRecords())
|
||||||
}
|
})
|
||||||
this._y.on('beforeTransaction', this._beforeTransactionHandler)
|
|
||||||
this._domObserverListener = mutations => {
|
this._domObserverListener = mutations => {
|
||||||
this._mutualExclude(() => {
|
this._mutualExclude(() => {
|
||||||
this._y.transact(() => {
|
this._y.transact(() => {
|
||||||
@@ -295,9 +274,19 @@ export default class YXmlFragment extends YArray {
|
|||||||
}
|
}
|
||||||
switch (mutation.type) {
|
switch (mutation.type) {
|
||||||
case 'characterData':
|
case 'characterData':
|
||||||
var change = diff(yxml.toString(), dom.nodeValue)
|
var diffs = diff(yxml.toString(), dom.nodeValue)
|
||||||
yxml.delete(change.pos, change.remove)
|
var pos = 0
|
||||||
yxml.insert(change.pos, change.insert)
|
for (var i = 0; i < diffs.length; i++) {
|
||||||
|
var d = diffs[i]
|
||||||
|
if (d[0] === 0) { // EQUAL
|
||||||
|
pos += d[1].length
|
||||||
|
} else if (d[0] === -1) { // DELETE
|
||||||
|
yxml.delete(pos, d[1].length)
|
||||||
|
} else { // INSERT
|
||||||
|
yxml.insert(pos, d[1])
|
||||||
|
pos += d[1].length
|
||||||
|
}
|
||||||
|
}
|
||||||
break
|
break
|
||||||
case 'attributes':
|
case 'attributes':
|
||||||
if (yxml.constructor === YXmlFragment) {
|
if (yxml.constructor === YXmlFragment) {
|
||||||
@@ -324,9 +313,6 @@ export default class YXmlFragment extends YArray {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
for (let dom of diffChildren) {
|
for (let dom of diffChildren) {
|
||||||
if (dom.yOnChildrenChanged !== undefined) {
|
|
||||||
dom.yOnChildrenChanged()
|
|
||||||
}
|
|
||||||
if (dom._yxml != null && dom._yxml !== false) {
|
if (dom._yxml != null && dom._yxml !== false) {
|
||||||
applyChangesFromDom(dom)
|
applyChangesFromDom(dom)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,6 @@ export default class YXmlHook extends YMap {
|
|||||||
}
|
}
|
||||||
return this._dom
|
return this._dom
|
||||||
}
|
}
|
||||||
_unbindFromDom () {
|
|
||||||
this._dom._yxml = null
|
|
||||||
this._yxml = null
|
|
||||||
// TODO: cleanup hook?
|
|
||||||
}
|
|
||||||
_fromBinary (y, decoder) {
|
_fromBinary (y, decoder) {
|
||||||
const missing = super._fromBinary(y, decoder)
|
const missing = super._fromBinary(y, decoder)
|
||||||
this.hookName = decoder.readVarString()
|
this.hookName = decoder.readVarString()
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export function afterTransactionSelectionFixer (y, transaction, remote) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (shouldUpdate) {
|
if (shouldUpdate) {
|
||||||
|
console.info('updating selection!!')
|
||||||
browserSelection.setBaseAndExtent(
|
browserSelection.setBaseAndExtent(
|
||||||
anchorNode,
|
anchorNode,
|
||||||
anchorOffset,
|
anchorOffset,
|
||||||
@@ -75,4 +76,7 @@ export function afterTransactionSelectionFixer (y, transaction, remote) {
|
|||||||
focusOffset
|
focusOffset
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// delete, so the objects can be gc'd
|
||||||
|
relativeSelection = null
|
||||||
|
browserSelection = null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ export function reflectChangesOnDom (events, _document) {
|
|||||||
// let anchorViewPosition = getAnchorViewPosition(yxml._scrollElement)
|
// let anchorViewPosition = getAnchorViewPosition(yxml._scrollElement)
|
||||||
if (yxml.constructor === YXmlText) {
|
if (yxml.constructor === YXmlText) {
|
||||||
yxml._dom.nodeValue = yxml.toString()
|
yxml._dom.nodeValue = yxml.toString()
|
||||||
} else if (event.attributesChanged !== undefined) {
|
} else {
|
||||||
// update attributes
|
// update attributes
|
||||||
event.attributesChanged.forEach(attributeName => {
|
event.attributesChanged.forEach(attributeName => {
|
||||||
const value = yxml.getAttribute(attributeName)
|
const value = yxml.getAttribute(attributeName)
|
||||||
@@ -193,27 +193,19 @@ export function reflectChangesOnDom (events, _document) {
|
|||||||
* only in the attributes (above)
|
* only in the attributes (above)
|
||||||
*/
|
*/
|
||||||
if (event.childListChanged && yxml.constructor !== YXmlHook) {
|
if (event.childListChanged && yxml.constructor !== YXmlHook) {
|
||||||
let currentChild = dom.firstChild
|
// create fragment of undeleted nodes
|
||||||
|
const fragment = _document.createDocumentFragment()
|
||||||
yxml.forEach(function (t) {
|
yxml.forEach(function (t) {
|
||||||
let expectedChild = t.getDom(_document)
|
fragment.appendChild(t.getDom(_document))
|
||||||
if (expectedChild.parentNode === dom) {
|
|
||||||
// is already attached to the dom. Look for it
|
|
||||||
while (currentChild !== expectedChild) {
|
|
||||||
let del = currentChild
|
|
||||||
currentChild = currentChild.nextSibling
|
|
||||||
dom.removeChild(del)
|
|
||||||
}
|
|
||||||
currentChild = currentChild.nextSibling
|
|
||||||
} else {
|
|
||||||
// this dom is not yet attached to dom
|
|
||||||
dom.insertBefore(expectedChild, currentChild)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
while (currentChild !== null) {
|
// remove remainding nodes
|
||||||
let tmp = currentChild.nextSibling
|
let lastChild = dom.lastChild
|
||||||
dom.removeChild(currentChild)
|
while (lastChild !== null) {
|
||||||
currentChild = tmp
|
dom.removeChild(lastChild)
|
||||||
|
lastChild = dom.lastChild
|
||||||
}
|
}
|
||||||
|
// insert fragment of undeleted nodes
|
||||||
|
dom.appendChild(fragment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* TODO: smartscrolling
|
/* TODO: smartscrolling
|
||||||
|
|||||||
@@ -11,10 +11,6 @@ export default class ID {
|
|||||||
return id !== null && id.user === this.user && id.clock === this.clock
|
return id !== null && id.user === this.user && id.clock === this.clock
|
||||||
}
|
}
|
||||||
lessThan (id) {
|
lessThan (id) {
|
||||||
if (id.constructor === ID) {
|
return this.user < id.user || (this.user === id.user && this.clock < id.clock)
|
||||||
return this.user < id.user || (this.user === id.user && this.clock < id.clock)
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
export default class NamedEventHandler {
|
export default class NamedEventHandler {
|
||||||
constructor () {
|
constructor () {
|
||||||
this._eventListener = new Map()
|
this._eventListener = new Map()
|
||||||
this._stateListener = new Map()
|
|
||||||
}
|
}
|
||||||
_getListener (name) {
|
_getListener (name) {
|
||||||
let listeners = this._eventListener.get(name)
|
let listeners = this._eventListener.get(name)
|
||||||
@@ -22,32 +21,16 @@ export default class NamedEventHandler {
|
|||||||
let listeners = this._getListener(name)
|
let listeners = this._getListener(name)
|
||||||
listeners.on.add(f)
|
listeners.on.add(f)
|
||||||
}
|
}
|
||||||
_initStateListener (name) {
|
|
||||||
let state = this._stateListener.get(name)
|
|
||||||
if (state === undefined) {
|
|
||||||
state = {}
|
|
||||||
state.promise = new Promise(function (resolve) {
|
|
||||||
state.resolve = resolve
|
|
||||||
})
|
|
||||||
this._stateListener.set(name, state)
|
|
||||||
}
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
when (name) {
|
|
||||||
return this._initStateListener(name).promise
|
|
||||||
}
|
|
||||||
off (name, f) {
|
off (name, f) {
|
||||||
if (name == null || f == null) {
|
if (name == null || f == null) {
|
||||||
throw new Error('You must specify event name and function!')
|
throw new Error('You must specify event name and function!')
|
||||||
}
|
}
|
||||||
const listener = this._eventListener.get(name)
|
const listener = this._eventListener.get(name)
|
||||||
if (listener !== undefined) {
|
if (listener !== undefined) {
|
||||||
listener.on.delete(f)
|
listener.remove(f)
|
||||||
listener.once.delete(f)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit (name, ...args) {
|
emit (name, ...args) {
|
||||||
this._initStateListener(name).resolve()
|
|
||||||
const listener = this._eventListener.get(name)
|
const listener = this._eventListener.get(name)
|
||||||
if (listener !== undefined) {
|
if (listener !== undefined) {
|
||||||
listener.on.forEach(f => f.apply(null, args))
|
listener.on.forEach(f => f.apply(null, args))
|
||||||
|
|||||||
@@ -12,10 +12,6 @@ export default class RootID {
|
|||||||
return id !== null && id.user === this.user && id.name === this.name && id.type === this.type
|
return id !== null && id.user === this.user && id.name === this.name && id.type === this.type
|
||||||
}
|
}
|
||||||
lessThan (id) {
|
lessThan (id) {
|
||||||
if (id.constructor === RootID) {
|
return this.user < id.user || (this.user === id.user && (this.name < id.name || (this.name === id.name && this.type < id.type)))
|
||||||
return this.user < id.user || (this.user === id.user && (this.name < id.name || (this.name === id.name && this.type < id.type)))
|
|
||||||
} else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
|
|
||||||
export function createMutualExclude () {
|
|
||||||
var token = true
|
|
||||||
return function mutualExclude (f) {
|
|
||||||
if (token) {
|
|
||||||
token = false
|
|
||||||
try {
|
|
||||||
f()
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e)
|
|
||||||
}
|
|
||||||
token = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,31 +2,37 @@ import ID from './ID.js'
|
|||||||
import RootID from './RootID.js'
|
import RootID from './RootID.js'
|
||||||
|
|
||||||
export function getRelativePosition (type, offset) {
|
export function getRelativePosition (type, offset) {
|
||||||
let t = type._start
|
if (offset === 0) {
|
||||||
while (t !== null) {
|
return ['startof', type._id.user, type._id.clock || null, type._id.name || null, type._id.type || null]
|
||||||
if (t._deleted === false) {
|
} else {
|
||||||
if (t._length > offset) {
|
let t = type._start
|
||||||
return [t._id.user, t._id.clock + offset]
|
while (t !== null) {
|
||||||
|
if (t._deleted === false) {
|
||||||
|
if (t._length >= offset) {
|
||||||
|
return [t._id.user, t._id.clock + offset - 1]
|
||||||
|
}
|
||||||
|
if (t._right === null) {
|
||||||
|
return [t._id.user, t._id.clock + t._length - 1]
|
||||||
|
}
|
||||||
|
offset -= t._length
|
||||||
}
|
}
|
||||||
offset -= t._length
|
t = t._right
|
||||||
}
|
}
|
||||||
t = t._right
|
return null
|
||||||
}
|
}
|
||||||
return ['endof', type._id.user, type._id.clock || null, type._id.name || null, type._id.type || null]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fromRelativePosition (y, rpos) {
|
export function fromRelativePosition (y, rpos) {
|
||||||
if (rpos[0] === 'endof') {
|
if (rpos[0] === 'startof') {
|
||||||
let id
|
let id
|
||||||
if (rpos[3] === null) {
|
if (rpos[3] === null) {
|
||||||
id = new ID(rpos[1], rpos[2])
|
id = new ID(rpos[1], rpos[2])
|
||||||
} else {
|
} else {
|
||||||
id = new RootID(rpos[3], rpos[4])
|
id = new RootID(rpos[3], rpos[4])
|
||||||
}
|
}
|
||||||
const type = y.os.get(id)
|
|
||||||
return {
|
return {
|
||||||
type,
|
type: y.os.get(id),
|
||||||
offset: type.length
|
offset: 0
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let offset = 0
|
let offset = 0
|
||||||
@@ -36,7 +42,7 @@ export function fromRelativePosition (y, rpos) {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
if (!struct._deleted) {
|
if (!struct._deleted) {
|
||||||
offset = rpos[1] - struct._id.clock
|
offset = rpos[1] - struct._id.clock + 1
|
||||||
}
|
}
|
||||||
struct = struct._left
|
struct = struct._left
|
||||||
while (struct !== null) {
|
while (struct !== null) {
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
|
|
||||||
export default function simpleDiff (a, b) {
|
|
||||||
let left = 0 // number of same characters counting from left
|
|
||||||
let right = 0 // number of same characters counting from right
|
|
||||||
while (left < a.length && left < b.length && a[left] === b[left]) {
|
|
||||||
left++
|
|
||||||
}
|
|
||||||
if (left !== a.length || left !== b.length) {
|
|
||||||
// Only check right if a !== b
|
|
||||||
while (right + left < a.length && right + left < b.length && a[a.length - right - 1] === b[b.length - right - 1]) {
|
|
||||||
right++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
pos: left,
|
|
||||||
remove: a.length - left - right,
|
|
||||||
insert: b.slice(left, b.length - right)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
80
src/Y.js
80
src/Y.js
@@ -5,7 +5,6 @@ import { generateUserID } from './Util/generateUserID.js'
|
|||||||
import RootID from './Util/RootID.js'
|
import RootID from './Util/RootID.js'
|
||||||
import NamedEventHandler from './Util/NamedEventHandler.js'
|
import NamedEventHandler from './Util/NamedEventHandler.js'
|
||||||
import UndoManager from './Util/UndoManager.js'
|
import UndoManager from './Util/UndoManager.js'
|
||||||
import { integrateRemoteStructs } from './MessageHandler/integrateRemoteStructs.js'
|
|
||||||
|
|
||||||
import { messageToString, messageToRoomname } from './MessageHandler/messageToString.js'
|
import { messageToString, messageToRoomname } from './MessageHandler/messageToString.js'
|
||||||
|
|
||||||
@@ -22,58 +21,26 @@ import { addStruct as addType } from './Util/structReferences.js'
|
|||||||
import debug from 'debug'
|
import debug from 'debug'
|
||||||
import Transaction from './Transaction.js'
|
import Transaction from './Transaction.js'
|
||||||
|
|
||||||
import TextareaBinding from './Binding/TextareaBinding.js'
|
|
||||||
|
|
||||||
import { toBinary, fromBinary } from './MessageHandler/binaryEncode.js'
|
|
||||||
|
|
||||||
export default class Y extends NamedEventHandler {
|
export default class Y extends NamedEventHandler {
|
||||||
constructor (room, opts, persistence) {
|
constructor (opts) {
|
||||||
super()
|
super()
|
||||||
this.room = room
|
|
||||||
if (opts != null) {
|
|
||||||
opts.connector.room = room
|
|
||||||
}
|
|
||||||
this._contentReady = false
|
|
||||||
this._opts = opts
|
this._opts = opts
|
||||||
this.userID = generateUserID()
|
this.userID = opts._userID != null ? opts._userID : generateUserID()
|
||||||
this.share = {}
|
this.share = {}
|
||||||
this.ds = new DeleteStore(this)
|
this.ds = new DeleteStore(this)
|
||||||
this.os = new OperationStore(this)
|
this.os = new OperationStore(this)
|
||||||
this.ss = new StateStore(this)
|
this.ss = new StateStore(this)
|
||||||
|
this.connector = new Y[opts.connector.name](this, opts.connector)
|
||||||
|
if (opts.persistence != null) {
|
||||||
|
this.persistence = new Y[opts.persistence.name](this, opts.persistence)
|
||||||
|
this.persistence.retrieveContent()
|
||||||
|
} else {
|
||||||
|
this.persistence = null
|
||||||
|
}
|
||||||
|
this.connected = true
|
||||||
this._missingStructs = new Map()
|
this._missingStructs = new Map()
|
||||||
this._readyToIntegrate = []
|
this._readyToIntegrate = []
|
||||||
this._transaction = null
|
this._transaction = null
|
||||||
this.connector = null
|
|
||||||
this.connected = false
|
|
||||||
let initConnection = () => {
|
|
||||||
if (opts != null) {
|
|
||||||
this.connector = new Y[opts.connector.name](this, opts.connector)
|
|
||||||
this.connected = true
|
|
||||||
this.emit('connectorReady')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (persistence != null) {
|
|
||||||
this.persistence = persistence
|
|
||||||
persistence._init(this).then(initConnection)
|
|
||||||
} else {
|
|
||||||
this.persistence = null
|
|
||||||
initConnection()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_setContentReady () {
|
|
||||||
if (!this._contentReady) {
|
|
||||||
this._contentReady = true
|
|
||||||
this.emit('content')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
whenContentReady () {
|
|
||||||
if (this._contentReady) {
|
|
||||||
return Promise.resolve()
|
|
||||||
} else {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
this.once('content', resolve)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_beforeChange () {}
|
_beforeChange () {}
|
||||||
transact (f, remote = false) {
|
transact (f, remote = false) {
|
||||||
@@ -123,6 +90,9 @@ export default class Y extends NamedEventHandler {
|
|||||||
set _start (start) {
|
set _start (start) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
get room () {
|
||||||
|
return this._opts.connector.room
|
||||||
|
}
|
||||||
define (name, TypeConstructor) {
|
define (name, TypeConstructor) {
|
||||||
let id = new RootID(name, TypeConstructor)
|
let id = new RootID(name, TypeConstructor)
|
||||||
let type = this.os.get(id)
|
let type = this.os.get(id)
|
||||||
@@ -153,18 +123,11 @@ export default class Y extends NamedEventHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
destroy () {
|
destroy () {
|
||||||
super.destroy()
|
|
||||||
this.share = null
|
this.share = null
|
||||||
if (this.connector != null) {
|
if (this.connector.destroy != null) {
|
||||||
if (this.connector.destroy != null) {
|
this.connector.destroy()
|
||||||
this.connector.destroy()
|
} else {
|
||||||
} else {
|
this.connector.disconnect()
|
||||||
this.connector.disconnect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.persistence !== null) {
|
|
||||||
this.persistence.deinit(this)
|
|
||||||
this.persistence = null
|
|
||||||
}
|
}
|
||||||
this.os = null
|
this.os = null
|
||||||
this.ds = null
|
this.ds = null
|
||||||
@@ -192,7 +155,7 @@ Y.extend = function extendYjs () {
|
|||||||
|
|
||||||
// TODO: The following assignments should be moved to yjs-dist
|
// TODO: The following assignments should be moved to yjs-dist
|
||||||
Y.AbstractConnector = Connector
|
Y.AbstractConnector = Connector
|
||||||
Y.AbstractPersistence = Persistence
|
Y.Persisence = Persistence
|
||||||
Y.Array = YArray
|
Y.Array = YArray
|
||||||
Y.Map = YMap
|
Y.Map = YMap
|
||||||
Y.Text = YText
|
Y.Text = YText
|
||||||
@@ -201,17 +164,12 @@ Y.XmlFragment = YXmlFragment
|
|||||||
Y.XmlText = YXmlText
|
Y.XmlText = YXmlText
|
||||||
Y.XmlHook = YXmlHook
|
Y.XmlHook = YXmlHook
|
||||||
|
|
||||||
Y.TextareaBinding = TextareaBinding
|
|
||||||
|
|
||||||
Y.utils = {
|
Y.utils = {
|
||||||
BinaryDecoder,
|
BinaryDecoder,
|
||||||
UndoManager,
|
UndoManager,
|
||||||
getRelativePosition,
|
getRelativePosition,
|
||||||
fromRelativePosition,
|
fromRelativePosition,
|
||||||
addType,
|
addType
|
||||||
integrateRemoteStructs,
|
|
||||||
toBinary,
|
|
||||||
fromBinary
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Y.debug = debug
|
Y.debug = debug
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
import { test } from '../node_modules/cutest/cutest.mjs'
|
|
||||||
import simpleDiff from '../src/Util/simpleDiff.js'
|
|
||||||
import Chance from 'chance'
|
|
||||||
|
|
||||||
function runDiffTest (t, a, b, expected) {
|
|
||||||
let result = simpleDiff(a, b)
|
|
||||||
t.compare(result, expected, `Compare "${a}" with "${b}"`)
|
|
||||||
}
|
|
||||||
|
|
||||||
test('diff tests', async function diff1 (t) {
|
|
||||||
runDiffTest(t, 'abc', 'axc', { pos: 1, remove: 1, insert: 'x' })
|
|
||||||
runDiffTest(t, 'bc', 'xc', { pos: 0, remove: 1, insert: 'x' })
|
|
||||||
runDiffTest(t, 'ab', 'ax', { pos: 1, remove: 1, insert: 'x' })
|
|
||||||
runDiffTest(t, 'b', 'x', { pos: 0, remove: 1, insert: 'x' })
|
|
||||||
runDiffTest(t, '', 'abc', { pos: 0, remove: 0, insert: 'abc' })
|
|
||||||
runDiffTest(t, 'abc', 'xyz', { pos: 0, remove: 3, insert: 'xyz' })
|
|
||||||
runDiffTest(t, 'axz', 'au', { pos: 1, remove: 2, insert: 'u' })
|
|
||||||
runDiffTest(t, 'ax', 'axy', { pos: 2, remove: 0, insert: 'y' })
|
|
||||||
})
|
|
||||||
|
|
||||||
test('random diff tests', async function randomDiff (t) {
|
|
||||||
const chance = new Chance(t.getSeed() * 1000000000)
|
|
||||||
let a = chance.word()
|
|
||||||
let b = chance.word()
|
|
||||||
let change = simpleDiff(a, b)
|
|
||||||
let arr = Array.from(a)
|
|
||||||
arr.splice(change.pos, change.remove, ...Array.from(change.insert))
|
|
||||||
t.assert(arr.join('') === b, 'Applying change information is correct')
|
|
||||||
})
|
|
||||||
@@ -54,9 +54,6 @@ test('varString', async function varString (t) {
|
|||||||
testEncoding(t, writeVarString, readVarString, 'test!')
|
testEncoding(t, writeVarString, readVarString, 'test!')
|
||||||
testEncoding(t, writeVarString, readVarString, '☺☺☺')
|
testEncoding(t, writeVarString, readVarString, '☺☺☺')
|
||||||
testEncoding(t, writeVarString, readVarString, '1234')
|
testEncoding(t, writeVarString, readVarString, '1234')
|
||||||
testEncoding(t, writeVarString, readVarString, '쾟')
|
|
||||||
testEncoding(t, writeVarString, readVarString, '龟') // surrogate length 3
|
|
||||||
testEncoding(t, writeVarString, readVarString, '😝') // surrogate length 4
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('varString random', async function varStringRandom (t) {
|
test('varString random', async function varStringRandom (t) {
|
||||||
@@ -3,6 +3,6 @@
|
|||||||
<head>
|
<head>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script type="module" src="./index.js"></script>
|
<script type="module" src="./encode-decode.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
import './red-black-tree.js'
|
|
||||||
import './y-array.tests.js'
|
|
||||||
import './y-map.tests.js'
|
|
||||||
import './y-xml.tests.js'
|
|
||||||
import './encode-decode.tests.js'
|
|
||||||
import './diff.tests.js'
|
|
||||||
@@ -280,6 +280,7 @@ test('deep element insert', async function xml16 (t) {
|
|||||||
deepElement.append(boldElement)
|
deepElement.append(boldElement)
|
||||||
deepElement.append(attrElement)
|
deepElement.append(attrElement)
|
||||||
dom0.append(deepElement)
|
dom0.append(deepElement)
|
||||||
|
console.log(dom0.outerHTML)
|
||||||
let str0 = dom0.outerHTML
|
let str0 = dom0.outerHTML
|
||||||
await flushAll(t, users)
|
await flushAll(t, users)
|
||||||
let str1 = dom1.outerHTML
|
let str1 = dom1.outerHTML
|
||||||
@@ -339,6 +340,7 @@ test('Filtering remote changes', async function xmlFilteringRemote (t) {
|
|||||||
// check dom
|
// check dom
|
||||||
paragraph.getDom().setAttribute('malicious', 'true')
|
paragraph.getDom().setAttribute('malicious', 'true')
|
||||||
span.getDom().setAttribute('malicious', 'true')
|
span.getDom().setAttribute('malicious', 'true')
|
||||||
|
console.log(xml0.toString())
|
||||||
// check incoming attributes
|
// check incoming attributes
|
||||||
xml1.get(0).get(0).setAttribute('malicious', 'true')
|
xml1.get(0).get(0).setAttribute('malicious', 'true')
|
||||||
xml1.insert(0, [new Y.XmlElement('hideMe')])
|
xml1.insert(0, [new Y.XmlElement('hideMe')])
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ export async function initArrays (t, opts) {
|
|||||||
} else {
|
} else {
|
||||||
connOpts = Object.assign({ role: 'slave' }, conn)
|
connOpts = Object.assign({ role: 'slave' }, conn)
|
||||||
}
|
}
|
||||||
let y = new Y(connOpts.room, {
|
let y = new Y({
|
||||||
_userID: i, // evil hackery, don't try this at home
|
_userID: i, // evil hackery, don't try this at home
|
||||||
connector: connOpts
|
connector: connOpts
|
||||||
})
|
})
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
272
y.test.js
272
y.test.js
@@ -1,8 +1,8 @@
|
|||||||
(function (global, factory) {
|
(function (global, factory) {
|
||||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory() :
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||||
typeof define === 'function' && define.amd ? define(factory) :
|
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
||||||
(factory());
|
(factory((global['y-tests'] = {})));
|
||||||
}(this, (function () { 'use strict';
|
}(this, (function (exports) { 'use strict';
|
||||||
|
|
||||||
class N {
|
class N {
|
||||||
// A created node is always red!
|
// A created node is always red!
|
||||||
@@ -2201,38 +2201,15 @@ class YEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class YArrayEvent extends YEvent {
|
class YArrayEvent extends YEvent {
|
||||||
constructor (yarray, remote, transaction) {
|
constructor (yarray, remote) {
|
||||||
super(yarray);
|
super(yarray);
|
||||||
this.remote = remote;
|
this.remote = remote;
|
||||||
this._transaction = transaction;
|
|
||||||
}
|
|
||||||
get addedElements () {
|
|
||||||
const target = this.target;
|
|
||||||
const transaction = this._transaction;
|
|
||||||
const addedElements = new Set();
|
|
||||||
transaction.newTypes.forEach(function (type) {
|
|
||||||
if (type._parent === target && !transaction.deletedStructs.has(type)) {
|
|
||||||
addedElements.add(type);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return addedElements
|
|
||||||
}
|
|
||||||
get removedElements () {
|
|
||||||
const target = this.target;
|
|
||||||
const transaction = this._transaction;
|
|
||||||
const removedElements = new Set();
|
|
||||||
transaction.deletedStructs.forEach(function (struct) {
|
|
||||||
if (struct._parent === target && !transaction.newTypes.has(struct)) {
|
|
||||||
removedElements.add(struct);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return removedElements
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class YArray extends Type {
|
class YArray extends Type {
|
||||||
_callObserver (transaction, parentSubs, remote) {
|
_callObserver (transaction, parentSubs, remote) {
|
||||||
this._callEventHandler(transaction, new YArrayEvent(this, remote, transaction));
|
this._callEventHandler(transaction, new YArrayEvent(this, remote));
|
||||||
}
|
}
|
||||||
get (pos) {
|
get (pos) {
|
||||||
let n = this._start;
|
let n = this._start;
|
||||||
@@ -2403,12 +2380,8 @@ class YArray extends Type {
|
|||||||
prevJsonIns._content.push(c);
|
prevJsonIns._content.push(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (prevJsonIns !== null) {
|
if (prevJsonIns !== null && y !== null) {
|
||||||
if (y !== null) {
|
prevJsonIns._integrate(y);
|
||||||
prevJsonIns._integrate(y);
|
|
||||||
} else if (prevJsonIns._left === null) {
|
|
||||||
this._start = prevJsonIns;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -2437,17 +2410,6 @@ class YArray extends Type {
|
|||||||
}
|
}
|
||||||
this.insertAfter(left, content);
|
this.insertAfter(left, content);
|
||||||
}
|
}
|
||||||
push (content) {
|
|
||||||
let n = this._start;
|
|
||||||
let lastUndeleted = null;
|
|
||||||
while (n !== null) {
|
|
||||||
if (!n._deleted) {
|
|
||||||
lastUndeleted = n;
|
|
||||||
}
|
|
||||||
n = n._right;
|
|
||||||
}
|
|
||||||
this.insertAfter(lastUndeleted, content);
|
|
||||||
}
|
|
||||||
_logString () {
|
_logString () {
|
||||||
const left = this._left !== null ? this._left._lastId : null;
|
const left = this._left !== null ? this._left._lastId : null;
|
||||||
const origin = this._origin !== null ? this._origin._lastId : null;
|
const origin = this._origin !== null ? this._origin._lastId : null;
|
||||||
@@ -2591,17 +2553,14 @@ class YText extends YArray {
|
|||||||
let right = this._start;
|
let right = this._start;
|
||||||
let count = 0;
|
let count = 0;
|
||||||
while (right !== null) {
|
while (right !== null) {
|
||||||
const rightLen = right._deleted ? 0 : (right._length - 1);
|
if (count <= pos && pos < count + right._length) {
|
||||||
if (count <= pos && pos <= count + rightLen) {
|
|
||||||
const splitDiff = pos - count;
|
const splitDiff = pos - count;
|
||||||
right = right._splitAt(this._y, splitDiff);
|
right = right._splitAt(this._y, pos - count);
|
||||||
left = right._left;
|
left = right._left;
|
||||||
count += splitDiff;
|
count += splitDiff;
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (!right._deleted) {
|
count += right._length;
|
||||||
count += right._length;
|
|
||||||
}
|
|
||||||
left = right;
|
left = right;
|
||||||
right = right._right;
|
right = right._right;
|
||||||
}
|
}
|
||||||
@@ -2761,7 +2720,7 @@ function reflectChangesOnDom (events, _document) {
|
|||||||
// let anchorViewPosition = getAnchorViewPosition(yxml._scrollElement)
|
// let anchorViewPosition = getAnchorViewPosition(yxml._scrollElement)
|
||||||
if (yxml.constructor === YXmlText) {
|
if (yxml.constructor === YXmlText) {
|
||||||
yxml._dom.nodeValue = yxml.toString();
|
yxml._dom.nodeValue = yxml.toString();
|
||||||
} else if (event.attributesChanged !== undefined) {
|
} else {
|
||||||
// update attributes
|
// update attributes
|
||||||
event.attributesChanged.forEach(attributeName => {
|
event.attributesChanged.forEach(attributeName => {
|
||||||
const value = yxml.getAttribute(attributeName);
|
const value = yxml.getAttribute(attributeName);
|
||||||
@@ -2780,27 +2739,19 @@ function reflectChangesOnDom (events, _document) {
|
|||||||
* only in the attributes (above)
|
* only in the attributes (above)
|
||||||
*/
|
*/
|
||||||
if (event.childListChanged && yxml.constructor !== YXmlHook) {
|
if (event.childListChanged && yxml.constructor !== YXmlHook) {
|
||||||
let currentChild = dom.firstChild;
|
// create fragment of undeleted nodes
|
||||||
|
const fragment = _document.createDocumentFragment();
|
||||||
yxml.forEach(function (t) {
|
yxml.forEach(function (t) {
|
||||||
let expectedChild = t.getDom(_document);
|
fragment.appendChild(t.getDom(_document));
|
||||||
if (expectedChild.parentNode === dom) {
|
|
||||||
// is already attached to the dom. Look for it
|
|
||||||
while (currentChild !== expectedChild) {
|
|
||||||
let del = currentChild;
|
|
||||||
currentChild = currentChild.nextSibling;
|
|
||||||
dom.removeChild(del);
|
|
||||||
}
|
|
||||||
currentChild = currentChild.nextSibling;
|
|
||||||
} else {
|
|
||||||
// this dom is not yet attached to dom
|
|
||||||
dom.insertBefore(expectedChild, currentChild);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
while (currentChild !== null) {
|
// remove remainding nodes
|
||||||
let tmp = currentChild.nextSibling;
|
let lastChild = dom.lastChild;
|
||||||
dom.removeChild(currentChild);
|
while (lastChild !== null) {
|
||||||
currentChild = tmp;
|
dom.removeChild(lastChild);
|
||||||
|
lastChild = dom.lastChild;
|
||||||
}
|
}
|
||||||
|
// insert fragment of undeleted nodes
|
||||||
|
dom.appendChild(fragment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* TODO: smartscrolling
|
/* TODO: smartscrolling
|
||||||
@@ -2982,6 +2933,7 @@ function afterTransactionSelectionFixer (y, transaction, remote) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (shouldUpdate) {
|
if (shouldUpdate) {
|
||||||
|
console.info('updating selection!!');
|
||||||
browserSelection.setBaseAndExtent(
|
browserSelection.setBaseAndExtent(
|
||||||
anchorNode,
|
anchorNode,
|
||||||
anchorOffset,
|
anchorOffset,
|
||||||
@@ -2989,6 +2941,9 @@ function afterTransactionSelectionFixer (y, transaction, remote) {
|
|||||||
focusOffset
|
focusOffset
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// delete, so the objects can be gc'd
|
||||||
|
relativeSelection = null;
|
||||||
|
browserSelection = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
class YXmlEvent extends YEvent {
|
class YXmlEvent extends YEvent {
|
||||||
@@ -3756,7 +3711,7 @@ function domToYXml (parent, doms, _document) {
|
|||||||
}
|
}
|
||||||
if (parent._domFilter(d.nodeName, new Map()) !== null) {
|
if (parent._domFilter(d.nodeName, new Map()) !== null) {
|
||||||
let type;
|
let type;
|
||||||
const hookName = d._yjsHook || (d.dataset != null ? d.dataset.yjsHook : undefined);
|
const hookName = d._yjsHook;
|
||||||
if (hookName !== undefined) {
|
if (hookName !== undefined) {
|
||||||
type = new YXmlHook(hookName, d);
|
type = new YXmlHook(hookName, d);
|
||||||
} else if (d.nodeType === d.TEXT_NODE) {
|
} else if (d.nodeType === d.TEXT_NODE) {
|
||||||
@@ -3794,7 +3749,7 @@ class YXmlTreeWalker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
if (!n._deleted && (n.constructor === YXmlFragment._YXmlElement || n.constructor === YXmlFragment) && n._start !== null) {
|
if (!n._deleted && n.constructor === YXmlFragment._YXmlElement && n._start !== null) {
|
||||||
// walk down in the tree
|
// walk down in the tree
|
||||||
n = n._start;
|
n = n._start;
|
||||||
} else {
|
} else {
|
||||||
@@ -3882,23 +3837,6 @@ class YXmlFragment extends YArray {
|
|||||||
}
|
}
|
||||||
setDomFilter (f) {
|
setDomFilter (f) {
|
||||||
this._domFilter = f;
|
this._domFilter = f;
|
||||||
let attributes = new Map();
|
|
||||||
if (this.getAttributes !== undefined) {
|
|
||||||
let attrs = this.getAttributes();
|
|
||||||
for (let key in attrs) {
|
|
||||||
attributes.set(key, attrs[key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let result = this._domFilter(this.nodeName, new Map(attributes));
|
|
||||||
if (result === null) {
|
|
||||||
this._delete(this._y);
|
|
||||||
} else {
|
|
||||||
attributes.forEach((value, key) => {
|
|
||||||
if (!result.has(key)) {
|
|
||||||
this.removeAttribute(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.forEach(xml => {
|
this.forEach(xml => {
|
||||||
xml.setDomFilter(f);
|
xml.setDomFilter(f);
|
||||||
});
|
});
|
||||||
@@ -4024,7 +3962,7 @@ class YXmlFragment extends YArray {
|
|||||||
mutations.forEach(mutation => {
|
mutations.forEach(mutation => {
|
||||||
const dom = mutation.target;
|
const dom = mutation.target;
|
||||||
const yxml = dom._yxml;
|
const yxml = dom._yxml;
|
||||||
if (yxml == null || yxml.constructor === YXmlHook) {
|
if (yxml == null) {
|
||||||
// dom element is filtered
|
// dom element is filtered
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -4240,7 +4178,6 @@ class YXmlHook extends YMap {
|
|||||||
if (hookName !== undefined) {
|
if (hookName !== undefined) {
|
||||||
this.hookName = hookName;
|
this.hookName = hookName;
|
||||||
this._dom = dom;
|
this._dom = dom;
|
||||||
dom._yjsHook = hookName;
|
|
||||||
dom._yxml = this;
|
dom._yxml = this;
|
||||||
getHook(hookName).fillType(dom, this);
|
getHook(hookName).fillType(dom, this);
|
||||||
}
|
}
|
||||||
@@ -4251,15 +4188,9 @@ class YXmlHook extends YMap {
|
|||||||
const dom = getHook(this.hookName).createDom(this);
|
const dom = getHook(this.hookName).createDom(this);
|
||||||
this._dom = dom;
|
this._dom = dom;
|
||||||
dom._yxml = this;
|
dom._yxml = this;
|
||||||
dom._yjsHook = this.hookName;
|
|
||||||
}
|
}
|
||||||
return this._dom
|
return this._dom
|
||||||
}
|
}
|
||||||
_unbindFromDom () {
|
|
||||||
this._dom._yxml = null;
|
|
||||||
this._yxml = null;
|
|
||||||
// TODO: cleanup hook?
|
|
||||||
}
|
|
||||||
_fromBinary (y, decoder) {
|
_fromBinary (y, decoder) {
|
||||||
const missing = super._fromBinary(y, decoder);
|
const missing = super._fromBinary(y, decoder);
|
||||||
this.hookName = decoder.readVarString();
|
this.hookName = decoder.readVarString();
|
||||||
@@ -4275,12 +4206,6 @@ class YXmlHook extends YMap {
|
|||||||
}
|
}
|
||||||
super._integrate(y);
|
super._integrate(y);
|
||||||
}
|
}
|
||||||
setDomFilter () {
|
|
||||||
// TODO: implement new modfilter method!
|
|
||||||
}
|
|
||||||
enableSmartScrolling () {
|
|
||||||
// TODO: implement new smartscrolling method!
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
YXmlHook.addHook = addHook;
|
YXmlHook.addHook = addHook;
|
||||||
|
|
||||||
@@ -4743,7 +4668,7 @@ var y = d * 365.25;
|
|||||||
* @api public
|
* @api public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var index = function(val, options) {
|
var ms = function(val, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var type = typeof val;
|
var type = typeof val;
|
||||||
if (type === 'string' && val.length > 0) {
|
if (type === 'string' && val.length > 0) {
|
||||||
@@ -4885,7 +4810,7 @@ exports.coerce = coerce;
|
|||||||
exports.disable = disable;
|
exports.disable = disable;
|
||||||
exports.enable = enable;
|
exports.enable = enable;
|
||||||
exports.enabled = enabled;
|
exports.enabled = enabled;
|
||||||
exports.humanize = index;
|
exports.humanize = ms;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The currently active debug mode names, and names to skip.
|
* The currently active debug mode names, and names to skip.
|
||||||
@@ -4944,8 +4869,8 @@ function createDebug(namespace) {
|
|||||||
|
|
||||||
// set `diff` timestamp
|
// set `diff` timestamp
|
||||||
var curr = +new Date();
|
var curr = +new Date();
|
||||||
var ms = curr - (prevTime || curr);
|
var ms$$1 = curr - (prevTime || curr);
|
||||||
self.diff = ms;
|
self.diff = ms$$1;
|
||||||
self.prev = prevTime;
|
self.prev = prevTime;
|
||||||
self.curr = curr;
|
self.curr = curr;
|
||||||
prevTime = curr;
|
prevTime = curr;
|
||||||
@@ -4964,19 +4889,19 @@ function createDebug(namespace) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// apply any `formatters` transformations
|
// apply any `formatters` transformations
|
||||||
var index$$1 = 0;
|
var index = 0;
|
||||||
args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) {
|
args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) {
|
||||||
// if we encounter an escaped % then don't increase the array index
|
// if we encounter an escaped % then don't increase the array index
|
||||||
if (match === '%%') return match;
|
if (match === '%%') return match;
|
||||||
index$$1++;
|
index++;
|
||||||
var formatter = exports.formatters[format];
|
var formatter = exports.formatters[format];
|
||||||
if ('function' === typeof formatter) {
|
if ('function' === typeof formatter) {
|
||||||
var val = args[index$$1];
|
var val = args[index];
|
||||||
match = formatter.call(self, val);
|
match = formatter.call(self, val);
|
||||||
|
|
||||||
// now we need to remove `args[index]` since it's inlined in the `format`
|
// now we need to remove `args[index]` since it's inlined in the `format`
|
||||||
args.splice(index$$1, 1);
|
args.splice(index, 1);
|
||||||
index$$1--;
|
index--;
|
||||||
}
|
}
|
||||||
return match;
|
return match;
|
||||||
});
|
});
|
||||||
@@ -5939,7 +5864,7 @@ if (typeof Y !== 'undefined') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var chance_1 = createCommonjsModule(function (module, exports) {
|
var chance_1 = createCommonjsModule(function (module, exports) {
|
||||||
// Chance.js 1.0.10
|
// Chance.js 1.0.12
|
||||||
// http://chancejs.com
|
// http://chancejs.com
|
||||||
// (c) 2013 Victor Quinn
|
// (c) 2013 Victor Quinn
|
||||||
// Chance may be freely distributed or modified under the MIT license.
|
// Chance may be freely distributed or modified under the MIT license.
|
||||||
@@ -6004,7 +5929,7 @@ var chance_1 = createCommonjsModule(function (module, exports) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Chance.prototype.VERSION = "1.0.10";
|
Chance.prototype.VERSION = "1.0.12";
|
||||||
|
|
||||||
// Random helper functions
|
// Random helper functions
|
||||||
function initOptions(options, defaults) {
|
function initOptions(options, defaults) {
|
||||||
@@ -6223,6 +6148,16 @@ var chance_1 = createCommonjsModule(function (module, exports) {
|
|||||||
return integer.toString(16);
|
return integer.toString(16);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Chance.prototype.letter = function(options) {
|
||||||
|
options = initOptions(options, {casing: 'lower'});
|
||||||
|
var pool = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
var letter = this.character({pool: pool});
|
||||||
|
if (options.casing === 'upper') {
|
||||||
|
letter = letter.toUpperCase();
|
||||||
|
}
|
||||||
|
return letter;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a random string
|
* Return a random string
|
||||||
*
|
*
|
||||||
@@ -7165,8 +7100,25 @@ var chance_1 = createCommonjsModule(function (module, exports) {
|
|||||||
return this.word({length: options.length}) + '@' + (options.domain || this.domain());
|
return this.word({length: options.length}) + '@' + (options.domain || this.domain());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* #Description:
|
||||||
|
* ===============================================
|
||||||
|
* Generate a random Facebook id, aka fbid.
|
||||||
|
*
|
||||||
|
* NOTE: At the moment (Sep 2017), Facebook ids are
|
||||||
|
* "numeric strings" of length 16.
|
||||||
|
* However, Facebook Graph API documentation states that
|
||||||
|
* "it is extremely likely to change over time".
|
||||||
|
* @see https://developers.facebook.com/docs/graph-api/overview/
|
||||||
|
*
|
||||||
|
* #Examples:
|
||||||
|
* ===============================================
|
||||||
|
* chance.fbid() => '1000035231661304'
|
||||||
|
*
|
||||||
|
* @return [string] facebook id
|
||||||
|
*/
|
||||||
Chance.prototype.fbid = function () {
|
Chance.prototype.fbid = function () {
|
||||||
return parseInt('10000' + this.natural({max: 100000000000}), 10);
|
return '10000' + this.string({pool: "1234567890", length: 11});
|
||||||
};
|
};
|
||||||
|
|
||||||
Chance.prototype.google_analytics = function () {
|
Chance.prototype.google_analytics = function () {
|
||||||
@@ -8007,8 +7959,72 @@ var chance_1 = createCommonjsModule(function (module, exports) {
|
|||||||
|
|
||||||
// -- End Regional
|
// -- End Regional
|
||||||
|
|
||||||
|
// -- Music --
|
||||||
|
|
||||||
|
Chance.prototype.note = function(options) {
|
||||||
|
// choices for 'notes' option:
|
||||||
|
// flatKey - chromatic scale with flat notes (default)
|
||||||
|
// sharpKey - chromatic scale with sharp notes
|
||||||
|
// flats - just flat notes
|
||||||
|
// sharps - just sharp notes
|
||||||
|
// naturals - just natural notes
|
||||||
|
// all - naturals, sharps and flats
|
||||||
|
options = initOptions(options, { notes : 'flatKey'});
|
||||||
|
var scales = {
|
||||||
|
naturals: ['C', 'D', 'E', 'F', 'G', 'A', 'B'],
|
||||||
|
flats: ['D♭', 'E♭', 'G♭', 'A♭', 'B♭'],
|
||||||
|
sharps: ['C♯', 'D♯', 'F♯', 'G♯', 'A♯']
|
||||||
|
};
|
||||||
|
scales.all = scales.naturals.concat(scales.flats.concat(scales.sharps));
|
||||||
|
scales.flatKey = scales.naturals.concat(scales.flats);
|
||||||
|
scales.sharpKey = scales.naturals.concat(scales.sharps);
|
||||||
|
return this.pickone(scales[options.notes]);
|
||||||
|
};
|
||||||
|
|
||||||
|
Chance.prototype.midi_note = function(options) {
|
||||||
|
var min = 0;
|
||||||
|
var max = 127;
|
||||||
|
options = initOptions(options, { min : min, max : max });
|
||||||
|
return this.integer({min: options.min, max: options.max});
|
||||||
|
};
|
||||||
|
|
||||||
|
Chance.prototype.chord_quality = function(options) {
|
||||||
|
options = initOptions(options, { jazz: true });
|
||||||
|
var chord_qualities = ['maj', 'min', 'aug', 'dim'];
|
||||||
|
if (options.jazz){
|
||||||
|
chord_qualities = [
|
||||||
|
'maj7',
|
||||||
|
'min7',
|
||||||
|
'7',
|
||||||
|
'sus',
|
||||||
|
'dim',
|
||||||
|
'ø'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return this.pickone(chord_qualities);
|
||||||
|
};
|
||||||
|
|
||||||
|
Chance.prototype.chord = function (options) {
|
||||||
|
options = initOptions(options);
|
||||||
|
return this.note(options) + this.chord_quality(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
Chance.prototype.tempo = function (options) {
|
||||||
|
var min = 40;
|
||||||
|
var max = 320;
|
||||||
|
options = initOptions(options, {min: min, max: max});
|
||||||
|
return this.integer({min: options.min, max: options.max});
|
||||||
|
};
|
||||||
|
|
||||||
|
// -- End Music
|
||||||
|
|
||||||
// -- Miscellaneous --
|
// -- Miscellaneous --
|
||||||
|
|
||||||
|
// Coin - Flip, flip, flipadelphia
|
||||||
|
Chance.prototype.coin = function(options) {
|
||||||
|
return this.bool() ? "heads" : "tails";
|
||||||
|
};
|
||||||
|
|
||||||
// Dice - For all the board game geeks out there, myself included ;)
|
// Dice - For all the board game geeks out there, myself included ;)
|
||||||
function diceFn (range) {
|
function diceFn (range) {
|
||||||
return function () {
|
return function () {
|
||||||
@@ -13489,7 +13505,7 @@ async function applyRandomTests (t, mods, iterations) {
|
|||||||
return initInformation
|
return initInformation
|
||||||
}
|
}
|
||||||
|
|
||||||
var index$1$1 = function (str) {
|
var index$1 = function (str) {
|
||||||
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
|
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
|
||||||
return '%' + c.charCodeAt(0).toString(16).toUpperCase();
|
return '%' + c.charCodeAt(0).toString(16).toUpperCase();
|
||||||
});
|
});
|
||||||
@@ -13675,7 +13691,7 @@ function parserForArrayFormat(opts) {
|
|||||||
|
|
||||||
function encode(value, opts) {
|
function encode(value, opts) {
|
||||||
if (opts.encode) {
|
if (opts.encode) {
|
||||||
return opts.strict ? index$1$1(value) : encodeURIComponent(value);
|
return opts.strict ? index$1(value) : encodeURIComponent(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@@ -13787,7 +13803,7 @@ var stringify = function (obj, opts) {
|
|||||||
}).join('&') : '';
|
}).join('&') : '';
|
||||||
};
|
};
|
||||||
|
|
||||||
var index$2 = {
|
var index = {
|
||||||
extract: extract,
|
extract: extract,
|
||||||
parse: parse$1,
|
parse: parse$1,
|
||||||
stringify: stringify
|
stringify: stringify
|
||||||
@@ -13802,7 +13818,7 @@ const browserSupport =
|
|||||||
|
|
||||||
function createTestLink (params) {
|
function createTestLink (params) {
|
||||||
if (typeof location !== 'undefined') {
|
if (typeof location !== 'undefined') {
|
||||||
var query = index$2.parse(location.search);
|
var query = index.parse(location.search);
|
||||||
delete query.test;
|
delete query.test;
|
||||||
delete query.seed;
|
delete query.seed;
|
||||||
delete query.args;
|
delete query.args;
|
||||||
@@ -13812,7 +13828,7 @@ function createTestLink (params) {
|
|||||||
query[name] = params[name];
|
query[name] = params[name];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return location.protocol + '//' + location.host + location.pathname + '?' + index$2.stringify(query) + location.hash
|
return location.protocol + '//' + location.host + location.pathname + '?' + index.stringify(query) + location.hash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13823,7 +13839,7 @@ class TestHandler {
|
|||||||
this.repeatingRun = 0;
|
this.repeatingRun = 0;
|
||||||
this.tests = {};
|
this.tests = {};
|
||||||
if (typeof location !== 'undefined') {
|
if (typeof location !== 'undefined') {
|
||||||
this.opts = index$2.parse(location.search);
|
this.opts = index.parse(location.search);
|
||||||
if (this.opts.case != null) {
|
if (this.opts.case != null) {
|
||||||
this.opts.case = Number(this.opts.case);
|
this.opts.case = Number(this.opts.case);
|
||||||
}
|
}
|
||||||
@@ -13964,7 +13980,7 @@ function createCommonjsModule$1(fn, module) {
|
|||||||
return module = { exports: {} }, fn(module, module.exports), module.exports;
|
return module = { exports: {} }, fn(module, module.exports), module.exports;
|
||||||
}
|
}
|
||||||
|
|
||||||
var isBrowser = typeof index$2 !== 'undefined';
|
var isBrowser = typeof index !== 'undefined';
|
||||||
|
|
||||||
var environment = {
|
var environment = {
|
||||||
isBrowser: isBrowser
|
isBrowser: isBrowser
|
||||||
@@ -18513,8 +18529,8 @@ var stacktraceGps = createCommonjsModule$1(function (module, exports) {
|
|||||||
* @returns {String} original representation of the base64-encoded string.
|
* @returns {String} original representation of the base64-encoded string.
|
||||||
*/
|
*/
|
||||||
function _atob(b64str) {
|
function _atob(b64str) {
|
||||||
if (typeof index$2 !== 'undefined' && index$2.atob) {
|
if (typeof index !== 'undefined' && index.atob) {
|
||||||
return index$2.atob(b64str);
|
return index.atob(b64str);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('You must supply a polyfill for window.atob in this environment');
|
throw new Error('You must supply a polyfill for window.atob in this environment');
|
||||||
}
|
}
|
||||||
@@ -19024,7 +19040,7 @@ var stacktrace = createCommonjsModule$1(function (module, exports) {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
index$2.stacktrace = stacktrace;
|
index.stacktrace = stacktrace;
|
||||||
|
|
||||||
function test (testDescription, ...args) {
|
function test (testDescription, ...args) {
|
||||||
let location = stacktrace.getSync()[1];
|
let location = stacktrace.getSync()[1];
|
||||||
@@ -19312,6 +19328,7 @@ test('deep element insert', async function xml16 (t) {
|
|||||||
deepElement.append(boldElement);
|
deepElement.append(boldElement);
|
||||||
deepElement.append(attrElement);
|
deepElement.append(attrElement);
|
||||||
dom0.append(deepElement);
|
dom0.append(deepElement);
|
||||||
|
console.log(dom0.outerHTML);
|
||||||
let str0 = dom0.outerHTML;
|
let str0 = dom0.outerHTML;
|
||||||
await flushAll(t, users);
|
await flushAll(t, users);
|
||||||
let str1 = dom1.outerHTML;
|
let str1 = dom1.outerHTML;
|
||||||
@@ -19371,6 +19388,7 @@ test('Filtering remote changes', async function xmlFilteringRemote (t) {
|
|||||||
// check dom
|
// check dom
|
||||||
paragraph.getDom().setAttribute('malicious', 'true');
|
paragraph.getDom().setAttribute('malicious', 'true');
|
||||||
span.getDom().setAttribute('malicious', 'true');
|
span.getDom().setAttribute('malicious', 'true');
|
||||||
|
console.log(xml0.toString());
|
||||||
// check incoming attributes
|
// check incoming attributes
|
||||||
xml1.get(0).get(0).setAttribute('malicious', 'true');
|
xml1.get(0).get(0).setAttribute('malicious', 'true');
|
||||||
xml1.insert(0, [new Y$1.XmlElement('hideMe')]);
|
xml1.insert(0, [new Y$1.XmlElement('hideMe')]);
|
||||||
@@ -19481,5 +19499,7 @@ test('y-xml: Random tests (1000)', async function xmlRandom1000 (t) {
|
|||||||
await applyRandomTests(t, xmlTransactions, 1000);
|
await applyRandomTests(t, xmlTransactions, 1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
})));
|
})));
|
||||||
//# sourceMappingURL=y.test.js.map
|
//# sourceMappingURL=y.test.js.map
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user