diff --git a/copyparty/broker_mpw.py b/copyparty/broker_mpw.py
index b4b540d8..815ca50a 100644
--- a/copyparty/broker_mpw.py
+++ b/copyparty/broker_mpw.py
@@ -73,7 +73,7 @@ class MpWorker(object):
if PY2:
sck = pickle.loads(sck) # nosec
- self.log(str(addr), "-" * 4 + "C-qpop")
+ self.log("%s %s" % addr, "-" * 4 + "C-qpop")
self.httpsrv.accept(sck, addr)
with self.mutex:
diff --git a/copyparty/broker_thr.py b/copyparty/broker_thr.py
index 189aaffd..855387bf 100644
--- a/copyparty/broker_thr.py
+++ b/copyparty/broker_thr.py
@@ -28,7 +28,7 @@ class BrokerThr(object):
def put(self, want_retval, dest, *args):
if dest == "httpconn":
sck, addr = args
- self.log(str(addr), "-" * 4 + "C-qpop")
+ self.log("%s %s" % addr, "-" * 4 + "C-qpop")
self.httpsrv.accept(sck, addr)
else:
diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py
index cf2d52f1..015d65e2 100644
--- a/copyparty/httpcli.py
+++ b/copyparty/httpcli.py
@@ -708,7 +708,14 @@ class HttpCli(object):
def tx_md(self, fs_path):
logmsg = "{:4} {} ".format("", self.req)
- html_path = os.path.join(E.mod, "web/md.html")
+ if "edit" in self.uparam:
+ html_path = "web/mde.html"
+ template = self.conn.tpl_mde
+ else:
+ html_path = "web/md.html"
+ template = self.conn.tpl_md
+
+ html_path = os.path.join(E.mod, html_path)
st = os.stat(fsenc(fs_path))
sz_md = st.st_size
@@ -726,7 +733,7 @@ class HttpCli(object):
"title": html_escape(self.vpath, quote=False),
"md": "",
}
- sz_html = len(self.conn.tpl_md.render(**targs).encode("utf-8"))
+ sz_html = len(template.render(**targs).encode("utf-8"))
self.send_headers(sz_html + sz_md, status)
logmsg += str(status)
@@ -738,7 +745,7 @@ class HttpCli(object):
md = f.read()
targs["md"] = md.decode("utf-8", "replace")
- html = self.conn.tpl_md.render(**targs).encode("utf-8")
+ html = template.render(**targs).encode("utf-8")
try:
self.s.sendall(html)
except:
diff --git a/copyparty/httpconn.py b/copyparty/httpconn.py
index e1bda616..bca54b8f 100644
--- a/copyparty/httpconn.py
+++ b/copyparty/httpconn.py
@@ -36,6 +36,7 @@ class HttpConn(object):
self.tpl_browser = env.get_template("browser.html")
self.tpl_msg = env.get_template("msg.html")
self.tpl_md = env.get_template("md.html")
+ self.tpl_mde = env.get_template("mde.html")
def respath(self, res_name):
return os.path.join(E.mod, "web", res_name)
diff --git a/copyparty/httpsrv.py b/copyparty/httpsrv.py
index eb36374d..7182a7b9 100644
--- a/copyparty/httpsrv.py
+++ b/copyparty/httpsrv.py
@@ -38,7 +38,7 @@ class HttpSrv(object):
def accept(self, sck, addr):
"""takes an incoming tcp connection and creates a thread to handle it"""
- self.log(str(addr), "-" * 5 + "C-cthr")
+ self.log("%s %s" % addr, "-" * 5 + "C-cthr")
thr = threading.Thread(target=self.thr_client, args=(sck, addr))
thr.daemon = True
thr.start()
@@ -66,16 +66,18 @@ class HttpSrv(object):
thr.start()
try:
- self.log(str(addr), "-" * 6 + "C-crun")
+ self.log("%s %s" % addr, "-" * 6 + "C-crun")
cli.run()
finally:
- self.log(str(addr), "-" * 7 + "C-done")
+ self.log("%s %s" % addr, "-" * 7 + "C-done")
try:
sck.shutdown(socket.SHUT_RDWR)
sck.close()
except (OSError, socket.error) as ex:
- self.log(str(addr), "shut_rdwr err:\n {}\n {}".format(repr(sck), ex))
+ self.log(
+ "%s %s" % addr, "shut_rdwr err:\n {}\n {}".format(repr(sck), ex),
+ )
if ex.errno not in [10038, 107, 57, 9]:
# 10038 No longer considered a socket
# 107 Transport endpoint not connected
diff --git a/copyparty/tcpsrv.py b/copyparty/tcpsrv.py
index d346ea68..29e5f349 100644
--- a/copyparty/tcpsrv.py
+++ b/copyparty/tcpsrv.py
@@ -64,7 +64,7 @@ class TcpSrv(object):
self.log("tcpsrv", "-" * 2 + "C-acc1")
sck, addr = self.srv.accept()
- self.log(str(addr), "-" * 3 + "C-acc2")
+ self.log("%s %s" % addr, "-" * 3 + "C-acc2")
self.num_clients.add()
self.hub.broker.put(False, "httpconn", sck, addr)
diff --git a/copyparty/web/md.html b/copyparty/web/md.html
index 9cbb39fa..d9fb97bf 100644
--- a/copyparty/web/md.html
+++ b/copyparty/web/md.html
@@ -11,7 +11,7 @@
dark
- there will soon be more buttons on this row so it looks less dumb
+
edit
diff --git a/copyparty/web/md.js b/copyparty/web/md.js
index 56e894dd..0c4ae026 100644
--- a/copyparty/web/md.js
+++ b/copyparty/web/md.js
@@ -14,15 +14,15 @@ var dom_md = document.getElementById('mt');
// add toolbar buttons
(function () {
var n = document.location + '';
- n = n.substr(n.indexOf('//') + 2).split('/');
+ n = n.substr(n.indexOf('//') + 2).split('?')[0].split('/');
n[0] = 'top';
+ var loc = [];
var nav = [];
- var url = '/';
for (var a = 0; a < n.length; a++) {
if (a > 0)
- url += n[a] + '/';
+ loc.push(n[a]);
- nav.push('
' + n[a] + '');
+ nav.push('
' + n[a] + '');
}
dom_nav.innerHTML = nav.join('');
})();
diff --git a/copyparty/web/mde.css b/copyparty/web/mde.css
new file mode 100644
index 00000000..c69c24af
--- /dev/null
+++ b/copyparty/web/mde.css
@@ -0,0 +1,75 @@
+/* fontawesome is 2big */
+.fa { font-size: 1.5em; line-height: 1em; margin: -3em; position: relative; left: -.05em; font-style: normal }
+.fa-bold:before { content: 'B'; font-weight: bold }
+.fa-italic:before { content: 'I'; font-style: italic }
+.fa-strikethrough:before { content: ' S '; text-decoration: line-through }
+.fa-header:before { content: 'H'; font-weight: bold; font-family: serif; top: -.2em; left: .5em }
+.fa-quote-left:before { content: '❝'; font-family: serif; top: -.5em }
+.fa-list-ul:before { content: '•' }
+.fa-list-ol:before { content: '①' }
+.fa-link:before { content: '🔗'; font-size: .8em }
+.fa-image:before { content: '🎨' }
+.fa-eye:before { content: '👀'; font-size: .9em }
+.fa-columns:before { content: '◫' }
+.fa-arrows-alt:before { content: '⛶' }
+.fa-undo:before { content: '⟲' }
+.fa-redo:before { content: '⟳' }
+.fa-question-circle:before { content: '?' }
+.fa-code:before { content: '‹/›'; font-size: .8em; }
+.fa-eraser:before { content: '⁋' }
+.fa-table:before { content: '⊞' }
+.fa-minus:before { content: '−' }
+
+/*
+https://dev.w3.org/html5/html-author/charref
+http://xahlee.info/comp/unicode_arrows.html
+https://www.fileformat.info/info/unicode/block/miscellaneous_symbols_and_pictographs/list.htm
+↶ ↷ 💾 🗙
+*/
+
+button { border: 1px solid #999 !important; }
+
+html, body {
+ margin: 0;
+ padding: 0;
+ min-height: 100%;
+ font-family: sans-serif;
+}
+#mn {
+ font-weight: normal;
+ margin: 1.3em 0 .7em 1em;
+ font-size: 1.4em;
+}
+#mn a {
+ color: #444;
+ margin: 0 0 0 -.2em;
+ padding: 0 0 0 .4em;
+ text-decoration: none;
+}
+#mn a:first-child {
+ padding-left: .5em;
+}
+#mn a:last-child {
+ padding-right: .5em;
+}
+#mn a:not(:last-child):after {
+ content: '';
+ width: 1.05em;
+ height: 1.05em;
+ margin: -.2em .3em -.2em -.4em;
+ display: inline-block;
+ border: 1px solid rgba(0,0,0,0.3);
+ border-width: .05em .05em 0 0;
+ transform: rotate(45deg);
+}
+#mn a:hover {
+ color: #000;
+ text-decoration: underline;
+}
+
+*[data-ln]:before {
+ content: attr(data-ln);
+ font-size: .8em;
+ margin: 0 .4em;
+ color: #f0c;
+}
diff --git a/copyparty/web/mde.html b/copyparty/web/mde.html
new file mode 100644
index 00000000..93c01647
--- /dev/null
+++ b/copyparty/web/mde.html
@@ -0,0 +1,29 @@
+
+
+
📝🎉 {{ title }}
+
+
+
+
+
+
+
+
+
+
+
Loading
+ if you're still reading this, check that javascript is allowed
+
+
+
+
+
+
+
+
+
+
diff --git a/copyparty/web/mde.js b/copyparty/web/mde.js
new file mode 100644
index 00000000..5a0a108c
--- /dev/null
+++ b/copyparty/web/mde.js
@@ -0,0 +1,40 @@
+var dom_wrap = document.getElementById('mw');
+var dom_nav = document.getElementById('mn');
+var dom_doc = document.getElementById('m');
+var dom_md = document.getElementById('mt');
+
+(function () {
+ var n = document.location + '';
+ n = n.substr(n.indexOf('//') + 2).split('?')[0].split('/');
+ n[0] = 'top';
+ var loc = [];
+ var nav = [];
+ for (var a = 0; a < n.length; a++) {
+ if (a > 0)
+ loc.push(n[a]);
+
+ nav.push('
' + n[a] + '');
+ }
+ dom_nav.innerHTML = nav.join('');
+})();
+
+(function () {
+ var mde = new EasyMDE({
+ autoDownloadFontAwesome: false,
+ autofocus: true,
+ insertTexts: ["[](", ")"],
+ renderingConfig: {
+ markedOptions: {
+ breaks: true,
+ gfm: true
+ }
+ },
+ spellChecker: false,
+ tabSize: 4,
+ showIcons: ['strikethrough', 'code', 'table', 'undo', 'redo', 'heading', 'clean-block', 'horizontal-rule']
+ });
+ var loader = document.getElementById('ml');
+ loader.parentNode.removeChild(loader);
+})();
+
+zsetTimeout(function () { window.location.reload(true); }, 1000);
diff --git a/scripts/deps-docker/Dockerfile b/scripts/deps-docker/Dockerfile
index 571156f7..020b67ba 100644
--- a/scripts/deps-docker/Dockerfile
+++ b/scripts/deps-docker/Dockerfile
@@ -4,7 +4,8 @@ ENV ver_asmcrypto=2821dd1dedd1196c378f5854037dda5c869313f3 \
ver_markdownit=10.0.0 \
ver_showdown=1.9.1 \
ver_marked=1.0.0 \
- ver_ogvjs=1.6.1
+ ver_ogvjs=1.6.1 \
+ ver_mde=2.10.1
# download
@@ -12,6 +13,7 @@ RUN apk add make g++ git bash npm patch wget tar pigz brotli gzip unzip \
&& wget https://github.com/brion/ogv.js/releases/download/$ver_ogvjs/ogvjs-$ver_ogvjs.zip -O ogvjs.zip \
&& wget https://github.com/asmcrypto/asmcrypto.js/archive/$ver_asmcrypto.tar.gz -O asmcrypto.tgz \
&& wget https://github.com/markedjs/marked/archive/v$ver_marked.tar.gz -O marked.tgz \
+ && wget https://github.com/Ionaru/easy-markdown-editor/archive/$ver_mde.tar.gz -O mde.tgz \
&& unzip ogvjs.zip \
&& (tar -xf asmcrypto.tgz \
&& cd asmcrypto.js-$ver_asmcrypto \
@@ -20,7 +22,13 @@ RUN apk add make g++ git bash npm patch wget tar pigz brotli gzip unzip \
&& cd marked-$ver_marked \
&& npm install \
&& npm i grunt uglify-js -g ) \
+ && (tar -xf mde.tgz \
+ && cd easy-markdown-editor* \
+ && npm install \
+ && npm i gulp-cli -g ) \
&& mkdir /z/dist
+# && wget https://github.com/FortAwesome/Font-Awesome/releases/download/5.0.11/fontawesome-free-5.0.11.zip -O fontawesome.zip \
+# && unzip fontawesome.zip \
# uncomment if you wanna test the abandoned markdown converters
@@ -74,10 +82,26 @@ RUN cd marked-$ver_marked \
&& patch -p1 < /z/marked.patch \
&& npm run build \
&& cp -pv marked.min.js /z/dist/marked.js \
- && cp -pv lib/marked.js /z/dist/marked.full.js
+ && cp -pv lib/marked.js /z/dist/marked.full.js \
+ && mkdir -p /z/nodepkgs \
+ && ln -s $(pwd) /z/nodepkgs/marked
# && npm run test \
+# build easymde (TODO man this thing is big)
+RUN cd easy-markdown-editor-$ver_mde \
+ && sed -ri 's`https://registry.npmjs.org/marked/-/marked-0.8.2.tgz`file:/z/nodepkgs/marked`' package-lock.json \
+ && sed -ri 's`("marked": ")[^"]+`\1file:/z/nodepkgs/marked`' ./package.json \
+ && npm install \
+ && gulp \
+ && cp -pv dist/easymde.min.css /z/dist/easymde.css \
+ && cp -pv dist/easymde.min.js /z/dist/easymde.js \
+ && sed -ri '/pipe.terser/d; /cleanCSS/d' gulpfile.js \
+ && gulp \
+ && cp -pv dist/easymde.min.css /z/dist/easymde.full.css \
+ && cp -pv dist/easymde.min.js /z/dist/easymde.full.js
+
+
# build showdown (abandoned; disabled by default)
COPY showdown.patch /z/
RUN [ $build_abandoned ] || exit 0; \
@@ -126,6 +150,9 @@ COPY zopfli.makefile /z/dist/Makefile
RUN cd /z/dist \
&& make -j$(nproc) \
&& rm Makefile
+# && cp -pv "$(find /z/fontawesome-fre* -name fa-regular-400.woff | head -n 1)" fontawesome.woff
+# && cp -pv "$(find /z/fontawesome-fre* -name fontawesome.min.css | head -n 1)" fontawesome.css \
+# && sed -ri 's`@font-face.*``' fontawesome.css \
# showdown: abandoned due to code-blocks in lists failing
@@ -156,5 +183,5 @@ RUN cd /z/dist \
# f=../../copyparty/web/deps/marked.js.gz; (cd ~ed/src/ && diff -NarU1 marked-1.0.0-orig/ marked-1.0.0-edit/) >marked.patch; make && printf '%d ' $(wc -c <$f) $(gzip -d <$f | wc -c); echo
-# d=/home/ed/dev/copyparty/scripts/deps-docker/; scp Dockerfile marked-ln.patch root@$bip:$d && ssh root@$bip "cd $d && make" && ssh root@$bip 'tar -cC /home/ed/dev/copyparty/copyparty/web deps' | (cd ../../copyparty/web/; cat > the.tgz; tar -xvf the.tgz)
+# d=/home/ed/dev/copyparty/scripts/deps-docker/; tar -cf ../x . && ssh root@$bip "cd $d && tar -xv >&2 && make >&2 && tar -cC ../../copyparty/web deps" <../x | (cd ../../copyparty/web/; cat > the.tgz; tar -xvf the.tgz)
# gzip -dkf ../dev/copyparty/copyparty/web/deps/deps/marked.full.js.gz && diff -NarU2 ../dev/copyparty/copyparty/web/deps/{,deps/}marked.full.js