Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
653a436b88 | ||
|
|
5ab60028ce | ||
|
|
428d825f41 | ||
|
|
b9f9c762eb |
@@ -2,142 +2,24 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<link rel="stylesheet" href="../bower_components/quill/dist/quill.snow.css" />
|
<link rel="stylesheet" href="../bower_components/quill/dist/quill.snow.css" />
|
||||||
|
<link href="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.5.1/katex.min.css" rel="stylesheet">
|
||||||
|
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.2.0/styles/monokai-sublime.min.css" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
#quill {
|
#quill-container {
|
||||||
border: 1px solid gray;
|
border: 1px solid gray;
|
||||||
box-shadow: 0px 0px 10px gray;
|
box-shadow: 0px 0px 10px gray;
|
||||||
}
|
}
|
||||||
#toolbar {
|
|
||||||
border-bottom: 1px solid gray;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="quill">
|
<div id="quill-container">
|
||||||
<!-- Create the toolbar container -->
|
<div id="quill">
|
||||||
<div id="toolbar" class="toolbar">
|
|
||||||
<span class="ql-format-group">
|
|
||||||
<select title="Font" class="ql-font">
|
|
||||||
<option value="sans-serif" selected="">Sans Serif</option>
|
|
||||||
<option value="serif">Serif</option>
|
|
||||||
<option value="monospace">Monospace</option>
|
|
||||||
</select>
|
|
||||||
<select title="Size" class="ql-size">
|
|
||||||
<option value="10px">Small</option>
|
|
||||||
<option value="13px" selected="">Normal</option>
|
|
||||||
<option value="18px">Large</option>
|
|
||||||
<option value="32px">Huge</option>
|
|
||||||
</select>
|
|
||||||
</span>
|
|
||||||
<span class="ql-format-group">
|
|
||||||
<span title="Bold" class="ql-format-button ql-bold"></span>
|
|
||||||
<span class="ql-format-separator"></span>
|
|
||||||
<span title="Italic" class="ql-format-button ql-italic"></span>
|
|
||||||
<span class="ql-format-separator"></span>
|
|
||||||
<span title="Underline" class="ql-format-button ql-underline"></span>
|
|
||||||
<span class="ql-format-separator"></span>
|
|
||||||
<span title="Strikethrough" class="ql-format-button ql-strike"></span>
|
|
||||||
</span>
|
|
||||||
<span class="ql-format-group">
|
|
||||||
<select title="Text Color" class="ql-color">
|
|
||||||
<option value="rgb(0, 0, 0)" label="rgb(0, 0, 0)" selected=""></option>
|
|
||||||
<option value="rgb(230, 0, 0)" label="rgb(230, 0, 0)"></option>
|
|
||||||
<option value="rgb(255, 153, 0)" label="rgb(255, 153, 0)"></option>
|
|
||||||
<option value="rgb(255, 255, 0)" label="rgb(255, 255, 0)"></option>
|
|
||||||
<option value="rgb(0, 138, 0)" label="rgb(0, 138, 0)"></option>
|
|
||||||
<option value="rgb(0, 102, 204)" label="rgb(0, 102, 204)"></option>
|
|
||||||
<option value="rgb(153, 51, 255)" label="rgb(153, 51, 255)"></option>
|
|
||||||
<option value="rgb(255, 255, 255)" label="rgb(255, 255, 255)"></option>
|
|
||||||
<option value="rgb(250, 204, 204)" label="rgb(250, 204, 204)"></option>
|
|
||||||
<option value="rgb(255, 235, 204)" label="rgb(255, 235, 204)"></option>
|
|
||||||
<option value="rgb(255, 255, 204)" label="rgb(255, 255, 204)"></option>
|
|
||||||
<option value="rgb(204, 232, 204)" label="rgb(204, 232, 204)"></option>
|
|
||||||
<option value="rgb(204, 224, 245)" label="rgb(204, 224, 245)"></option>
|
|
||||||
<option value="rgb(235, 214, 255)" label="rgb(235, 214, 255)"></option>
|
|
||||||
<option value="rgb(187, 187, 187)" label="rgb(187, 187, 187)"></option>
|
|
||||||
<option value="rgb(240, 102, 102)" label="rgb(240, 102, 102)"></option>
|
|
||||||
<option value="rgb(255, 194, 102)" label="rgb(255, 194, 102)"></option>
|
|
||||||
<option value="rgb(255, 255, 102)" label="rgb(255, 255, 102)"></option>
|
|
||||||
<option value="rgb(102, 185, 102)" label="rgb(102, 185, 102)"></option>
|
|
||||||
<option value="rgb(102, 163, 224)" label="rgb(102, 163, 224)"></option>
|
|
||||||
<option value="rgb(194, 133, 255)" label="rgb(194, 133, 255)"></option>
|
|
||||||
<option value="rgb(136, 136, 136)" label="rgb(136, 136, 136)"></option>
|
|
||||||
<option value="rgb(161, 0, 0)" label="rgb(161, 0, 0)"></option>
|
|
||||||
<option value="rgb(178, 107, 0)" label="rgb(178, 107, 0)"></option>
|
|
||||||
<option value="rgb(178, 178, 0)" label="rgb(178, 178, 0)"></option>
|
|
||||||
<option value="rgb(0, 97, 0)" label="rgb(0, 97, 0)"></option>
|
|
||||||
<option value="rgb(0, 71, 178)" label="rgb(0, 71, 178)"></option>
|
|
||||||
<option value="rgb(107, 36, 178)" label="rgb(107, 36, 178)"></option>
|
|
||||||
<option value="rgb(68, 68, 68)" label="rgb(68, 68, 68)"></option>
|
|
||||||
<option value="rgb(92, 0, 0)" label="rgb(92, 0, 0)"></option>
|
|
||||||
<option value="rgb(102, 61, 0)" label="rgb(102, 61, 0)"></option>
|
|
||||||
<option value="rgb(102, 102, 0)" label="rgb(102, 102, 0)"></option>
|
|
||||||
<option value="rgb(0, 55, 0)" label="rgb(0, 55, 0)"></option>
|
|
||||||
<option value="rgb(0, 41, 102)" label="rgb(0, 41, 102)"></option>
|
|
||||||
<option value="rgb(61, 20, 102)" label="rgb(61, 20, 102)"></option>
|
|
||||||
</select>
|
|
||||||
<span class="ql-format-separator"></span>
|
|
||||||
<select title="Background Color" class="ql-background">
|
|
||||||
<option value="rgb(0, 0, 0)" label="rgb(0, 0, 0)"></option>
|
|
||||||
<option value="rgb(230, 0, 0)" label="rgb(230, 0, 0)"></option>
|
|
||||||
<option value="rgb(255, 153, 0)" label="rgb(255, 153, 0)"></option>
|
|
||||||
<option value="rgb(255, 255, 0)" label="rgb(255, 255, 0)"></option>
|
|
||||||
<option value="rgb(0, 138, 0)" label="rgb(0, 138, 0)"></option>
|
|
||||||
<option value="rgb(0, 102, 204)" label="rgb(0, 102, 204)"></option>
|
|
||||||
<option value="rgb(153, 51, 255)" label="rgb(153, 51, 255)"></option>
|
|
||||||
<option value="rgb(255, 255, 255)" label="rgb(255, 255, 255)" selected=""></option>
|
|
||||||
<option value="rgb(250, 204, 204)" label="rgb(250, 204, 204)"></option>
|
|
||||||
<option value="rgb(255, 235, 204)" label="rgb(255, 235, 204)"></option>
|
|
||||||
<option value="rgb(255, 255, 204)" label="rgb(255, 255, 204)"></option>
|
|
||||||
<option value="rgb(204, 232, 204)" label="rgb(204, 232, 204)"></option>
|
|
||||||
<option value="rgb(204, 224, 245)" label="rgb(204, 224, 245)"></option>
|
|
||||||
<option value="rgb(235, 214, 255)" label="rgb(235, 214, 255)"></option>
|
|
||||||
<option value="rgb(187, 187, 187)" label="rgb(187, 187, 187)"></option>
|
|
||||||
<option value="rgb(240, 102, 102)" label="rgb(240, 102, 102)"></option>
|
|
||||||
<option value="rgb(255, 194, 102)" label="rgb(255, 194, 102)"></option>
|
|
||||||
<option value="rgb(255, 255, 102)" label="rgb(255, 255, 102)"></option>
|
|
||||||
<option value="rgb(102, 185, 102)" label="rgb(102, 185, 102)"></option>
|
|
||||||
<option value="rgb(102, 163, 224)" label="rgb(102, 163, 224)"></option>
|
|
||||||
<option value="rgb(194, 133, 255)" label="rgb(194, 133, 255)"></option>
|
|
||||||
<option value="rgb(136, 136, 136)" label="rgb(136, 136, 136)"></option>
|
|
||||||
<option value="rgb(161, 0, 0)" label="rgb(161, 0, 0)"></option>
|
|
||||||
<option value="rgb(178, 107, 0)" label="rgb(178, 107, 0)"></option>
|
|
||||||
<option value="rgb(178, 178, 0)" label="rgb(178, 178, 0)"></option>
|
|
||||||
<option value="rgb(0, 97, 0)" label="rgb(0, 97, 0)"></option>
|
|
||||||
<option value="rgb(0, 71, 178)" label="rgb(0, 71, 178)"></option>
|
|
||||||
<option value="rgb(107, 36, 178)" label="rgb(107, 36, 178)"></option>
|
|
||||||
<option value="rgb(68, 68, 68)" label="rgb(68, 68, 68)"></option>
|
|
||||||
<option value="rgb(92, 0, 0)" label="rgb(92, 0, 0)"></option>
|
|
||||||
<option value="rgb(102, 61, 0)" label="rgb(102, 61, 0)"></option>
|
|
||||||
<option value="rgb(102, 102, 0)" label="rgb(102, 102, 0)"></option>
|
|
||||||
<option value="rgb(0, 55, 0)" label="rgb(0, 55, 0)"></option>
|
|
||||||
<option value="rgb(0, 41, 102)" label="rgb(0, 41, 102)"></option>
|
|
||||||
<option value="rgb(61, 20, 102)" label="rgb(61, 20, 102)"></option>
|
|
||||||
</select>
|
|
||||||
</span>
|
|
||||||
<span class="ql-format-group">
|
|
||||||
<span title="List" class="ql-format-button ql-list"></span>
|
|
||||||
<span class="ql-format-separator"></span>
|
|
||||||
<span title="Bullet" class="ql-format-button ql-bullet"></span>
|
|
||||||
<span class="ql-format-separator"></span>
|
|
||||||
<select title="Text Alignment" class="ql-align">
|
|
||||||
<option value="left" label="Left" selected=""></option>
|
|
||||||
<option value="center" label="Center"></option>
|
|
||||||
<option value="right" label="Right"></option>
|
|
||||||
<option value="justify" label="Justify"></option>
|
|
||||||
</select>
|
|
||||||
</span>
|
|
||||||
<span class="ql-format-group">
|
|
||||||
<span title="Link" class="ql-format-button ql-link"></span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Create the editor container -->
|
|
||||||
<div id="editor">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Include the Quill library -->
|
<!-- Include the Quill library -->
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.5.1/katex.min.js" type="text/javascript"></script>
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.2.0/highlight.min.js" type="text/javascript"></script>
|
||||||
<script src="../bower_components/quill/dist/quill.js"></script>
|
<script src="../bower_components/quill/dist/quill.js"></script>
|
||||||
<script src="../bower_components/yjs/y.es6"></script>
|
<script src="../bower_components/yjs/y.es6"></script>
|
||||||
<script src="./index.js"></script>
|
<script src="./index.js"></script>
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ Y({
|
|||||||
name: 'memory'
|
name: 'memory'
|
||||||
},
|
},
|
||||||
connector: {
|
connector: {
|
||||||
name: 'websockets-client',
|
name: 'webrtc',
|
||||||
room: 'richtext-example'
|
room: 'richtext-example-quill-beta'
|
||||||
},
|
},
|
||||||
sourceDir: '/bower_components',
|
sourceDir: '/bower_components',
|
||||||
share: {
|
share: {
|
||||||
@@ -18,13 +18,22 @@ Y({
|
|||||||
window.yQuill = y
|
window.yQuill = y
|
||||||
|
|
||||||
// create quill element
|
// create quill element
|
||||||
window.quill = new Quill('#editor', {
|
window.quill = new Quill('#quill', {
|
||||||
modules: {
|
modules: {
|
||||||
'toolbar': { container: '#toolbar' },
|
formula: true,
|
||||||
'link-tooltip': true
|
syntax: true,
|
||||||
|
toolbar: [
|
||||||
|
[{ size: ['small', false, 'large', 'huge'] }],
|
||||||
|
['bold', 'italic', 'underline'],
|
||||||
|
[{ color: [] }, { background: [] }], // Snow theme fills in values
|
||||||
|
[{ script: 'sub' }, { script: 'super' }],
|
||||||
|
['link', 'image'],
|
||||||
|
['link', 'code-block'],
|
||||||
|
[{list: 'ordered' }]
|
||||||
|
]
|
||||||
},
|
},
|
||||||
theme: 'snow'
|
theme: 'snow'
|
||||||
})
|
});
|
||||||
// bind quill to richtext type
|
// bind quill to richtext type
|
||||||
y.share.richtext.bind(window.quill)
|
y.share.richtext.bind(window.quill)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "yjs",
|
"name": "yjs",
|
||||||
"version": "11.1.0",
|
"version": "11.2.2",
|
||||||
"homepage": "y-js.org",
|
"homepage": "y-js.org",
|
||||||
"authors": [
|
"authors": [
|
||||||
"Kevin Jahns <kevin.jahns@rwth-aachen.de>"
|
"Kevin Jahns <kevin.jahns@rwth-aachen.de>"
|
||||||
|
|||||||
333
y.es6
333
y.es6
@@ -421,7 +421,7 @@ module.exports = function (Y/* :any */) {
|
|||||||
module.exports = function (Y) {
|
module.exports = function (Y) {
|
||||||
var globalRoom = {
|
var globalRoom = {
|
||||||
users: {},
|
users: {},
|
||||||
buffers: {}, // TODO: reimplement this idea. This does not cover all cases!! Here, you have a queue which is unrealistic (i.e. think about multiple incoming connections)
|
buffers: {},
|
||||||
removeUser: function (user) {
|
removeUser: function (user) {
|
||||||
for (var i in this.users) {
|
for (var i in this.users) {
|
||||||
this.users[i].userLeft(user)
|
this.users[i].userLeft(user)
|
||||||
@@ -951,68 +951,89 @@ module.exports = function (Y /* :any */) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (defined == null) {
|
if (defined == null) {
|
||||||
var isGarbageCollected = yield* this.isGarbageCollected(op.id)
|
var opid = op.id
|
||||||
|
var isGarbageCollected = yield* this.isGarbageCollected(opid)
|
||||||
if (!isGarbageCollected) {
|
if (!isGarbageCollected) {
|
||||||
yield* Y.Struct[op.struct].execute.call(this, op)
|
yield* Y.Struct[op.struct].execute.call(this, op)
|
||||||
yield* this.addOperation(op)
|
yield* this.addOperation(op)
|
||||||
yield* this.store.operationAdded(this, op)
|
yield* this.store.operationAdded(this, op)
|
||||||
|
if (!Y.utils.compareIds(opid, op.id)) {
|
||||||
|
// operationAdded changed op
|
||||||
|
op = yield* this.getOperation(opid)
|
||||||
|
}
|
||||||
// if insertion, try to combine with left
|
// if insertion, try to combine with left
|
||||||
yield* this.tryCombineWithLeft(op)
|
yield* this.tryCombineWithLeft(op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// called by a transaction when an operation is added
|
/*
|
||||||
|
* Called by a transaction when an operation is added.
|
||||||
|
* This function is especially important for y-indexeddb, where several instances may share a single database.
|
||||||
|
* Every time an operation is created by one instance, it is send to all other instances and operationAdded is called
|
||||||
|
*
|
||||||
|
* If it's not a Delete operation:
|
||||||
|
* * Checks if another operation is executable (listenersById)
|
||||||
|
* * Update state, if possible
|
||||||
|
*
|
||||||
|
* Always:
|
||||||
|
* * Call type
|
||||||
|
*/
|
||||||
* operationAdded (transaction, op) {
|
* operationAdded (transaction, op) {
|
||||||
// increase SS
|
if (op.struct === 'Delete') {
|
||||||
yield* transaction.updateState(op.id[0])
|
var target = yield* transaction.getInsertion(op.target)
|
||||||
|
var type = this.initializedTypes[JSON.stringify(target.parent)]
|
||||||
var opLen = op.content != null ? op.content.length : 1
|
if (type != null) {
|
||||||
for (let i = 0; i < opLen; i++) {
|
yield* type._changed(transaction, op)
|
||||||
// notify whenOperation listeners (by id)
|
}
|
||||||
var sid = JSON.stringify([op.id[0], op.id[1] + i])
|
} else {
|
||||||
var l = this.listenersById[sid]
|
// increase SS
|
||||||
delete this.listenersById[sid]
|
yield* transaction.updateState(op.id[0])
|
||||||
|
var opLen = op.content != null ? op.content.length : 1
|
||||||
if (l != null) {
|
for (let i = 0; i < opLen; i++) {
|
||||||
for (var key in l) {
|
// notify whenOperation listeners (by id)
|
||||||
var listener = l[key]
|
var sid = JSON.stringify([op.id[0], op.id[1] + i])
|
||||||
if (--listener.missing === 0) {
|
var l = this.listenersById[sid]
|
||||||
this.whenOperationsExist([], listener.op)
|
delete this.listenersById[sid]
|
||||||
|
if (l != null) {
|
||||||
|
for (var key in l) {
|
||||||
|
var listener = l[key]
|
||||||
|
if (--listener.missing === 0) {
|
||||||
|
this.whenOperationsExist([], listener.op)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
var t = this.initializedTypes[JSON.stringify(op.parent)]
|
||||||
var t = this.initializedTypes[JSON.stringify(op.parent)]
|
|
||||||
|
|
||||||
// if parent is deleted, mark as gc'd and return
|
// if parent is deleted, mark as gc'd and return
|
||||||
if (op.parent != null) {
|
if (op.parent != null) {
|
||||||
var parentIsDeleted = yield* transaction.isDeleted(op.parent)
|
var parentIsDeleted = yield* transaction.isDeleted(op.parent)
|
||||||
if (parentIsDeleted) {
|
if (parentIsDeleted) {
|
||||||
yield* transaction.deleteList(op.id)
|
yield* transaction.deleteList(op.id)
|
||||||
return
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// notify parent, if it was instanciated as a custom type
|
// notify parent, if it was instanciated as a custom type
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
let o = Y.utils.copyOperation(op)
|
let o = Y.utils.copyOperation(op)
|
||||||
yield* t._changed(transaction, o)
|
yield* t._changed(transaction, o)
|
||||||
}
|
}
|
||||||
if (!op.deleted) {
|
if (!op.deleted) {
|
||||||
// Delete if DS says this is actually deleted
|
// Delete if DS says this is actually deleted
|
||||||
var len = op.content != null ? op.content.length : 1
|
var len = op.content != null ? op.content.length : 1
|
||||||
var startId = op.id // You must not use op.id in the following loop, because op will change when deleted
|
var startId = op.id // You must not use op.id in the following loop, because op will change when deleted
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
var id = [startId[0], startId[1] + i]
|
var id = [startId[0], startId[1] + i]
|
||||||
var opIsDeleted = yield* transaction.isDeleted(id)
|
var opIsDeleted = yield* transaction.isDeleted(id)
|
||||||
if (opIsDeleted) {
|
if (opIsDeleted) {
|
||||||
var delop = {
|
var delop = {
|
||||||
struct: 'Delete',
|
struct: 'Delete',
|
||||||
target: id
|
target: id
|
||||||
|
}
|
||||||
|
yield* this.tryExecute.call(transaction, delop)
|
||||||
}
|
}
|
||||||
yield* this.tryExecute.call(transaction, delop)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1741,14 +1762,11 @@ module.exports = function (Y/* :any */) {
|
|||||||
right = null
|
right = null
|
||||||
}
|
}
|
||||||
if (callType && !preventCallType) {
|
if (callType && !preventCallType) {
|
||||||
var type = this.store.initializedTypes[JSON.stringify(target.parent)]
|
yield* this.store.operationAdded(this, {
|
||||||
if (type != null) {
|
struct: 'Delete',
|
||||||
yield* type._changed(this, {
|
target: target.id,
|
||||||
struct: 'Delete',
|
length: targetLength
|
||||||
target: target.id,
|
})
|
||||||
length: targetLength
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// need to gc in the end!
|
// need to gc in the end!
|
||||||
yield* this.store.addToGarbageCollector.call(this, target, left)
|
yield* this.store.addToGarbageCollector.call(this, target, left)
|
||||||
@@ -1992,6 +2010,7 @@ module.exports = function (Y/* :any */) {
|
|||||||
if (o.right != null) {
|
if (o.right != null) {
|
||||||
var right = yield* this.getOperation(o.right)
|
var right = yield* this.getOperation(o.right)
|
||||||
right.left = o.left
|
right.left = o.left
|
||||||
|
yield* this.setOperation(right)
|
||||||
|
|
||||||
if (o.originOf != null && o.originOf.length > 0) {
|
if (o.originOf != null && o.originOf.length > 0) {
|
||||||
// find new origin of right ops
|
// find new origin of right ops
|
||||||
@@ -2058,10 +2077,6 @@ module.exports = function (Y/* :any */) {
|
|||||||
}
|
}
|
||||||
// we don't need to set right here, because
|
// we don't need to set right here, because
|
||||||
// right should be in o.originOf => it is set it the previous for loop
|
// right should be in o.originOf => it is set it the previous for loop
|
||||||
} else {
|
|
||||||
// we didn't need to reset the origin of right
|
|
||||||
// so we have to set right here
|
|
||||||
yield* this.setOperation(right)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// o may originate in another operation.
|
// o may originate in another operation.
|
||||||
@@ -2681,6 +2696,153 @@ module.exports = function (Y /* : any*/) {
|
|||||||
receivedOp (op) {
|
receivedOp (op) {
|
||||||
if (this.awaiting <= 0) {
|
if (this.awaiting <= 0) {
|
||||||
this.onevent(op)
|
this.onevent(op)
|
||||||
|
} else if (op.struct === 'Delete') {
|
||||||
|
var self = this
|
||||||
|
var checkDelete = function checkDelete (d) {
|
||||||
|
if (d.length == null) {
|
||||||
|
throw new Error('This shouldn\'t happen! d.length must be defined!')
|
||||||
|
}
|
||||||
|
// we check if o deletes something in self.waiting
|
||||||
|
// if so, we remove the deleted operation
|
||||||
|
for (var w = 0; w < self.waiting.length; w++) {
|
||||||
|
var i = self.waiting[w]
|
||||||
|
if (i.struct === 'Insert' && i.id[0] === d.target[0]) {
|
||||||
|
var iLength = i.hasOwnProperty('content') ? i.content.length : 1
|
||||||
|
var dStart = d.target[1]
|
||||||
|
var dEnd = d.target[1] + (d.length || 1)
|
||||||
|
var iStart = i.id[1]
|
||||||
|
var iEnd = i.id[1] + iLength
|
||||||
|
// Check if they don't overlap
|
||||||
|
if (iEnd <= dStart || dEnd <= iStart) {
|
||||||
|
// no overlapping
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// we check all overlapping cases. All cases:
|
||||||
|
/*
|
||||||
|
1) iiiii
|
||||||
|
ddddd
|
||||||
|
--> modify i and d
|
||||||
|
2) iiiiiii
|
||||||
|
ddddd
|
||||||
|
--> modify i, remove d
|
||||||
|
3) iiiiiii
|
||||||
|
ddd
|
||||||
|
--> remove d, modify i, and create another i (for the right hand side)
|
||||||
|
4) iiiii
|
||||||
|
ddddddd
|
||||||
|
--> remove i, modify d
|
||||||
|
5) iiiiiii
|
||||||
|
ddddddd
|
||||||
|
--> remove both i and d (**)
|
||||||
|
6) iiiiiii
|
||||||
|
ddddd
|
||||||
|
--> modify i, remove d
|
||||||
|
7) iii
|
||||||
|
ddddddd
|
||||||
|
--> remove i, create and apply two d with checkDelete(d) (**)
|
||||||
|
8) iiiii
|
||||||
|
ddddddd
|
||||||
|
--> remove i, modify d (**)
|
||||||
|
9) iiiii
|
||||||
|
ddddd
|
||||||
|
--> modify i and d
|
||||||
|
(**) (also check if i contains content or type)
|
||||||
|
*/
|
||||||
|
// TODO: I left some debugger statements, because I want to debug all cases once in production. REMEMBER END TODO
|
||||||
|
if (iStart < dStart) {
|
||||||
|
if (dStart < iEnd) {
|
||||||
|
if (iEnd < dEnd) {
|
||||||
|
// Case 1
|
||||||
|
// remove the right part of i's content
|
||||||
|
i.content.splice(dStart - iStart)
|
||||||
|
// remove the start of d's deletion
|
||||||
|
d.length = dEnd - iEnd
|
||||||
|
d.target = [d.target[0], iEnd]
|
||||||
|
continue
|
||||||
|
} else if (iEnd === dEnd) {
|
||||||
|
// Case 2
|
||||||
|
i.content.splice(dStart - iStart)
|
||||||
|
// remove d, we do that by simply ending this function
|
||||||
|
return
|
||||||
|
} else { // (dEnd < iEnd)
|
||||||
|
// Case 3
|
||||||
|
var newI = {
|
||||||
|
id: [i.id[0], dEnd],
|
||||||
|
content: i.content.slice(dEnd - iStart),
|
||||||
|
struct: 'Insert'
|
||||||
|
}
|
||||||
|
self.waiting.push(newI)
|
||||||
|
i.content.splice(dStart - iStart)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (dStart === iStart) {
|
||||||
|
if (iEnd < dEnd) {
|
||||||
|
// Case 4
|
||||||
|
d.length = dEnd - iEnd
|
||||||
|
d.target = [d.target[0], iEnd]
|
||||||
|
i.content = []
|
||||||
|
continue
|
||||||
|
} else if (iEnd === dEnd) {
|
||||||
|
// Case 5
|
||||||
|
self.waiting.splice(w, 1)
|
||||||
|
return
|
||||||
|
} else { // (dEnd < iEnd)
|
||||||
|
// Case 6
|
||||||
|
i.content = i.content.slice(dEnd - iStart)
|
||||||
|
i.id = [i.id[0], dEnd]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else { // (dStart < iStart)
|
||||||
|
if (iStart < dEnd) {
|
||||||
|
// they overlap
|
||||||
|
/*
|
||||||
|
7) iii
|
||||||
|
ddddddd
|
||||||
|
--> remove i, create and apply two d with checkDelete(d) (**)
|
||||||
|
8) iiiii
|
||||||
|
ddddddd
|
||||||
|
--> remove i, modify d (**)
|
||||||
|
9) iiiii
|
||||||
|
ddddd
|
||||||
|
--> modify i and d
|
||||||
|
*/
|
||||||
|
if (iEnd < dEnd) {
|
||||||
|
// Case 7
|
||||||
|
// debugger // TODO: You did not test this case yet!!!! (add the debugger here)
|
||||||
|
self.waiting.splice(w, 1)
|
||||||
|
checkDelete({
|
||||||
|
target: [d.target[0], dStart],
|
||||||
|
length: iStart - dStart,
|
||||||
|
struct: 'Delete'
|
||||||
|
})
|
||||||
|
checkDelete({
|
||||||
|
target: [d.target[0], iEnd],
|
||||||
|
length: iEnd - dEnd,
|
||||||
|
struct: 'Delete'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
} else if (iEnd === dEnd) {
|
||||||
|
// Case 8
|
||||||
|
self.waiting.splice(w, 1)
|
||||||
|
w--
|
||||||
|
d.length -= iLength
|
||||||
|
continue
|
||||||
|
} else { // dEnd < iEnd
|
||||||
|
// Case 9
|
||||||
|
d.length = iStart - dStart
|
||||||
|
i.content.splice(0, dEnd - iStart)
|
||||||
|
i.id = [i.id[0], dEnd]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// finished with remaining operations
|
||||||
|
self.waiting.push(d)
|
||||||
|
}
|
||||||
|
checkDelete(op)
|
||||||
} else {
|
} else {
|
||||||
this.waiting.push(op)
|
this.waiting.push(op)
|
||||||
}
|
}
|
||||||
@@ -2765,11 +2927,27 @@ module.exports = function (Y /* : any*/) {
|
|||||||
ins.push(o)
|
ins.push(o)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
this.waiting = []
|
||||||
// put in executable order
|
// put in executable order
|
||||||
ins = notSoSmartSort(ins)
|
ins = notSoSmartSort(ins)
|
||||||
ins.forEach(this.onevent)
|
// this.onevent can trigger the creation of another operation
|
||||||
dels.forEach(this.onevent)
|
// -> check if this.awaiting increased & stop computation if it does
|
||||||
this.waiting = []
|
for (var i = 0; i < ins.length; i++) {
|
||||||
|
if (this.awaiting === 0) {
|
||||||
|
this.onevent(ins[i])
|
||||||
|
} else {
|
||||||
|
this.waiting = this.waiting.concat(ins.slice(i))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < dels.length; i++) {
|
||||||
|
if (this.awaiting === 0) {
|
||||||
|
this.onevent(dels[i])
|
||||||
|
} else {
|
||||||
|
this.waiting = this.waiting.concat(dels.slice(i))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3214,6 +3392,7 @@ function requestModules (modules) {
|
|||||||
})
|
})
|
||||||
promises.push(requireModule.promise)
|
promises.push(requireModule.promise)
|
||||||
} else {
|
} else {
|
||||||
|
console.info('YJS: Please do not depend on automatic requiring of modules anymore! Extend modules as follows `require(\'y-modulename\')(Y)`')
|
||||||
require(modulename)(Y)
|
require(modulename)(Y)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -3260,23 +3439,25 @@ function Y (opts/* :YOptions */) /* :Promise<YConfig> */ {
|
|||||||
modules.push(opts.share[name])
|
modules.push(opts.share[name])
|
||||||
}
|
}
|
||||||
Y.sourceDir = opts.sourceDir
|
Y.sourceDir = opts.sourceDir
|
||||||
return Y.requestModules(modules).then(function () {
|
return new Promise(function (resolve, reject) {
|
||||||
return new Promise(function (resolve, reject) {
|
setTimeout(function () {
|
||||||
if (opts == null) reject('An options object is expected! ')
|
Y.requestModules(modules).then(function () {
|
||||||
else if (opts.connector == null) reject('You must specify a connector! (missing connector property)')
|
if (opts == null) reject('An options object is expected! ')
|
||||||
else if (opts.connector.name == null) reject('You must specify connector name! (missing connector.name property)')
|
else if (opts.connector == null) reject('You must specify a connector! (missing connector property)')
|
||||||
else if (opts.db == null) reject('You must specify a database! (missing db property)')
|
else if (opts.connector.name == null) reject('You must specify connector name! (missing connector.name property)')
|
||||||
else if (opts.connector.name == null) reject('You must specify db name! (missing db.name property)')
|
else if (opts.db == null) reject('You must specify a database! (missing db property)')
|
||||||
else if (opts.share == null) reject('You must specify a set of shared types!')
|
else if (opts.connector.name == null) reject('You must specify db name! (missing db.name property)')
|
||||||
else {
|
else if (opts.share == null) reject('You must specify a set of shared types!')
|
||||||
var yconfig = new YConfig(opts)
|
else {
|
||||||
yconfig.db.whenUserIdSet(function () {
|
var yconfig = new YConfig(opts)
|
||||||
yconfig.init(function () {
|
yconfig.db.whenUserIdSet(function () {
|
||||||
resolve(yconfig)
|
yconfig.init(function () {
|
||||||
|
resolve(yconfig)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
}
|
}).catch(reject)
|
||||||
})
|
}, 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user