pad

minimal etherpad alternative  https://pad.ce9e.org
git clone https://git.ce9e.org/pad.git

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    13 
   15    -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 editor
   12    -1 
   13    -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));