Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3d21b5c8e | ||
|
|
3eafd78710 | ||
|
|
e30e16c91b |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
|
node_modules
|
||||||
bower_components
|
bower_components
|
||||||
|
|||||||
24
Examples/Monaco/index.html
Normal file
24
Examples/Monaco/index.html
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="monacoContainer"></div>
|
||||||
|
<style>
|
||||||
|
#monacoContainer {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="../bower_components/yjs/y.es6"></script>
|
||||||
|
<script src="../bower_components/y-array/y-array.es6"></script>
|
||||||
|
<script src="../bower_components/y-text/y-text.es6"></script>
|
||||||
|
<script src="../bower_components/y-websockets-client/y-websockets-client.es6"></script>
|
||||||
|
<script src="../bower_components/y-memory/y-memory.es6"></script>
|
||||||
|
<script src="../node_modules/monaco-editor/min/vs/loader.js"></script>
|
||||||
|
<script src="./index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
31
Examples/Monaco/index.js
Normal file
31
Examples/Monaco/index.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/* global Y */
|
||||||
|
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
@@ -1,21 +1,31 @@
|
|||||||
/* global Y, Quill */
|
/* global Y, Quill */
|
||||||
|
|
||||||
|
// register yjs service worker
|
||||||
|
if('serviceWorker' in navigator){
|
||||||
|
// Register service worker
|
||||||
|
// it is important to copy yjs-sw-template to the root directory!
|
||||||
|
navigator.serviceWorker.register('./yjs-sw-template.js').then(function(reg){
|
||||||
|
console.log("Yjs service worker registration succeeded. Scope is " + reg.scope);
|
||||||
|
}).catch(function(err){
|
||||||
|
console.error("Yjs service worker registration failed with error " + err);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// initialize a shared object. This function call returns a promise!
|
// initialize a shared object. This function call returns a promise!
|
||||||
Y({
|
Y({
|
||||||
db: {
|
db: {
|
||||||
name: 'memory'
|
name: 'memory'
|
||||||
},
|
},
|
||||||
connector: {
|
connector: {
|
||||||
name: 'webworker',
|
name: 'serviceworker',
|
||||||
url: '../bower_components/y-webworker/yjs-webworker.js',
|
room: 'ServiceWorkerExample2'
|
||||||
room: 'WebWorkerExample2'
|
|
||||||
},
|
},
|
||||||
sourceDir: '/bower_components',
|
sourceDir: '/bower_components',
|
||||||
share: {
|
share: {
|
||||||
richtext: 'Richtext' // y.share.richtext is of type Y.Richtext
|
richtext: 'Richtext' // y.share.richtext is of type Y.Richtext
|
||||||
}
|
}
|
||||||
}).then(function (y) {
|
}).then(function (y) {
|
||||||
window.yQuill = y
|
window.yServiceWorker = y
|
||||||
|
|
||||||
// create quill element
|
// create quill element
|
||||||
window.quill = new Quill('#quill', {
|
window.quill = new Quill('#quill', {
|
||||||
22
Examples/ServiceWorker/yjs-sw-template.js
Normal file
22
Examples/ServiceWorker/yjs-sw-template.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/* eslint-env worker */
|
||||||
|
|
||||||
|
// copy and modify this file
|
||||||
|
|
||||||
|
self.DBConfig = {
|
||||||
|
name: 'indexeddb'
|
||||||
|
}
|
||||||
|
self.ConnectorConfig = {
|
||||||
|
name: 'websockets-client',
|
||||||
|
// url: '..',
|
||||||
|
options: {
|
||||||
|
jsonp: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
importScripts(
|
||||||
|
'/bower_components/yjs/y.js',
|
||||||
|
'/bower_components/y-memory/y-memory.js',
|
||||||
|
'/bower_components/y-indexeddb/y-indexeddb.js',
|
||||||
|
'/bower_components/y-websockets-client/y-websockets-client.js',
|
||||||
|
'/bower_components/y-serviceworker/yjs-sw-include.js'
|
||||||
|
)
|
||||||
10
Examples/package.json
Normal file
10
Examples/package.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "examples",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"author": "Kevin Jahns",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"monaco-editor": "^0.8.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,7 +40,7 @@ is a list of the modules we know of:
|
|||||||
|[map](https://github.com/y-js/y-map) | A shared Map implementation. Maps from text to any stringify-able object |
|
|[map](https://github.com/y-js/y-map) | A shared Map implementation. Maps from text to any stringify-able object |
|
||||||
|[array](https://github.com/y-js/y-array) | A shared Array implementation |
|
|[array](https://github.com/y-js/y-array) | A shared Array implementation |
|
||||||
|[xml](https://github.com/y-js/y-xml) | An implementation of the DOM. You can create a two way binding to Browser DOM objects |
|
|[xml](https://github.com/y-js/y-xml) | An implementation of the DOM. You can create a two way binding to Browser DOM objects |
|
||||||
|[text](https://github.com/y-js/y-text) | Collaborate on text. Supports two way binding to the [Ace Editor](https://ace.c9.io), [CodeMirror](https://codemirror.net/), textareas, input elements, and HTML elements (e.g. <*h1*>, or <*p*>) |
|
|[text](https://github.com/y-js/y-text) | Collaborate on text. Supports two way binding to the [Ace Editor](https://ace.c9.io), [CodeMirror](https://codemirror.net/), [Monaco](https://github.com/Microsoft/monaco-editor), textareas, input elements, and HTML elements (e.g. <*h1*>, or <*p*>) |
|
||||||
|[richtext](https://github.com/y-js/y-richtext) | Collaborate on rich text. Supports two way binding to the [Quill Rich Text Editor](http://quilljs.com/)|
|
|[richtext](https://github.com/y-js/y-richtext) | Collaborate on rich text. Supports two way binding to the [Quill Rich Text Editor](http://quilljs.com/)|
|
||||||
|
|
||||||
##### Other
|
##### Other
|
||||||
@@ -170,6 +170,11 @@ soon, if possible.
|
|||||||
immediately going to be resolved, without waiting for any confirmation from
|
immediately going to be resolved, without waiting for any confirmation from
|
||||||
the server. Use with caution.
|
the server. Use with caution.
|
||||||
* Have a look at the used connector repository to see all available options.
|
* Have a look at the used connector repository to see all available options.
|
||||||
|
* *Only if you know what you are doing:* Set
|
||||||
|
`options.connector.preferUntransformed = true` in order receive the shared
|
||||||
|
data untransformed. This is very efficient as the database content is simply
|
||||||
|
copied to this client. This does only work if this client receives content
|
||||||
|
from only one client.
|
||||||
* options.sourceDir (browser only)
|
* options.sourceDir (browser only)
|
||||||
* Path where all y-* modules are stored
|
* Path where all y-* modules are stored
|
||||||
* Defaults to `/bower_components`
|
* Defaults to `/bower_components`
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "yjs",
|
"name": "yjs",
|
||||||
"version": "12.1.7",
|
"version": "12.2.0",
|
||||||
"homepage": "y-js.org",
|
"homepage": "y-js.org",
|
||||||
"authors": [
|
"authors": [
|
||||||
"Kevin Jahns <kevin.jahns@rwth-aachen.de>"
|
"Kevin Jahns <kevin.jahns@rwth-aachen.de>"
|
||||||
|
|||||||
519
y.es6
519
y.es6
@@ -1,161 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* yjs - A framework for real-time p2p shared editing on any data
|
* yjs - A framework for real-time p2p shared editing on any data
|
||||||
* @version v12.1.6
|
* @version v12.1.7
|
||||||
* @link http://y-js.org
|
* @link http://y-js.org
|
||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Y = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Y = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||||
/**
|
|
||||||
* Helpers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var s = 1000
|
|
||||||
var m = s * 60
|
|
||||||
var h = m * 60
|
|
||||||
var d = h * 24
|
|
||||||
var y = d * 365.25
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse or format the given `val`.
|
|
||||||
*
|
|
||||||
* Options:
|
|
||||||
*
|
|
||||||
* - `long` verbose formatting [false]
|
|
||||||
*
|
|
||||||
* @param {String|Number} val
|
|
||||||
* @param {Object} options
|
|
||||||
* @throws {Error} throw an error if val is not a non-empty string or a number
|
|
||||||
* @return {String|Number}
|
|
||||||
* @api public
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function (val, options) {
|
|
||||||
options = options || {}
|
|
||||||
var type = typeof val
|
|
||||||
if (type === 'string' && val.length > 0) {
|
|
||||||
return parse(val)
|
|
||||||
} else if (type === 'number' && isNaN(val) === false) {
|
|
||||||
return options.long ?
|
|
||||||
fmtLong(val) :
|
|
||||||
fmtShort(val)
|
|
||||||
}
|
|
||||||
throw new Error('val is not a non-empty string or a valid number. val=' + JSON.stringify(val))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the given `str` and return milliseconds.
|
|
||||||
*
|
|
||||||
* @param {String} str
|
|
||||||
* @return {Number}
|
|
||||||
* @api private
|
|
||||||
*/
|
|
||||||
|
|
||||||
function parse(str) {
|
|
||||||
str = String(str)
|
|
||||||
if (str.length > 10000) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str)
|
|
||||||
if (!match) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var n = parseFloat(match[1])
|
|
||||||
var type = (match[2] || 'ms').toLowerCase()
|
|
||||||
switch (type) {
|
|
||||||
case 'years':
|
|
||||||
case 'year':
|
|
||||||
case 'yrs':
|
|
||||||
case 'yr':
|
|
||||||
case 'y':
|
|
||||||
return n * y
|
|
||||||
case 'days':
|
|
||||||
case 'day':
|
|
||||||
case 'd':
|
|
||||||
return n * d
|
|
||||||
case 'hours':
|
|
||||||
case 'hour':
|
|
||||||
case 'hrs':
|
|
||||||
case 'hr':
|
|
||||||
case 'h':
|
|
||||||
return n * h
|
|
||||||
case 'minutes':
|
|
||||||
case 'minute':
|
|
||||||
case 'mins':
|
|
||||||
case 'min':
|
|
||||||
case 'm':
|
|
||||||
return n * m
|
|
||||||
case 'seconds':
|
|
||||||
case 'second':
|
|
||||||
case 'secs':
|
|
||||||
case 'sec':
|
|
||||||
case 's':
|
|
||||||
return n * s
|
|
||||||
case 'milliseconds':
|
|
||||||
case 'millisecond':
|
|
||||||
case 'msecs':
|
|
||||||
case 'msec':
|
|
||||||
case 'ms':
|
|
||||||
return n
|
|
||||||
default:
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Short format for `ms`.
|
|
||||||
*
|
|
||||||
* @param {Number} ms
|
|
||||||
* @return {String}
|
|
||||||
* @api private
|
|
||||||
*/
|
|
||||||
|
|
||||||
function fmtShort(ms) {
|
|
||||||
if (ms >= d) {
|
|
||||||
return Math.round(ms / d) + 'd'
|
|
||||||
}
|
|
||||||
if (ms >= h) {
|
|
||||||
return Math.round(ms / h) + 'h'
|
|
||||||
}
|
|
||||||
if (ms >= m) {
|
|
||||||
return Math.round(ms / m) + 'm'
|
|
||||||
}
|
|
||||||
if (ms >= s) {
|
|
||||||
return Math.round(ms / s) + 's'
|
|
||||||
}
|
|
||||||
return ms + 'ms'
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Long format for `ms`.
|
|
||||||
*
|
|
||||||
* @param {Number} ms
|
|
||||||
* @return {String}
|
|
||||||
* @api private
|
|
||||||
*/
|
|
||||||
|
|
||||||
function fmtLong(ms) {
|
|
||||||
return plural(ms, d, 'day') ||
|
|
||||||
plural(ms, h, 'hour') ||
|
|
||||||
plural(ms, m, 'minute') ||
|
|
||||||
plural(ms, s, 'second') ||
|
|
||||||
ms + ' ms'
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pluralization helper.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function plural(ms, n, name) {
|
|
||||||
if (ms < n) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (ms < n * 1.5) {
|
|
||||||
return Math.floor(ms / n) + ' ' + name
|
|
||||||
}
|
|
||||||
return Math.ceil(ms / n) + ' ' + name + 's'
|
|
||||||
}
|
|
||||||
|
|
||||||
},{}],2:[function(require,module,exports){
|
|
||||||
(function (process){
|
(function (process){
|
||||||
/**
|
/**
|
||||||
* This is the web browser implementation of `debug()`.
|
* This is the web browser implementation of `debug()`.
|
||||||
@@ -345,7 +194,7 @@ function localstorage() {
|
|||||||
|
|
||||||
}).call(this,require('_process'))
|
}).call(this,require('_process'))
|
||||||
|
|
||||||
},{"./debug":3,"_process":4}],3:[function(require,module,exports){
|
},{"./debug":2,"_process":4}],2:[function(require,module,exports){
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the common logic for both the Node.js and web browser
|
* This is the common logic for both the Node.js and web browser
|
||||||
@@ -489,7 +338,7 @@ function enable(namespaces) {
|
|||||||
exports.names = [];
|
exports.names = [];
|
||||||
exports.skips = [];
|
exports.skips = [];
|
||||||
|
|
||||||
var split = (namespaces || '').split(/[\s,]+/);
|
var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
|
||||||
var len = split.length;
|
var len = split.length;
|
||||||
|
|
||||||
for (var i = 0; i < len; i++) {
|
for (var i = 0; i < len; i++) {
|
||||||
@@ -549,7 +398,158 @@ function coerce(val) {
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
},{"ms":1}],4:[function(require,module,exports){
|
},{"ms":3}],3:[function(require,module,exports){
|
||||||
|
/**
|
||||||
|
* Helpers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var s = 1000
|
||||||
|
var m = s * 60
|
||||||
|
var h = m * 60
|
||||||
|
var d = h * 24
|
||||||
|
var y = d * 365.25
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse or format the given `val`.
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
*
|
||||||
|
* - `long` verbose formatting [false]
|
||||||
|
*
|
||||||
|
* @param {String|Number} val
|
||||||
|
* @param {Object} [options]
|
||||||
|
* @throws {Error} throw an error if val is not a non-empty string or a number
|
||||||
|
* @return {String|Number}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function (val, options) {
|
||||||
|
options = options || {}
|
||||||
|
var type = typeof val
|
||||||
|
if (type === 'string' && val.length > 0) {
|
||||||
|
return parse(val)
|
||||||
|
} else if (type === 'number' && isNaN(val) === false) {
|
||||||
|
return options.long ?
|
||||||
|
fmtLong(val) :
|
||||||
|
fmtShort(val)
|
||||||
|
}
|
||||||
|
throw new Error('val is not a non-empty string or a valid number. val=' + JSON.stringify(val))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the given `str` and return milliseconds.
|
||||||
|
*
|
||||||
|
* @param {String} str
|
||||||
|
* @return {Number}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function parse(str) {
|
||||||
|
str = String(str)
|
||||||
|
if (str.length > 10000) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str)
|
||||||
|
if (!match) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var n = parseFloat(match[1])
|
||||||
|
var type = (match[2] || 'ms').toLowerCase()
|
||||||
|
switch (type) {
|
||||||
|
case 'years':
|
||||||
|
case 'year':
|
||||||
|
case 'yrs':
|
||||||
|
case 'yr':
|
||||||
|
case 'y':
|
||||||
|
return n * y
|
||||||
|
case 'days':
|
||||||
|
case 'day':
|
||||||
|
case 'd':
|
||||||
|
return n * d
|
||||||
|
case 'hours':
|
||||||
|
case 'hour':
|
||||||
|
case 'hrs':
|
||||||
|
case 'hr':
|
||||||
|
case 'h':
|
||||||
|
return n * h
|
||||||
|
case 'minutes':
|
||||||
|
case 'minute':
|
||||||
|
case 'mins':
|
||||||
|
case 'min':
|
||||||
|
case 'm':
|
||||||
|
return n * m
|
||||||
|
case 'seconds':
|
||||||
|
case 'second':
|
||||||
|
case 'secs':
|
||||||
|
case 'sec':
|
||||||
|
case 's':
|
||||||
|
return n * s
|
||||||
|
case 'milliseconds':
|
||||||
|
case 'millisecond':
|
||||||
|
case 'msecs':
|
||||||
|
case 'msec':
|
||||||
|
case 'ms':
|
||||||
|
return n
|
||||||
|
default:
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Short format for `ms`.
|
||||||
|
*
|
||||||
|
* @param {Number} ms
|
||||||
|
* @return {String}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function fmtShort(ms) {
|
||||||
|
if (ms >= d) {
|
||||||
|
return Math.round(ms / d) + 'd'
|
||||||
|
}
|
||||||
|
if (ms >= h) {
|
||||||
|
return Math.round(ms / h) + 'h'
|
||||||
|
}
|
||||||
|
if (ms >= m) {
|
||||||
|
return Math.round(ms / m) + 'm'
|
||||||
|
}
|
||||||
|
if (ms >= s) {
|
||||||
|
return Math.round(ms / s) + 's'
|
||||||
|
}
|
||||||
|
return ms + 'ms'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Long format for `ms`.
|
||||||
|
*
|
||||||
|
* @param {Number} ms
|
||||||
|
* @return {String}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function fmtLong(ms) {
|
||||||
|
return plural(ms, d, 'day') ||
|
||||||
|
plural(ms, h, 'hour') ||
|
||||||
|
plural(ms, m, 'minute') ||
|
||||||
|
plural(ms, s, 'second') ||
|
||||||
|
ms + ' ms'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pluralization helper.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function plural(ms, n, name) {
|
||||||
|
if (ms < n) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (ms < n * 1.5) {
|
||||||
|
return Math.floor(ms / n) + ' ' + name
|
||||||
|
}
|
||||||
|
return Math.ceil(ms / n) + ' ' + name + 's'
|
||||||
|
}
|
||||||
|
|
||||||
|
},{}],4:[function(require,module,exports){
|
||||||
// shim for using process in browser
|
// shim for using process in browser
|
||||||
var process = module.exports = {};
|
var process = module.exports = {};
|
||||||
|
|
||||||
@@ -561,35 +561,83 @@ var process = module.exports = {};
|
|||||||
var cachedSetTimeout;
|
var cachedSetTimeout;
|
||||||
var cachedClearTimeout;
|
var cachedClearTimeout;
|
||||||
|
|
||||||
|
function defaultSetTimout() {
|
||||||
|
throw new Error('setTimeout has not been defined');
|
||||||
|
}
|
||||||
|
function defaultClearTimeout () {
|
||||||
|
throw new Error('clearTimeout has not been defined');
|
||||||
|
}
|
||||||
(function () {
|
(function () {
|
||||||
try {
|
try {
|
||||||
cachedSetTimeout = setTimeout;
|
if (typeof setTimeout === 'function') {
|
||||||
} catch (e) {
|
cachedSetTimeout = setTimeout;
|
||||||
cachedSetTimeout = function () {
|
} else {
|
||||||
throw new Error('setTimeout is not defined');
|
cachedSetTimeout = defaultSetTimout;
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
cachedSetTimeout = defaultSetTimout;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
cachedClearTimeout = clearTimeout;
|
if (typeof clearTimeout === 'function') {
|
||||||
} catch (e) {
|
cachedClearTimeout = clearTimeout;
|
||||||
cachedClearTimeout = function () {
|
} else {
|
||||||
throw new Error('clearTimeout is not defined');
|
cachedClearTimeout = defaultClearTimeout;
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
cachedClearTimeout = defaultClearTimeout;
|
||||||
}
|
}
|
||||||
} ())
|
} ())
|
||||||
function runTimeout(fun) {
|
function runTimeout(fun) {
|
||||||
if (cachedSetTimeout === setTimeout) {
|
if (cachedSetTimeout === setTimeout) {
|
||||||
|
//normal enviroments in sane situations
|
||||||
return setTimeout(fun, 0);
|
return setTimeout(fun, 0);
|
||||||
} else {
|
|
||||||
return cachedSetTimeout.call(null, fun, 0);
|
|
||||||
}
|
}
|
||||||
|
// if setTimeout wasn't available but was latter defined
|
||||||
|
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
|
||||||
|
cachedSetTimeout = setTimeout;
|
||||||
|
return setTimeout(fun, 0);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// when when somebody has screwed with setTimeout but no I.E. maddness
|
||||||
|
return cachedSetTimeout(fun, 0);
|
||||||
|
} catch(e){
|
||||||
|
try {
|
||||||
|
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
|
||||||
|
return cachedSetTimeout.call(null, fun, 0);
|
||||||
|
} catch(e){
|
||||||
|
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
|
||||||
|
return cachedSetTimeout.call(this, fun, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
function runClearTimeout(marker) {
|
function runClearTimeout(marker) {
|
||||||
if (cachedClearTimeout === clearTimeout) {
|
if (cachedClearTimeout === clearTimeout) {
|
||||||
clearTimeout(marker);
|
//normal enviroments in sane situations
|
||||||
} else {
|
return clearTimeout(marker);
|
||||||
cachedClearTimeout.call(null, marker);
|
|
||||||
}
|
}
|
||||||
|
// if clearTimeout wasn't available but was latter defined
|
||||||
|
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
|
||||||
|
cachedClearTimeout = clearTimeout;
|
||||||
|
return clearTimeout(marker);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// when when somebody has screwed with setTimeout but no I.E. maddness
|
||||||
|
return cachedClearTimeout(marker);
|
||||||
|
} catch (e){
|
||||||
|
try {
|
||||||
|
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
|
||||||
|
return cachedClearTimeout.call(null, marker);
|
||||||
|
} catch (e){
|
||||||
|
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
|
||||||
|
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
|
||||||
|
return cachedClearTimeout.call(this, marker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
var queue = [];
|
var queue = [];
|
||||||
var draining = false;
|
var draining = false;
|
||||||
@@ -672,6 +720,10 @@ process.off = noop;
|
|||||||
process.removeListener = noop;
|
process.removeListener = noop;
|
||||||
process.removeAllListeners = noop;
|
process.removeAllListeners = noop;
|
||||||
process.emit = noop;
|
process.emit = noop;
|
||||||
|
process.prependListener = noop;
|
||||||
|
process.prependOnceListener = noop;
|
||||||
|
|
||||||
|
process.listeners = function (name) { return [] }
|
||||||
|
|
||||||
process.binding = function (name) {
|
process.binding = function (name) {
|
||||||
throw new Error('process.binding is not supported');
|
throw new Error('process.binding is not supported');
|
||||||
@@ -703,7 +755,6 @@ module.exports = function (Y/* :any */) {
|
|||||||
syncingClients: Array<UserId>;
|
syncingClients: Array<UserId>;
|
||||||
forwardToSyncingClients: boolean;
|
forwardToSyncingClients: boolean;
|
||||||
debug: boolean;
|
debug: boolean;
|
||||||
broadcastedHB: boolean;
|
|
||||||
syncStep2: Promise;
|
syncStep2: Promise;
|
||||||
userId: UserId;
|
userId: UserId;
|
||||||
send: Function;
|
send: Function;
|
||||||
@@ -722,6 +773,11 @@ module.exports = function (Y/* :any */) {
|
|||||||
if (opts == null) {
|
if (opts == null) {
|
||||||
opts = {}
|
opts = {}
|
||||||
}
|
}
|
||||||
|
// Prefer to receive untransformed operations. This does only work if
|
||||||
|
// this client receives operations from only one other client.
|
||||||
|
// In particular, this does not work with y-webrtc.
|
||||||
|
// It will work with y-websockets-client
|
||||||
|
this.preferUntransformed = opts.preferUntransformed || false
|
||||||
if (opts.role == null || opts.role === 'master') {
|
if (opts.role == null || opts.role === 'master') {
|
||||||
this.role = 'master'
|
this.role = 'master'
|
||||||
} else if (opts.role === 'slave') {
|
} else if (opts.role === 'slave') {
|
||||||
@@ -741,7 +797,6 @@ module.exports = function (Y/* :any */) {
|
|||||||
this.syncingClients = []
|
this.syncingClients = []
|
||||||
this.forwardToSyncingClients = opts.forwardToSyncingClients !== false
|
this.forwardToSyncingClients = opts.forwardToSyncingClients !== false
|
||||||
this.debug = opts.debug === true
|
this.debug = opts.debug === true
|
||||||
this.broadcastedHB = false
|
|
||||||
this.syncStep2 = Promise.resolve()
|
this.syncStep2 = Promise.resolve()
|
||||||
this.broadcastOpBuffer = []
|
this.broadcastOpBuffer = []
|
||||||
this.protocolVersion = 11
|
this.protocolVersion = 11
|
||||||
@@ -762,13 +817,13 @@ module.exports = function (Y/* :any */) {
|
|||||||
}
|
}
|
||||||
reconnect () {
|
reconnect () {
|
||||||
this.log('reconnecting..')
|
this.log('reconnecting..')
|
||||||
|
this.y.db.startGarbageCollector()
|
||||||
}
|
}
|
||||||
disconnect () {
|
disconnect () {
|
||||||
this.log('discronnecting..')
|
this.log('discronnecting..')
|
||||||
this.connections = {}
|
this.connections = {}
|
||||||
this.isSynced = false
|
this.isSynced = false
|
||||||
this.currentSyncTarget = null
|
this.currentSyncTarget = null
|
||||||
this.broadcastedHB = false
|
|
||||||
this.syncingClients = []
|
this.syncingClients = []
|
||||||
this.whenSyncedListeners = []
|
this.whenSyncedListeners = []
|
||||||
return this.y.db.stopGarbageCollector()
|
return this.y.db.stopGarbageCollector()
|
||||||
@@ -780,7 +835,6 @@ module.exports = function (Y/* :any */) {
|
|||||||
}
|
}
|
||||||
this.isSynced = false
|
this.isSynced = false
|
||||||
this.currentSyncTarget = null
|
this.currentSyncTarget = null
|
||||||
this.broadcastedHB = false
|
|
||||||
this.findNextSyncTarget()
|
this.findNextSyncTarget()
|
||||||
}
|
}
|
||||||
setUserId (userId) {
|
setUserId (userId) {
|
||||||
@@ -867,13 +921,17 @@ module.exports = function (Y/* :any */) {
|
|||||||
this.y.db.requestTransaction(function *() {
|
this.y.db.requestTransaction(function *() {
|
||||||
var stateSet = yield* this.getStateSet()
|
var stateSet = yield* this.getStateSet()
|
||||||
var deleteSet = yield* this.getDeleteSet()
|
var deleteSet = yield* this.getDeleteSet()
|
||||||
conn.send(syncUser, {
|
var answer = {
|
||||||
type: 'sync step 1',
|
type: 'sync step 1',
|
||||||
stateSet: stateSet,
|
stateSet: stateSet,
|
||||||
deleteSet: deleteSet,
|
deleteSet: deleteSet,
|
||||||
protocolVersion: conn.protocolVersion,
|
protocolVersion: conn.protocolVersion,
|
||||||
auth: conn.authInfo
|
auth: conn.authInfo
|
||||||
})
|
}
|
||||||
|
if (conn.preferUntransformed && Object.keys(stateSet).length === 0) {
|
||||||
|
answer.preferUntransformed = true
|
||||||
|
}
|
||||||
|
conn.send(syncUser, answer)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
if (!conn.isSynced) {
|
if (!conn.isSynced) {
|
||||||
@@ -979,15 +1037,19 @@ module.exports = function (Y/* :any */) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var ds = yield* this.getDeleteSet()
|
var ds = yield* this.getDeleteSet()
|
||||||
var ops = yield* this.getOperations(m.stateSet)
|
var answer = {
|
||||||
conn.send(sender, {
|
|
||||||
type: 'sync step 2',
|
type: 'sync step 2',
|
||||||
os: ops,
|
|
||||||
stateSet: currentStateSet,
|
stateSet: currentStateSet,
|
||||||
deleteSet: ds,
|
deleteSet: ds,
|
||||||
protocolVersion: this.protocolVersion,
|
protocolVersion: this.protocolVersion,
|
||||||
auth: this.authInfo
|
auth: this.authInfo
|
||||||
})
|
}
|
||||||
|
if (message.preferUntransformed === true && Object.keys(m.stateSet).length === 0) {
|
||||||
|
answer.osUntransformed = yield* this.getOperationsUntransformed()
|
||||||
|
} else {
|
||||||
|
answer.os = yield* this.getOperations(m.stateSet)
|
||||||
|
}
|
||||||
|
conn.send(sender, answer)
|
||||||
if (this.forwardToSyncingClients) {
|
if (this.forwardToSyncingClients) {
|
||||||
conn.syncingClients.push(sender)
|
conn.syncingClients.push(sender)
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
@@ -1005,9 +1067,6 @@ module.exports = function (Y/* :any */) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else if (message.type === 'sync step 2' && canWrite(auth)) {
|
} else if (message.type === 'sync step 2' && canWrite(auth)) {
|
||||||
let conn = this
|
|
||||||
var broadcastHB = !this.broadcastedHB
|
|
||||||
this.broadcastedHB = true
|
|
||||||
var db = this.y.db
|
var db = this.y.db
|
||||||
var defer = {}
|
var defer = {}
|
||||||
defer.promise = new Promise(function (resolve) {
|
defer.promise = new Promise(function (resolve) {
|
||||||
@@ -1017,7 +1076,15 @@ module.exports = function (Y/* :any */) {
|
|||||||
let m /* :MessageSyncStep2 */ = message
|
let m /* :MessageSyncStep2 */ = message
|
||||||
db.requestTransaction(function * () {
|
db.requestTransaction(function * () {
|
||||||
yield* this.applyDeleteSet(m.deleteSet)
|
yield* this.applyDeleteSet(m.deleteSet)
|
||||||
this.store.apply(m.os)
|
if (m.osUntransformed != null) {
|
||||||
|
yield* this.applyOperationsUntransformed(m.osUntransformed, m.stateSet)
|
||||||
|
} else {
|
||||||
|
this.store.apply(m.os)
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* This just sends the complete hb after some time
|
||||||
|
* Mostly for debugging..
|
||||||
|
*
|
||||||
db.requestTransaction(function * () {
|
db.requestTransaction(function * () {
|
||||||
var ops = yield* this.getOperations(m.stateSet)
|
var ops = yield* this.getOperations(m.stateSet)
|
||||||
if (ops.length > 0) {
|
if (ops.length > 0) {
|
||||||
@@ -1031,8 +1098,9 @@ module.exports = function (Y/* :any */) {
|
|||||||
conn.broadcastOps(ops)
|
conn.broadcastOps(ops)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defer.resolve()
|
|
||||||
})
|
})
|
||||||
|
*/
|
||||||
|
defer.resolve()
|
||||||
})
|
})
|
||||||
} else if (message.type === 'sync done') {
|
} else if (message.type === 'sync done') {
|
||||||
var self = this
|
var self = this
|
||||||
@@ -1204,7 +1272,7 @@ module.exports = function (Y) {
|
|||||||
ps.push(self.users[name].y.db.whenTransactionsFinished())
|
ps.push(self.users[name].y.db.whenTransactionsFinished())
|
||||||
}
|
}
|
||||||
Promise.all(ps).then(resolve, reject)
|
Promise.all(ps).then(resolve, reject)
|
||||||
}, 0)
|
}, 10)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
flushOne: function flushOne () {
|
flushOne: function flushOne () {
|
||||||
@@ -1314,11 +1382,15 @@ module.exports = function (Y) {
|
|||||||
return Y.utils.globalRoom.flushAll()
|
return Y.utils.globalRoom.flushAll()
|
||||||
}
|
}
|
||||||
disconnect () {
|
disconnect () {
|
||||||
|
var waitForMe = Promise.resolve()
|
||||||
if (!this.isDisconnected()) {
|
if (!this.isDisconnected()) {
|
||||||
globalRoom.removeUser(this.userId)
|
globalRoom.removeUser(this.userId)
|
||||||
super.disconnect()
|
waitForMe = super.disconnect()
|
||||||
}
|
}
|
||||||
return this.y.db.whenTransactionsFinished()
|
var self = this
|
||||||
|
return waitForMe.then(function () {
|
||||||
|
return self.y.db.whenTransactionsFinished()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
flush () {
|
flush () {
|
||||||
var self = this
|
var self = this
|
||||||
@@ -1382,6 +1454,7 @@ module.exports = function (Y /* :any */) {
|
|||||||
*/
|
*/
|
||||||
constructor (y, opts) {
|
constructor (y, opts) {
|
||||||
this.y = y
|
this.y = y
|
||||||
|
this.dbOpts = opts
|
||||||
var os = this
|
var os = this
|
||||||
this.userId = null
|
this.userId = null
|
||||||
var resolve
|
var resolve
|
||||||
@@ -1418,12 +1491,6 @@ module.exports = function (Y /* :any */) {
|
|||||||
}
|
}
|
||||||
this.gc1 = [] // first stage
|
this.gc1 = [] // first stage
|
||||||
this.gc2 = [] // second stage -> after that, remove the op
|
this.gc2 = [] // second stage -> after that, remove the op
|
||||||
this.gc = opts.gc == null || opts.gc
|
|
||||||
if (this.gc) {
|
|
||||||
this.gcTimeout = !opts.gcTimeout ? 50000 : opts.gcTimeout
|
|
||||||
} else {
|
|
||||||
this.gcTimeout = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
function garbageCollect () {
|
function garbageCollect () {
|
||||||
return os.whenTransactionsFinished().then(function () {
|
return os.whenTransactionsFinished().then(function () {
|
||||||
@@ -1458,13 +1525,23 @@ module.exports = function (Y /* :any */) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.garbageCollect = garbageCollect
|
this.garbageCollect = garbageCollect
|
||||||
if (this.gcTimeout > 0) {
|
this.startGarbageCollector()
|
||||||
garbageCollect()
|
|
||||||
}
|
|
||||||
this.repairCheckInterval = !opts.repairCheckInterval ? 6000 : opts.repairCheckInterval
|
this.repairCheckInterval = !opts.repairCheckInterval ? 6000 : opts.repairCheckInterval
|
||||||
this.opsReceivedTimestamp = new Date()
|
this.opsReceivedTimestamp = new Date()
|
||||||
this.startRepairCheck()
|
this.startRepairCheck()
|
||||||
}
|
}
|
||||||
|
startGarbageCollector () {
|
||||||
|
this.gc = this.dbOpts.gc == null || this.dbOpts.gc
|
||||||
|
if (this.gc) {
|
||||||
|
this.gcTimeout = !this.dbOpts.gcTimeout ? 50000 : this.dbOpts.gcTimeout
|
||||||
|
} else {
|
||||||
|
this.gcTimeout = -1
|
||||||
|
}
|
||||||
|
if (this.gcTimeout > 0) {
|
||||||
|
this.garbageCollect()
|
||||||
|
}
|
||||||
|
}
|
||||||
startRepairCheck () {
|
startRepairCheck () {
|
||||||
var os = this
|
var os = this
|
||||||
if (this.repairCheckInterval > 0) {
|
if (this.repairCheckInterval > 0) {
|
||||||
@@ -3373,6 +3450,56 @@ module.exports = function (Y/* :any */) {
|
|||||||
}
|
}
|
||||||
return send.reverse()
|
return send.reverse()
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* Get the plain untransformed operations from the database.
|
||||||
|
* You can apply these operations using .applyOperationsUntransformed(ops)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
* getOperationsUntransformed () {
|
||||||
|
var ops = []
|
||||||
|
yield* this.os.iterate(this, null, null, function * (op) {
|
||||||
|
if (op.id[0] !== '_') {
|
||||||
|
ops.push(Y.Struct[op.struct].encode(op))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
untransformed: ops
|
||||||
|
}
|
||||||
|
}
|
||||||
|
* applyOperationsUntransformed (m, stateSet) {
|
||||||
|
var ops = m.untransformed
|
||||||
|
for (var i = 0; i < ops.length; i++) {
|
||||||
|
var op = ops[i]
|
||||||
|
// create, and modify parent, if it is created implicitly
|
||||||
|
if (op.parent != null && op.parent[0] === '_') {
|
||||||
|
if (op.struct === 'Insert') {
|
||||||
|
// update parents .map/start/end properties
|
||||||
|
if (op.parentSub != null && op.left == null) {
|
||||||
|
// op is child of Map
|
||||||
|
let parent = yield* this.getOperation(op.parent)
|
||||||
|
parent.map[op.parentSub] = op.id
|
||||||
|
yield* this.setOperation(parent)
|
||||||
|
} else if (op.right == null || op.left == null) {
|
||||||
|
let parent = yield* this.getOperation(op.parent)
|
||||||
|
if (op.right == null) {
|
||||||
|
parent.end = Y.utils.getLastId(op)
|
||||||
|
}
|
||||||
|
if (op.left == null) {
|
||||||
|
parent.start = op.id
|
||||||
|
}
|
||||||
|
yield* this.setOperation(parent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yield* this.os.put(op)
|
||||||
|
}
|
||||||
|
for (var user in stateSet) {
|
||||||
|
yield* this.ss.put({
|
||||||
|
id: [user],
|
||||||
|
clock: stateSet[user]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
/* this is what we used before.. use this as a reference..
|
/* this is what we used before.. use this as a reference..
|
||||||
* makeOperationReady (startSS, op) {
|
* makeOperationReady (startSS, op) {
|
||||||
op = Y.Struct[op.struct].encode(op)
|
op = Y.Struct[op.struct].encode(op)
|
||||||
@@ -4408,6 +4535,6 @@ class YConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
},{"./Connector.js":5,"./Connectors/Test.js":6,"./Database.js":7,"./Struct.js":8,"./Transaction.js":9,"./Utils.js":10,"debug":2}]},{},[11])(11)
|
},{"./Connector.js":5,"./Connectors/Test.js":6,"./Database.js":7,"./Struct.js":8,"./Transaction.js":9,"./Utils.js":10,"debug":1}]},{},[11])(11)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user