Compare commits

..

6 Commits

Author SHA1 Message Date
Kevin Jahns
2e486d4f46 v13.0.0-48 -- distribution files 2018-01-29 16:42:20 -08:00
Kevin Jahns
a81a2cd553 13.0.0-48 2018-01-29 16:41:52 -08:00
Kevin Jahns
c0d24bdba4 lint 2018-01-29 16:41:27 -08:00
Kevin Jahns
40e913e9c5 add toBinary and fromBinary to Y.utils 2018-01-29 16:39:09 -08:00
Kevin Jahns
94f6a0fd9c implement Y.*Binding approach 2018-01-29 11:55:28 -08:00
Kevin Jahns
41a88dbc43 fix examples for Yjs@13 2018-01-25 17:28:33 -07:00
38 changed files with 351 additions and 305 deletions

View File

@@ -24,7 +24,8 @@
<body>
<div id="aceContainer"></div>
<script src="../bower_components/yjs/y.js"></script>
<script src="../../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="./index.js"></script>

View File

@@ -1,24 +1,17 @@
/* global Y, ace */
Y({
db: {
name: 'memory'
},
let y = new Y('ace-example', {
connector: {
name: 'websockets-client',
room: 'ace-example'
},
sourceDir: '/bower_components',
share: {
ace: 'Text' // y.share.textarea is of type Y.Text
url: 'http://127.0.0.1:1234'
}
}).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)

View File

@@ -13,7 +13,7 @@
<input type="submit" value="Send">
</form>
<script src="../../y.js"></script>
<script src="../../../y-websockets-client/dist/y-websockets-client.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -1,10 +1,9 @@
/* global Y */
// initialize a shared object. This function call returns a promise!
var y = new Y({
let y = new Y('chat-example', {
connector: {
name: 'websockets-client',
room: 'chat-example'
url: 'http://127.0.0.1:1234'
}
})
@@ -23,6 +22,7 @@ function appendMessage (message, position) {
p.appendChild(document.createTextNode(message.message))
chatcontainer.insertBefore(p, chatcontainer.children[position] || null)
}
// This function makes sure that only 7 messages exist in the chat history.
// The rest is deleted
function cleanupChat () {
@@ -30,23 +30,17 @@ function cleanupChat () {
chatprotocol.delete(0, chatprotocol.length - 7)
}
}
cleanupChat()
// Insert the initial content
chatprotocol.toArray().forEach(appendMessage)
cleanupChat()
// whenever content changes, make sure to reflect the changes in the DOM
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
cleanupChat()
chatcontainer.innerHTML = ''
chatprotocol.toArray().forEach(appendMessage)
})
document.querySelector('#chatform').onsubmit = function (event) {
// the form is submitted

View File

@@ -5,7 +5,8 @@
<body>
<div id="codeMirrorContainer"></div>
<script src="../bower_components/yjs/y.js"></script>
<script src="../../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/mode/javascript/javascript.js"></script>
<link rel="stylesheet" href="../bower_components/codemirror/lib/codemirror.css">

View File

@@ -1,24 +1,16 @@
/* global Y, CodeMirror */
// initialize a shared object. This function call returns a promise!
Y({
db: {
name: 'memory'
},
let y = new Y('codemirror-example', {
connector: {
name: 'websockets-client',
room: 'codemirror-example'
},
sourceDir: '/bower_components',
share: {
codemirror: 'Text' // y.share.codemirror is of type Y.Text
url: 'http://127.0.0.1:1234'
}
}).then(function (y) {
window.yCodeMirror = y
var editor = CodeMirror(document.querySelector('#codeMirrorContainer'), {
mode: 'javascript',
lineNumbers: true
})
y.share.codemirror.bindCodeMirror(editor)
})
window.yCodeMirror = y
var editor = CodeMirror(document.querySelector('#codeMirrorContainer'), {
mode: 'javascript',
lineNumbers: true
})
y.define('codemirror', Y.Text).bindCodeMirror(editor)

View File

@@ -12,7 +12,8 @@
</style>
<button type="button" id="clearDrawingCanvas">Clear Drawing</button>
<svg id="drawingCanvas" viewbox="0 0 100 100" width="100%"></svg>
<script src="../yjs-dist.js"></script>
<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>
</body>

View File

@@ -1,11 +1,9 @@
/* globals Y, d3 */
let y = new Y({
let y = new Y('drawing-example', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234',
room: 'drawing-example'
// maxBufferLength: 100
url: 'http://127.0.0.1:1234'
}
})

View File

@@ -1,7 +1,8 @@
<!DOCTYPE html>
<html>
</head>
<script src="../yjs-dist.js"></script>
<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>

View File

@@ -107,15 +107,13 @@ Y.XmlHook.addHook('magic-drawing', {
}
})
// initialize a shared object. This function call returns a promise!
let y = new Y({
let y = new Y('html-editor-drawing-hook-example', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234',
room: 'html-editor-example6'
// maxBufferLength: 100
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, {

View File

@@ -1,7 +1,8 @@
<!DOCTYPE html>
<html>
</head>
<script src="../yjs-dist.js"></script>
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="./index.js"></script>
</head>
<body contenteditable="true">

View File

@@ -4,18 +4,14 @@ window.onload = function () {
window.yXmlType.bindToDom(document.body)
}
const persistence = new Y.IndexedDB()
// initialize a shared object. This function call returns a promise!
let y = new Y('htmleditor', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234',
room: 'html-editor'
// maxBufferLength: 100
url: 'http://127.0.0.1:1234'
}
}, persistence)
window.yXml = y
})
window.y = y
window.yXmlType = y.define('xml', Y.XmlFragment)
window.undoManager = new Y.utils.UndoManager(window.yXmlType, {
captureTimeout: 500

View File

@@ -16,6 +16,9 @@
width: 100%;
}
</style>
<script type="module" src="./index.js"></script>
<script src="../../y.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>
</html>

View File

@@ -7,12 +7,13 @@ const connector = {
room: 'codemirror-example'
}
}
// initialize a shared object. This function call returns a promise!
const y = Y('codemirror-example', connector, persistence)
const y = new Y('codemirror-example', connector, persistence)
window.yCodeMirror = y
var editor = CodeMirror(document.querySelector('#codeMirrorContainer'), {
mode: 'javascript',
lineNumbers: true
})
y.share.codemirror.bindCodeMirror(editor)
y.define('codemirror', Y.Text).bindCodeMirror(editor)

View File

@@ -10,7 +10,7 @@
.one {
grid-column: 1 ;
}
.two {
.two {
grid-column: 2;
}
.three {
@@ -49,10 +49,7 @@
</div>
</div>
<script src="../../y.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='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -1,64 +1,38 @@
/* global Y */
Y({
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'))
function bindYjsInstance (y, suffix) {
y.define('textarea', Y.Text).bind(document.getElementById('textarea' + suffix))
y.connector.socket.on('connection', function () {
document.getElementById('container2').removeAttribute('disconnected')
document.getElementById('container' + suffix).removeAttribute('disconnected')
})
y.connector.socket.on('disconnect', function () {
document.getElementById('container2').setAttribute('disconnected', true)
document.getElementById('container' + suffix).setAttribute('disconnected', true)
})
})
}
Y({
db: {
name: 'memory'
},
let y1 = new Y('infinite-example', {
connector: {
name: 'websockets-client',
room: 'Textarea-example',
url: 'https://yjs-v13-third.herokuapp.com/'
},
share: {
textarea: 'Text'
url: 'http://127.0.0.1:1234'
}
}).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')

View File

@@ -17,9 +17,7 @@
</g>
</svg>
<script src="../../y.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='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="../bower_components/d3/d3.js"></script>
<script src="./index.js"></script>
</body>

View File

@@ -1,74 +1,67 @@
/* @flow */
/* global Y, d3 */
// initialize a shared object. This function call returns a promise!
Y({
db: {
name: 'memory'
},
let y = new Y('jigsaw-example', {
connector: {
name: 'websockets-client',
room: 'Puzzle-example',
url: 'http://localhost:1234'
},
share: {
piece1: 'Map',
piece2: 'Map',
piece3: 'Map',
piece4: 'Map'
url: 'http://127.0.0.1:1234'
}
}).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})
})
})
var data = [y.share.piece1, y.share.piece2, y.share.piece3, y.share.piece4]
var pieces = d3.select(document.querySelector('#puzzle-example')).selectAll('path').data(data)
let jigsaw = y.define('jigsaw', Y.Map)
window.yJigsaw = y
pieces
.classed('draggable', true)
.attr('transform', function (piece) {
var translation = piece.get('translation') || {x: 0, y: 0}
return 'translate(' + translation.x + ',' + translation.y + ')'
}).call(drag)
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
jigsaw.set(piece, {x: x, y: y})
})
data.forEach(function (piece) {
piece.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('translation') || {x: 0, y: 0}
return 'translate(' + translation.x + ',' + translation.y + ')'
})
})
var data = ['piece1', 'piece2', 'piece3', 'piece4']
var pieces = d3.select(document.querySelector('#puzzle-example')).selectAll('path').data(data)
pieces
.classed('draggable', true)
.attr('transform', function (piece) {
var translation = piece.get('translation') || {x: 0, y: 0}
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 + ')'
})
})
})

