- commit
- 06a6cea858a4dc877d5ee6a38322ca5a7c36b974
- parent
- 5804bfc1f454deb651197898693abacd3ca5ef25
- Author
- Tobias Bengfort <tobias.bengfort@posteo.de>
- Date
- 2020-05-05 17:40
storage
Diffstat
M | README.md | 3 | +-- |
M | index.html | 4 | +--- |
M | static/index.js | 46 | ++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 48 insertions, 5 deletions
diff --git a/README.md b/README.md
@@ -10,8 +10,7 @@ one is different. This project concentrates on: 10 10 - **Manual conflict resolution**. No advanced operational transforms, no 11 11 eventual consistency. In practice, conflicts are rare and even sophisticated 12 12 algorithms are not doing a stellar job.13 -1 - **Real time collaboration**. No database, no persistence (for now at least).14 1315 -1 So this is ~170 lines of javascript code backed by a-1 14 So this is ~220 lines of javascript code backed by a 16 15 [via](https://github.com/xi/via) server. A demo is available at 17 16 <https://pad.ce9e.org/>.
diff --git a/index.html b/index.html
@@ -8,9 +8,7 @@ 8 8 <link rel="stylesheet" href="/static/style.css"> 9 9 </head> 10 10 <body>11 -1 <textarea autocomplete="off" readonly autofocus placeholder="Collaborative editor12 -113 -1 Warning: All text is deleted when the last person leaves."></textarea>-1 11 <textarea autocomplete="off" readonly autofocus></textarea> 14 12 <script type="module" src="/static/index.js"></script> 15 13 </body> 16 14 </html>
diff --git a/static/index.js b/static/index.js
@@ -12,6 +12,31 @@ var stagedChanges = []; 12 12 13 13 document.title += ' - ' + room; 14 14 -1 15 var throttled = function(fn, timeout) { -1 16 var blocked = false; -1 17 var needsCall = false; -1 18 -1 19 var wrapper = function(force) { -1 20 if (blocked && !force) { -1 21 needsCall = true; -1 22 return; -1 23 } -1 24 -1 25 fn(); -1 26 blocked = true; -1 27 needsCall = false; -1 28 -1 29 setTimeout(function() { -1 30 blocked = false; -1 31 if (needsCall) { -1 32 wrapper(); -1 33 } -1 34 }, timeout); -1 35 }; -1 36 -1 37 return wrapper; -1 38 }; -1 39 15 40 var setText = function(text, start, end) { 16 41 if (text !== el.value) { 17 42 el.value = text; @@ -21,6 +46,10 @@ var setText = function(text, start, end) { 21 46 } 22 47 }; 23 48 -1 49 var backup = throttled(function() { -1 50 signal.store(room, el.value); -1 51 }, 10000); -1 52 24 53 var applyChanges = function(changes) { 25 54 var text = el.value; 26 55 var selection = [el.selectionStart, el.selectionEnd]; @@ -34,13 +63,28 @@ el.addEventListener('input', function() { 34 63 var change = context.diff(old, el.value, 3); 35 64 context.pushChange(localChanges, change); 36 65 old = el.value; -1 66 backup(); 37 67 }); 38 68 39 69 signal.listen(room, function(msg) { 40 70 if (msg.sender === id) { 41 71 return; 42 72 } else if (msg.type === 'open') { -1 73 // request current document from peers 43 74 signal.send(room, {sender: id, type: 'request'}); -1 75 -1 76 // fall back to last saved document after timeout -1 77 setTimeout(function() { -1 78 if (!el.value) { -1 79 signal.restore(room).then(text => { -1 80 if (!el.value) { -1 81 setText(text, 0, 0); -1 82 } -1 83 }).finally(() => { -1 84 el.readOnly = false; -1 85 }); -1 86 } -1 87 }, 1000); 44 88 } else if (msg.type === 'error') { 45 89 el.readOnly = true; 46 90 } else if (msg.type === 'changes') { @@ -65,3 +109,5 @@ setInterval(function() { 65 109 }); 66 110 } 67 111 }, 500); -1 112 -1 113 window.addEventListener('beforeunload', () => backup(true));