From 42abcc897cd1990dca8698cc657faab582758218 Mon Sep 17 00:00:00 2001 From: Kevin Jahns Date: Fri, 19 May 2017 02:21:50 +0200 Subject: [PATCH] added examples --- examples/ace/index.html | 32 +++++++++ examples/ace/index.js | 24 +++++++ examples/bower.json | 29 ++++++++ examples/chat/index.html | 18 +++++ examples/chat/index.js | 75 ++++++++++++++++++++ examples/codemirror/index.html | 23 +++++++ examples/codemirror/index.js | 24 +++++++ examples/drawing/index.html | 19 +++++ examples/drawing/index.js | 84 +++++++++++++++++++++++ examples/jigsaw/index.html | 23 +++++++ examples/jigsaw/index.js | 69 +++++++++++++++++++ examples/monaco/index.html | 24 +++++++ examples/monaco/index.js | 31 +++++++++ examples/package.json | 10 +++ examples/quill/index.html | 31 +++++++++ examples/quill/index.js | 39 +++++++++++ examples/serviceworker/index.html | 31 +++++++++ examples/serviceworker/index.js | 49 +++++++++++++ examples/serviceworker/yjs-sw-template.js | 22 ++++++ examples/textarea/index.html | 8 +++ examples/textarea/index.js | 23 +++++++ examples/xml/index.html | 39 +++++++++++ examples/xml/index.js | 21 ++++++ package.json | 5 +- rollup.dist.js | 2 +- 25 files changed, 753 insertions(+), 2 deletions(-) create mode 100644 examples/ace/index.html create mode 100644 examples/ace/index.js create mode 100644 examples/bower.json create mode 100644 examples/chat/index.html create mode 100644 examples/chat/index.js create mode 100644 examples/codemirror/index.html create mode 100644 examples/codemirror/index.js create mode 100644 examples/drawing/index.html create mode 100644 examples/drawing/index.js create mode 100644 examples/jigsaw/index.html create mode 100644 examples/jigsaw/index.js create mode 100644 examples/monaco/index.html create mode 100644 examples/monaco/index.js create mode 100644 examples/package.json create mode 100644 examples/quill/index.html create mode 100644 examples/quill/index.js create mode 100644 examples/serviceworker/index.html create mode 100644 examples/serviceworker/index.js create mode 100644 examples/serviceworker/yjs-sw-template.js create mode 100644 examples/textarea/index.html create mode 100644 examples/textarea/index.js create mode 100644 examples/xml/index.html create mode 100644 examples/xml/index.js diff --git a/examples/ace/index.html b/examples/ace/index.html new file mode 100644 index 00000000..c1c5242e --- /dev/null +++ b/examples/ace/index.html @@ -0,0 +1,32 @@ + + + + + + + +
+ + + + + + diff --git a/examples/ace/index.js b/examples/ace/index.js new file mode 100644 index 00000000..8228968a --- /dev/null +++ b/examples/ace/index.js @@ -0,0 +1,24 @@ +/* global Y, ace */ + +Y({ + db: { + name: 'memory' + }, + connector: { + name: 'websockets-client', + room: 'ace-example' + }, + sourceDir: '/bower_components', + share: { + ace: 'Text' // y.share.textarea is of type Y.Text + } +}).then(function (y) { + window.yAce = y + + // bind the textarea to a shared text element + var editor = ace.edit('aceContainer') + editor.setTheme('ace/theme/chrome') + editor.getSession().setMode('ace/mode/javascript') + + y.share.ace.bindAce(editor) +}) diff --git a/examples/bower.json b/examples/bower.json new file mode 100644 index 00000000..d4114831 --- /dev/null +++ b/examples/bower.json @@ -0,0 +1,29 @@ +{ + "name": "yjs-examples", + "version": "0.0.0", + "homepage": "y-js.org", + "authors": [ + "Kevin Jahns " + ], + "description": "Examples for Yjs", + "license": "MIT", + "ignore": [], + "dependencies": { + "yjs": "latest", + "y-array": "latest", + "y-map": "latest", + "y-memory": "latest", + "y-richtext": "latest", + "y-webrtc": "latest", + "y-websockets-client": "latest", + "y-text": "latest", + "y-indexeddb": "latest", + "y-xml": "latest", + "quill": "^1.0.0-rc.2", + "ace": "~1.2.3", + "ace-builds": "~1.2.3", + "jquery": "~2.2.2", + "d3": "^3.5.16", + "codemirror": "^5.25.0" + } +} diff --git a/examples/chat/index.html b/examples/chat/index.html new file mode 100644 index 00000000..c6edee7f --- /dev/null +++ b/examples/chat/index.html @@ -0,0 +1,18 @@ + + + + +
+
+ + + +
+ + + + diff --git a/examples/chat/index.js b/examples/chat/index.js new file mode 100644 index 00000000..39369597 --- /dev/null +++ b/examples/chat/index.js @@ -0,0 +1,75 @@ +/* @flow */ +/* global Y */ + +// initialize a shared object. This function call returns a promise! +Y({ + db: { + name: 'memory' + }, + connector: { + name: 'websockets-client', + room: 'chat-example' + }, + sourceDir: '/bower_components', + share: { + chat: 'Array' + } +}).then(function (y) { + window.yChat = y + // This functions inserts a message at the specified position in the DOM + function appendMessage(message, position) { + var p = document.createElement('p') + var uname = document.createElement('span') + uname.appendChild(document.createTextNode(message.username + ": ")) + p.appendChild(uname) + p.appendChild(document.createTextNode(message.message)) + document.querySelector('#chat').insertBefore(p, chat.children[position] || null) + } + // This function makes sure that only 7 messages exist in the chat history. + // The rest is deleted + function cleanupChat () { + var len + while ((len = y.share.chat.length) > 7) { + y.share.chat.delete(0) + } + } + // Insert the initial content + y.share.chat.toArray().forEach(appendMessage) + cleanupChat() + + // whenever content changes, make sure to reflect the changes in the DOM + y.share.chat.observe(function (event) { + if (event.type === 'insert') { + for (var i = 0; i < event.length; i++) { + appendMessage(event.values[i], event.index + i) + } + } else if (event.type === 'delete') { + for (var i = 0; i < event.length; i++) { + chat.children[event.index].remove() + } + } + // concurrent insertions may result in a history > 7, so cleanup here + cleanupChat() + }) + document.querySelector('#chatform').onsubmit = function (event) { + // the form is submitted + var message = { + username: this.querySelector("[name=username]").value, + message: this.querySelector("[name=message]").value + } + if (message.username.length > 0 && message.message.length > 0) { + if (y.share.chat.length > 6) { + // If we are goint to insert the 8th element, make sure to delete first. + y.share.chat.delete(0) + } + // Here we insert a message in the shared chat type. + // This will call the observe function (see line 40) + // and reflect the change in the DOM + y.share.chat.push([message]) + this.querySelector("[name=message]").value = "" + } + // Do not send this form! + event.preventDefault() + return false + } +}) \ No newline at end of file diff --git a/examples/codemirror/index.html b/examples/codemirror/index.html new file mode 100644 index 00000000..eef60f2f --- /dev/null +++ b/examples/codemirror/index.html @@ -0,0 +1,23 @@ + + + + + +
+ + + + + + + + + diff --git a/examples/codemirror/index.js b/examples/codemirror/index.js new file mode 100644 index 00000000..b307579b --- /dev/null +++ b/examples/codemirror/index.js @@ -0,0 +1,24 @@ +/* global Y, CodeMirror */ + +// initialize a shared object. This function call returns a promise! +Y({ + db: { + name: 'memory' + }, + connector: { + name: 'websockets-client', + room: 'codemirror-example' + }, + sourceDir: '/bower_components', + share: { + codemirror: 'Text' // y.share.codemirror is of type Y.Text + } +}).then(function (y) { + window.yCodeMirror = y + + var editor = CodeMirror(document.querySelector('#codeMirrorContainer'), { + mode: 'javascript', + lineNumbers: true + }) + y.share.codemirror.bindCodeMirror(editor) +}) diff --git a/examples/drawing/index.html b/examples/drawing/index.html new file mode 100644 index 00000000..75e4ed53 --- /dev/null +++ b/examples/drawing/index.html @@ -0,0 +1,19 @@ + + + + + + + + + + + diff --git a/examples/drawing/index.js b/examples/drawing/index.js new file mode 100644 index 00000000..7d954967 --- /dev/null +++ b/examples/drawing/index.js @@ -0,0 +1,84 @@ +/* globals Y, d3 */ +'strict mode' + +Y({ + db: { + name: 'memory' + }, + connector: { + name: 'websockets-client', + room: 'drawing-example' + // url: 'localhost:1234' + }, + sourceDir: '/bower_components', + share: { + drawing: 'Array' + } +}).then(function (y) { + window.yDrawing = y + var drawing = y.share.drawing + var renderPath = d3.svg.line() + .x(function (d) { return d[0] }) + .y(function (d) { return d[1] }) + .interpolate('basis') + + var svg = d3.select('#drawingCanvas') + .call(d3.behavior.drag() + .on('dragstart', dragstart) + .on('drag', drag) + .on('dragend', dragend)) + + // create line from a shared array object and update the line when the array changes + function drawLine (yarray) { + var line = svg.append('path').datum(yarray.toArray()) + line.attr('d', renderPath) + yarray.observe(function (event) { + // we only implement insert events that are appended to the end of the array + event.values.forEach(function (value) { + line.datum().push(value) + }) + line.attr('d', renderPath) + }) + } + // call drawLine every time an array is appended + y.share.drawing.observe(function (event) { + if (event.type === 'insert') { + event.values.forEach(drawLine) + } else { + // just remove all elements (thats what we do anyway) + svg.selectAll('path').remove() + } + }) + // draw all existing content + for (var i = 0; i < drawing.length; i++) { + drawLine(drawing.get(i)) + } + + // clear canvas on request + document.querySelector('#clearDrawingCanvas').onclick = function () { + drawing.delete(0, drawing.length) + } + + var sharedLine = null + function dragstart () { + drawing.insert(drawing.length, [Y.Array]) + sharedLine = drawing.get(drawing.length - 1) + } + + // After one dragged event is recognized, we ignore them for 33ms. + var ignoreDrag = null + function drag () { + if (sharedLine != null && ignoreDrag == null) { + ignoreDrag = window.setTimeout(function () { + ignoreDrag = null + }, 33) + sharedLine.push([d3.mouse(this)]) + } + } + + function dragend () { + sharedLine = null + window.clearTimeout(ignoreDrag) + ignoreDrag = null + } +}) diff --git a/examples/jigsaw/index.html b/examples/jigsaw/index.html new file mode 100644 index 00000000..028306fd --- /dev/null +++ b/examples/jigsaw/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + diff --git a/examples/jigsaw/index.js b/examples/jigsaw/index.js new file mode 100644 index 00000000..ba535daa --- /dev/null +++ b/examples/jigsaw/index.js @@ -0,0 +1,69 @@ +/* @flow */ +/* global Y, d3 */ + +// initialize a shared object. This function call returns a promise! +Y({ + db: { + name: 'memory' + }, + connector: { + name: 'websockets-client', + room: 'Puzzle-example' + }, + sourceDir: '/bower_components', + share: { + piece1: 'Map', + piece2: 'Map', + piece3: 'Map', + piece4: 'Map' + } +}).then(function (y) { + window.yJigsaw = y + var origin // mouse start position - translation of piece + var drag = d3.behavior.drag() + .on('dragstart', function (params) { + // get the translation of the element + var translation = d3.select(this).attr('transform').slice(10,-1).split(',').map(Number) + // mouse coordinates + var mouse = d3.mouse(this.parentNode) + origin = { + x: mouse[0] - translation[0], + y: mouse[1] - translation[1] + } + }) + .on("drag", function(){ + var mouse = d3.mouse(this.parentNode) + var x = mouse[0] - origin.x // =^= mouse - mouse at dragstart + translation at dragstart + var y = mouse[1] - origin.y + d3.select(this).attr("transform", "translate(" + x + "," + y + ")") + }) + .on('dragend', function (piece, i) { + // save the current translation of the puzzle piece + var mouse = d3.mouse(this.parentNode) + var x = mouse[0] - origin.x + var y = mouse[1] - origin.y + piece.set('translation', {x: x, y: y}) + }) + + 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) + + 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){ + 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 + ")" + }) + }) + }) +}) \ No newline at end of file diff --git a/examples/monaco/index.html b/examples/monaco/index.html new file mode 100644 index 00000000..cfd3cd0c --- /dev/null +++ b/examples/monaco/index.html @@ -0,0 +1,24 @@ + + + + + +
+ + + + + + + + + + diff --git a/examples/monaco/index.js b/examples/monaco/index.js new file mode 100644 index 00000000..76fe1916 --- /dev/null +++ b/examples/monaco/index.js @@ -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) + }) +}) + diff --git a/examples/package.json b/examples/package.json new file mode 100644 index 00000000..1340c78a --- /dev/null +++ b/examples/package.json @@ -0,0 +1,10 @@ +{ + "name": "examples", + "version": "0.0.0", + "description": "", + "author": "Kevin Jahns", + "license": "MIT", + "dependencies": { + "monaco-editor": "^0.8.3" + } +} diff --git a/examples/quill/index.html b/examples/quill/index.html new file mode 100644 index 00000000..d0aea5a7 --- /dev/null +++ b/examples/quill/index.html @@ -0,0 +1,31 @@ + + + + + + + + + + + +
+
+
+
+ + + + + + + + + diff --git a/examples/quill/index.js b/examples/quill/index.js new file mode 100644 index 00000000..b1a441b5 --- /dev/null +++ b/examples/quill/index.js @@ -0,0 +1,39 @@ +/* global Y, Quill */ + +// initialize a shared object. This function call returns a promise! + +Y({ + db: { + name: 'memory' + }, + connector: { + name: 'websockets-client', + room: 'richtext-example-quill-1.0-test' + }, + sourceDir: '/bower_components', + share: { + richtext: 'Richtext' // y.share.richtext is of type Y.Richtext + } +}).then(function (y) { + window.yQuill = y + + // create quill element + window.quill = new Quill('#quill', { + modules: { + formula: 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' + }); + // bind quill to richtext type + y.share.richtext.bind(window.quill) +}) \ No newline at end of file diff --git a/examples/serviceworker/index.html b/examples/serviceworker/index.html new file mode 100644 index 00000000..d0aea5a7 --- /dev/null +++ b/examples/serviceworker/index.html @@ -0,0 +1,31 @@ + + + + + + + + + + + +
+
+
+
+ + + + + + + + + diff --git a/examples/serviceworker/index.js b/examples/serviceworker/index.js new file mode 100644 index 00000000..f4db86ca --- /dev/null +++ b/examples/serviceworker/index.js @@ -0,0 +1,49 @@ +/* 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! +Y({ + db: { + name: 'memory' + }, + connector: { + name: 'serviceworker', + room: 'ServiceWorkerExample2' + }, + sourceDir: '/bower_components', + share: { + richtext: 'Richtext' // y.share.richtext is of type Y.Richtext + } +}).then(function (y) { + window.yServiceWorker = y + + // create quill element + window.quill = new Quill('#quill', { + modules: { + formula: 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' + }) + // bind quill to richtext type + y.share.richtext.bind(window.quill) +}) diff --git a/examples/serviceworker/yjs-sw-template.js b/examples/serviceworker/yjs-sw-template.js new file mode 100644 index 00000000..0fc8dd13 --- /dev/null +++ b/examples/serviceworker/yjs-sw-template.js @@ -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' +) diff --git a/examples/textarea/index.html b/examples/textarea/index.html new file mode 100644 index 00000000..62d3713e --- /dev/null +++ b/examples/textarea/index.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/examples/textarea/index.js b/examples/textarea/index.js new file mode 100644 index 00000000..407e1e51 --- /dev/null +++ b/examples/textarea/index.js @@ -0,0 +1,23 @@ +/* global Y */ + +// initialize a shared object. This function call returns a promise! +Y({ + db: { + name: 'memory' + }, + connector: { + name: 'websockets-client', + room: 'Textarea-example' + // url: '127.0.0.1:1234' + }, + sourceDir: '/bower_components', + share: { + textarea: 'Text' // y.share.textarea is of type Y.Text + } +}).then(function (y) { + window.yTextarea = y + + // bind the textarea to a shared text element + y.share.textarea.bind(document.getElementById('textfield')) + // thats it.. +}) diff --git a/examples/xml/index.html b/examples/xml/index.html new file mode 100644 index 00000000..ab8c93e5 --- /dev/null +++ b/examples/xml/index.html @@ -0,0 +1,39 @@ + + + + + + + + +

