Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
013fee2421 | ||
|
|
bb45abbb70 | ||
|
|
67b47fd868 | ||
|
|
2c18b9ffad | ||
|
|
a6b7d76544 | ||
|
|
442ea7ec70 | ||
|
|
747da52c0b | ||
|
|
cd3f4a72d6 | ||
|
|
2c852c85c6 | ||
|
|
434ec84837 | ||
|
|
2b618cd83c | ||
|
|
f4327529b9 | ||
|
|
67189f4d44 | ||
|
|
6225fb4dfd |
14
.gitignore
vendored
14
.gitignore
vendored
@@ -1,15 +1,3 @@
|
|||||||
node_modules
|
node_modules
|
||||||
bower_components
|
bower_components
|
||||||
build
|
/y.*
|
||||||
build_test
|
|
||||||
.directory
|
|
||||||
.codio
|
|
||||||
.settings
|
|
||||||
.jshintignore
|
|
||||||
.jshintrc
|
|
||||||
.validate.json
|
|
||||||
/y.js
|
|
||||||
/y.js.map
|
|
||||||
/y-*
|
|
||||||
.vscode
|
|
||||||
jsconfig.json
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
/* @flow */
|
/* global Y, chat */
|
||||||
/* global Y */
|
|
||||||
|
|
||||||
// initialize a shared object. This function call returns a promise!
|
// initialize a shared object. This function call returns a promise!
|
||||||
Y({
|
Y({
|
||||||
@@ -17,10 +16,10 @@ Y({
|
|||||||
}).then(function (y) {
|
}).then(function (y) {
|
||||||
window.yChat = y
|
window.yChat = y
|
||||||
// This functions inserts a message at the specified position in the DOM
|
// This functions inserts a message at the specified position in the DOM
|
||||||
function appendMessage(message, position) {
|
function appendMessage (message, position) {
|
||||||
var p = document.createElement('p')
|
var p = document.createElement('p')
|
||||||
var uname = document.createElement('span')
|
var uname = document.createElement('span')
|
||||||
uname.appendChild(document.createTextNode(message.username + ": "))
|
uname.appendChild(document.createTextNode(message.username + ': '))
|
||||||
p.appendChild(uname)
|
p.appendChild(uname)
|
||||||
p.appendChild(document.createTextNode(message.message))
|
p.appendChild(document.createTextNode(message.message))
|
||||||
document.querySelector('#chat').insertBefore(p, chat.children[position] || null)
|
document.querySelector('#chat').insertBefore(p, chat.children[position] || null)
|
||||||
@@ -28,23 +27,22 @@ Y({
|
|||||||
// This function makes sure that only 7 messages exist in the chat history.
|
// This function makes sure that only 7 messages exist in the chat history.
|
||||||
// The rest is deleted
|
// The rest is deleted
|
||||||
function cleanupChat () {
|
function cleanupChat () {
|
||||||
var len
|
if (y.share.chat.length > 7) {
|
||||||
while ((len = y.share.chat.length) > 7) {
|
y.share.chat.delete(0, y.chat.length - 7)
|
||||||
y.share.chat.delete(0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Insert the initial content
|
// Insert the initial content
|
||||||
y.share.chat.toArray().forEach(appendMessage)
|
y.share.chat.toArray().forEach(appendMessage)
|
||||||
cleanupChat()
|
cleanupChat()
|
||||||
|
|
||||||
// whenever content changes, make sure to reflect the changes in the DOM
|
// whenever content changes, make sure to reflect the changes in the DOM
|
||||||
y.share.chat.observe(function (event) {
|
y.share.chat.observe(function (event) {
|
||||||
if (event.type === 'insert') {
|
if (event.type === 'insert') {
|
||||||
for (var i = 0; i < event.length; i++) {
|
for (let i = 0; i < event.length; i++) {
|
||||||
appendMessage(event.values[i], event.index + i)
|
appendMessage(event.values[i], event.index + i)
|
||||||
}
|
}
|
||||||
} else if (event.type === 'delete') {
|
} else if (event.type === 'delete') {
|
||||||
for (var i = 0; i < event.length; i++) {
|
for (let i = 0; i < event.length; i++) {
|
||||||
chat.children[event.index].remove()
|
chat.children[event.index].remove()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,8 +52,8 @@ Y({
|
|||||||
document.querySelector('#chatform').onsubmit = function (event) {
|
document.querySelector('#chatform').onsubmit = function (event) {
|
||||||
// the form is submitted
|
// the form is submitted
|
||||||
var message = {
|
var message = {
|
||||||
username: this.querySelector("[name=username]").value,
|
username: this.querySelector('[name=username]').value,
|
||||||
message: this.querySelector("[name=message]").value
|
message: this.querySelector('[name=message]').value
|
||||||
}
|
}
|
||||||
if (message.username.length > 0 && message.message.length > 0) {
|
if (message.username.length > 0 && message.message.length > 0) {
|
||||||
if (y.share.chat.length > 6) {
|
if (y.share.chat.length > 6) {
|
||||||
@@ -66,10 +64,10 @@ Y({
|
|||||||
// This will call the observe function (see line 40)
|
// This will call the observe function (see line 40)
|
||||||
// and reflect the change in the DOM
|
// and reflect the change in the DOM
|
||||||
y.share.chat.push([message])
|
y.share.chat.push([message])
|
||||||
this.querySelector("[name=message]").value = ""
|
this.querySelector('[name=message]').value = ''
|
||||||
}
|
}
|
||||||
// Do not send this form!
|
// Do not send this form!
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -19,11 +19,16 @@ Y({
|
|||||||
}
|
}
|
||||||
}).then(function (y) {
|
}).then(function (y) {
|
||||||
window.yJigsaw = y
|
window.yJigsaw = y
|
||||||
var origin // mouse start position - translation of piece
|
var origin // mouse start position - translation of piece
|
||||||
var drag = d3.behavior.drag()
|
var drag = d3.behavior.drag()
|
||||||
.on('dragstart', function (params) {
|
.on('dragstart', function (params) {
|
||||||
// get the translation of the element
|
// get the translation of the element
|
||||||
var translation = d3.select(this).attr('transform').slice(10,-1).split(',').map(Number)
|
var translation = d3
|
||||||
|
.select(this)
|
||||||
|
.attr('transform')
|
||||||
|
.slice(10, -1)
|
||||||
|
.split(',')
|
||||||
|
.map(Number)
|
||||||
// mouse coordinates
|
// mouse coordinates
|
||||||
var mouse = d3.mouse(this.parentNode)
|
var mouse = d3.mouse(this.parentNode)
|
||||||
origin = {
|
origin = {
|
||||||
@@ -31,11 +36,11 @@ Y({
|
|||||||
y: mouse[1] - translation[1]
|
y: mouse[1] - translation[1]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.on("drag", function(){
|
.on('drag', function () {
|
||||||
var mouse = d3.mouse(this.parentNode)
|
var mouse = d3.mouse(this.parentNode)
|
||||||
var x = mouse[0] - origin.x // =^= mouse - mouse at dragstart + translation at dragstart
|
var x = mouse[0] - origin.x // =^= mouse - mouse at dragstart + translation at dragstart
|
||||||
var y = mouse[1] - origin.y
|
var y = mouse[1] - origin.y
|
||||||
d3.select(this).attr("transform", "translate(" + x + "," + y + ")")
|
d3.select(this).attr('transform', 'translate(' + x + ',' + y + ')')
|
||||||
})
|
})
|
||||||
.on('dragend', function (piece, i) {
|
.on('dragend', function (piece, i) {
|
||||||
// save the current translation of the puzzle piece
|
// save the current translation of the puzzle piece
|
||||||
@@ -46,24 +51,24 @@ Y({
|
|||||||
})
|
})
|
||||||
|
|
||||||
var data = [y.share.piece1, y.share.piece2, y.share.piece3, y.share.piece4]
|
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)
|
var pieces = d3.select(document.querySelector('#puzzle-example')).selectAll('path').data(data)
|
||||||
|
|
||||||
pieces
|
pieces
|
||||||
.classed('draggable', true)
|
.classed('draggable', true)
|
||||||
.attr("transform", function (piece) {
|
.attr('transform', function (piece) {
|
||||||
var translation = piece.get('translation') || {x: 0, y: 0}
|
var translation = piece.get('translation') || {x: 0, y: 0}
|
||||||
return "translate(" + translation.x + "," + translation.y + ")"
|
return 'translate(' + translation.x + ',' + translation.y + ')'
|
||||||
}).call(drag)
|
}).call(drag)
|
||||||
|
|
||||||
data.forEach(function(piece){
|
data.forEach(function (piece) {
|
||||||
piece.observe(function () {
|
piece.observe(function () {
|
||||||
// whenever a property of a piece changes, update the translation of the pieces
|
// whenever a property of a piece changes, update the translation of the pieces
|
||||||
pieces
|
pieces
|
||||||
.transition()
|
.transition()
|
||||||
.attr("transform", function (piece) {
|
.attr('transform', function (piece) {
|
||||||
var translation = piece.get('translation') || {x: 0, y: 0}
|
var translation = piece.get('translation') || {x: 0, y: 0}
|
||||||
return "translate(" + translation.x + "," + translation.y + ")"
|
return 'translate(' + translation.x + ',' + translation.y + ')'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/* global Y */
|
/* global Y, monaco */
|
||||||
|
|
||||||
require.config({ paths: { 'vs': '../node_modules/monaco-editor/min/vs' }})
|
require.config({ paths: { 'vs': '../node_modules/monaco-editor/min/vs' } })
|
||||||
require(['vs/editor/editor.main'], function() {
|
|
||||||
|
|
||||||
|
require(['vs/editor/editor.main'], function () {
|
||||||
// Initialize a shared object. This function call returns a promise!
|
// Initialize a shared object. This function call returns a promise!
|
||||||
Y({
|
Y({
|
||||||
db: {
|
db: {
|
||||||
@@ -28,4 +28,3 @@ require(['vs/editor/editor.main'], function() {
|
|||||||
y.share.monaco.bindMonaco(editor)
|
y.share.monaco.bindMonaco(editor)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
1173
examples/package-lock.json
generated
Normal file
1173
examples/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,5 +6,11 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"monaco-editor": "^0.8.3"
|
"monaco-editor": "^0.8.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"standard": "^10.0.2"
|
||||||
|
},
|
||||||
|
"standard": {
|
||||||
|
"ignore": ["bower_components"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,11 +29,11 @@ Y({
|
|||||||
[{ script: 'sub' }, { script: 'super' }],
|
[{ script: 'sub' }, { script: 'super' }],
|
||||||
['link', 'image'],
|
['link', 'image'],
|
||||||
['link', 'code-block'],
|
['link', 'code-block'],
|
||||||
[{list: 'ordered' }]
|
[{ 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,13 +1,13 @@
|
|||||||
/* global Y, Quill */
|
/* global Y, Quill */
|
||||||
|
|
||||||
// register yjs service worker
|
// register yjs service worker
|
||||||
if('serviceWorker' in navigator){
|
if ('serviceWorker' in navigator) {
|
||||||
// Register service worker
|
// Register service worker
|
||||||
// it is important to copy yjs-sw-template to the root directory!
|
// it is important to copy yjs-sw-template to the root directory!
|
||||||
navigator.serviceWorker.register('./yjs-sw-template.js').then(function(reg){
|
navigator.serviceWorker.register('./yjs-sw-template.js').then(function (reg) {
|
||||||
console.log("Yjs service worker registration succeeded. Scope is " + reg.scope);
|
console.log('Yjs service worker registration succeeded. Scope is ' + reg.scope)
|
||||||
}).catch(function(err){
|
}).catch(function (err) {
|
||||||
console.error("Yjs service worker registration failed with error " + err);
|
console.error('Yjs service worker registration failed with error ' + err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ Y({
|
|||||||
[{ script: 'sub' }, { script: 'super' }],
|
[{ script: 'sub' }, { script: 'super' }],
|
||||||
['link', 'image'],
|
['link', 'image'],
|
||||||
['link', 'code-block'],
|
['link', 'code-block'],
|
||||||
[{list: 'ordered' }]
|
[{ list: 'ordered' }]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
theme: 'snow'
|
theme: 'snow'
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<script src="../../../y-array/y-array.js"></script>
|
<script src="../../../y-array/y-array.js"></script>
|
||||||
<script src="../../../y-text/dist/y-text.js"></script>
|
<script src="../../../y-text/dist/y-text.js"></script>
|
||||||
<script src="../../../y-memory/y-memory.js"></script>
|
<script src="../../../y-memory/y-memory.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>
|
<script src="./index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Y({
|
|||||||
},
|
},
|
||||||
connector: {
|
connector: {
|
||||||
name: 'websockets-client',
|
name: 'websockets-client',
|
||||||
room: 'Textarea-example'
|
room: 'Textarea-example-dev'
|
||||||
// url: '127.0.0.1:1234'
|
// url: '127.0.0.1:1234'
|
||||||
},
|
},
|
||||||
sourceDir: '/bower_components',
|
sourceDir: '/bower_components',
|
||||||
|
|||||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "yjs",
|
"name": "yjs",
|
||||||
"version": "13.0.0-1",
|
"version": "13.0.0-7",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": {
|
"acorn": {
|
||||||
|
|||||||
12
package.json
12
package.json
@@ -1,13 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "yjs",
|
"name": "yjs",
|
||||||
"version": "13.0.0-1",
|
"version": "13.0.0-7",
|
||||||
"description": "A framework for real-time p2p shared editing on any data",
|
"description": "A framework for real-time p2p shared editing on any data",
|
||||||
"main": "./src/y.js",
|
"main": "./y.node.js",
|
||||||
|
"browser": "./y.js",
|
||||||
|
"module": "./src/y.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"test": "npm run lint",
|
||||||
"lint": "standard",
|
"lint": "standard",
|
||||||
"dist": "rollup -c rollup.dist.js",
|
"dist": "rollup -c rollup.browser.js; rollup -c rollup.node.js",
|
||||||
"serve": "concurrently 'serve ..' 'rollup -wc rollup.dist.js -o examples/bower_components/yjs/y.js'",
|
"postversion": "npm run dist",
|
||||||
"postversion": "npm run lint && npm run dist",
|
|
||||||
"postpublish": "tag-dist-files --overwrite-existing-tag"
|
"postpublish": "tag-dist-files --overwrite-existing-tag"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
|||||||
26
rollup.node.js
Normal file
26
rollup.node.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import nodeResolve from 'rollup-plugin-node-resolve'
|
||||||
|
import commonjs from 'rollup-plugin-commonjs'
|
||||||
|
var pkg = require('./package.json')
|
||||||
|
|
||||||
|
export default {
|
||||||
|
entry: 'src/y.js',
|
||||||
|
moduleName: 'Y',
|
||||||
|
format: 'umd',
|
||||||
|
plugins: [
|
||||||
|
nodeResolve({
|
||||||
|
main: true,
|
||||||
|
module: true,
|
||||||
|
browser: true
|
||||||
|
}),
|
||||||
|
commonjs()
|
||||||
|
],
|
||||||
|
dest: 'y.node.js',
|
||||||
|
sourceMap: true,
|
||||||
|
banner: `
|
||||||
|
/**
|
||||||
|
* ${pkg.name} - ${pkg.description}
|
||||||
|
* @version v${pkg.version}
|
||||||
|
* @license ${pkg.license}
|
||||||
|
*/
|
||||||
|
`
|
||||||
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
/* @flow */
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
function canRead (auth) { return auth === 'read' || auth === 'write' }
|
function canRead (auth) { return auth === 'read' || auth === 'write' }
|
||||||
function canWrite (auth) { return auth === 'write' }
|
function canWrite (auth) { return auth === 'write' }
|
||||||
@@ -143,7 +141,9 @@ export default function extendConnector (Y/* :any */) {
|
|||||||
this.log('User joined: %s', user)
|
this.log('User joined: %s', user)
|
||||||
this.connections[user] = {
|
this.connections[user] = {
|
||||||
isSynced: false,
|
isSynced: false,
|
||||||
role: role
|
role: role,
|
||||||
|
waitingMessages: [],
|
||||||
|
auth: null
|
||||||
}
|
}
|
||||||
let defer = {}
|
let defer = {}
|
||||||
defer.promise = new Promise(function (resolve) { defer.resolve = resolve })
|
defer.promise = new Promise(function (resolve) { defer.resolve = resolve })
|
||||||
@@ -269,11 +269,20 @@ export default function extendConnector (Y/* :any */) {
|
|||||||
})
|
})
|
||||||
return Promise.reject(new Error('Incompatible protocol version'))
|
return Promise.reject(new Error('Incompatible protocol version'))
|
||||||
}
|
}
|
||||||
if (message.auth != null && this.connections[sender] != null) {
|
if ((message.type === 'sync step 1' || message.type === 'sync step 2') && this.connections[sender] != null && this.connections[sender].auth == null) {
|
||||||
// authenticate using auth in message
|
// authenticate using auth in message
|
||||||
var auth = this.checkAuth(message.auth, this.y)
|
var auth = this.checkAuth(message.auth, this.y)
|
||||||
this.connections[sender].auth = auth
|
this.connections[sender].auth = auth
|
||||||
auth.then(auth => {
|
auth.then(auth => {
|
||||||
|
// in case operations were received before sender was received
|
||||||
|
// we apply the messages after authentication
|
||||||
|
this.connections[sender].syncStep2.promise.then(() => {
|
||||||
|
// we do it after sync step 1
|
||||||
|
this.connections[sender].waitingMessages.forEach(msg => {
|
||||||
|
this.receiveMessage(sender, msg)
|
||||||
|
})
|
||||||
|
this.connections[sender].waitingMessages = null
|
||||||
|
})
|
||||||
for (var f of this.userEventListeners) {
|
for (var f of this.userEventListeners) {
|
||||||
f({
|
f({
|
||||||
action: 'userAuthenticated',
|
action: 'userAuthenticated',
|
||||||
@@ -282,9 +291,6 @@ export default function extendConnector (Y/* :any */) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else if (this.connections[sender] != null && this.connections[sender].auth == null) {
|
|
||||||
// authenticate without otherwise
|
|
||||||
this.connections[sender].auth = this.checkAuth(null, this.y)
|
|
||||||
}
|
}
|
||||||
if (this.connections[sender] != null && this.connections[sender].auth != null) {
|
if (this.connections[sender] != null && this.connections[sender].auth != null) {
|
||||||
return this.connections[sender].auth.then((auth) => {
|
return this.connections[sender].auth.then((auth) => {
|
||||||
@@ -384,8 +390,13 @@ export default function extendConnector (Y/* :any */) {
|
|||||||
this.y.db.apply(message.ops)
|
this.y.db.apply(message.ops)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
} else if (this.connections[sender] != null) {
|
||||||
|
// wait for authentication
|
||||||
|
let senderConn = this.connections[sender]
|
||||||
|
senderConn.waitingMessages = senderConn.waitingMessages || []
|
||||||
|
senderConn.waitingMessages.push(message)
|
||||||
} else {
|
} else {
|
||||||
return Promise.reject(new Error('Unable to deliver message'))
|
return Promise.reject(new Error('Unknown user - Unable to deliver message'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_setSyncedWith (user) {
|
_setSyncedWith (user) {
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ export default function extendTransaction (Y) {
|
|||||||
send.push(Y.Struct[op.struct].encode(op))
|
send.push(Y.Struct[op.struct].encode(op))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.store.y.connector.isSynced && send.length > 0) { // TODO: && !this.store.forwardAppliedOperations (but then i don't send delete ops)
|
if (send.length > 0) { // TODO: && !this.store.forwardAppliedOperations (but then i don't send delete ops)
|
||||||
// is connected, and this is not going to be send in addOperation
|
// is connected, and this is not going to be send in addOperation
|
||||||
this.store.y.connector.broadcastOps(send)
|
this.store.y.connector.broadcastOps(send)
|
||||||
}
|
}
|
||||||
@@ -712,7 +712,7 @@ export default function extendTransaction (Y) {
|
|||||||
}
|
}
|
||||||
* addOperation (op) {
|
* addOperation (op) {
|
||||||
yield * this.os.put(op)
|
yield * this.os.put(op)
|
||||||
if (this.store.y.connector.isSynced && this.store.forwardAppliedOperations && typeof op.id[1] !== 'string') {
|
if (this.store.forwardAppliedOperations && typeof op.id[1] !== 'string') {
|
||||||
// is connected, and this is not going to be send in addOperation
|
// is connected, and this is not going to be send in addOperation
|
||||||
this.store.y.connector.broadcastOps([op])
|
this.store.y.connector.broadcastOps([op])
|
||||||
}
|
}
|
||||||
|
|||||||
1
y.node.js.map
Normal file
1
y.node.js.map
Normal file
File diff suppressed because one or more lines are too long
1
y.test.js.map
Normal file
1
y.test.js.map
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user