pad

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

commit
562b29dc8b63034771b2490d3396be0107441841
parent
999c372e054a971af726711f0f54ab459a0c8965
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2020-10-15 11:06
Merge branch 'feature-via-history'

Diffstat

M static/pad.js 81 +++++++++++++++++++++++++++++--------------------------------
M static/utils.js 1 -
D static/via.js 30 ------------------------------

3 files changed, 39 insertions, 73 deletions


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

@@ -1,12 +1,12 @@
    1     1 import * as utils from './utils.js';
    2     2 import * as diff from './diff.js';
    3    -1 import * as via from './via.js';
    4     3 
    5     4 if (!location.hash) {
    6     5 	location.hash = utils.randomString(10);
    7     6 }
    8     7 
    9     8 var room = 'pad/' + location.hash.slice(1);
   -1     9 var url = 'https://via.ce9e.org/hmsg/' + room;
   10    10 var id = utils.randomString(6);
   11    11 
   12    12 var el = document.querySelector('textarea');
@@ -17,19 +17,17 @@ var stagedChanges = [];
   17    17 
   18    18 document.title += ' - ' + location.hash.slice(1);
   19    19 
   20    -1 var backup = utils.throttled(function() {
   21    -1 	if (!el.readonly) {
   22    -1 		via.store(room, el.value, true);
   23    -1 	}
   24    -1 }, 10000);
   25    -1 
   26    20 var sendChanges = utils.throttled(function() {
   27    21 	if (stagedChanges.length) {
   28    22 		setTimeout(sendChanges, 500);
   29    23 	} else {
   30    24 		stagedChanges = localChanges;
   31    25 		localChanges = [];
   32    -1 		via.send(room, [id, 'changes', stagedChanges]).catch(() => {
   -1    26 		var data = [id, 'changes', stagedChanges];
   -1    27 		return fetch(url, {
   -1    28 			method: 'POST',
   -1    29 			body: JSON.stringify(data),
   -1    30 		}).catch(() => {
   33    31 			localChanges = stagedChanges.concat(localChanges);
   34    32 			stagedChanges = [];
   35    33 			sendChanges();
@@ -70,48 +68,47 @@ var applyChanges = function(changes) {
   70    68 	}
   71    69 };
   72    70 
   73    -1 el.addEventListener('input', function() {
   74    -1 	var change = diff.diff(old, el.value, 3);
   75    -1 	diff.pushChange(localChanges, change);
   76    -1 	old = el.value;
   77    -1 	sendChanges();
   78    -1 	backup();
   79    -1 });
   80    -1 
   81    -1 via.listen(room, function(msg) {
   82    -1 	if (msg[1] === 'open') {
   83    -1 		// request current document from peers
   84    -1 		via.send(room, [id, 'request']);
   85    -1 
   86    -1 		// fall back to last saved document after timeout
   87    -1 		setTimeout(function() {
   88    -1 			if (!el.value) {
   89    -1 				via.restore(room).then(text => {
   90    -1 					if (!el.value) {
   91    -1 						el.value = text;
   92    -1 						old = text;
   93    -1 					}
   94    -1 				}).finally(() => {
   95    -1 					el.readOnly = false;
   96    -1 				});
   97    -1 			}
   98    -1 		}, 1000);
   99    -1 	} else if (msg[1] === 'changes' && !el.readOnly) {
   -1    71 var handleMessage = function(msg) {
   -1    72 	if (msg[1] === 'changes') {
  100    73 		if (msg[0] === id) {
  101    74 			stagedChanges = [];
  102    75 		} else {
  103    76 			applyChanges(msg[2]);
  104    77 		}
  105    -1 	} else if (msg[1] === 'request' && msg[0] !== id) {
  106    -1 		via.send(room, [id, 'text', el.value]);
  107    -1 	} else if (msg[1] === 'text' && !el.value) {
  108    -1 		el.value = msg[2];
  109    -1 		old = msg[2];
  110    -1 		el.readOnly = false;
  111    78 	}
   -1    79 };
   -1    80 
   -1    81 var optimize = function(lastEventId) {
   -1    82 	var change = diff.diff('', el.value, 3);
   -1    83 	var data = [id, 'changes', [change]];
   -1    84 	fetch(url, {
   -1    85 		method: 'PUT',
   -1    86 		body: JSON.stringify(data),
   -1    87 		headers: {'Last-Event-ID': lastEventId},
   -1    88 	});
   -1    89 };
   -1    90 
   -1    91 el.addEventListener('input', function() {
   -1    92 	var change = diff.diff(old, el.value, 3);
   -1    93 	diff.pushChange(localChanges, change);
   -1    94 	old = el.value;
   -1    95 	sendChanges();
  112    96 });
  113    97 
  114    -1 window.addEventListener('beforeunload', backup.unthrottled);
  115    98 window.addEventListener('offline', function() {
  116    99 	el.readOnly = true;
  117   100 });
   -1   101 
   -1   102 var evtSource = new EventSource(url);
   -1   103 evtSource.onopen = function() {
   -1   104 	el.readOnly = false;
   -1   105 };
   -1   106 evtSource.onmessage = function(event) {
   -1   107 	if (!el.readOnly) {
   -1   108 		handleMessage(JSON.parse(event.data));
   -1   109 
   -1   110 		if (Math.random() < 0.05) {
   -1   111 			optimize(event.lastEventId);
   -1   112 		}
   -1   113 	}
   -1   114 };

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

@@ -22,6 +22,5 @@ export var throttled = function(fn, timeout) {
   22    22 		}
   23    23 	};
   24    24 
   25    -1 	wrapper.unthrottled = fn;
   26    25 	return wrapper;
   27    26 };

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

@@ -1,30 +0,0 @@
    1    -1 var baseUrl = 'https://via.ce9e.org/';
    2    -1 
    3    -1 var post = function(key, data, beacon) {
    4    -1 	var body = JSON.stringify(data);
    5    -1 	if (beacon) {
    6    -1 		return navigator.sendBeacon(baseUrl + key, body);
    7    -1 	} else {
    8    -1 		return fetch(baseUrl + key, {method: 'POST', body: body});
    9    -1 	}
   10    -1 };
   11    -1 
   12    -1 export var send = function(key, data, beacon) {
   13    -1 	return post('msg/' + key, data, beacon);
   14    -1 };
   15    -1 
   16    -1 export var listen = function(key, fn) {
   17    -1 	var evtSource = new EventSource(baseUrl + 'msg/' + key);
   18    -1 	evtSource.onmessage = msg => fn(JSON.parse(msg.data));
   19    -1 	evtSource.onopen = () => fn([null, 'open']);
   20    -1 };
   21    -1 
   22    -1 export var store = function(key, data, beacon) {
   23    -1 	return post('store/' + key, data, beacon);
   24    -1 };
   25    -1 
   26    -1 export var restore = function(key) {
   27    -1 	return fetch(baseUrl + 'store/' + key)
   28    -1 		.then(r => r.text())
   29    -1 		.then(s => JSON.parse(s));
   30    -1 };