pad

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

commit
52d98c11cbfcf6671ee96f48c60ee767d853eac2
parent
06a6cea858a4dc877d5ee6a38322ca5a7c36b974
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2020-05-05 18:26
refactor

Diffstat

M index.html 2 +-
R static/index.js -> static/pad.js 54 +++++++++++++++++-------------------------------------
A static/utils.js 35 +++++++++++++++++++++++++++++++++++
R static/signal.js -> static/via.js 25 ++++++++++---------------

4 files changed, 63 insertions, 53 deletions


diff --git a/index.html b/index.html

@@ -9,6 +9,6 @@
    9     9 </head>
   10    10 <body>
   11    11 	<textarea autocomplete="off" readonly autofocus></textarea>
   12    -1 	<script type="module" src="/static/index.js"></script>
   -1    12 	<script type="module" src="/static/pad.js"></script>
   13    13 </body>
   14    14 </html>

diff --git a/static/index.js b/static/pad.js

@@ -1,41 +1,21 @@
   -1     1 import * as utils from './utils.js';
    1     2 import * as context from './context.js';
    2    -1 import * as signal from './signal.js';
   -1     3 import * as via from './via.js';
    3     4 
    4    -1 var room = location.hash.substr(1);
    5    -1 var id = signal.randomString(10);
    6    -1 var el = document.querySelector('textarea');
   -1     5 if (!location.hash) {
   -1     6 	location.hash = utils.randomString(10);
   -1     7 }
   -1     8 
   -1     9 var room = 'pad/' + location.hash.slice(1);
   -1    10 var id = utils.randomString(6);
    7    11 
   -1    12 var el = document.querySelector('textarea');
    8    13 var old = el.value;
    9    14 
   10    15 var localChanges = [];
   11    16 var stagedChanges = [];
   12    17 
   13    -1 document.title += ' - ' + room;
   14    -1 
   15    -1 var throttled = function(fn, timeout) {
   16    -1 	var blocked = false;
   17    -1 	var needsCall = false;
   18    -1 
   19    -1 	var wrapper = function(force) {
   20    -1 		if (blocked && !force) {
   21    -1 			needsCall = true;
   22    -1 			return;
   23    -1 		}
   24    -1 
   25    -1 		fn();
   26    -1 		blocked = true;
   27    -1 		needsCall = false;
   28    -1 
   29    -1 		setTimeout(function() {
   30    -1 			blocked = false;
   31    -1 			if (needsCall) {
   32    -1 				wrapper();
   33    -1 			}
   34    -1 		}, timeout);
   35    -1 	};
   36    -1 
   37    -1 	return wrapper;
   38    -1 };
   -1    18 document.title += ' - ' + location.hash.slice(1);
   39    19 
   40    20 var setText = function(text, start, end) {
   41    21 	if (text !== el.value) {
@@ -46,8 +26,8 @@ var setText = function(text, start, end) {
   46    26 	}
   47    27 };
   48    28 
   49    -1 var backup = throttled(function() {
   50    -1 	signal.store(room, el.value);
   -1    29 var backup = utils.throttled(function() {
   -1    30 	via.store(room, el.value, true);
   51    31 }, 10000);
   52    32 
   53    33 var applyChanges = function(changes) {
@@ -66,17 +46,17 @@ el.addEventListener('input', function() {
   66    46 	backup();
   67    47 });
   68    48 
   69    -1 signal.listen(room, function(msg) {
   -1    49 via.listen(room, function(msg) {
   70    50 	if (msg.sender === id) {
   71    51 		return;
   72    52 	} else if (msg.type === 'open') {
   73    53 		// request current document from peers
   74    -1 		signal.send(room, {sender: id, type: 'request'});
   -1    54 		via.send(room, {sender: id, type: 'request'});
   75    55 
   76    56 		// fall back to last saved document after timeout
   77    57 		setTimeout(function() {
   78    58 			if (!el.value) {
   79    -1 				signal.restore(room).then(text => {
   -1    59 				via.restore(room).then(text => {
   80    60 					if (!el.value) {
   81    61 						setText(text, 0, 0);
   82    62 					}
@@ -90,7 +70,7 @@ signal.listen(room, function(msg) {
   90    70 	} else if (msg.type === 'changes') {
   91    71 		applyChanges(msg.data);
   92    72 	} else if (msg.type === 'request') {
   93    -1 		signal.send(room, {sender: id, type: 'text', data: el.value});
   -1    73 		via.send(room, {sender: id, type: 'text', data: el.value});
   94    74 	} else if (msg.type === 'text' && !el.value) {
   95    75 		setText(msg.data, 0, 0);
   96    76 		el.readOnly = false;
@@ -102,7 +82,7 @@ setInterval(function() {
  102    82 		stagedChanges = localChanges;
  103    83 		localChanges = [];
  104    84 		var msg = {sender: id, type: 'changes', data: stagedChanges};
  105    -1 		signal.send(room, msg).catch(() => {
   -1    85 		via.send(room, msg).catch(() => {
  106    86 			localChanges = stagedChanges.concat(localChanges);
  107    87 		}).finally(() => {
  108    88 			stagedChanges = [];

diff --git a/static/utils.js b/static/utils.js

@@ -0,0 +1,35 @@
   -1     1 var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
   -1     2 
   -1     3 export var randomString = function(length) {
   -1     4 	var result = [];
   -1     5 	for (var i = 0; i < length; i++) {
   -1     6 		var k = Math.floor(Math.random() * chars.length);
   -1     7 		result.push(chars[k]);
   -1     8 	}
   -1     9 	return result.join('');
   -1    10 };
   -1    11 
   -1    12 export var throttled = function(fn, timeout) {
   -1    13 	var blocked = false;
   -1    14 	var needsCall = false;
   -1    15 
   -1    16 	var wrapper = function(force) {
   -1    17 		if (blocked && !force) {
   -1    18 			needsCall = true;
   -1    19 			return;
   -1    20 		}
   -1    21 
   -1    22 		fn();
   -1    23 		blocked = true;
   -1    24 		needsCall = false;
   -1    25 
   -1    26 		setTimeout(function() {
   -1    27 			blocked = false;
   -1    28 			if (needsCall) {
   -1    29 				wrapper();
   -1    30 			}
   -1    31 		}, timeout);
   -1    32 	};
   -1    33 
   -1    34 	return wrapper;
   -1    35 };

diff --git a/static/signal.js b/static/via.js

@@ -1,17 +1,16 @@
    1    -1 var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    2     1 var baseUrl = 'https://via.ce9e.org/';
    3     2 
    4    -1 export var randomString = function(length) {
    5    -1 	var result = [];
    6    -1 	for (var i = 0; i < length; i++) {
    7    -1 		var k = Math.floor(Math.random() * chars.length);
    8    -1 		result.push(chars[k]);
   -1     3 var post = function(key, data, beacon) {
   -1     4 	var body = JSON.stringify(data);
   -1     5 	if (beacon) {
   -1     6 		return navigator.sendBeacon(baseUrl + key, body);
   -1     7 	} else {
   -1     8 		return fetch(baseUrl + key, {method: 'POST', body: body});
    9     9 	}
   10    -1 	return result.join('');
   11    10 };
   12    11 
   13    -1 export var send = function(key, data) {
   14    -1 	return fetch(baseUrl + 'msg/' + key, {method: 'POST', body: JSON.stringify(data)});
   -1    12 export var send = function(key, data, beacon) {
   -1    13 	return post('msg/' + key, data, beacon);
   15    14 };
   16    15 
   17    16 export var listen = function(key, fn) {
@@ -21,8 +20,8 @@ export var listen = function(key, fn) {
   21    20 	evtSource.onerror = () => fn({type: 'error'});
   22    21 };
   23    22 
   24    -1 export var store = function(key, data) {
   25    -1 	return navigator.sendBeacon(baseUrl + 'store/' + key, JSON.stringify(data));
   -1    23 export var store = function(key, data, beacon) {
   -1    24 	return post('store/' + key, data, beacon);
   26    25 };
   27    26 
   28    27 export var restore = function(key) {
@@ -30,7 +29,3 @@ export var restore = function(key) {
   30    29 		.then(r => r.text())
   31    30 		.then(s => JSON.parse(s));
   32    31 };
   33    -1 
   34    -1 if (!location.hash) {
   35    -1 	location.hash = randomString(10);
   36    -1 }