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).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+