diff --git a/copyparty/__main__.py b/copyparty/__main__.py
index a0d7251d..e346ac18 100644
--- a/copyparty/__main__.py
+++ b/copyparty/__main__.py
@@ -123,20 +123,17 @@ def main():
"""
),
)
- ap.add_argument(
- "-c", metavar="PATH", type=str, action="append", help="add config file"
- )
+ ap.add_argument("-c", metavar="PATH", type=str, action="append", help="add config file")
ap.add_argument("-i", metavar="IP", type=str, default="0.0.0.0", help="ip to bind")
ap.add_argument("-p", metavar="PORT", type=int, default=3923, help="port to bind")
ap.add_argument("-nc", metavar="NUM", type=int, default=64, help="max num clients")
- ap.add_argument(
- "-j", metavar="CORES", type=int, default=1, help="max num cpu cores"
- )
+ ap.add_argument("-j", metavar="CORES", type=int, default=1, help="max num cpu cores")
ap.add_argument("-a", metavar="ACCT", type=str, action="append", help="add account")
ap.add_argument("-v", metavar="VOL", type=str, action="append", help="add volume")
ap.add_argument("-q", action="store_true", help="quiet")
ap.add_argument("-ed", action="store_true", help="enable ?dots")
ap.add_argument("-emp", action="store_true", help="enable markdown plugins")
+ ap.add_argument("-mcr", metavar="SEC", type=int, default=60, help="md-editor mod-chk rate")
ap.add_argument("-nw", action="store_true", help="disable writes (benchmark)")
ap.add_argument("-nih", action="store_true", help="no info hostname")
ap.add_argument("-nid", action="store_true", help="no info disk-usage")
diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py
index 46fd96c8..6b51b2e4 100644
--- a/copyparty/httpcli.py
+++ b/copyparty/httpcli.py
@@ -964,6 +964,7 @@ class HttpCli(object):
"title": html_escape(self.vpath),
"lastmod": int(ts_md * 1000),
"md_plug": "true" if self.args.emp else "false",
+ "md_chk_rate": self.args.mcr,
"md": "",
}
sz_html = len(template.render(**targs).encode("utf-8"))
diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js
index cdecea51..236f1408 100644
--- a/copyparty/web/browser.js
+++ b/copyparty/web/browser.js
@@ -27,7 +27,7 @@ var mp = (function () {
};
var re_audio = new RegExp('\.(opus|ogg|m4a|aac|mp3|wav|flac)$', 'i');
- var trs = document.getElementById('files').getElementsByTagName('tbody')[0].getElementsByTagName('tr');
+ var trs = ebi('files').getElementsByTagName('tbody')[0].getElementsByTagName('tr');
for (var a = 0, aa = trs.length; a < aa; a++) {
var tds = trs[a].getElementsByTagName('td');
var link = tds[1].getElementsByTagName('a')[0];
@@ -70,8 +70,8 @@ var mp = (function () {
// toggle player widget
var widget = (function () {
var ret = {};
- var widget = document.getElementById('widget');
- var wtoggle = document.getElementById('wtoggle');
+ var widget = ebi('widget');
+ var wtoggle = ebi('wtoggle');
var touchmode = false;
var side_open = false;
var was_paused = true;
diff --git a/copyparty/web/md.html b/copyparty/web/md.html
index 29498133..6bc43ba1 100644
--- a/copyparty/web/md.html
+++ b/copyparty/web/md.html
@@ -126,7 +126,8 @@ write markdown (most html is 🙆 too)
var last_modified = {{ lastmod }};
var md_opt = {
link_md_as_html: false,
- allow_plugins: {{ md_plug }}
+ allow_plugins: {{ md_plug }},
+ modpoll_freq: {{ md_chk_rate }}
};
(function () {
diff --git a/copyparty/web/md.js b/copyparty/web/md.js
index d81c8aef..74d4b57e 100644
--- a/copyparty/web/md.js
+++ b/copyparty/web/md.js
@@ -1,12 +1,12 @@
"use strict";
-var dom_toc = document.getElementById('toc');
-var dom_wrap = document.getElementById('mw');
-var dom_hbar = document.getElementById('mh');
-var dom_nav = document.getElementById('mn');
-var dom_pre = document.getElementById('mp');
-var dom_src = document.getElementById('mt');
-var dom_navtgl = document.getElementById('navtoggle');
+var dom_toc = ebi('toc');
+var dom_wrap = ebi('mw');
+var dom_hbar = ebi('mh');
+var dom_nav = ebi('mn');
+var dom_pre = ebi('mp');
+var dom_src = ebi('mt');
+var dom_navtgl = ebi('navtoggle');
// chrome 49 needs this
@@ -161,7 +161,7 @@ function copydom(src, dst, lv) {
function md_plug_err(ex, js) {
- var errbox = document.getElementById('md_errbox');
+ var errbox = ebi('md_errbox');
if (errbox)
errbox.parentNode.removeChild(errbox);
@@ -367,7 +367,7 @@ function convert_markdown(md_text, dest_dom) {
function init_toc() {
- var loader = document.getElementById('ml');
+ var loader = ebi('ml');
loader.parentNode.removeChild(loader);
var anchors = []; // list of toc entries, complex objects
diff --git a/copyparty/web/md2.css b/copyparty/web/md2.css
index 1de6257d..655cf040 100644
--- a/copyparty/web/md2.css
+++ b/copyparty/web/md2.css
@@ -77,32 +77,52 @@ html.dark #mt {
background: #f97;
border-radius: .15em;
}
+html.dark #save.force-save {
+ color: #fca;
+ background: #720;
+}
#save.disabled {
opacity: .4;
}
+#helpbox,
+#toast {
+ background: #f7f7f7;
+ border-radius: .4em;
+ z-index: 9001;
+}
#helpbox {
display: none;
position: fixed;
- background: #f7f7f7;
- box-shadow: 0 .5em 2em #777;
- border-radius: .4em;
padding: 2em;
top: 4em;
overflow-y: auto;
+ box-shadow: 0 .5em 2em #777;
height: calc(100% - 12em);
left: calc(50% - 15em);
right: 0;
width: 30em;
- z-index: 9001;
}
#helpclose {
display: block;
}
html.dark #helpbox {
- background: #222;
box-shadow: 0 .5em 2em #444;
+}
+html.dark #helpbox,
+html.dark #toast {
+ background: #222;
border: 1px solid #079;
border-width: 1px 0;
}
+#toast {
+ font-weight: bold;
+ text-align: center;
+ padding: .6em 0;
+ position: fixed;
+ z-index: 9001;
+ top: 30%;
+ transition: opacity 0.2s ease-in-out;
+ opacity: 1;
+}
# mt {opacity: .5;top:1px}
diff --git a/copyparty/web/md2.js b/copyparty/web/md2.js
index 0db410db..74dca04a 100644
--- a/copyparty/web/md2.js
+++ b/copyparty/web/md2.js
@@ -11,15 +11,15 @@ var js_uni_whitelist = eval('\'' + esc_uni_whitelist + '\'');
// dom nodes
-var dom_swrap = document.getElementById('mtw');
-var dom_sbs = document.getElementById('sbs');
-var dom_nsbs = document.getElementById('nsbs');
-var dom_tbox = document.getElementById('toolsbox');
+var dom_swrap = ebi('mtw');
+var dom_sbs = ebi('sbs');
+var dom_nsbs = ebi('nsbs');
+var dom_tbox = ebi('toolsbox');
var dom_ref = (function () {
var d = document.createElement('div');
d.setAttribute('id', 'mtr');
dom_swrap.appendChild(d);
- d = document.getElementById('mtr');
+ d = ebi('mtr');
// hide behind the textarea (offsetTop is not computed if display:none)
dom_src.style.zIndex = '4';
d.style.zIndex = '3';
@@ -108,7 +108,7 @@ var draw_md = (function () {
map_src = genmap(dom_ref, map_src);
map_pre = genmap(dom_pre, map_pre);
- cls(document.getElementById('save'), 'disabled', src == server_md);
+ cls(ebi('save'), 'disabled', src == server_md);
var t1 = new Date().getTime();
delay = t1 - t0 > 100 ? 25 : 1;
@@ -223,14 +223,108 @@ redraw = (function () {
})();
+// modification checker
+function Modpoll() {
+ this.skip_one = true;
+ this.disabled = false;
+
+ this.periodic = function () {
+ var that = this;
+ setTimeout(function () {
+ that.periodic();
+ }, 1000 * md_opt.modpoll_freq);
+
+ var skip = null;
+
+ if (ebi('toast'))
+ skip = 'toast';
+
+ else if (this.skip_one)
+ skip = 'saved';
+
+ else if (this.disabled)
+ skip = 'disabled';
+
+ if (skip) {
+ console.log('modpoll skip, ' + skip);
+ this.skip_one = false;
+ return;
+ }
+
+ console.log('modpoll...');
+ var url = (document.location + '').split('?')[0] + '?raw&_=' + new Date().getTime();
+ var xhr = new XMLHttpRequest();
+ xhr.modpoll = this;
+ xhr.open('GET', url, true);
+ xhr.responseType = 'text';
+ xhr.onreadystatechange = this.cb;
+ xhr.send();
+ }
+
+ this.cb = function () {
+ if (this.modpoll.disabled || this.modpoll.skip_one) {
+ console.log('modpoll abort');
+ return;
+ }
+
+ if (this.readyState != XMLHttpRequest.DONE)
+ return;
+
+ if (this.status !== 200) {
+ console.log('modpoll err ' + this.status + ": " + this.responseText);
+ return;
+ }
+
+ if (!this.responseText)
+ return;
+
+ var server_ref = server_md.replace(/\r/g, '');
+ var server_now = this.responseText.replace(/\r/g, '');
+
+ if (server_ref != server_now) {
+ console.log("modpoll diff |" + server_ref.length + "|, |" + server_now.length + "|");
+ this.modpoll.disabled = true;
+ var msg = [
+ "The document has changed on the server.
" +
+ "The changes will NOT be loaded into your editor automatically.",
+
+ "Press F5 or CTRL-R to refresh the page,
" +
+ "replacing your document with the server copy.",
+
+ "You can click this message to ignore and contnue."
+ ];
+ return toast(false, "box-shadow:0 1em 2em rgba(64,64,64,0.8);font-weight:normal",
+ 36, "
" + msg.join('
\n') + '
'); + } + + console.log('modpoll eq'); + } + + if (md_opt.modpoll_freq > 0) + this.periodic(); + + return this; +}; +var modpoll = new Modpoll(); + + +window.onbeforeunload = function (e) { + if ((ebi("save").getAttribute('class') + '').indexOf('disabled') >= 0) + return; //nice (todo) + + e.preventDefault(); //ff + e.returnValue = ''; //chrome +}; + + // save handler function save(e) { if (e) e.preventDefault(); - var save_btn = document.getElementById("save"), + var save_btn = ebi("save"), save_cls = save_btn.getAttribute('class') + ''; if (save_cls.indexOf('disabled') >= 0) { - toast('font-size:2em;color:#fc6;width:9em;', 'no changes'); + toast(true, ";font-size:2em;color:#c90", 9, "no changes"); return; } @@ -254,6 +348,8 @@ function save(e) { xhr.onreadystatechange = save_cb; xhr.btn = save_btn; xhr.txt = txt; + + modpoll.skip_one = true; // skip one iteration while we save xhr.send(fd); } @@ -347,23 +443,44 @@ function savechk_cb() { last_modified = this.lastmod; server_md = this.txt; draw_md(); - toast('font-size:6em;font-family:serif;color:#cf6;width:4em;', + toast(true, ";font-size:6em;font-family:serif;color:#9b4", 4, 'OK✔️' + this.ntry + ''); + + modpoll.disabled = false; } -function toast(style, msg) { - var ok = document.createElement('div'); - style += 'font-weight:bold;background:#444;border-radius:.3em;padding:.6em 0;position:fixed;top:30%;left:calc(50% - 2em);text-align:center;z-index:9001;transition:opacity 0.2s ease-in-out;opacity:1'; +function toast(autoclose, style, width, msg) { + var ok = ebi("toast"); + if (ok) + ok.parentNode.removeChild(ok); + + style = "width:" + width + "em;left:calc(50% - " + (width / 2) + "em);" + style; + ok = document.createElement('div'); + ok.setAttribute('id', 'toast'); ok.setAttribute('style', style); ok.innerHTML = msg; - var parent = document.getElementById('m'); + var parent = ebi('m'); document.documentElement.appendChild(ok); - setTimeout(function () { - ok.style.opacity = 0; - }, 500); - setTimeout(function () { - ok.parentNode.removeChild(ok); - }, 750); + + var hide = function (delay) { + delay = delay || 0; + + setTimeout(function () { + ok.style.opacity = 0; + }, delay); + + setTimeout(function () { + if (ok.parentNode) + ok.parentNode.removeChild(ok); + }, delay + 250); + } + + ok.onclick = function () { + hide(0); + }; + + if (autoclose) + hide(500); } @@ -806,7 +923,7 @@ function cfg_uni(e) { return false; } if (ev.code == "Escape" || kc == 27) { - var d = document.getElementById('helpclose'); + var d = ebi('helpclose'); if (d) d.click(); } @@ -863,22 +980,22 @@ function cfg_uni(e) { } } document.onkeydown = keydown; - document.getElementById('save').onclick = save; + ebi('save').onclick = save; })(); -document.getElementById('tools').onclick = function (e) { +ebi('tools').onclick = function (e) { if (e) e.preventDefault(); var is_open = dom_tbox.getAttribute('class') != 'open'; dom_tbox.setAttribute('class', is_open ? 'open' : ''); }; -document.getElementById('help').onclick = function (e) { +ebi('help').onclick = function (e) { if (e) e.preventDefault(); dom_tbox.setAttribute('class', ''); - var dom = document.getElementById('helpbox'); + var dom = ebi('helpbox'); var dtxt = dom.getElementsByTagName('textarea'); if (dtxt.length > 0) { convert_markdown(dtxt[0].value, dom); @@ -886,16 +1003,16 @@ document.getElementById('help').onclick = function (e) { } dom.style.display = 'block'; - document.getElementById('helpclose').onclick = function () { + ebi('helpclose').onclick = function () { dom.style.display = 'none'; }; }; -document.getElementById('fmt_table').onclick = fmt_table; -document.getElementById('mark_uni').onclick = mark_uni; -document.getElementById('iter_uni').onclick = iter_uni; -document.getElementById('cfg_uni').onclick = cfg_uni; +ebi('fmt_table').onclick = fmt_table; +ebi('mark_uni').onclick = mark_uni; +ebi('iter_uni').onclick = iter_uni; +ebi('cfg_uni').onclick = cfg_uni; // blame steen @@ -1019,7 +1136,7 @@ action_stack = (function () { })(); /* -document.getElementById('help').onclick = function () { +ebi('help').onclick = function () { var c1 = getComputedStyle(dom_src).cssText.split(';'); var c2 = getComputedStyle(dom_ref).cssText.split(';'); var max = Math.min(c1.length, c2.length); diff --git a/copyparty/web/mde.html b/copyparty/web/mde.html index 7a6847fa..e88c297f 100644 --- a/copyparty/web/mde.html +++ b/copyparty/web/mde.html @@ -25,7 +25,8 @@ var last_modified = {{ lastmod }}; var md_opt = { link_md_as_html: false, - allow_plugins: {{ md_plug }} + allow_plugins: {{ md_plug }}, + modpoll_freq: {{ md_chk_rate }} }; var lightswitch = (function () { diff --git a/copyparty/web/mde.js b/copyparty/web/mde.js index 4630bd39..13a385ba 100644 --- a/copyparty/web/mde.js +++ b/copyparty/web/mde.js @@ -1,9 +1,9 @@ "use strict"; -var dom_wrap = document.getElementById('mw'); -var dom_nav = document.getElementById('mn'); -var dom_doc = document.getElementById('m'); -var dom_md = document.getElementById('mt'); +var dom_wrap = ebi('mw'); +var dom_nav = ebi('mn'); +var dom_doc = ebi('m'); +var dom_md = ebi('mt'); (function () { var n = document.location + ''; @@ -65,7 +65,7 @@ var mde = (function () { mde.codemirror.on("change", function () { md_changed(mde); }); - var loader = document.getElementById('ml'); + var loader = ebi('ml'); loader.parentNode.removeChild(loader); return mde; })(); @@ -215,7 +215,7 @@ function save_chk() { var ok = document.createElement('div'); ok.setAttribute('style', 'font-size:6em;font-family:serif;font-weight:bold;color:#cf6;background:#444;border-radius:.3em;padding:.6em 0;position:fixed;top:30%;left:calc(50% - 2em);width:4em;text-align:center;z-index:9001;transition:opacity 0.2s ease-in-out;opacity:1'); ok.innerHTML = 'OK✔️'; - var parent = document.getElementById('m'); + var parent = ebi('m'); document.documentElement.appendChild(ok); setTimeout(function () { ok.style.opacity = 0; diff --git a/copyparty/web/up2k.js b/copyparty/web/up2k.js index d827c563..1e4cd9a3 100644 --- a/copyparty/web/up2k.js +++ b/copyparty/web/up2k.js @@ -38,7 +38,7 @@ function goto(dest) { obj[a].classList.remove('act'); if (dest) { - document.getElementById('op_' + dest).classList.add('act'); + ebi('op_' + dest).classList.add('act'); document.querySelector('#ops>a[data-dest=' + dest + ']').classList.add('act'); var fn = window['goto_' + dest]; @@ -66,7 +66,7 @@ function goto_up2k() { if (op !== null && op !== '.') goto(op); } - document.getElementById('ops').style.display = 'block'; + ebi('ops').style.display = 'block'; })();