Shared DOM Example

+

Use native DOM function or jQuery to manipulate the shared DOM (window.sharedDom).

+
+ + +
+
+ + +
+
+ + +
+ + + + diff --git a/examples/xml/index.js b/examples/xml/index.js new file mode 100644 index 00000000..8a0f026e --- /dev/null +++ b/examples/xml/index.js @@ -0,0 +1,21 @@ +/* global Y */ + +// initialize a shared object. This function call returns a promise! +Y({ + db: { + name: 'memory' + }, + connector: { + name: 'websockets-client', + room: 'Xml-example' + }, + sourceDir: '/bower_components', + share: { + xml: 'Xml("p")' // y.share.xml is of type Y.Xml with tagname "p" + } +}).then(function (y) { + window.yXml = y + // bind xml type to a dom, and put it in body + window.sharedDom = y.share.xml.getDom() + document.body.appendChild(window.sharedDom) +}) diff --git a/package.json b/package.json index e9a981dc..2f304c43 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "./src/y.js", "scripts": { "lint": "standard", - "dist": "rollup -c rollup.dist.js" + "dist": "rollup -c rollup.dist.js", + "serve": "concurrently 'serve examples' 'rollup -wc rollup.dist.js -o examples/bower_components/yjs/y.js'" }, "pre-commit": [ "lint", @@ -42,8 +43,10 @@ "babel-plugin-external-helpers": "^6.22.0", "babel-plugin-transform-regenerator": "^6.24.1", "babel-plugin-transform-runtime": "^6.23.0", + "concurrently": "^3.4.0", "rollup-plugin-babel": "^2.7.1", "rollup-plugin-commonjs": "^8.0.2", + "rollup-plugin-inject": "^2.0.0", "rollup-plugin-multi-entry": "^2.0.1", "rollup-plugin-node-resolve": "^3.0.0", "rollup-plugin-uglify": "^1.0.2", diff --git a/rollup.dist.js b/rollup.dist.js index 0ec4b137..6c3f1777 100644 --- a/rollup.dist.js +++ b/rollup.dist.js @@ -7,7 +7,7 @@ var pkg = require('./package.json') export default { entry: 'src/y.js', - moduleName: 'yjs', + moduleName: 'Y', format: 'umd', plugins: [ nodeResolve({