jsonsync
Version:
Transport-agnostic operation-rich peer-to-peer JSON synchronization
159 lines (151 loc) • 5.31 kB
HTML
<meta charset=utf-8><title> JsonSync demo </title>
<h1> JsonSync </h1>
<p>Transport-agnostic operation-rich peer-to-peer JSON synchronization.
Open-source (MIT) on <a href='https://github.com/espadrine/jsonsync'>GitHub</a>.
</p>
<h1> Demonstration </h1>
<p> Here are two JSON editors. We simulate a 2-second latency between the two.
</p>
<section id=demos>
<div id=demo1></div>
<div id=demo2></div>
</section>
<style>
#demos { display: flex; }
#demos > div { width: 50%; }
#demos ol { margin-top: 0; margin-bottom: 0; padding: 0; }
</style>
<script src=./jsonsync.js></script>
<script>
// JSON editor implemented over DOM.
var jsonEditor = function(dom, jsonsync) {
var json = {}
var changeValue = function(event) {
event.target.dataset.path
}
var deleteValue = function(event) {
var path = event.target.dataset.path
jsonsync.remove(path)
json = jsonsync.content
showJson(json)
}
var insertValueToArray = function(event) {
var path = event.target.dataset.path
var key = prompt("Enter a JSON index wherein to insert a value.")
var value = prompt("Enter a JSON value to insert.")
try {
value = JSON.parse(value)
} catch(e) { alert(e); return }
jsonsync.add(path + '/' + (+key), value)
json = jsonsync.content
showJson(json)
}
var insertValueToObject = function(event) {
var path = event.target.dataset.path
var key = prompt("Enter a JSON key wherein to insert a value.")
var value = prompt("Enter a JSON value to insert.")
try {
value = JSON.parse(value)
} catch(e) { alert(e); return }
jsonsync.add(path + '/' + key, value)
json = jsonsync.content
showJson(json)
}
var domFromJson = function(json, path) {
var div = document.createElement('div')
if (json === null || typeof json === 'boolean' || typeof json === 'number'
|| typeof json === 'string') {
var value = document.createElement('div')
value.textContent = JSON.stringify(json)
value.dataset.path = path
value.addEventListener('click', changeValue)
value.style.display = 'inline'
var button = document.createElement('button')
button.textContent = 'delete'
button.dataset.path = path
button.addEventListener('click', deleteValue)
div.appendChild(value)
div.appendChild(button)
} else if (Object(json) instanceof Array) {
div = document.createElement('ol')
for (var i = 0; i < json.length; i++) {
var subdiv = domFromJson(json[i], path + '/' + i)
var li = document.createElement('li')
li.appendChild(subdiv)
div.appendChild(li)
}
var insbut = document.createElement('button')
insbut.textContent = 'insert'
insbut.dataset.path = path
insbut.addEventListener('click', insertValueToArray)
var delbut = document.createElement('button')
delbut.textContent = 'delete'
delbut.dataset.path = path
delbut.addEventListener('click', deleteValue)
div.appendChild(insbut)
div.appendChild(delbut)
} else {
for (var key in json) {
var keyDom = document.createElement('div')
keyDom.textContent = key + ':'
div.appendChild(keyDom)
div.appendChild(domFromJson(json[key], path + '/' + key))
}
var insbut = document.createElement('button')
insbut.textContent = 'insert'
insbut.dataset.path = path
insbut.addEventListener('click', insertValueToObject)
var delbut = document.createElement('button')
delbut.textContent = 'delete'
delbut.dataset.path = path
delbut.addEventListener('click', deleteValue)
div.appendChild(insbut)
div.appendChild(delbut)
}
div.style.marginLeft = '20px'
return div
}
var showJson = function(json) {
dom.innerHTML = ''
dom.appendChild(domFromJson(json, ''))
}
showJson(json)
jsonsync.on('update', function() {
json = jsonsync.content
showJson(json)
})
}
// Simulate a network.
var networkLatency = function(f) { setTimeout(f, 2000) }
var channel = function() {
var end1 = {receive: function(){}}, end2 = {receive: function(){}}
end1.send = function(str) { networkLatency(function(){ end2.receive(str) }) }
end1.on = function(evt, listn) { end1[evt] = listn }
end2.send = function(str) { networkLatency(function(){ end1.receive(str) }) }
end2.on = function(evt, listn) { end2[evt] = listn }
return [end1, end2]
}
// Each "real" node has its own Network object.
// The Networks object sets up their interaction.
var Networks = function() { this.networks = [] }
Networks.prototype = {
addNode: function() {
var nodes = this.networks.map(function(network) {
var chan = channel()
network.nodes.push(chan[0])
return chan[1]
})
var network = {nodes: nodes, on: function(){}}
this.networks.push(network)
return network
}
}
var networks = new Networks()
var network1 = networks.addNode()
var network2 = networks.addNode()
var jsonsync1 = new JsonSync({network: network1, value: {}, machine: [0]})
var jsonsync2 = new JsonSync({network: network2, value: {}, machine: [1]})
// Set up the editors.
jsonEditor(document.getElementById('demo1'), jsonsync1)
jsonEditor(document.getElementById('demo2'), jsonsync2)
</script>