View File

@@ -13,8 +13,8 @@
width: 100%;
}
</style>
<script src="../bower_components/yjs/y.js"></script>
<script src="../bower_components/y-websockets-client/y-websockets-client.js"></script>
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="../node_modules/monaco-editor/min/vs/loader.js"></script>
<script src="./index.js"></script>
</body>

View File

@@ -2,29 +2,21 @@
require.config({ paths: { 'vs': '../node_modules/monaco-editor/min/vs' } })
require(['vs/editor/editor.main'], function () {
// 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
var editor = monaco.editor.create(document.getElementById('monacoContainer'), {
language: 'javascript'
})
// Bind to y.share.monaco
y.share.monaco.bindMonaco(editor)
})
let y = new Y('monaco-example', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
}
})
require(['vs/editor/editor.main'], function () {
window.yMonaco = y
// Create Monaco editor
var editor = monaco.editor.create(document.getElementById('monacoContainer'), {
language: 'javascript'
})
// Bind to y.share.monaco
y.define('monaco', Y.Text).bindMonaco(editor)
})

View File

@@ -26,10 +26,7 @@
<script src="../bower_components/quill/dist/quill.js"></script>
-->
<script src="../../y.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='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -1,11 +1,9 @@
<!DOCTYPE html>
<html>
<body>
<textarea style="width:80%;" rows=40 id="textfield" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
<textarea style="width:80%;" rows=40 autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
<script src="../../y.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='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -1,23 +1,15 @@
/* global Y */
// initialize a shared object. This function call returns a promise!
Y({
db: {
name: 'memory'
},
let y = new Y('textarea-example', {
connector: {
name: 'websockets-client',
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'))
url: 'http://127.0.0.1:1234'
}
})
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)

View File

@@ -3,7 +3,8 @@
</head>
<!-- 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="../yjs-dist.js"></script>
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="./index.js"></script>
</head>
<body>

View File

@@ -1,23 +1,13 @@
/* global Y */
// initialize a shared object. This function call returns a promise!
Y({
db: {
name: 'memory'
},
let y = new Y('xml-example', {
connector: {
name: 'websockets-client',
// 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"
url: 'http://127.0.0.1:1234'
}
}).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)

2
package-lock.json generated
View File

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

View File

@@ -1,6 +1,6 @@
{
"name": "yjs",
"version": "13.0.0-47",
"version": "13.0.0-48",
"description": "A framework for real-time p2p shared editing on any data",
"main": "./y.node.js",
"browser": "./y.js",

14
src/Binding/Binding.js Normal file
View File

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

View File

View File

@@ -0,0 +1,45 @@
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()
}
}

View File

@@ -113,9 +113,11 @@ export default class Item {
* - Check if this is struct deleted
*/
_integrate (y) {
y._transaction.newTypes.add(this)
const parent = this._parent
const selfID = this._id
const userState = selfID === null ? 0 : y.ss.getState(selfID.user)
const user = selfID === null ? y.userID : selfID.user
const userState = y.ss.getState(user)
if (selfID === null) {
this._id = y.ss.getNextID(this._length)
} else if (selfID.user === RootFakeUserID) {

View File

@@ -133,7 +133,6 @@ export default class Type extends Item {
this._deepEventHandler.removeEventListener(f)
}
_integrate (y) {
y._transaction.newTypes.add(this)
super._integrate(y)
this._y = y
// when integrating children we must make sure to

View File

@@ -9,17 +9,21 @@ class YArrayEvent extends YEvent {
super(yarray)
this.remote = remote
this._transaction = transaction
this._addedElements = null
}
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
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

View File

@@ -22,6 +22,10 @@ import { addStruct as addType } from './Util/structReferences.js'
import debug from 'debug'
import Transaction from './Transaction.js'
import TextareaBinding from './Binding/TextareaBinding.js'
import { toBinary, fromBinary } from './MessageHandler/binaryEncode.js'
export default class Y extends NamedEventHandler {
constructor (room, opts, persistence) {
super()
@@ -197,13 +201,17 @@ Y.XmlFragment = YXmlFragment
Y.XmlText = YXmlText
Y.XmlHook = YXmlHook
Y.TextareaBinding = TextareaBinding
Y.utils = {
BinaryDecoder,
UndoManager,
getRelativePosition,
fromRelativePosition,
addType,
integrateRemoteStructs
integrateRemoteStructs,
toBinary,
fromBinary
}
Y.debug = debug

8
y.js

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,7 @@
/**
* yjs - A framework for real-time p2p shared editing on any data
* @version v13.0.0-47
* @version v13.0.0-48
* @license MIT
*/
@@ -1402,9 +1402,11 @@ class Item {
* - Check if this is struct deleted
*/
_integrate (y) {
y._transaction.newTypes.add(this);
const parent = this._parent;
const selfID = this._id;
const userState = selfID === null ? 0 : y.ss.getState(selfID.user);
const user = selfID === null ? y.userID : selfID.user;
const userState = y.ss.getState(user);
if (selfID === null) {
this._id = y.ss.getNextID(this._length);
} else if (selfID.user === RootFakeUserID) {
@@ -1770,7 +1772,6 @@ class Type extends Item {
this._deepEventHandler.removeEventListener(f);
}
_integrate (y) {
y._transaction.newTypes.add(this);
super._integrate(y);
this._y = y;
// when integrating children we must make sure to
@@ -1944,17 +1945,21 @@ class YArrayEvent extends YEvent {
super(yarray);
this.remote = remote;
this._transaction = transaction;
this._addedElements = null;
}
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
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;
@@ -4748,6 +4753,59 @@ class AbstractPersistence {
}
}
class Binding {
constructor (type, target) {
this.type = type;
this.target = target;
this._mutualExclude = createMutualExclude();
}
destroy () {
this.type = null;
this.target = null;
}
}
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);
});
}
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();
}
}
class Y$1 extends NamedEventHandler {
constructor (room, opts, persistence) {
super();
@@ -4923,13 +4981,17 @@ Y$1.XmlFragment = YXmlFragment;
Y$1.XmlText = YXmlText;
Y$1.XmlHook = YXmlHook;
Y$1.TextareaBinding = TextareaBinding;
Y$1.utils = {
BinaryDecoder,
UndoManager,
getRelativePosition,
fromRelativePosition,
addType: addStruct,
integrateRemoteStructs
integrateRemoteStructs,
toBinary,
fromBinary
};
Y$1.debug = browser;

File diff suppressed because one or more lines are too long