Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7da1dd233 | ||
|
|
678ef296b4 | ||
|
|
9e5627d805 | ||
|
|
5958ee4439 | ||
|
|
7127e57f0e | ||
|
|
ee9c6dc8aa | ||
|
|
92779b3f48 | ||
|
|
2f1baf17d4 | ||
|
|
583da3d4a9 | ||
|
|
bf9ff78bcc | ||
|
|
2cb07792cc | ||
|
|
47bc8bb466 | ||
|
|
94ad1f5732 | ||
|
|
09557fbe83 | ||
|
|
1c0f44fa4e | ||
|
|
fc4d59d2d7 | ||
|
|
12345fbacc | ||
|
|
2e33c8d222 | ||
|
|
db5f07f164 | ||
|
|
e050e69a43 | ||
|
|
27cb1d4fc7 | ||
|
|
5d6a740947 | ||
|
|
da3f68c363 | ||
|
|
d7d1c3685c |
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -9,8 +9,6 @@
|
|||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"args": [
|
"args": [
|
||||||
"-j",
|
|
||||||
"0",
|
|
||||||
//"-nw",
|
//"-nw",
|
||||||
"-a",
|
"-a",
|
||||||
"ed:wark",
|
"ed:wark",
|
||||||
|
|||||||
15
README.md
15
README.md
@@ -19,6 +19,8 @@ turn your phone or raspi into a portable file server with resumable uploads/down
|
|||||||
* Android-Chrome: set max "parallel uploads" for 200% upload speed (android bug)
|
* Android-Chrome: set max "parallel uploads" for 200% upload speed (android bug)
|
||||||
* Android-Firefox: takes a while to select files (in order to avoid the above android-chrome issue)
|
* Android-Firefox: takes a while to select files (in order to avoid the above android-chrome issue)
|
||||||
* Desktop-Firefox: may use gigabytes of RAM if your connection is great and your files are massive
|
* Desktop-Firefox: may use gigabytes of RAM if your connection is great and your files are massive
|
||||||
|
* paper-printing is affected by dark/light-mode! use lightmode for color, darkmode for grayscale
|
||||||
|
* because no browsers currently implement the media-query to do this properly orz
|
||||||
|
|
||||||
|
|
||||||
## status
|
## status
|
||||||
@@ -59,13 +61,16 @@ launch either of them and it'll unpack and run copyparty, assuming you have pyth
|
|||||||
|
|
||||||
pls note that `copyparty-sfx.sh` will fail if you rename `copyparty-sfx.py` to `copyparty.py` and keep it in the same folder because `sys.path` is funky
|
pls note that `copyparty-sfx.sh` will fail if you rename `copyparty-sfx.py` to `copyparty.py` and keep it in the same folder because `sys.path` is funky
|
||||||
|
|
||||||
if you don't need all the features you can repack the sfx and save a bunch of space, tho currently the only removable feature is the opus/vorbis javascript decoder which is needed by apple devices to play foss audio files
|
if you don't need all the features you can repack the sfx and save a bunch of space; all you need is an sfx and a copy of this repo (nothing else to download or build, except for either msys2 or WSL if you're on windows)
|
||||||
|
* `724K` original size as of v0.4.0
|
||||||
|
* `256K` after `./scripts/make-sfx.sh re no-ogv`
|
||||||
|
* `164K` after `./scripts/make-sfx.sh re no-ogv no-cm`
|
||||||
|
|
||||||
steps to reduce the sfx size from `720 kB` to `250 kB` roughly:
|
the features you can opt to drop are
|
||||||
* run one of the sfx'es once to unpack it
|
* `ogv`.js, the opus/vorbis decoder which is needed by apple devices to play foss audio files
|
||||||
* `./scripts/make-sfx.sh re no-ogv` creates a new pair of sfx
|
* `cm`/easymde, the "fancy" markdown editor
|
||||||
|
|
||||||
no internet connection needed, just download an sfx and the repo zip (also if you're on windows use msys2)
|
for the `re`pack to work, first run one of the sfx'es once to unpack it
|
||||||
|
|
||||||
|
|
||||||
# install on android
|
# install on android
|
||||||
|
|||||||
52
bin/copyparty-fuse.py
Executable file → Normal file
52
bin/copyparty-fuse.py
Executable file → Normal file
@@ -22,7 +22,9 @@ from urllib.parse import quote_from_bytes as quote
|
|||||||
try:
|
try:
|
||||||
from fuse import FUSE, FuseOSError, Operations
|
from fuse import FUSE, FuseOSError, Operations
|
||||||
except:
|
except:
|
||||||
print("\n could not import fuse;\n pip install fusepy\n")
|
print(
|
||||||
|
"\n could not import fuse; these may help:\n python3 -m pip install --user fusepy\n apt install libfuse\n modprobe fuse"
|
||||||
|
)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
@@ -34,9 +36,7 @@ usage:
|
|||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
sudo apk add fuse-dev
|
sudo apk add fuse-dev
|
||||||
python3 -m venv ~/pe/ve.fusepy
|
python3 -m pip install --user fusepy
|
||||||
. ~/pe/ve.fusepy/bin/activate
|
|
||||||
pip install fusepy
|
|
||||||
|
|
||||||
|
|
||||||
MB/s
|
MB/s
|
||||||
@@ -60,20 +60,21 @@ def boring_log(msg):
|
|||||||
def rice_tid():
|
def rice_tid():
|
||||||
tid = threading.current_thread().ident
|
tid = threading.current_thread().ident
|
||||||
c = struct.unpack(b"B" * 5, struct.pack(b">Q", tid)[-5:])
|
c = struct.unpack(b"B" * 5, struct.pack(b">Q", tid)[-5:])
|
||||||
return "".join("\033[1;37;48;5;{}m{:02x}".format(x, x) for x in c)
|
return "".join("\033[1;37;48;5;{}m{:02x}".format(x, x) for x in c) + "\033[0m"
|
||||||
|
|
||||||
|
|
||||||
def fancy_log(msg):
|
def fancy_log(msg):
|
||||||
print("{}\033[0m {}\n".format(rice_tid(), msg), end="")
|
print("{} {}\n".format(rice_tid(), msg), end="")
|
||||||
|
|
||||||
|
|
||||||
def null_log(msg):
|
def null_log(msg):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
log = boring_log
|
info = fancy_log
|
||||||
log = fancy_log
|
log = fancy_log
|
||||||
log = threadless_log
|
dbg = fancy_log
|
||||||
|
log = null_log
|
||||||
dbg = null_log
|
dbg = null_log
|
||||||
|
|
||||||
|
|
||||||
@@ -118,7 +119,7 @@ class Gateway(object):
|
|||||||
try:
|
try:
|
||||||
return self.conns[tid]
|
return self.conns[tid]
|
||||||
except:
|
except:
|
||||||
log("new conn [{}] [{}]".format(self.web_host, self.web_port))
|
info("new conn [{}] [{}]".format(self.web_host, self.web_port))
|
||||||
|
|
||||||
conn = http.client.HTTPConnection(self.web_host, self.web_port, timeout=260)
|
conn = http.client.HTTPConnection(self.web_host, self.web_port, timeout=260)
|
||||||
|
|
||||||
@@ -146,13 +147,13 @@ class Gateway(object):
|
|||||||
return c.getresponse()
|
return c.getresponse()
|
||||||
|
|
||||||
def listdir(self, path):
|
def listdir(self, path):
|
||||||
web_path = "/" + "/".join([self.web_root, path])
|
web_path = "/" + "/".join([self.web_root, path]) + "?dots"
|
||||||
|
|
||||||
r = self.sendreq("GET", self.quotep(web_path))
|
r = self.sendreq("GET", self.quotep(web_path))
|
||||||
if r.status != 200:
|
if r.status != 200:
|
||||||
self.closeconn()
|
self.closeconn()
|
||||||
raise Exception(
|
raise Exception(
|
||||||
"http error {} reading dir {} in {:x}".format(
|
"http error {} reading dir {} in {}".format(
|
||||||
r.status, web_path, rice_tid()
|
r.status, web_path, rice_tid()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -160,15 +161,15 @@ class Gateway(object):
|
|||||||
return self.parse_html(r)
|
return self.parse_html(r)
|
||||||
|
|
||||||
def download_file_range(self, path, ofs1, ofs2):
|
def download_file_range(self, path, ofs1, ofs2):
|
||||||
web_path = "/" + "/".join([self.web_root, path])
|
web_path = "/" + "/".join([self.web_root, path]) + "?raw"
|
||||||
hdr_range = "bytes={}-{}".format(ofs1, ofs2)
|
hdr_range = "bytes={}-{}".format(ofs1, ofs2 - 1)
|
||||||
log("downloading {}".format(hdr_range))
|
log("downloading {}".format(hdr_range))
|
||||||
|
|
||||||
r = self.sendreq("GET", self.quotep(web_path), headers={"Range": hdr_range})
|
r = self.sendreq("GET", self.quotep(web_path), headers={"Range": hdr_range})
|
||||||
if r.status != http.client.PARTIAL_CONTENT:
|
if r.status != http.client.PARTIAL_CONTENT:
|
||||||
self.closeconn()
|
self.closeconn()
|
||||||
raise Exception(
|
raise Exception(
|
||||||
"http error {} reading file {} range {} in {:x}".format(
|
"http error {} reading file {} range {} in {}".format(
|
||||||
r.status, web_path, hdr_range, rice_tid()
|
r.status, web_path, hdr_range, rice_tid()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -246,14 +247,14 @@ class CPPF(Operations):
|
|||||||
self.filecache = []
|
self.filecache = []
|
||||||
self.filecache_mtx = threading.Lock()
|
self.filecache_mtx = threading.Lock()
|
||||||
|
|
||||||
log("up")
|
info("up")
|
||||||
|
|
||||||
def clean_dircache(self):
|
def clean_dircache(self):
|
||||||
"""not threadsafe"""
|
"""not threadsafe"""
|
||||||
now = time.time()
|
now = time.time()
|
||||||
cutoff = 0
|
cutoff = 0
|
||||||
for cn in self.dircache:
|
for cn in self.dircache:
|
||||||
if cn.ts - now > 1:
|
if now - cn.ts > 1:
|
||||||
cutoff += 1
|
cutoff += 1
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
@@ -398,7 +399,7 @@ class CPPF(Operations):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
buf = self.gw.download_file_range(path, h_ofs, h_end - 1)
|
buf = self.gw.download_file_range(path, h_ofs, h_end)
|
||||||
ret = buf[-buf_ofs:] + cdr
|
ret = buf[-buf_ofs:] + cdr
|
||||||
|
|
||||||
elif car:
|
elif car:
|
||||||
@@ -416,7 +417,7 @@ class CPPF(Operations):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
buf = self.gw.download_file_range(path, h_ofs, h_end - 1)
|
buf = self.gw.download_file_range(path, h_ofs, h_end)
|
||||||
ret = car + buf[:buf_ofs]
|
ret = car + buf[:buf_ofs]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -438,7 +439,7 @@ class CPPF(Operations):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
buf = self.gw.download_file_range(path, h_ofs, h_end - 1)
|
buf = self.gw.download_file_range(path, h_ofs, h_end)
|
||||||
ret = buf[buf_ofs:buf_end]
|
ret = buf[buf_ofs:buf_end]
|
||||||
|
|
||||||
cn = CacheNode([path, h_ofs], buf)
|
cn = CacheNode([path, h_ofs], buf)
|
||||||
@@ -472,13 +473,16 @@ class CPPF(Operations):
|
|||||||
log("read {} @ {} len {} end {}".format(path, offset, length, ofs2))
|
log("read {} @ {} len {} end {}".format(path, offset, length, ofs2))
|
||||||
|
|
||||||
file_sz = self.getattr(path)["st_size"]
|
file_sz = self.getattr(path)["st_size"]
|
||||||
if ofs2 >= file_sz:
|
if ofs2 > file_sz:
|
||||||
ofs2 = file_sz - 1
|
ofs2 = file_sz
|
||||||
log("truncate to len {} end {}".format((ofs2 - offset) + 1, ofs2))
|
log("truncate to len {} end {}".format(ofs2 - offset, ofs2))
|
||||||
|
|
||||||
|
if file_sz == 0 or offset >= ofs2:
|
||||||
|
return b""
|
||||||
|
|
||||||
# toggle cache here i suppose
|
# toggle cache here i suppose
|
||||||
# return self.get_cached_file(path, offset, ofs2, file_sz)
|
# return self.get_cached_file(path, offset, ofs2, file_sz)
|
||||||
return self.gw.download_file_range(path, offset, ofs2 - 1)
|
return self.gw.download_file_range(path, offset, ofs2)
|
||||||
|
|
||||||
def getattr(self, path, fh=None):
|
def getattr(self, path, fh=None):
|
||||||
path = path.strip("/")
|
path = path.strip("/")
|
||||||
@@ -495,7 +499,7 @@ class CPPF(Operations):
|
|||||||
|
|
||||||
cn = self.get_cached_dir(dirpath)
|
cn = self.get_cached_dir(dirpath)
|
||||||
if cn:
|
if cn:
|
||||||
# log('cache ok')
|
log("cache ok")
|
||||||
dents = cn.data
|
dents = cn.data
|
||||||
else:
|
else:
|
||||||
log("cache miss")
|
log("cache miss")
|
||||||
|
|||||||
@@ -129,11 +129,14 @@ def main():
|
|||||||
ap.add_argument("-i", metavar="IP", type=str, default="0.0.0.0", help="ip to bind")
|
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=1234, help="port to bind")
|
ap.add_argument("-p", metavar="PORT", type=int, default=1234, help="port to bind")
|
||||||
ap.add_argument("-nc", metavar="NUM", type=int, default=16, help="max num clients")
|
ap.add_argument("-nc", metavar="NUM", type=int, default=16, help="max num clients")
|
||||||
ap.add_argument("-j", metavar="CORES", type=int, 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("-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("-v", metavar="VOL", type=str, action="append", help="add volume")
|
||||||
ap.add_argument("-q", action="store_true", help="quiet")
|
ap.add_argument("-q", action="store_true", help="quiet")
|
||||||
ap.add_argument("-nw", action="store_true", help="benchmark: disable writing")
|
ap.add_argument("-ed", action="store_true", help="enable ?dots")
|
||||||
|
ap.add_argument("-nw", action="store_true", help="disable writes (benchmark)")
|
||||||
al = ap.parse_args()
|
al = ap.parse_args()
|
||||||
|
|
||||||
SvcHub(al).run()
|
SvcHub(al).run()
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
VERSION = (0, 4, 0)
|
VERSION = (0, 4, 3)
|
||||||
CODENAME = "NIH"
|
CODENAME = "NIH"
|
||||||
BUILD_DT = (2020, 5, 13)
|
BUILD_DT = (2020, 5, 17)
|
||||||
|
|
||||||
S_VERSION = ".".join(map(str, VERSION))
|
S_VERSION = ".".join(map(str, VERSION))
|
||||||
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class BrokerMp(object):
|
|||||||
self.mutex = threading.Lock()
|
self.mutex = threading.Lock()
|
||||||
|
|
||||||
cores = self.args.j
|
cores = self.args.j
|
||||||
if cores is None:
|
if not cores:
|
||||||
cores = mp.cpu_count()
|
cores = mp.cpu_count()
|
||||||
|
|
||||||
self.log("broker", "booting {} subprocesses".format(cores))
|
self.log("broker", "booting {} subprocesses".format(cores))
|
||||||
|
|||||||
@@ -769,11 +769,20 @@ class HttpCli(object):
|
|||||||
else:
|
else:
|
||||||
upper = file_sz
|
upper = file_sz
|
||||||
|
|
||||||
if lower < 0 or lower >= file_sz or upper < 0 or upper > file_sz:
|
if upper > file_sz:
|
||||||
|
upper = file_sz
|
||||||
|
|
||||||
|
if lower < 0 or lower >= upper:
|
||||||
raise Exception()
|
raise Exception()
|
||||||
|
|
||||||
except:
|
except:
|
||||||
raise Pebkac(400, "invalid range requested: " + hrange)
|
err = "invalid range ({}), size={}".format(hrange, file_sz)
|
||||||
|
self.loud_reply(
|
||||||
|
err,
|
||||||
|
status=416,
|
||||||
|
headers={"Content-Range": "bytes */{}".format(file_sz)},
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
status = 206
|
status = 206
|
||||||
self.out_headers["Content-Range"] = "bytes {}-{}/{}".format(
|
self.out_headers["Content-Range"] = "bytes {}-{}/{}".format(
|
||||||
@@ -941,9 +950,13 @@ class HttpCli(object):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# show dotfiles if permitted and requested
|
||||||
|
if not self.args.ed or "dots" not in self.uparam:
|
||||||
|
vfs_ls = exclude_dotfiles(vfs_ls)
|
||||||
|
|
||||||
dirs = []
|
dirs = []
|
||||||
files = []
|
files = []
|
||||||
for fn in exclude_dotfiles(vfs_ls):
|
for fn in vfs_ls:
|
||||||
base = ""
|
base = ""
|
||||||
href = fn
|
href = fn
|
||||||
if self.absolute_urls and vpath:
|
if self.absolute_urls and vpath:
|
||||||
|
|||||||
@@ -80,8 +80,9 @@ class HttpSrv(object):
|
|||||||
"%s %s" % addr,
|
"%s %s" % addr,
|
||||||
"shut_rdwr err:\n {}\n {}".format(repr(sck), ex),
|
"shut_rdwr err:\n {}\n {}".format(repr(sck), ex),
|
||||||
)
|
)
|
||||||
if ex.errno not in [10038, 107, 57, 9]:
|
if ex.errno not in [10038, 10054, 107, 57, 9]:
|
||||||
# 10038 No longer considered a socket
|
# 10038 No longer considered a socket
|
||||||
|
# 10054 Foribly closed by remote
|
||||||
# 107 Transport endpoint not connected
|
# 107 Transport endpoint not connected
|
||||||
# 57 Socket is not connected
|
# 57 Socket is not connected
|
||||||
# 9 Bad file descriptor
|
# 9 Bad file descriptor
|
||||||
|
|||||||
@@ -129,8 +129,8 @@ class SvcHub(object):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def check_mp_enable(self):
|
def check_mp_enable(self):
|
||||||
if self.args.j == 0:
|
if self.args.j == 1:
|
||||||
self.log("root", "multiprocessing disabled by argument -j 0;")
|
self.log("root", "multiprocessing disabled by argument -j 1;")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if mp.cpu_count() <= 1:
|
if mp.cpu_count() <= 1:
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ HTTPCODE = {
|
|||||||
404: "Not Found",
|
404: "Not Found",
|
||||||
405: "Method Not Allowed",
|
405: "Method Not Allowed",
|
||||||
413: "Payload Too Large",
|
413: "Payload Too Large",
|
||||||
|
416: "Requested Range Not Satisfiable",
|
||||||
422: "Unprocessable Entity",
|
422: "Unprocessable Entity",
|
||||||
500: "Internal Server Error",
|
500: "Internal Server Error",
|
||||||
501: "Not Implemented",
|
501: "Not Implemented",
|
||||||
@@ -309,18 +310,7 @@ def get_boundary(headers):
|
|||||||
def read_header(sr):
|
def read_header(sr):
|
||||||
ret = b""
|
ret = b""
|
||||||
while True:
|
while True:
|
||||||
if ret.endswith(b"\r\n\r\n"):
|
buf = sr.recv(1024)
|
||||||
break
|
|
||||||
elif ret.endswith(b"\r\n\r"):
|
|
||||||
n = 1
|
|
||||||
elif ret.endswith(b"\r\n"):
|
|
||||||
n = 2
|
|
||||||
elif ret.endswith(b"\r"):
|
|
||||||
n = 3
|
|
||||||
else:
|
|
||||||
n = 4
|
|
||||||
|
|
||||||
buf = sr.recv(n)
|
|
||||||
if not buf:
|
if not buf:
|
||||||
if not ret:
|
if not ret:
|
||||||
return None
|
return None
|
||||||
@@ -332,11 +322,15 @@ def read_header(sr):
|
|||||||
)
|
)
|
||||||
|
|
||||||
ret += buf
|
ret += buf
|
||||||
|
ofs = ret.find(b"\r\n\r\n")
|
||||||
|
if ofs < 0:
|
||||||
|
if len(ret) > 1024 * 64:
|
||||||
|
raise Pebkac(400, "header 2big")
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
if len(ret) > 1024 * 64:
|
sr.unrecv(ret[ofs + 4 :])
|
||||||
raise Pebkac(400, "header 2big")
|
return ret[:ofs].decode("utf-8", "surrogateescape").split("\r\n")
|
||||||
|
|
||||||
return ret[:-4].decode("utf-8", "surrogateescape").split("\r\n")
|
|
||||||
|
|
||||||
|
|
||||||
def undot(path):
|
def undot(path):
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th>File Name</th>
|
<th>File Name</th>
|
||||||
<th>File Size</th>
|
<th sort="int">File Size</th>
|
||||||
<th>Date</th>
|
<th>Date</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|||||||
@@ -106,7 +106,9 @@ function makeSortable(table) {
|
|||||||
if (th) i = th.length;
|
if (th) i = th.length;
|
||||||
else return; // if no `<thead>` then do nothing
|
else return; // if no `<thead>` then do nothing
|
||||||
while (--i >= 0) (function (i) {
|
while (--i >= 0) (function (i) {
|
||||||
th[i].addEventListener('click', function () { sortTable(table, i) });
|
th[i].onclick = function () {
|
||||||
|
sortTable(table, i);
|
||||||
|
};
|
||||||
}(i));
|
}(i));
|
||||||
}
|
}
|
||||||
makeSortable(o('files'));
|
makeSortable(o('files'));
|
||||||
@@ -123,7 +125,6 @@ var mp = (function () {
|
|||||||
'cover_url': ''
|
'cover_url': ''
|
||||||
};
|
};
|
||||||
var re_audio = new RegExp('\.(opus|ogg|m4a|aac|mp3|wav|flac)$', 'i');
|
var re_audio = new RegExp('\.(opus|ogg|m4a|aac|mp3|wav|flac)$', 'i');
|
||||||
var re_cover = new RegExp('^(cover|folder|cd|front|back)\.(jpe?g|png|gif)$', 'i');
|
|
||||||
|
|
||||||
var trs = document.getElementById('files').getElementsByTagName('tbody')[0].getElementsByTagName('tr');
|
var trs = document.getElementById('files').getElementsByTagName('tbody')[0].getElementsByTagName('tr');
|
||||||
for (var a = 0, aa = trs.length; a < aa; a++) {
|
for (var a = 0, aa = trs.length; a < aa; a++) {
|
||||||
@@ -414,15 +415,6 @@ var vbar = (function () {
|
|||||||
var x = e.clientX - rect.left;
|
var x = e.clientX - rect.left;
|
||||||
var mul = x * 1.0 / rect.width;
|
var mul = x * 1.0 / rect.width;
|
||||||
|
|
||||||
/*
|
|
||||||
dbg(//Math.round(rect.width) + 'x' + Math.round(rect.height) + '+' +
|
|
||||||
//Math.round(rect.left) + '+' + Math.round(rect.top) + ', ' +
|
|
||||||
//Math.round(e.clientX) + 'x' + Math.round(e.clientY) + ', ' +
|
|
||||||
Math.round(mp.au.currentTime * 10) / 10 + ', ' +
|
|
||||||
Math.round(mp.au.duration * 10) / 10 + '*' +
|
|
||||||
Math.round(mul * 1000) / 1000);
|
|
||||||
*/
|
|
||||||
|
|
||||||
mp.au.currentTime = mp.au.duration * mul;
|
mp.au.currentTime = mp.au.duration * mul;
|
||||||
|
|
||||||
if (mp.au === mp.au_native)
|
if (mp.au === mp.au_native)
|
||||||
@@ -483,8 +475,14 @@ function setclass(id, clas) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var iOS = !!navigator.platform &&
|
var need_ogv = true;
|
||||||
/iPad|iPhone|iPod/.test(navigator.platform);
|
try {
|
||||||
|
need_ogv = new Audio().canPlayType('audio/ogg; codecs=opus') !== 'probably';
|
||||||
|
|
||||||
|
if (/ Edge\//.exec(navigator.userAgent + ''))
|
||||||
|
need_ogv = true;
|
||||||
|
}
|
||||||
|
catch (ex) { }
|
||||||
|
|
||||||
|
|
||||||
// plays the tid'th audio file on the page
|
// plays the tid'th audio file on the page
|
||||||
@@ -507,7 +505,7 @@ function play(tid, call_depth) {
|
|||||||
var hack_attempt_play = true;
|
var hack_attempt_play = true;
|
||||||
|
|
||||||
var url = mp.tracks[tid];
|
var url = mp.tracks[tid];
|
||||||
if (iOS && /\.(ogg|opus)$/i.test(url)) {
|
if (need_ogv && /\.(ogg|opus)$/i.test(url)) {
|
||||||
if (mp.au_ogvjs) {
|
if (mp.au_ogvjs) {
|
||||||
mp.au = mp.au_ogvjs;
|
mp.au = mp.au_ogvjs;
|
||||||
}
|
}
|
||||||
@@ -594,7 +592,6 @@ function evau_error(e) {
|
|||||||
err += '\n\nFile: «' + decodeURIComponent(eplaya.src.split('/').slice(-1)[0]) + '»';
|
err += '\n\nFile: «' + decodeURIComponent(eplaya.src.split('/').slice(-1)[0]) + '»';
|
||||||
|
|
||||||
alert(err);
|
alert(err);
|
||||||
play(eplaya.tid + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -613,7 +610,7 @@ function show_modal(html) {
|
|||||||
function unblocked() {
|
function unblocked() {
|
||||||
var dom = o('blocked');
|
var dom = o('blocked');
|
||||||
if (dom)
|
if (dom)
|
||||||
dom.remove();
|
dom.parentNode.removeChild(dom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'scp';
|
||||||
|
src: local('Source Code Pro Regular'), local('SourceCodePro-Regular'), url(/.cpr/deps/scp.woff2) format('woff2');
|
||||||
|
}
|
||||||
html, body {
|
html, body {
|
||||||
color: #333;
|
color: #333;
|
||||||
background: #eee;
|
background: #eee;
|
||||||
@@ -9,6 +13,7 @@ html, body {
|
|||||||
}
|
}
|
||||||
#mw {
|
#mw {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
padding: 0 1.5em;
|
||||||
}
|
}
|
||||||
pre, code, a {
|
pre, code, a {
|
||||||
color: #480;
|
color: #480;
|
||||||
@@ -22,7 +27,7 @@ code {
|
|||||||
font-size: .96em;
|
font-size: .96em;
|
||||||
}
|
}
|
||||||
pre, code {
|
pre, code {
|
||||||
font-family: monospace, monospace;
|
font-family: 'scp', monospace, monospace;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
@@ -42,7 +47,7 @@ pre code {
|
|||||||
pre code:last-child {
|
pre code:last-child {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
pre code:before {
|
pre code::before {
|
||||||
content: counter(precode);
|
content: counter(precode);
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -83,6 +88,7 @@ h3 {
|
|||||||
h1 a, h3 a, h5 a,
|
h1 a, h3 a, h5 a,
|
||||||
h2 a, h4 a, h6 a {
|
h2 a, h4 a, h6 a {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
|
display: block;
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -167,14 +173,12 @@ small {
|
|||||||
}
|
}
|
||||||
table {
|
table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
|
margin: 1em 0;
|
||||||
}
|
}
|
||||||
td {
|
th, td {
|
||||||
padding: .2em .5em;
|
padding: .2em .5em;
|
||||||
border: .12em solid #aaa;
|
border: .12em solid #aaa;
|
||||||
}
|
}
|
||||||
th {
|
|
||||||
border: .12em solid #aaa;
|
|
||||||
}
|
|
||||||
blink {
|
blink {
|
||||||
animation: blinker .7s cubic-bezier(.9, 0, .1, 1) infinite;
|
animation: blinker .7s cubic-bezier(.9, 0, .1, 1) infinite;
|
||||||
}
|
}
|
||||||
@@ -197,13 +201,15 @@ blink {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
#mw {
|
#mw {
|
||||||
padding: 0 1em;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
#mp {
|
#mp {
|
||||||
max-width: 54em;
|
max-width: 52em;
|
||||||
margin-bottom: 6em;
|
margin-bottom: 6em;
|
||||||
|
word-break: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
word-wrap: break-word; /*ie*/
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@@ -237,12 +243,6 @@ blink {
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
width: calc(100% - 1em);
|
width: calc(100% - 1em);
|
||||||
}
|
}
|
||||||
#mn.undocked {
|
|
||||||
position: fixed;
|
|
||||||
padding: 1.2em 0 1em 1em;
|
|
||||||
box-shadow: 0 0 .5em rgba(0, 0, 0, 0.3);
|
|
||||||
background: #f7f7f7;
|
|
||||||
}
|
|
||||||
#mn a {
|
#mn a {
|
||||||
color: #444;
|
color: #444;
|
||||||
background: none;
|
background: none;
|
||||||
@@ -260,7 +260,7 @@ blink {
|
|||||||
#mn a:last-child {
|
#mn a:last-child {
|
||||||
padding-right: .5em;
|
padding-right: .5em;
|
||||||
}
|
}
|
||||||
#mn a:not(:last-child):after {
|
#mn a:not(:last-child)::after {
|
||||||
content: '';
|
content: '';
|
||||||
width: 1.05em;
|
width: 1.05em;
|
||||||
height: 1.05em;
|
height: 1.05em;
|
||||||
@@ -354,7 +354,7 @@ blink {
|
|||||||
background: #282828;
|
background: #282828;
|
||||||
border: .07em dashed #444;
|
border: .07em dashed #444;
|
||||||
}
|
}
|
||||||
html.dark #mn a:not(:last-child):after {
|
html.dark #mn a:not(:last-child)::after {
|
||||||
border-color: rgba(255,255,255,0.3);
|
border-color: rgba(255,255,255,0.3);
|
||||||
}
|
}
|
||||||
html.dark #mn a {
|
html.dark #mn a {
|
||||||
@@ -373,19 +373,19 @@ blink {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 70em) {
|
@media screen and (min-width: 66em) {
|
||||||
#mw {
|
#mw {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
left: 14em;
|
left: 14em;
|
||||||
left: calc(100% - 57em);
|
left: calc(100% - 55em);
|
||||||
max-width: none;
|
max-width: none;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
scrollbar-color: #eb0 #f7f7f7;
|
scrollbar-color: #eb0 #f7f7f7;
|
||||||
}
|
}
|
||||||
#toc {
|
#toc {
|
||||||
width: 13em;
|
width: 13em;
|
||||||
width: calc(100% - 57.3em);
|
width: calc(100% - 55.3em);
|
||||||
max-width: 30em;
|
max-width: 30em;
|
||||||
background: #eee;
|
background: #eee;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -424,32 +424,126 @@ blink {
|
|||||||
html.dark #mw {
|
html.dark #mw {
|
||||||
scrollbar-color: #b80 #282828;
|
scrollbar-color: #b80 #282828;
|
||||||
}
|
}
|
||||||
html.dark #mn.undocked {
|
html.dark #toc::-webkit-scrollbar-track {
|
||||||
box-shadow: 0 0 .5em #555;
|
background: #282828;
|
||||||
border: none;
|
}
|
||||||
background: #0a0a0a;
|
html.dark #toc::-webkit-scrollbar {
|
||||||
|
background: #282828;
|
||||||
|
width: .8em;
|
||||||
|
}
|
||||||
|
html.dark #toc::-webkit-scrollbar-thumb {
|
||||||
|
background: #b80;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media screen and (min-width: 87.5em) {
|
@media screen and (min-width: 85.5em) {
|
||||||
#toc { width: 30em }
|
#toc { width: 30em }
|
||||||
#mw { left: 30.5em }
|
#mw { left: 30.5em }
|
||||||
}
|
}
|
||||||
@media print {
|
@media print {
|
||||||
|
@page {
|
||||||
|
size: A4;
|
||||||
|
padding: 0;
|
||||||
|
margin: .5in .6in;
|
||||||
|
mso-header-margin: .6in;
|
||||||
|
mso-footer-margin: .6in;
|
||||||
|
mso-paper-source: 0;
|
||||||
|
}
|
||||||
a {
|
a {
|
||||||
color: #079;
|
color: #079;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
border-bottom: .07em solid #4ac;
|
border-bottom: .07em solid #4ac;
|
||||||
padding: 0 .3em;
|
padding: 0 .3em;
|
||||||
}
|
}
|
||||||
#toc {
|
|
||||||
margin: 0 !important;
|
|
||||||
}
|
|
||||||
#toc>ul {
|
#toc>ul {
|
||||||
border-left: .1em solid #84c4dd;
|
border-left: .1em solid #84c4dd;
|
||||||
}
|
}
|
||||||
#mn, #mh {
|
#mn, #mh {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
html, body, #toc, #mw {
|
||||||
|
margin: 0 !important;
|
||||||
|
word-break: break-word;
|
||||||
|
width: 52em;
|
||||||
|
}
|
||||||
|
#toc {
|
||||||
|
margin-left: 1em !important;
|
||||||
|
}
|
||||||
|
#toc a {
|
||||||
|
color: #000 !important;
|
||||||
|
}
|
||||||
|
#toc a::after {
|
||||||
|
/* hopefully supported by browsers eventually */
|
||||||
|
content: leader('.') target-counter(attr(href), page);
|
||||||
|
}
|
||||||
|
a[ctr]::before {
|
||||||
|
content: attr(ctr) '. ';
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
margin: 2em 0;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
margin: 2em 0 0 0;
|
||||||
|
}
|
||||||
|
h1, h2, h3 {
|
||||||
|
page-break-inside: avoid;
|
||||||
|
}
|
||||||
|
h1::after,
|
||||||
|
h2::after,
|
||||||
|
h3::after {
|
||||||
|
content: 'orz';
|
||||||
|
color: transparent;
|
||||||
|
display: block;
|
||||||
|
line-height: 1em;
|
||||||
|
padding: 4em 0 0 0;
|
||||||
|
margin: 0 0 -5em 0;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
page-break-inside: avoid;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
page-break-inside: auto;
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
page-break-inside: avoid;
|
||||||
|
page-break-after: auto;
|
||||||
|
}
|
||||||
|
thead {
|
||||||
|
display: table-header-group;
|
||||||
|
}
|
||||||
|
tfoot {
|
||||||
|
display: table-footer-group;
|
||||||
|
}
|
||||||
|
#mp a.vis::after {
|
||||||
|
content: ' (' attr(href) ')';
|
||||||
|
border-bottom: 1px solid #bbb;
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
blockquote {
|
||||||
|
border-color: #555;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
border-color: #bbb;
|
||||||
|
}
|
||||||
|
pre, pre code {
|
||||||
|
border-color: #999;
|
||||||
|
}
|
||||||
|
pre code::before {
|
||||||
|
color: #058;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
html.dark a {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
html.dark pre,
|
||||||
|
html.dark code {
|
||||||
|
color: #240;
|
||||||
|
}
|
||||||
|
html.dark p>em,
|
||||||
|
html.dark li>em {
|
||||||
|
color: #940;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
{%- else %}
|
{%- else %}
|
||||||
<a href="?edit">edit (basic)</a>
|
<a href="?edit">edit (basic)</a>
|
||||||
<a href="?edit2">edit (fancy)</a>
|
<a href="?edit2">edit (fancy)</a>
|
||||||
|
<a href="?raw">view raw</a>
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
</div>
|
</div>
|
||||||
<div id="toc"></div>
|
<div id="toc"></div>
|
||||||
@@ -41,14 +42,14 @@
|
|||||||
<div id="helpbox">
|
<div id="helpbox">
|
||||||
<textarea>
|
<textarea>
|
||||||
|
|
||||||
write markdown (html is permitted)
|
write markdown (most html is 🙆 too)
|
||||||
|
|
||||||
### hotkey list
|
## hotkey list
|
||||||
* `Ctrl-S` to save
|
* `Ctrl-S` to save
|
||||||
* `Ctrl-H` / `Ctrl-Shift-H` to create a header
|
* `Ctrl-H` / `Ctrl-Shift-H` to create a header
|
||||||
* `TAB` / `Shift-TAB` to indent/dedent a selection
|
* `TAB` / `Shift-TAB` to indent/dedent a selection
|
||||||
|
|
||||||
### toolbar
|
## toolbar
|
||||||
1. toggle dark mode
|
1. toggle dark mode
|
||||||
2. show/hide navigation bar
|
2. show/hide navigation bar
|
||||||
3. save changes on server
|
3. save changes on server
|
||||||
@@ -56,8 +57,56 @@ write markdown (html is permitted)
|
|||||||
5. toggle editor/preview
|
5. toggle editor/preview
|
||||||
6. this thing :^)
|
6. this thing :^)
|
||||||
|
|
||||||
.
|
## markdown
|
||||||
|
|||
|
||||||
|
|--|--|
|
||||||
|
|`**bold**`|**bold**|
|
||||||
|
|`_italic_`|_italic_|
|
||||||
|
|`~~strike~~`|~~strike~~|
|
||||||
|
|`` `code` ``|`code`|
|
||||||
|
|`[](#hotkey-list)`|[](#hotkey-list)|
|
||||||
|
|`[](/foo/bar.md#header)`|[](/foo/bar.md#header)|
|
||||||
|
|`<blink>💯</blink>`|<blink>💯</blink>|
|
||||||
|
|
||||||
|
## tables
|
||||||
|
|left-aligned|centered|right-aligned
|
||||||
|
| ---------- | :----: | ----------:
|
||||||
|
|one |two |three
|
||||||
|
|
||||||
|
|left-aligned|centered|right-aligned
|
||||||
|
| ---------- | :----: | ----------:
|
||||||
|
|one |two |three
|
||||||
|
|
||||||
|
## lists
|
||||||
|
* one
|
||||||
|
* two
|
||||||
|
1. one
|
||||||
|
1. two
|
||||||
|
* one
|
||||||
|
* two
|
||||||
|
1. one
|
||||||
|
1. two
|
||||||
|
|
||||||
|
## headers
|
||||||
|
# level 1
|
||||||
|
## level 2
|
||||||
|
### level 3
|
||||||
|
|
||||||
|
## quote
|
||||||
|
> hello
|
||||||
|
> hello
|
||||||
|
|
||||||
|
## codeblock
|
||||||
|
four spaces (no tab pls)
|
||||||
|
|
||||||
|
## code in lists
|
||||||
|
* foo
|
||||||
|
bar
|
||||||
|
six spaces total
|
||||||
|
* foo
|
||||||
|
bar
|
||||||
|
six spaces total
|
||||||
|
.
|
||||||
</textarea>
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|||||||
@@ -6,10 +6,48 @@ var dom_pre = document.getElementById('mp');
|
|||||||
var dom_src = document.getElementById('mt');
|
var dom_src = document.getElementById('mt');
|
||||||
var dom_navtgl = document.getElementById('navtoggle');
|
var dom_navtgl = document.getElementById('navtoggle');
|
||||||
|
|
||||||
|
|
||||||
|
// chrome 49 needs this
|
||||||
|
var chromedbg = function () { console.log(arguments); }
|
||||||
|
|
||||||
|
// null-logger
|
||||||
|
var dbg = function () { };
|
||||||
|
|
||||||
|
// replace dbg with the real deal here or in the console:
|
||||||
|
// dbg = chromedbg
|
||||||
|
// dbg = console.log
|
||||||
|
|
||||||
|
|
||||||
function hesc(txt) {
|
function hesc(txt) {
|
||||||
return txt.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
return txt.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function cls(dom, name, add) {
|
||||||
|
var re = new RegExp('(^| )' + name + '( |$)');
|
||||||
|
var lst = (dom.getAttribute('class') + '').replace(re, "$1$2").replace(/ /, "");
|
||||||
|
dom.setAttribute('class', lst + (add ? ' ' + name : ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function static(obj) {
|
||||||
|
return JSON.parse(JSON.stringify(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// dodge browser issues
|
||||||
|
(function () {
|
||||||
|
var ua = navigator.userAgent;
|
||||||
|
if (ua.indexOf(') Gecko/') !== -1 && /Linux| Mac /.exec(ua)) {
|
||||||
|
// necessary on ff-68.7 at least
|
||||||
|
var s = document.createElement('style');
|
||||||
|
s.innerHTML = '@page { margin: .5in .6in .8in .6in; }';
|
||||||
|
console.log(s.innerHTML);
|
||||||
|
document.head.appendChild(s);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
// add navbar
|
// add navbar
|
||||||
(function () {
|
(function () {
|
||||||
var n = document.location + '';
|
var n = document.location + '';
|
||||||
@@ -28,17 +66,116 @@ function hesc(txt) {
|
|||||||
dom_nav.innerHTML = nav.join('');
|
dom_nav.innerHTML = nav.join('');
|
||||||
})();
|
})();
|
||||||
|
|
||||||
function convert_markdown(md_text) {
|
|
||||||
|
// faster than replacing the entire html (chrome 1.8x, firefox 1.6x)
|
||||||
|
function copydom(src, dst, lv) {
|
||||||
|
var sc = src.childNodes,
|
||||||
|
dc = dst.childNodes;
|
||||||
|
|
||||||
|
if (sc.length !== dc.length) {
|
||||||
|
dbg("replace L%d (%d/%d) |%d|",
|
||||||
|
lv, sc.length, dc.length, src.innerHTML.length);
|
||||||
|
|
||||||
|
dst.innerHTML = src.innerHTML;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rpl = [];
|
||||||
|
for (var a = sc.length - 1; a >= 0; a--) {
|
||||||
|
var st = sc[a].tagName,
|
||||||
|
dt = dc[a].tagName;
|
||||||
|
|
||||||
|
if (st !== dt) {
|
||||||
|
dbg("replace L%d (%d/%d) type %s/%s", lv, a, sc.length, st, dt);
|
||||||
|
rpl.push(a);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sa = sc[a].attributes || [],
|
||||||
|
da = dc[a].attributes || [];
|
||||||
|
|
||||||
|
if (sa.length !== da.length) {
|
||||||
|
dbg("replace L%d (%d/%d) attr# %d/%d",
|
||||||
|
lv, a, sc.length, sa.length, da.length);
|
||||||
|
|
||||||
|
rpl.push(a);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dirty = false;
|
||||||
|
for (var b = sa.length - 1; b >= 0; b--) {
|
||||||
|
var name = sa[b].name,
|
||||||
|
sv = sa[b].value,
|
||||||
|
dv = dc[a].getAttribute(name);
|
||||||
|
|
||||||
|
if (name == "data-ln" && sv !== dv) {
|
||||||
|
dc[a].setAttribute(name, sv);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sv !== dv) {
|
||||||
|
dbg("replace L%d (%d/%d) attr %s [%s] [%s]",
|
||||||
|
lv, a, sc.length, name, sv, dv);
|
||||||
|
|
||||||
|
dirty = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dirty)
|
||||||
|
rpl.push(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO pure guessing
|
||||||
|
if (rpl.length > sc.length / 3) {
|
||||||
|
dbg("replace L%d fully, %s (%d/%d) |%d|",
|
||||||
|
lv, rpl.length, sc.length, src.innerHTML.length);
|
||||||
|
|
||||||
|
dst.innerHTML = src.innerHTML;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// repl is reversed; build top-down
|
||||||
|
var nbytes = 0;
|
||||||
|
for (var a = rpl.length - 1; a >= 0; a--) {
|
||||||
|
var html = sc[rpl[a]].outerHTML;
|
||||||
|
dc[rpl[a]].outerHTML = html;
|
||||||
|
nbytes += html.length;
|
||||||
|
}
|
||||||
|
if (nbytes > 0)
|
||||||
|
dbg("replaced %d bytes L%d", nbytes, lv);
|
||||||
|
|
||||||
|
for (var a = 0; a < sc.length; a++)
|
||||||
|
copydom(sc[a], dc[a], lv + 1);
|
||||||
|
|
||||||
|
if (src.innerHTML !== dst.innerHTML) {
|
||||||
|
dbg("setting %d bytes L%d", src.innerHTML.length, lv);
|
||||||
|
dst.innerHTML = src.innerHTML;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function convert_markdown(md_text, dest_dom) {
|
||||||
marked.setOptions({
|
marked.setOptions({
|
||||||
//headerPrefix: 'h-',
|
//headerPrefix: 'h-',
|
||||||
breaks: true,
|
breaks: true,
|
||||||
gfm: true
|
gfm: true
|
||||||
});
|
});
|
||||||
var html = marked(md_text);
|
var md_html = marked(md_text);
|
||||||
dom_pre.innerHTML = html;
|
var md_dom = new DOMParser().parseFromString(md_html, "text/html").body;
|
||||||
|
|
||||||
|
var nodes = md_dom.getElementsByTagName('a');
|
||||||
|
for (var a = nodes.length - 1; a >= 0; a--) {
|
||||||
|
var href = nodes[a].getAttribute('href');
|
||||||
|
var txt = nodes[a].textContent;
|
||||||
|
|
||||||
|
if (!txt)
|
||||||
|
nodes[a].textContent = href;
|
||||||
|
else if (href !== txt)
|
||||||
|
nodes[a].setAttribute('class', 'vis');
|
||||||
|
}
|
||||||
|
|
||||||
// todo-lists (should probably be a marked extension)
|
// todo-lists (should probably be a marked extension)
|
||||||
var nodes = dom_pre.getElementsByTagName('input');
|
nodes = md_dom.getElementsByTagName('input');
|
||||||
for (var a = nodes.length - 1; a >= 0; a--) {
|
for (var a = nodes.length - 1; a >= 0; a--) {
|
||||||
var dom_box = nodes[a];
|
var dom_box = nodes[a];
|
||||||
if (dom_box.getAttribute('type') !== 'checkbox')
|
if (dom_box.getAttribute('type') !== 'checkbox')
|
||||||
@@ -58,9 +195,10 @@ function convert_markdown(md_text) {
|
|||||||
html.substr(html.indexOf('>') + 1);
|
html.substr(html.indexOf('>') + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var manip_nodes = dom_pre.getElementsByTagName('*');
|
// separate <code> for each line in <pre>
|
||||||
for (var a = manip_nodes.length - 1; a >= 0; a--) {
|
var nodes = md_dom.getElementsByTagName('pre');
|
||||||
var el = manip_nodes[a];
|
for (var a = nodes.length - 1; a >= 0; a--) {
|
||||||
|
var el = nodes[a];
|
||||||
|
|
||||||
var is_precode =
|
var is_precode =
|
||||||
el.tagName == 'PRE' &&
|
el.tagName == 'PRE' &&
|
||||||
@@ -77,18 +215,46 @@ function convert_markdown(md_text) {
|
|||||||
|
|
||||||
el.innerHTML = lines.join('');
|
el.innerHTML = lines.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// self-link headers
|
||||||
|
var id_seen = {},
|
||||||
|
dyn = md_dom.getElementsByTagName('*');
|
||||||
|
|
||||||
|
nodes = [];
|
||||||
|
for (var a = 0, aa = dyn.length; a < aa; a++)
|
||||||
|
if (/^[Hh]([1-6])/.exec(dyn[a].tagName) !== null)
|
||||||
|
nodes.push(dyn[a]);
|
||||||
|
|
||||||
|
for (var a = 0; a < nodes.length; a++) {
|
||||||
|
el = nodes[a];
|
||||||
|
var id = el.getAttribute('id'),
|
||||||
|
orig_id = id;
|
||||||
|
|
||||||
|
if (id_seen[id]) {
|
||||||
|
for (var n = 1; n < 4096; n++) {
|
||||||
|
id = orig_id + '-' + n;
|
||||||
|
if (!id_seen[id])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
el.setAttribute('id', id);
|
||||||
|
}
|
||||||
|
id_seen[id] = 1;
|
||||||
|
el.innerHTML = '<a href="#' + id + '">' + el.innerHTML + '</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
copydom(md_dom, dest_dom, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function init_toc() {
|
function init_toc() {
|
||||||
var loader = document.getElementById('ml');
|
var loader = document.getElementById('ml');
|
||||||
loader.parentNode.removeChild(loader);
|
loader.parentNode.removeChild(loader);
|
||||||
|
|
||||||
var anchors = []; // list of toc entries, complex objects
|
var anchors = []; // list of toc entries, complex objects
|
||||||
var anchor = null; // current toc node
|
var anchor = null; // current toc node
|
||||||
var id_seen = {}; // taken IDs
|
|
||||||
var html = []; // generated toc html
|
var html = []; // generated toc html
|
||||||
var lv = 0; // current indentation level in the toc html
|
var lv = 0; // current indentation level in the toc html
|
||||||
var re = new RegExp('^[Hh]([1-3])');
|
var ctr = [0, 0, 0, 0, 0, 0];
|
||||||
|
|
||||||
var manip_nodes_dyn = dom_pre.getElementsByTagName('*');
|
var manip_nodes_dyn = dom_pre.getElementsByTagName('*');
|
||||||
var manip_nodes = [];
|
var manip_nodes = [];
|
||||||
@@ -97,7 +263,7 @@ function init_toc() {
|
|||||||
|
|
||||||
for (var a = 0, aa = manip_nodes.length; a < aa; a++) {
|
for (var a = 0, aa = manip_nodes.length; a < aa; a++) {
|
||||||
var elm = manip_nodes[a];
|
var elm = manip_nodes[a];
|
||||||
var m = re.exec(elm.tagName);
|
var m = /^[Hh]([1-6])/.exec(elm.tagName);
|
||||||
var is_header = m !== null;
|
var is_header = m !== null;
|
||||||
if (is_header) {
|
if (is_header) {
|
||||||
var nlv = m[1];
|
var nlv = m[1];
|
||||||
@@ -109,24 +275,13 @@ function init_toc() {
|
|||||||
html.push('</ul>');
|
html.push('</ul>');
|
||||||
lv--;
|
lv--;
|
||||||
}
|
}
|
||||||
|
ctr[lv - 1]++;
|
||||||
|
for (var b = lv; b < 6; b++)
|
||||||
|
ctr[b] = 0;
|
||||||
|
|
||||||
var orig_id = elm.getAttribute('id');
|
elm.childNodes[0].setAttribute('ctr', ctr.slice(0, lv).join('.'));
|
||||||
var id = orig_id;
|
|
||||||
if (id_seen[id]) {
|
|
||||||
for (var n = 1; n < 4096; n++) {
|
|
||||||
id = orig_id + '-' + n;
|
|
||||||
if (!id_seen[id])
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
elm.setAttribute('id', id);
|
|
||||||
}
|
|
||||||
id_seen[id] = 1;
|
|
||||||
|
|
||||||
var ahref = '<a href="#' + id + '">' +
|
html.push('<li>' + elm.innerHTML + '</li>');
|
||||||
elm.innerHTML + '</a>';
|
|
||||||
|
|
||||||
html.push('<li>' + ahref + '</li>');
|
|
||||||
elm.innerHTML = ahref;
|
|
||||||
|
|
||||||
if (anchor != null)
|
if (anchor != null)
|
||||||
anchors.push(anchor);
|
anchors.push(anchor);
|
||||||
@@ -208,7 +363,7 @@ function init_toc() {
|
|||||||
|
|
||||||
|
|
||||||
// "main" :p
|
// "main" :p
|
||||||
convert_markdown(dom_src.value);
|
convert_markdown(dom_src.value, dom_pre);
|
||||||
var toc = init_toc();
|
var toc = init_toc();
|
||||||
|
|
||||||
|
|
||||||
@@ -240,40 +395,10 @@ var redraw = (function () {
|
|||||||
|
|
||||||
|
|
||||||
dom_navtgl.onclick = function () {
|
dom_navtgl.onclick = function () {
|
||||||
var timeout = null;
|
|
||||||
function show_nav(e) {
|
|
||||||
if (e && e.target == dom_hbar && e.pageX && e.pageX < dom_hbar.offsetWidth / 2)
|
|
||||||
return;
|
|
||||||
|
|
||||||
clearTimeout(timeout);
|
|
||||||
dom_nav.style.display = 'block';
|
|
||||||
}
|
|
||||||
function hide_nav() {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
timeout = setTimeout(function () {
|
|
||||||
dom_nav.style.display = 'none';
|
|
||||||
}, 30);
|
|
||||||
}
|
|
||||||
var hidden = dom_navtgl.innerHTML == 'hide nav';
|
var hidden = dom_navtgl.innerHTML == 'hide nav';
|
||||||
dom_navtgl.innerHTML = hidden ? 'show nav' : 'hide nav';
|
dom_navtgl.innerHTML = hidden ? 'show nav' : 'hide nav';
|
||||||
if (hidden) {
|
dom_nav.style.display = hidden ? 'none' : 'block';
|
||||||
dom_nav.setAttribute('class', 'undocked');
|
|
||||||
dom_nav.style.display = 'none';
|
|
||||||
dom_nav.style.top = dom_hbar.offsetHeight + 'px';
|
|
||||||
dom_nav.onmouseenter = show_nav;
|
|
||||||
dom_nav.onmouseleave = hide_nav;
|
|
||||||
dom_hbar.onmouseenter = show_nav;
|
|
||||||
dom_hbar.onmouseleave = hide_nav;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dom_nav.setAttribute('class', '');
|
|
||||||
dom_nav.style.display = 'block';
|
|
||||||
dom_nav.style.top = '0';
|
|
||||||
dom_nav.onmouseenter = null;
|
|
||||||
dom_nav.onmouseleave = null;
|
|
||||||
dom_hbar.onmouseenter = null;
|
|
||||||
dom_hbar.onmouseleave = null;
|
|
||||||
}
|
|
||||||
if (window.localStorage)
|
if (window.localStorage)
|
||||||
localStorage.setItem('hidenav', hidden ? 1 : 0);
|
localStorage.setItem('hidenav', hidden ? 1 : 0);
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,15 @@
|
|||||||
#mtw {
|
#mtw {
|
||||||
display: block;
|
display: block;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
left: .5em;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: calc(100% - 58em);
|
width: calc(100% - 56em);
|
||||||
}
|
}
|
||||||
#mw {
|
#mw {
|
||||||
left: calc(100% - 57em);
|
left: calc(100% - 55em);
|
||||||
|
overflow-y: auto;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -21,15 +24,17 @@
|
|||||||
}
|
}
|
||||||
#mw.preview,
|
#mw.preview,
|
||||||
#mtw.editor {
|
#mtw.editor {
|
||||||
z-index: 3;
|
z-index: 5;
|
||||||
}
|
}
|
||||||
#mtw.single,
|
#mtw.single,
|
||||||
#mw.single {
|
#mw.single {
|
||||||
left: calc((100% - 58em) / 2);
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
left: 1em;
|
||||||
|
left: max(1em, calc((100% - 56em) / 2));
|
||||||
}
|
}
|
||||||
#mtw.single {
|
#mtw.single {
|
||||||
width: 57em;
|
width: 55em;
|
||||||
|
width: min(55em, calc(100% - 2em));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -38,29 +43,34 @@
|
|||||||
}
|
}
|
||||||
#mt, #mtr {
|
#mt, #mtr {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100% - 5px);
|
height: calc(100% - 1px);
|
||||||
color: #444;
|
color: #444;
|
||||||
background: #f7f7f7;
|
background: #f7f7f7;
|
||||||
border: 1px solid #999;
|
border: 1px solid #999;
|
||||||
|
outline: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
font-family: 'consolas', monospace, monospace;
|
font-family: 'consolas', monospace, monospace;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-break: break-all;
|
word-break: break-word;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
word-wrap: break-word; /*ie*/
|
word-wrap: break-word; /*ie*/
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
line-height: 1.3em;
|
line-height: 1.3em;
|
||||||
font-size: .9em;
|
font-size: .9em;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
scrollbar-color: #eb0 #f7f7f7;
|
||||||
}
|
}
|
||||||
html.dark #mt {
|
html.dark #mt {
|
||||||
color: #eee;
|
color: #eee;
|
||||||
background: #222;
|
background: #222;
|
||||||
border: 1px solid #777;
|
border: 1px solid #777;
|
||||||
|
scrollbar-color: #b80 #282828;
|
||||||
}
|
}
|
||||||
#mtr {
|
#mtr {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 1px;
|
top: 0;
|
||||||
left: 1px;
|
left: 0;
|
||||||
}
|
}
|
||||||
#save.force-save {
|
#save.force-save {
|
||||||
color: #400;
|
color: #400;
|
||||||
@@ -95,8 +105,4 @@ html.dark #helpbox {
|
|||||||
border-width: 1px 0;
|
border-width: 1px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dbg:
|
# mt {opacity: .5;top:1px}
|
||||||
#mt {
|
|
||||||
opacity: .5;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|||||||
@@ -18,19 +18,13 @@ var dom_ref = (function () {
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
// replace it with the real deal in the console
|
|
||||||
var dbg = function () { };
|
|
||||||
// dbg = console.log
|
|
||||||
|
|
||||||
|
|
||||||
// line->scrollpos maps
|
// line->scrollpos maps
|
||||||
var map_src = [];
|
function genmapq(dom, query) {
|
||||||
var map_pre = [];
|
|
||||||
function genmap(dom) {
|
|
||||||
var ret = [];
|
var ret = [];
|
||||||
|
var last_y = -1;
|
||||||
var parent_y = 0;
|
var parent_y = 0;
|
||||||
var parent_n = null;
|
var parent_n = null;
|
||||||
var nodes = dom.querySelectorAll('*[data-ln]');
|
var nodes = dom.querySelectorAll(query);
|
||||||
for (var a = 0; a < nodes.length; a++) {
|
for (var a = 0; a < nodes.length; a++) {
|
||||||
var n = nodes[a];
|
var n = nodes[a];
|
||||||
var ln = parseInt(n.getAttribute('data-ln'));
|
var ln = parseInt(n.getAttribute('data-ln'));
|
||||||
@@ -39,7 +33,7 @@ function genmap(dom) {
|
|||||||
|
|
||||||
var y = 0;
|
var y = 0;
|
||||||
var par = n.offsetParent;
|
var par = n.offsetParent;
|
||||||
if (par != parent_n) {
|
if (par && par != parent_n) {
|
||||||
while (par && par != dom) {
|
while (par && par != dom) {
|
||||||
y += par.offsetTop;
|
y += par.offsetTop;
|
||||||
par = par.offsetParent;
|
par = par.offsetParent;
|
||||||
@@ -53,19 +47,47 @@ function genmap(dom) {
|
|||||||
while (ln > ret.length)
|
while (ln > ret.length)
|
||||||
ret.push(null);
|
ret.push(null);
|
||||||
|
|
||||||
ret.push(parent_y + n.offsetTop);
|
y = parent_y + n.offsetTop;
|
||||||
|
if (y <= last_y)
|
||||||
|
//console.log('awawa');
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//console.log('%d %d (%d+%d)', a, y, parent_y, n.offsetTop);
|
||||||
|
ret.push(y);
|
||||||
|
last_y = y;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
var map_src = [];
|
||||||
|
var map_pre = [];
|
||||||
|
function genmap(dom, oldmap) {
|
||||||
|
var find = nlines;
|
||||||
|
while (oldmap && find --> 0) {
|
||||||
|
var tmap = genmapq(dom, '*[data-ln="' + find + '"]');
|
||||||
|
if (!tmap || !tmap.length)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var cy = tmap[find];
|
||||||
|
var oy = parseInt(oldmap[find]);
|
||||||
|
if (cy + 24 > oy && cy - 24 < oy)
|
||||||
|
return oldmap;
|
||||||
|
|
||||||
|
console.log('map regen', dom.getAttribute('id'), find, oy, cy, oy - cy);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return genmapq(dom, '*[data-ln]');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// input handler
|
// input handler
|
||||||
var action_stack = null;
|
var action_stack = null;
|
||||||
var nlines = 0;
|
var nlines = 0;
|
||||||
(function () {
|
var draw_md = (function () {
|
||||||
dom_src.oninput = function (e) {
|
var delay = 1;
|
||||||
|
function draw_md() {
|
||||||
|
var t0 = new Date().getTime();
|
||||||
var src = dom_src.value;
|
var src = dom_src.value;
|
||||||
convert_markdown(src);
|
convert_markdown(src, dom_pre);
|
||||||
|
|
||||||
var lines = hesc(src).replace(/\r/g, "").split('\n');
|
var lines = hesc(src).replace(/\r/g, "").split('\n');
|
||||||
nlines = lines.length;
|
nlines = lines.length;
|
||||||
@@ -74,19 +96,25 @@ var nlines = 0;
|
|||||||
html.push('<span data-ln="' + (a + 1) + '">' + lines[a] + "</span>");
|
html.push('<span data-ln="' + (a + 1) + '">' + lines[a] + "</span>");
|
||||||
|
|
||||||
dom_ref.innerHTML = html.join('\n');
|
dom_ref.innerHTML = html.join('\n');
|
||||||
map_src = genmap(dom_ref);
|
map_src = genmap(dom_ref, map_src);
|
||||||
map_pre = genmap(dom_pre);
|
map_pre = genmap(dom_pre, map_pre);
|
||||||
|
|
||||||
var sb = document.getElementById('save');
|
cls(document.getElementById('save'), 'disabled', src == server_md);
|
||||||
var cl = (sb.getAttribute('class') + '').replace(/ disabled/, "");
|
|
||||||
if (src == server_md)
|
|
||||||
cl += ' disabled';
|
|
||||||
|
|
||||||
sb.setAttribute('class', cl);
|
var t1 = new Date().getTime();
|
||||||
|
delay = t1 - t0 > 100 ? 25 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeout = null;
|
||||||
|
dom_src.oninput = function (e) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = setTimeout(draw_md, delay);
|
||||||
if (action_stack)
|
if (action_stack)
|
||||||
action_stack.push();
|
action_stack.push();
|
||||||
}
|
};
|
||||||
dom_src.oninput();
|
|
||||||
|
draw_md();
|
||||||
|
return draw_md;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
@@ -96,9 +124,9 @@ redraw = (function () {
|
|||||||
var y = (dom_hbar.offsetTop + dom_hbar.offsetHeight) + 'px';
|
var y = (dom_hbar.offsetTop + dom_hbar.offsetHeight) + 'px';
|
||||||
dom_wrap.style.top = y;
|
dom_wrap.style.top = y;
|
||||||
dom_swrap.style.top = y;
|
dom_swrap.style.top = y;
|
||||||
dom_ref.style.width = (dom_src.offsetWidth - 4) + 'px';
|
dom_ref.style.width = getComputedStyle(dom_src).offsetWidth + 'px';
|
||||||
map_src = genmap(dom_ref);
|
map_src = genmap(dom_ref, map_src);
|
||||||
map_pre = genmap(dom_pre);
|
map_pre = genmap(dom_pre, map_pre);
|
||||||
dbg(document.body.clientWidth + 'x' + document.body.clientHeight);
|
dbg(document.body.clientWidth + 'x' + document.body.clientHeight);
|
||||||
}
|
}
|
||||||
function setsbs() {
|
function setsbs() {
|
||||||
@@ -296,7 +324,7 @@ function save_chk() {
|
|||||||
|
|
||||||
last_modified = this.lastmod;
|
last_modified = this.lastmod;
|
||||||
server_md = this.txt;
|
server_md = this.txt;
|
||||||
dom_src.oninput();
|
draw_md();
|
||||||
|
|
||||||
var ok = document.createElement('div');
|
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.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');
|
||||||
@@ -312,13 +340,26 @@ function save_chk() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// firefox bug: initial selection offset isn't cleared properly through js
|
||||||
|
var ff_clearsel = (function () {
|
||||||
|
if (navigator.userAgent.indexOf(') Gecko/') === -1)
|
||||||
|
return function () { }
|
||||||
|
|
||||||
|
return function () {
|
||||||
|
var txt = dom_src.value;
|
||||||
|
var y = dom_src.scrollTop;
|
||||||
|
dom_src.value = '';
|
||||||
|
dom_src.value = txt;
|
||||||
|
dom_src.scrollTop = y;
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
// returns car/cdr (selection bounds) and n1/n2 (grown to full lines)
|
// returns car/cdr (selection bounds) and n1/n2 (grown to full lines)
|
||||||
function linebounds(just_car) {
|
function linebounds(just_car, greedy_growth) {
|
||||||
var car = dom_src.selectionStart,
|
var car = dom_src.selectionStart,
|
||||||
cdr = dom_src.selectionEnd;
|
cdr = dom_src.selectionEnd;
|
||||||
|
|
||||||
dbg(car, cdr);
|
|
||||||
|
|
||||||
if (just_car)
|
if (just_car)
|
||||||
cdr = car;
|
cdr = car;
|
||||||
|
|
||||||
@@ -326,11 +367,13 @@ function linebounds(just_car) {
|
|||||||
n1 = Math.max(car, 0),
|
n1 = Math.max(car, 0),
|
||||||
n2 = Math.min(cdr, md.length - 1);
|
n2 = Math.min(cdr, md.length - 1);
|
||||||
|
|
||||||
if (n1 < n2 && md[n1] == '\n')
|
if (greedy_growth !== true) {
|
||||||
n1++;
|
if (n1 < n2 && md[n1] == '\n')
|
||||||
|
n1++;
|
||||||
|
|
||||||
if (n1 < n2 && md[n2 - 1] == '\n')
|
if (n1 < n2 && md[n2 - 1] == '\n')
|
||||||
n2 -= 2;
|
n2 -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
n1 = md.lastIndexOf('\n', n1 - 1) + 1;
|
n1 = md.lastIndexOf('\n', n1 - 1) + 1;
|
||||||
n2 = md.indexOf('\n', n2);
|
n2 = md.indexOf('\n', n2);
|
||||||
@@ -364,11 +407,8 @@ function setsel(s) {
|
|||||||
s.cdr = s.pre.length + s.sel.length;
|
s.cdr = s.pre.length + s.sel.length;
|
||||||
}
|
}
|
||||||
dom_src.value = [s.pre, s.sel, s.post].join('');
|
dom_src.value = [s.pre, s.sel, s.post].join('');
|
||||||
dom_src.setSelectionRange(s.car, s.cdr);
|
dom_src.setSelectionRange(s.car, s.cdr, dom_src.selectionDirection);
|
||||||
try {
|
dom_src.oninput();
|
||||||
dom_src.oninput();
|
|
||||||
}
|
|
||||||
catch (ex) { }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -408,17 +448,32 @@ function md_header(dedent) {
|
|||||||
|
|
||||||
// smart-home
|
// smart-home
|
||||||
function md_home(shift) {
|
function md_home(shift) {
|
||||||
var s = linebounds(!shift),
|
var s = linebounds(false, true),
|
||||||
ln = s.md.substring(s.n1, s.n2),
|
ln = s.md.substring(s.n1, s.n2),
|
||||||
m = /^[ \t#>+-]*(\* )?([0-9]+\. +)?/.exec(ln),
|
dir = dom_src.selectionDirection,
|
||||||
home = s.n1 + m[0].length,
|
rev = dir === 'backward',
|
||||||
car = (s.car == home) ? s.n1 : home,
|
p1 = rev ? s.car : s.cdr,
|
||||||
cdr = shift ? s.cdr : car;
|
p2 = rev ? s.cdr : s.car,
|
||||||
|
home = 0,
|
||||||
|
lf = ln.lastIndexOf('\n') + 1,
|
||||||
|
re = /^[ \t#>+-]*(\* )?([0-9]+\. +)?/;
|
||||||
|
|
||||||
if (car > cdr)
|
if (rev)
|
||||||
car = [cdr, cdr = car][0];
|
home = s.n1 + re.exec(ln)[0].length;
|
||||||
|
else
|
||||||
|
home = s.n1 + lf + re.exec(ln.substring(lf))[0].length;
|
||||||
|
|
||||||
dom_src.setSelectionRange(car, cdr);
|
p1 = (p1 !== home) ? home : (rev ? s.n1 : s.n1 + lf);
|
||||||
|
if (!shift)
|
||||||
|
p2 = p1;
|
||||||
|
|
||||||
|
if (rev !== p1 < p2)
|
||||||
|
dir = rev ? 'forward' : 'backward';
|
||||||
|
|
||||||
|
if (!shift)
|
||||||
|
ff_clearsel();
|
||||||
|
|
||||||
|
dom_src.setSelectionRange(Math.min(p1, p2), Math.max(p1, p2), dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -426,13 +481,42 @@ function md_home(shift) {
|
|||||||
function md_newline() {
|
function md_newline() {
|
||||||
var s = linebounds(true),
|
var s = linebounds(true),
|
||||||
ln = s.md.substring(s.n1, s.n2),
|
ln = s.md.substring(s.n1, s.n2),
|
||||||
m = /^[ \t#>+-]*(\* )?([0-9]+\. +)?/.exec(ln);
|
m1 = /^( *)([0-9]+)(\. +)/.exec(ln),
|
||||||
|
m2 = /^[ \t>+-]*(\* )?/.exec(ln);
|
||||||
|
|
||||||
s.pre = s.md.substring(0, s.car) + '\n' + m[0];
|
var pre = m2[0];
|
||||||
|
if (m1 !== null)
|
||||||
|
pre = m1[1] + (parseInt(m1[2]) + 1) + m1[3];
|
||||||
|
|
||||||
|
if (pre.length > s.car - s.n1)
|
||||||
|
// in gutter, do nothing
|
||||||
|
return true;
|
||||||
|
|
||||||
|
s.pre = s.md.substring(0, s.car) + '\n' + pre;
|
||||||
s.sel = '';
|
s.sel = '';
|
||||||
s.post = s.md.substring(s.car);
|
s.post = s.md.substring(s.car);
|
||||||
s.car = s.cdr = s.pre.length;
|
s.car = s.cdr = s.pre.length;
|
||||||
setsel(s);
|
setsel(s);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// backspace
|
||||||
|
function md_backspace() {
|
||||||
|
var s = linebounds(true),
|
||||||
|
ln = s.md.substring(s.n1, s.n2),
|
||||||
|
m = /^[ \t>+-]*(\* )?([0-9]+\. +)?/.exec(ln);
|
||||||
|
|
||||||
|
var v = m[0].replace(/[^ ]/g, " ");
|
||||||
|
if (v === m[0] || v.length !== ln.length)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
s.pre = s.md.substring(0, s.n1) + v;
|
||||||
|
s.sel = '';
|
||||||
|
s.post = s.md.substring(s.car);
|
||||||
|
s.car = s.cdr = s.pre.length;
|
||||||
|
setsel(s);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -461,8 +545,7 @@ function md_newline() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ctrl && !ev.shiftKey && (ev.code == "Enter" || kc == 13)) {
|
if (!ctrl && !ev.shiftKey && (ev.code == "Enter" || kc == 13)) {
|
||||||
md_newline();
|
return md_newline();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (ctrl && (ev.code == "KeyZ" || kc == 90)) {
|
if (ctrl && (ev.code == "KeyZ" || kc == 90)) {
|
||||||
if (ev.shiftKey)
|
if (ev.shiftKey)
|
||||||
@@ -476,6 +559,9 @@ function md_newline() {
|
|||||||
action_stack.redo();
|
action_stack.redo();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!ctrl && !ev.shiftKey && kc == 8) {
|
||||||
|
return md_backspace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
document.onkeydown = keydown;
|
document.onkeydown = keydown;
|
||||||
@@ -487,8 +573,10 @@ document.getElementById('help').onclick = function (e) {
|
|||||||
if (e) e.preventDefault();
|
if (e) e.preventDefault();
|
||||||
var dom = document.getElementById('helpbox');
|
var dom = document.getElementById('helpbox');
|
||||||
var dtxt = dom.getElementsByTagName('textarea');
|
var dtxt = dom.getElementsByTagName('textarea');
|
||||||
if (dtxt.length > 0)
|
if (dtxt.length > 0) {
|
||||||
dom.innerHTML = '<a href="#" id="helpclose">close</a>' + marked(dtxt[0].value);
|
convert_markdown(dtxt[0].value, dom);
|
||||||
|
dom.innerHTML = '<a href="#" id="helpclose">close</a>' + dom.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
dom.style.display = 'block';
|
dom.style.display = 'block';
|
||||||
document.getElementById('helpclose').onclick = function () {
|
document.getElementById('helpclose').onclick = function () {
|
||||||
@@ -499,14 +587,16 @@ document.getElementById('help').onclick = function (e) {
|
|||||||
|
|
||||||
// blame steen
|
// blame steen
|
||||||
action_stack = (function () {
|
action_stack = (function () {
|
||||||
var undos = [];
|
var hist = {
|
||||||
var redos = [];
|
un: [],
|
||||||
var sched_txt = '';
|
re: []
|
||||||
|
};
|
||||||
|
var sched_cpos = 0;
|
||||||
var sched_timer = null;
|
var sched_timer = null;
|
||||||
var ignore = false;
|
var ignore = false;
|
||||||
var ref = dom_src.value;
|
var ref = dom_src.value;
|
||||||
|
|
||||||
function diff(from, to) {
|
function diff(from, to, cpos) {
|
||||||
if (from === to)
|
if (from === to)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -532,34 +622,37 @@ action_stack = (function () {
|
|||||||
return {
|
return {
|
||||||
car: car,
|
car: car,
|
||||||
cdr: ++p2,
|
cdr: ++p2,
|
||||||
txt: txt
|
txt: txt,
|
||||||
|
cpos: cpos
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function undiff(from, change) {
|
function undiff(from, change) {
|
||||||
return {
|
return {
|
||||||
txt: from.substring(0, change.car) + change.txt + from.substring(change.cdr),
|
txt: from.substring(0, change.car) + change.txt + from.substring(change.cdr),
|
||||||
cursor: change.car + change.txt.length
|
cpos: change.cpos
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function apply(src, dst) {
|
function apply(src, dst) {
|
||||||
dbg('undos(%d) redos(%d)', undos.length, redos.length);
|
dbg('undos(%d) redos(%d)', hist.un.length, hist.re.length);
|
||||||
|
|
||||||
if (src.length === 0)
|
if (src.length === 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var state = undiff(ref, src.pop()),
|
var patch = src.pop(),
|
||||||
change = diff(ref, state.txt);
|
applied = undiff(ref, patch),
|
||||||
|
cpos = patch.cpos - (patch.cdr - patch.car) + patch.txt.length,
|
||||||
|
reverse = diff(ref, applied.txt, cpos);
|
||||||
|
|
||||||
if (change === null)
|
if (reverse === null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
dst.push(change);
|
dst.push(reverse);
|
||||||
ref = state.txt;
|
ref = applied.txt;
|
||||||
ignore = true; // just some browsers
|
ignore = true; // just some browsers
|
||||||
dom_src.value = ref;
|
dom_src.value = ref;
|
||||||
dom_src.setSelectionRange(state.cursor, state.cursor);
|
dom_src.setSelectionRange(cpos, cpos);
|
||||||
ignore = true; // all browsers
|
ignore = true; // all browsers
|
||||||
dom_src.oninput();
|
dom_src.oninput();
|
||||||
return true;
|
return true;
|
||||||
@@ -570,31 +663,36 @@ action_stack = (function () {
|
|||||||
ignore = false;
|
ignore = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
redos = [];
|
hist.re = [];
|
||||||
sched_txt = dom_src.value;
|
|
||||||
clearTimeout(sched_timer);
|
clearTimeout(sched_timer);
|
||||||
|
sched_cpos = dom_src.selectionEnd;
|
||||||
sched_timer = setTimeout(push, 500);
|
sched_timer = setTimeout(push, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
function undo() {
|
function undo() {
|
||||||
return apply(undos, redos);
|
if (hist.re.length == 0) {
|
||||||
|
clearTimeout(sched_timer);
|
||||||
|
push();
|
||||||
|
}
|
||||||
|
return apply(hist.un, hist.re);
|
||||||
}
|
}
|
||||||
|
|
||||||
function redo() {
|
function redo() {
|
||||||
return apply(redos, undos);
|
return apply(hist.re, hist.un);
|
||||||
}
|
}
|
||||||
|
|
||||||
function push() {
|
function push() {
|
||||||
var change = diff(ref, sched_txt, dom_src.selectionStart);
|
var newtxt = dom_src.value;
|
||||||
|
var change = diff(ref, newtxt, sched_cpos);
|
||||||
if (change !== null)
|
if (change !== null)
|
||||||
undos.push(change);
|
hist.un.push(change);
|
||||||
|
|
||||||
ref = sched_txt;
|
ref = newtxt;
|
||||||
dbg('undos(%d) redos(%d)', undos.length, redos.length);
|
dbg('undos(%d) redos(%d)', hist.un.length, hist.re.length);
|
||||||
if (undos.length > 0)
|
if (hist.un.length > 0)
|
||||||
dbg(undos.slice(-1)[0]);
|
dbg(static(hist.un.slice(-1)[0]));
|
||||||
if (redos.length > 0)
|
if (hist.re.length > 0)
|
||||||
dbg(redos.slice(-1)[0]);
|
dbg(static(hist.re.slice(-1)[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -602,8 +700,18 @@ action_stack = (function () {
|
|||||||
undo: undo,
|
undo: undo,
|
||||||
redo: redo,
|
redo: redo,
|
||||||
push: schedule_push,
|
push: schedule_push,
|
||||||
_undos: undos,
|
_hist: hist,
|
||||||
_redos: redos,
|
|
||||||
_ref: ref
|
_ref: ref
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
/*
|
||||||
|
document.getElementById('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);
|
||||||
|
for (var a = 0; a < max; a++)
|
||||||
|
if (c1[a] !== c2[a])
|
||||||
|
console.log(c1[a] + '\n' + c2[a]);
|
||||||
|
}
|
||||||
|
*/
|
||||||
@@ -39,6 +39,6 @@ var lightswitch = (function () {
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<script src="/.cpr/deps/easymde.full.js"></script>
|
<script src="/.cpr/deps/easymde.js"></script>
|
||||||
<script src="/.cpr/mde.js"></script>
|
<script src="/.cpr/mde.js"></script>
|
||||||
</body></html>
|
</body></html>
|
||||||
|
|||||||
@@ -80,3 +80,36 @@ for d in /usr /var; do find $d -type f -size +30M 2>/dev/null; done | while IFS=
|
|||||||
# py2 on osx
|
# py2 on osx
|
||||||
brew install python@2
|
brew install python@2
|
||||||
pip install virtualenv
|
pip install virtualenv
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## http 206
|
||||||
|
|
||||||
|
# az = abcdefghijklmnopqrstuvwxyz
|
||||||
|
|
||||||
|
printf '%s\r\n' 'GET /az HTTP/1.1' 'Host: ocv.me' 'Range: bytes=5-10' '' | ncat ocv.me 80
|
||||||
|
# Content-Range: bytes 5-10/26
|
||||||
|
# Content-Length: 6
|
||||||
|
# fghijk
|
||||||
|
|
||||||
|
Range: bytes=0-1 "ab" Content-Range: bytes 0-1/26
|
||||||
|
Range: bytes=24-24 "y" Content-Range: bytes 24-24/26
|
||||||
|
Range: bytes=24-25 "yz" Content-Range: bytes 24-25/26
|
||||||
|
Range: bytes=24- "yz" Content-Range: bytes 24-25/26
|
||||||
|
Range: bytes=25-29 "z" Content-Range: bytes 25-25/26
|
||||||
|
Range: bytes=26- Content-Range: bytes */26
|
||||||
|
HTTP/1.1 416 Requested Range Not Satisfiable
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## md perf
|
||||||
|
|
||||||
|
var tsh = [];
|
||||||
|
function convert_markdown(md_text, dest_dom) {
|
||||||
|
tsh.push(new Date().getTime());
|
||||||
|
while (tsh.length > 10)
|
||||||
|
tsh.shift();
|
||||||
|
if (tsh.length > 1) {
|
||||||
|
var end = tsh.slice(-2);
|
||||||
|
console.log("render", end.pop() - end.pop(), (tsh[tsh.length - 1] - tsh[0]) / (tsh.length - 1));
|
||||||
|
}
|
||||||
|
|||||||
10
docs/unirange.py
Normal file
10
docs/unirange.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
v = "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
||||||
|
for v in v.split(","):
|
||||||
|
if "+" in v:
|
||||||
|
v = v.split("+")[1]
|
||||||
|
if "-" in v:
|
||||||
|
lo, hi = v.split("-")
|
||||||
|
else:
|
||||||
|
lo = hi = v
|
||||||
|
for v in range(int(lo, 16), int(hi, 16) + 1):
|
||||||
|
print("{:4x} [{}]".format(v, chr(v)))
|
||||||
@@ -3,7 +3,7 @@ WORKDIR /z
|
|||||||
ENV ver_asmcrypto=2821dd1dedd1196c378f5854037dda5c869313f3 \
|
ENV ver_asmcrypto=2821dd1dedd1196c378f5854037dda5c869313f3 \
|
||||||
ver_markdownit=10.0.0 \
|
ver_markdownit=10.0.0 \
|
||||||
ver_showdown=1.9.1 \
|
ver_showdown=1.9.1 \
|
||||||
ver_marked=1.0.0 \
|
ver_marked=1.1.0 \
|
||||||
ver_ogvjs=1.6.1 \
|
ver_ogvjs=1.6.1 \
|
||||||
ver_mde=2.10.1 \
|
ver_mde=2.10.1 \
|
||||||
ver_codemirror=5.53.2 \
|
ver_codemirror=5.53.2 \
|
||||||
@@ -11,8 +11,11 @@ ENV ver_asmcrypto=2821dd1dedd1196c378f5854037dda5c869313f3 \
|
|||||||
ver_zopfli=1.0.3
|
ver_zopfli=1.0.3
|
||||||
|
|
||||||
|
|
||||||
# download
|
# download;
|
||||||
RUN apk add cmake make g++ git bash npm patch wget tar pigz brotli gzip unzip python3 python3-dev \
|
# the scp url is latin from https://fonts.googleapis.com/css2?family=Source+Code+Pro&display=swap
|
||||||
|
RUN mkdir -p /z/dist/no-pk \
|
||||||
|
&& wget https://fonts.gstatic.com/s/sourcecodepro/v11/HI_SiYsKILxRpg3hIP6sJ7fM7PqlPevW.woff2 -O scp.woff2 \
|
||||||
|
&& apk add cmake make g++ git bash npm patch wget tar pigz brotli gzip unzip python3 python3-dev brotli py3-brotli \
|
||||||
&& wget https://github.com/brion/ogv.js/releases/download/$ver_ogvjs/ogvjs-$ver_ogvjs.zip -O ogvjs.zip \
|
&& 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/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/markedjs/marked/archive/v$ver_marked.tar.gz -O marked.tgz \
|
||||||
@@ -36,23 +39,7 @@ RUN apk add cmake make g++ git bash npm patch wget tar pigz brotli gzip unzi
|
|||||||
&& npm install \
|
&& npm install \
|
||||||
&& npm i gulp-cli -g ) \
|
&& npm i gulp-cli -g ) \
|
||||||
&& unzip fontawesome.zip \
|
&& unzip fontawesome.zip \
|
||||||
&& tar -xf zopfli.tgz \
|
&& tar -xf zopfli.tgz
|
||||||
&& mkdir -p /z/dist/no-pk
|
|
||||||
|
|
||||||
|
|
||||||
# uncomment if you wanna test the abandoned markdown converters
|
|
||||||
#ENV build_abandoned=1
|
|
||||||
|
|
||||||
|
|
||||||
RUN [ $build_abandoned ] || exit 0; \
|
|
||||||
git clone --depth 1 --branch $ver_showdown https://github.com/showdownjs/showdown/ \
|
|
||||||
&& wget https://github.com/markdown-it/markdown-it/archive/$ver_markdownit.tar.gz -O markdownit.tgz \
|
|
||||||
&& (cd showdown \
|
|
||||||
&& npm install \
|
|
||||||
&& npm i grunt -g ) \
|
|
||||||
&& (tar -xf markdownit.tgz \
|
|
||||||
&& cd markdown-it-$ver_markdownit \
|
|
||||||
&& npm install )
|
|
||||||
|
|
||||||
|
|
||||||
# build fonttools (which needs zopfli)
|
# build fonttools (which needs zopfli)
|
||||||
@@ -80,31 +67,27 @@ RUN cd ogvjs-$ver_ogvjs \
|
|||||||
&& cp -pv \
|
&& cp -pv \
|
||||||
ogv.js \
|
ogv.js \
|
||||||
ogv-worker-audio.js \
|
ogv-worker-audio.js \
|
||||||
ogv-demuxer-ogg.js \
|
|
||||||
ogv-demuxer-ogg-wasm.js \
|
ogv-demuxer-ogg-wasm.js \
|
||||||
ogv-demuxer-ogg-wasm.wasm \
|
ogv-demuxer-ogg-wasm.wasm \
|
||||||
ogv-demuxer-webm.js \
|
|
||||||
ogv-demuxer-webm-wasm.js \
|
ogv-demuxer-webm-wasm.js \
|
||||||
ogv-demuxer-webm-wasm.wasm \
|
ogv-demuxer-webm-wasm.wasm \
|
||||||
ogv-decoder-audio-opus.js \
|
|
||||||
ogv-decoder-audio-opus-wasm.js \
|
ogv-decoder-audio-opus-wasm.js \
|
||||||
ogv-decoder-audio-opus-wasm.wasm \
|
ogv-decoder-audio-opus-wasm.wasm \
|
||||||
ogv-decoder-audio-vorbis.js \
|
|
||||||
ogv-decoder-audio-vorbis-wasm.js \
|
ogv-decoder-audio-vorbis-wasm.js \
|
||||||
ogv-decoder-audio-vorbis-wasm.wasm \
|
ogv-decoder-audio-vorbis-wasm.wasm \
|
||||||
dynamicaudio.swf \
|
|
||||||
/z/dist
|
/z/dist
|
||||||
|
|
||||||
|
# ogv-demuxer-ogg.js \
|
||||||
|
# ogv-demuxer-webm.js \
|
||||||
|
# ogv-decoder-audio-opus.js \
|
||||||
|
# ogv-decoder-audio-vorbis.js \
|
||||||
|
# dynamicaudio.swf \
|
||||||
|
|
||||||
|
|
||||||
# build marked
|
# build marked
|
||||||
RUN wget https://github.com/markedjs/marked/commit/5c166d4164791f643693478e4ac094d63d6e0c9a.patch -O marked-git-1.patch \
|
|
||||||
&& wget https://patch-diff.githubusercontent.com/raw/markedjs/marked/pull/1652.patch -O marked-git-2.patch
|
|
||||||
|
|
||||||
COPY marked.patch /z/
|
COPY marked.patch /z/
|
||||||
COPY marked-ln.patch /z/
|
COPY marked-ln.patch /z/
|
||||||
RUN cd marked-$ver_marked \
|
RUN cd marked-$ver_marked \
|
||||||
&& patch -p1 < /z/marked-git-1.patch \
|
|
||||||
&& patch -p1 < /z/marked-git-2.patch \
|
|
||||||
&& patch -p1 < /z/marked-ln.patch \
|
&& patch -p1 < /z/marked-ln.patch \
|
||||||
&& patch -p1 < /z/marked.patch \
|
&& patch -p1 < /z/marked.patch \
|
||||||
&& npm run build \
|
&& npm run build \
|
||||||
@@ -138,57 +121,10 @@ RUN cd easy-markdown-editor-$ver_mde \
|
|||||||
&& patch -p1 < /z/easymde-ln.patch \
|
&& patch -p1 < /z/easymde-ln.patch \
|
||||||
&& gulp \
|
&& gulp \
|
||||||
&& cp -pv dist/easymde.min.css /z/dist/easymde.css \
|
&& cp -pv dist/easymde.min.css /z/dist/easymde.css \
|
||||||
&& cp -pv dist/easymde.min.js /z/dist/easymde.js \
|
&& 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)
|
# build fontawesome and scp
|
||||||
COPY showdown.patch /z/
|
|
||||||
RUN [ $build_abandoned ] || exit 0; \
|
|
||||||
cd showdown \
|
|
||||||
&& rm -rf bin dist \
|
|
||||||
# # remove ellipsis plugin \
|
|
||||||
&& rm \
|
|
||||||
src/subParsers/ellipsis.js \
|
|
||||||
test/cases/ellipsis* \
|
|
||||||
# # remove html-to-md converter \
|
|
||||||
&& rm \
|
|
||||||
test/node/testsuite.makemd.js \
|
|
||||||
test/node/showdown.Converter.makeMarkdown.js \
|
|
||||||
# # remove emojis \
|
|
||||||
&& rm src/subParsers/emoji.js \
|
|
||||||
&& awk '/^showdown.helper.emojis/ {o=1} !o; /^\}/ {o=0}' \
|
|
||||||
>f <src/helpers.js \
|
|
||||||
&& mv f src/helpers.js \
|
|
||||||
&& rm -rf test/features/emojis \
|
|
||||||
# # remove ghmentions \
|
|
||||||
&& rm test/features/ghMentions.* \
|
|
||||||
# # remove option descriptions \
|
|
||||||
&& sed -ri '/descri(ption|be): /d' src/options.js \
|
|
||||||
&& patch -p1 < /z/showdown.patch
|
|
||||||
|
|
||||||
RUN [ $build_abandoned ] || exit 0; \
|
|
||||||
cd showdown \
|
|
||||||
&& grunt build \
|
|
||||||
&& sed -ri '/sourceMappingURL=showdown.min.js.map/d' dist/showdown.min.js \
|
|
||||||
&& mv dist/showdown.min.js /z/dist/showdown.js \
|
|
||||||
&& ls -al /z/dist/showdown.js
|
|
||||||
|
|
||||||
|
|
||||||
# build markdownit (abandoned; disabled by default)
|
|
||||||
COPY markdown-it.patch /z/
|
|
||||||
RUN [ $build_abandoned ] || exit 0; \
|
|
||||||
cd markdown-it-$ver_markdownit \
|
|
||||||
&& patch -p1 < /z/markdown-it.patch \
|
|
||||||
&& make browserify \
|
|
||||||
&& cp -pv dist/markdown-it.min.js /z/dist/markdown-it.js \
|
|
||||||
&& cp -pv dist/markdown-it.js /z/dist/markdown-it-full.js
|
|
||||||
|
|
||||||
|
|
||||||
# build fontawesome
|
|
||||||
COPY mini-fa.sh /z
|
COPY mini-fa.sh /z
|
||||||
COPY mini-fa.css /z
|
COPY mini-fa.css /z
|
||||||
RUN /bin/ash /z/mini-fa.sh
|
RUN /bin/ash /z/mini-fa.sh
|
||||||
@@ -203,38 +139,6 @@ RUN cd /z/dist \
|
|||||||
&& rmdir no-pk
|
&& rmdir no-pk
|
||||||
|
|
||||||
|
|
||||||
# showdown: abandoned due to code-blocks in lists failing
|
# git diff -U2 --no-index marked-1.1.0-orig/ marked-1.1.0-edit/ -U2 | sed -r '/^index /d;s`^(diff --git a/)[^/]+/(.* b/)[^/]+/`\1\2`; s`^(---|\+\+\+) ([ab]/)[^/]+/`\1 \2`' > ../dev/copyparty/scripts/deps-docker/marked-ln.patch
|
||||||
# 22770 orig
|
# 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; rm the.tgz)
|
||||||
# 12154 no-emojis
|
|
||||||
# 12134 no-srcmap
|
|
||||||
# 11189 no-descriptions
|
|
||||||
# 11152 no-ellipsis
|
|
||||||
# 10617 no-this.makeMd
|
|
||||||
# 9569 no-extensions
|
|
||||||
# 9537 no-extensions
|
|
||||||
# 9410 no-mentions
|
|
||||||
|
|
||||||
|
|
||||||
# markdown-it: abandoned because no header anchors (and too big)
|
|
||||||
# 32322 107754 orig (wowee)
|
|
||||||
# 19619 21392 71540 less entities
|
|
||||||
|
|
||||||
|
|
||||||
# marked:
|
|
||||||
# 9253 29773 orig
|
|
||||||
# 9159 29633 no copyright (reverted)
|
|
||||||
# 9040 29057 no sanitize
|
|
||||||
# 8870 28631 no email-mangle
|
|
||||||
# so really not worth it, just drop the patch when that stops working
|
|
||||||
|
|
||||||
|
|
||||||
# easymde:
|
|
||||||
# 91836 orig
|
|
||||||
# 88635 no spellcheck
|
|
||||||
# 88392 no urlRE
|
|
||||||
# 85651 less bidi
|
|
||||||
# 82855 less mode meta
|
|
||||||
|
|
||||||
|
|
||||||
# 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
|
# gzip -dkf ../dev/copyparty/copyparty/web/deps/deps/marked.full.js.gz && diff -NarU2 ../dev/copyparty/copyparty/web/deps/{,deps/}marked.full.js
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ add data-ln="%d" to most tags, %d is the source markdown line
|
|||||||
+ // this.ln will be bumped by recursive calls into this func;
|
+ // this.ln will be bumped by recursive calls into this func;
|
||||||
+ // reset the count and rely on the outermost token's raw only
|
+ // reset the count and rely on the outermost token's raw only
|
||||||
+ ln = this.ln;
|
+ ln = this.ln;
|
||||||
+
|
+
|
||||||
// newline
|
// newline
|
||||||
if (token = this.tokenizer.space(src)) {
|
if (token = this.tokenizer.space(src)) {
|
||||||
src = src.substring(token.raw.length);
|
src = src.substring(token.raw.length);
|
||||||
@@ -180,7 +180,7 @@ diff --git a/src/Parser.js b/src/Parser.js
|
|||||||
+ // similar to tables, writing contents before the <ul> tag
|
+ // similar to tables, writing contents before the <ul> tag
|
||||||
+ // so update the tag attribute as we go
|
+ // so update the tag attribute as we go
|
||||||
+ // (assuming all list entries got tagged with a source-line, probably safe w)
|
+ // (assuming all list entries got tagged with a source-line, probably safe w)
|
||||||
+ body += this.renderer.tag_ln(item.tokens[0].ln).listitem(itemBody, task, checked);
|
+ body += this.renderer.tag_ln((item.tokens[0] || token).ln).listitem(itemBody, task, checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
- out += this.renderer.list(body, ordered, start);
|
- out += this.renderer.list(body, ordered, start);
|
||||||
@@ -234,7 +234,7 @@ diff --git a/src/Renderer.js b/src/Renderer.js
|
|||||||
- return '<pre><code>'
|
- return '<pre><code>'
|
||||||
+ return '<pre' + this.ln + '><code>'
|
+ return '<pre' + this.ln + '><code>'
|
||||||
+ (escaped ? code : escape(code, true))
|
+ (escaped ? code : escape(code, true))
|
||||||
+ '</code></pre>';
|
+ '</code></pre>\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
- return '<pre><code class="'
|
- return '<pre><code class="'
|
||||||
|
|||||||
@@ -1,7 +1,141 @@
|
|||||||
diff -NarU1 marked-1.0.0-orig/src/defaults.js marked-1.0.0-edit/src/defaults.js
|
diff --git a/src/Lexer.js b/src/Lexer.js
|
||||||
--- marked-1.0.0-orig/src/defaults.js 2020-04-21 01:03:48.000000000 +0000
|
--- a/src/Lexer.js
|
||||||
+++ marked-1.0.0-edit/src/defaults.js 2020-04-25 19:16:56.124621393 +0000
|
+++ b/src/Lexer.js
|
||||||
@@ -9,10 +9,6 @@
|
@@ -5,5 +5,5 @@ const { block, inline } = require('./rules.js');
|
||||||
|
/**
|
||||||
|
* smartypants text replacement
|
||||||
|
- */
|
||||||
|
+ *
|
||||||
|
function smartypants(text) {
|
||||||
|
return text
|
||||||
|
@@ -26,5 +26,5 @@ function smartypants(text) {
|
||||||
|
/**
|
||||||
|
* mangle email addresses
|
||||||
|
- */
|
||||||
|
+ *
|
||||||
|
function mangle(text) {
|
||||||
|
let out = '',
|
||||||
|
@@ -439,5 +439,5 @@ module.exports = class Lexer {
|
||||||
|
|
||||||
|
// autolink
|
||||||
|
- if (token = this.tokenizer.autolink(src, mangle)) {
|
||||||
|
+ if (token = this.tokenizer.autolink(src)) {
|
||||||
|
src = src.substring(token.raw.length);
|
||||||
|
tokens.push(token);
|
||||||
|
@@ -446,5 +446,5 @@ module.exports = class Lexer {
|
||||||
|
|
||||||
|
// url (gfm)
|
||||||
|
- if (!inLink && (token = this.tokenizer.url(src, mangle))) {
|
||||||
|
+ if (!inLink && (token = this.tokenizer.url(src))) {
|
||||||
|
src = src.substring(token.raw.length);
|
||||||
|
tokens.push(token);
|
||||||
|
@@ -453,5 +453,5 @@ module.exports = class Lexer {
|
||||||
|
|
||||||
|
// text
|
||||||
|
- if (token = this.tokenizer.inlineText(src, inRawBlock, smartypants)) {
|
||||||
|
+ if (token = this.tokenizer.inlineText(src, inRawBlock)) {
|
||||||
|
src = src.substring(token.raw.length);
|
||||||
|
tokens.push(token);
|
||||||
|
diff --git a/src/Renderer.js b/src/Renderer.js
|
||||||
|
--- a/src/Renderer.js
|
||||||
|
+++ b/src/Renderer.js
|
||||||
|
@@ -140,5 +140,5 @@ module.exports = class Renderer {
|
||||||
|
|
||||||
|
link(href, title, text) {
|
||||||
|
- href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
|
||||||
|
+ href = cleanUrl(this.options.baseUrl, href);
|
||||||
|
if (href === null) {
|
||||||
|
return text;
|
||||||
|
@@ -153,5 +153,5 @@ module.exports = class Renderer {
|
||||||
|
|
||||||
|
image(href, title, text) {
|
||||||
|
- href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
|
||||||
|
+ href = cleanUrl(this.options.baseUrl, href);
|
||||||
|
if (href === null) {
|
||||||
|
return text;
|
||||||
|
diff --git a/src/Tokenizer.js b/src/Tokenizer.js
|
||||||
|
--- a/src/Tokenizer.js
|
||||||
|
+++ b/src/Tokenizer.js
|
||||||
|
@@ -287,11 +287,8 @@ module.exports = class Tokenizer {
|
||||||
|
if (cap) {
|
||||||
|
return {
|
||||||
|
- type: this.options.sanitize
|
||||||
|
- ? 'paragraph'
|
||||||
|
- : 'html',
|
||||||
|
+ type: 'html',
|
||||||
|
raw: cap[0],
|
||||||
|
- pre: !this.options.sanitizer
|
||||||
|
- && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
|
||||||
|
- text: this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0]
|
||||||
|
+ pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',
|
||||||
|
+ text: cap[0]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@@ -421,15 +418,9 @@ module.exports = class Tokenizer {
|
||||||
|
|
||||||
|
return {
|
||||||
|
- type: this.options.sanitize
|
||||||
|
- ? 'text'
|
||||||
|
- : 'html',
|
||||||
|
+ type: 'html',
|
||||||
|
raw: cap[0],
|
||||||
|
inLink,
|
||||||
|
inRawBlock,
|
||||||
|
- text: this.options.sanitize
|
||||||
|
- ? (this.options.sanitizer
|
||||||
|
- ? this.options.sanitizer(cap[0])
|
||||||
|
- : escape(cap[0]))
|
||||||
|
- : cap[0]
|
||||||
|
+ text: cap[0]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@@ -550,10 +541,10 @@ module.exports = class Tokenizer {
|
||||||
|
}
|
||||||
|
|
||||||
|
- autolink(src, mangle) {
|
||||||
|
+ autolink(src) {
|
||||||
|
const cap = this.rules.inline.autolink.exec(src);
|
||||||
|
if (cap) {
|
||||||
|
let text, href;
|
||||||
|
if (cap[2] === '@') {
|
||||||
|
- text = escape(this.options.mangle ? mangle(cap[1]) : cap[1]);
|
||||||
|
+ text = escape(cap[1]);
|
||||||
|
href = 'mailto:' + text;
|
||||||
|
} else {
|
||||||
|
@@ -578,10 +569,10 @@ module.exports = class Tokenizer {
|
||||||
|
}
|
||||||
|
|
||||||
|
- url(src, mangle) {
|
||||||
|
+ url(src) {
|
||||||
|
let cap;
|
||||||
|
if (cap = this.rules.inline.url.exec(src)) {
|
||||||
|
let text, href;
|
||||||
|
if (cap[2] === '@') {
|
||||||
|
- text = escape(this.options.mangle ? mangle(cap[0]) : cap[0]);
|
||||||
|
+ text = escape(cap[0]);
|
||||||
|
href = 'mailto:' + text;
|
||||||
|
} else {
|
||||||
|
@@ -615,12 +606,12 @@ module.exports = class Tokenizer {
|
||||||
|
}
|
||||||
|
|
||||||
|
- inlineText(src, inRawBlock, smartypants) {
|
||||||
|
+ inlineText(src, inRawBlock) {
|
||||||
|
const cap = this.rules.inline.text.exec(src);
|
||||||
|
if (cap) {
|
||||||
|
let text;
|
||||||
|
if (inRawBlock) {
|
||||||
|
- text = this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0];
|
||||||
|
+ text = cap[0];
|
||||||
|
} else {
|
||||||
|
- text = escape(this.options.smartypants ? smartypants(cap[0]) : cap[0]);
|
||||||
|
+ text = escape(cap[0]);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
diff --git a/src/defaults.js b/src/defaults.js
|
||||||
|
--- a/src/defaults.js
|
||||||
|
+++ b/src/defaults.js
|
||||||
|
@@ -8,12 +8,8 @@ function getDefaults() {
|
||||||
|
highlight: null,
|
||||||
langPrefix: 'language-',
|
langPrefix: 'language-',
|
||||||
- mangle: true,
|
- mangle: true,
|
||||||
pedantic: false,
|
pedantic: false,
|
||||||
@@ -12,10 +146,12 @@ diff -NarU1 marked-1.0.0-orig/src/defaults.js marked-1.0.0-edit/src/defaults.js
|
|||||||
smartLists: false,
|
smartLists: false,
|
||||||
- smartypants: false,
|
- smartypants: false,
|
||||||
tokenizer: null,
|
tokenizer: null,
|
||||||
diff -NarU1 marked-1.0.0-orig/src/helpers.js marked-1.0.0-edit/src/helpers.js
|
walkTokens: null,
|
||||||
--- marked-1.0.0-orig/src/helpers.js 2020-04-21 01:03:48.000000000 +0000
|
diff --git a/src/helpers.js b/src/helpers.js
|
||||||
+++ marked-1.0.0-edit/src/helpers.js 2020-04-25 18:58:43.001320210 +0000
|
--- a/src/helpers.js
|
||||||
@@ -65,16 +65,3 @@
|
+++ b/src/helpers.js
|
||||||
|
@@ -64,18 +64,5 @@ function edit(regex, opt) {
|
||||||
|
const nonWordAndColonTest = /[^\w:]/g;
|
||||||
const originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
|
const originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
|
||||||
-function cleanUrl(sanitize, base, href) {
|
-function cleanUrl(sanitize, base, href) {
|
||||||
- if (sanitize) {
|
- if (sanitize) {
|
||||||
@@ -33,7 +169,9 @@ diff -NarU1 marked-1.0.0-orig/src/helpers.js marked-1.0.0-edit/src/helpers.js
|
|||||||
- }
|
- }
|
||||||
+function cleanUrl(base, href) {
|
+function cleanUrl(base, href) {
|
||||||
if (base && !originIndependentUrl.test(href)) {
|
if (base && !originIndependentUrl.test(href)) {
|
||||||
@@ -224,8 +211,2 @@
|
href = resolveUrl(base, href);
|
||||||
|
@@ -223,10 +210,4 @@ function findClosingBracket(str, b) {
|
||||||
|
}
|
||||||
|
|
||||||
-function checkSanitizeDeprecation(opt) {
|
-function checkSanitizeDeprecation(opt) {
|
||||||
- if (opt && opt.sanitize && !opt.silent) {
|
- if (opt && opt.sanitize && !opt.silent) {
|
||||||
@@ -42,228 +180,161 @@ diff -NarU1 marked-1.0.0-orig/src/helpers.js marked-1.0.0-edit/src/helpers.js
|
|||||||
-}
|
-}
|
||||||
-
|
-
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@@ -240,4 +221,3 @@
|
escape,
|
||||||
|
@@ -239,5 +220,4 @@ module.exports = {
|
||||||
|
splitCells,
|
||||||
rtrim,
|
rtrim,
|
||||||
- findClosingBracket,
|
- findClosingBracket,
|
||||||
- checkSanitizeDeprecation
|
- checkSanitizeDeprecation
|
||||||
+ findClosingBracket
|
+ findClosingBracket
|
||||||
};
|
};
|
||||||
diff -NarU1 marked-1.0.0-orig/src/Lexer.js marked-1.0.0-edit/src/Lexer.js
|
diff --git a/src/marked.js b/src/marked.js
|
||||||
--- marked-1.0.0-orig/src/Lexer.js 2020-04-21 01:03:48.000000000 +0000
|
--- a/src/marked.js
|
||||||
+++ marked-1.0.0-edit/src/Lexer.js 2020-04-25 22:46:54.107584066 +0000
|
+++ b/src/marked.js
|
||||||
@@ -6,3 +6,3 @@
|
@@ -7,5 +7,4 @@ const Slugger = require('./Slugger.js');
|
||||||
* smartypants text replacement
|
const {
|
||||||
- */
|
|
||||||
+ *
|
|
||||||
function smartypants(text) {
|
|
||||||
@@ -27,3 +27,3 @@
|
|
||||||
* mangle email addresses
|
|
||||||
- */
|
|
||||||
+ *
|
|
||||||
function mangle(text) {
|
|
||||||
@@ -388,3 +388,3 @@
|
|
||||||
// autolink
|
|
||||||
- if (token = this.tokenizer.autolink(src, mangle)) {
|
|
||||||
+ if (token = this.tokenizer.autolink(src)) {
|
|
||||||
src = src.substring(token.raw.length);
|
|
||||||
@@ -395,3 +395,3 @@
|
|
||||||
// url (gfm)
|
|
||||||
- if (!inLink && (token = this.tokenizer.url(src, mangle))) {
|
|
||||||
+ if (!inLink && (token = this.tokenizer.url(src))) {
|
|
||||||
src = src.substring(token.raw.length);
|
|
||||||
@@ -402,3 +402,3 @@
|
|
||||||
// text
|
|
||||||
- if (token = this.tokenizer.inlineText(src, inRawBlock, smartypants)) {
|
|
||||||
+ if (token = this.tokenizer.inlineText(src, inRawBlock)) {
|
|
||||||
src = src.substring(token.raw.length);
|
|
||||||
diff -NarU1 marked-1.0.0-orig/src/marked.js marked-1.0.0-edit/src/marked.js
|
|
||||||
--- marked-1.0.0-orig/src/marked.js 2020-04-21 01:03:48.000000000 +0000
|
|
||||||
+++ marked-1.0.0-edit/src/marked.js 2020-04-25 22:42:55.140924439 +0000
|
|
||||||
@@ -8,3 +8,2 @@
|
|
||||||
merge,
|
merge,
|
||||||
- checkSanitizeDeprecation,
|
- checkSanitizeDeprecation,
|
||||||
escape
|
escape
|
||||||
@@ -37,3 +36,2 @@
|
} = require('./helpers.js');
|
||||||
opt = merge({}, marked.defaults, opt || {});
|
@@ -35,5 +34,4 @@ function marked(src, opt, callback) {
|
||||||
- checkSanitizeDeprecation(opt);
|
|
||||||
const highlight = opt.highlight;
|
opt = merge({}, marked.defaults, opt || {});
|
||||||
@@ -101,6 +99,5 @@
|
- checkSanitizeDeprecation(opt);
|
||||||
opt = merge({}, marked.defaults, opt || {});
|
|
||||||
- checkSanitizeDeprecation(opt);
|
if (callback) {
|
||||||
return Parser.parse(Lexer.lex(src, opt), opt);
|
@@ -108,5 +106,5 @@ function marked(src, opt, callback) {
|
||||||
|
return Parser.parse(tokens, opt);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
- e.message += '\nPlease report this to https://github.com/markedjs/marked.';
|
- e.message += '\nPlease report this to https://github.com/markedjs/marked.';
|
||||||
+ e.message += '\nmake issue @ https://github.com/9001/copyparty';
|
+ e.message += '\nmake issue @ https://github.com/9001/copyparty';
|
||||||
if ((opt || marked.defaults).silent) {
|
if (opt.silent) {
|
||||||
diff -NarU1 marked-1.0.0-orig/src/Renderer.js marked-1.0.0-edit/src/Renderer.js
|
return '<p>An error occurred:</p><pre>'
|
||||||
--- marked-1.0.0-orig/src/Renderer.js 2020-04-21 01:03:48.000000000 +0000
|
diff --git a/test/bench.js b/test/bench.js
|
||||||
+++ marked-1.0.0-edit/src/Renderer.js 2020-04-25 18:59:15.091319265 +0000
|
--- a/test/bench.js
|
||||||
@@ -134,3 +134,3 @@
|
+++ b/test/bench.js
|
||||||
link(href, title, text) {
|
@@ -33,5 +33,4 @@ async function runBench(options) {
|
||||||
- href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
|
breaks: false,
|
||||||
+ href = cleanUrl(this.options.baseUrl, href);
|
|
||||||
if (href === null) {
|
|
||||||
@@ -147,3 +147,3 @@
|
|
||||||
image(href, title, text) {
|
|
||||||
- href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
|
|
||||||
+ href = cleanUrl(this.options.baseUrl, href);
|
|
||||||
if (href === null) {
|
|
||||||
diff -NarU1 marked-1.0.0-orig/src/Tokenizer.js marked-1.0.0-edit/src/Tokenizer.js
|
|
||||||
--- marked-1.0.0-orig/src/Tokenizer.js 2020-04-21 01:03:48.000000000 +0000
|
|
||||||
+++ marked-1.0.0-edit/src/Tokenizer.js 2020-04-25 22:47:07.610917004 +0000
|
|
||||||
@@ -256,9 +256,6 @@
|
|
||||||
return {
|
|
||||||
- type: this.options.sanitize
|
|
||||||
- ? 'paragraph'
|
|
||||||
- : 'html',
|
|
||||||
- raw: cap[0],
|
|
||||||
- pre: !this.options.sanitizer
|
|
||||||
- && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
|
|
||||||
- text: this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0]
|
|
||||||
+ type: 'html',
|
|
||||||
+ raw: cap[0],
|
|
||||||
+ pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',
|
|
||||||
+ text: cap[0]
|
|
||||||
};
|
|
||||||
@@ -382,5 +379,3 @@
|
|
||||||
return {
|
|
||||||
- type: this.options.sanitize
|
|
||||||
- ? 'text'
|
|
||||||
- : 'html',
|
|
||||||
+ type: 'html',
|
|
||||||
raw: cap[0],
|
|
||||||
@@ -388,7 +383,3 @@
|
|
||||||
inRawBlock,
|
|
||||||
- text: this.options.sanitize
|
|
||||||
- ? (this.options.sanitizer
|
|
||||||
- ? this.options.sanitizer(cap[0])
|
|
||||||
- : escape(cap[0]))
|
|
||||||
- : cap[0]
|
|
||||||
+ text: cap[0]
|
|
||||||
};
|
|
||||||
@@ -504,3 +495,3 @@
|
|
||||||
|
|
||||||
- autolink(src, mangle) {
|
|
||||||
+ autolink(src) {
|
|
||||||
const cap = this.rules.inline.autolink.exec(src);
|
|
||||||
@@ -509,3 +500,3 @@
|
|
||||||
if (cap[2] === '@') {
|
|
||||||
- text = escape(this.options.mangle ? mangle(cap[1]) : cap[1]);
|
|
||||||
+ text = escape(cap[1]);
|
|
||||||
href = 'mailto:' + text;
|
|
||||||
@@ -532,3 +523,3 @@
|
|
||||||
|
|
||||||
- url(src, mangle) {
|
|
||||||
+ url(src) {
|
|
||||||
let cap;
|
|
||||||
@@ -537,3 +528,3 @@
|
|
||||||
if (cap[2] === '@') {
|
|
||||||
- text = escape(this.options.mangle ? mangle(cap[0]) : cap[0]);
|
|
||||||
+ text = escape(cap[0]);
|
|
||||||
href = 'mailto:' + text;
|
|
||||||
@@ -569,3 +560,3 @@
|
|
||||||
|
|
||||||
- inlineText(src, inRawBlock, smartypants) {
|
|
||||||
+ inlineText(src, inRawBlock) {
|
|
||||||
const cap = this.rules.inline.text.exec(src);
|
|
||||||
@@ -574,5 +565,5 @@
|
|
||||||
if (inRawBlock) {
|
|
||||||
- text = this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0];
|
|
||||||
+ text = cap[0];
|
|
||||||
} else {
|
|
||||||
- text = escape(this.options.smartypants ? smartypants(cap[0]) : cap[0]);
|
|
||||||
+ text = escape(cap[0]);
|
|
||||||
}
|
|
||||||
diff -NarU1 marked-1.0.0-orig/test/bench.js marked-1.0.0-edit/test/bench.js
|
|
||||||
--- marked-1.0.0-orig/test/bench.js 2020-04-21 01:03:48.000000000 +0000
|
|
||||||
+++ marked-1.0.0-edit/test/bench.js 2020-04-25 19:02:27.227980287 +0000
|
|
||||||
@@ -34,3 +34,2 @@
|
|
||||||
pedantic: false,
|
pedantic: false,
|
||||||
- sanitize: false,
|
- sanitize: false,
|
||||||
smartLists: false
|
smartLists: false
|
||||||
@@ -46,3 +45,2 @@
|
});
|
||||||
|
@@ -45,5 +44,4 @@ async function runBench(options) {
|
||||||
|
breaks: false,
|
||||||
pedantic: false,
|
pedantic: false,
|
||||||
- sanitize: false,
|
- sanitize: false,
|
||||||
smartLists: false
|
smartLists: false
|
||||||
@@ -59,3 +57,2 @@
|
});
|
||||||
|
@@ -58,5 +56,4 @@ async function runBench(options) {
|
||||||
|
breaks: false,
|
||||||
pedantic: false,
|
pedantic: false,
|
||||||
- sanitize: false,
|
- sanitize: false,
|
||||||
smartLists: false
|
smartLists: false
|
||||||
@@ -71,3 +68,2 @@
|
});
|
||||||
|
@@ -70,5 +67,4 @@ async function runBench(options) {
|
||||||
|
breaks: false,
|
||||||
pedantic: false,
|
pedantic: false,
|
||||||
- sanitize: false,
|
- sanitize: false,
|
||||||
smartLists: false
|
smartLists: false
|
||||||
@@ -84,3 +80,2 @@
|
});
|
||||||
|
@@ -83,5 +79,4 @@ async function runBench(options) {
|
||||||
|
breaks: false,
|
||||||
pedantic: true,
|
pedantic: true,
|
||||||
- sanitize: false,
|
- sanitize: false,
|
||||||
smartLists: false
|
smartLists: false
|
||||||
@@ -96,3 +91,2 @@
|
});
|
||||||
|
@@ -95,5 +90,4 @@ async function runBench(options) {
|
||||||
|
breaks: false,
|
||||||
pedantic: true,
|
pedantic: true,
|
||||||
- sanitize: false,
|
- sanitize: false,
|
||||||
smartLists: false
|
smartLists: false
|
||||||
diff -NarU1 marked-1.0.0-orig/test/specs/run-spec.js marked-1.0.0-edit/test/specs/run-spec.js
|
});
|
||||||
--- marked-1.0.0-orig/test/specs/run-spec.js 2020-04-21 01:03:48.000000000 +0000
|
diff --git a/test/specs/run-spec.js b/test/specs/run-spec.js
|
||||||
+++ marked-1.0.0-edit/test/specs/run-spec.js 2020-04-25 19:05:24.321308408 +0000
|
--- a/test/specs/run-spec.js
|
||||||
@@ -21,6 +21,2 @@
|
+++ b/test/specs/run-spec.js
|
||||||
|
@@ -22,8 +22,4 @@ function runSpecs(title, dir, showCompletionTable, options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
- if (spec.options.sanitizer) {
|
- if (spec.options.sanitizer) {
|
||||||
- // eslint-disable-next-line no-eval
|
- // eslint-disable-next-line no-eval
|
||||||
- spec.options.sanitizer = eval(spec.options.sanitizer);
|
- spec.options.sanitizer = eval(spec.options.sanitizer);
|
||||||
- }
|
- }
|
||||||
|
|
||||||
(spec.only ? fit : (spec.skip ? xit : it))('should ' + passFail + example, async() => {
|
(spec.only ? fit : (spec.skip ? xit : it))('should ' + passFail + example, async() => {
|
||||||
@@ -49,2 +45 @@
|
@@ -53,3 +49,2 @@ runSpecs('Original', './original', false, { gfm: false, pedantic: true });
|
||||||
|
runSpecs('New', './new');
|
||||||
runSpecs('ReDOS', './redos');
|
runSpecs('ReDOS', './redos');
|
||||||
-runSpecs('Security', './security', false, { silent: true }); // silent - do not show deprecation warning
|
-runSpecs('Security', './security', false, { silent: true }); // silent - do not show deprecation warning
|
||||||
diff -NarU1 marked-1.0.0-orig/test/unit/Lexer-spec.js marked-1.0.0-edit/test/unit/Lexer-spec.js
|
diff --git a/test/unit/Lexer-spec.js b/test/unit/Lexer-spec.js
|
||||||
--- marked-1.0.0-orig/test/unit/Lexer-spec.js 2020-04-21 01:03:48.000000000 +0000
|
--- a/test/unit/Lexer-spec.js
|
||||||
+++ marked-1.0.0-edit/test/unit/Lexer-spec.js 2020-04-25 22:47:27.170916427 +0000
|
+++ b/test/unit/Lexer-spec.js
|
||||||
@@ -464,3 +464,3 @@
|
@@ -465,5 +465,5 @@ a | b
|
||||||
|
});
|
||||||
|
|
||||||
- it('sanitize', () => {
|
- it('sanitize', () => {
|
||||||
+ /*it('sanitize', () => {
|
+ /*it('sanitize', () => {
|
||||||
expectTokens({
|
expectTokens({
|
||||||
@@ -482,3 +482,3 @@
|
md: '<div>html</div>',
|
||||||
|
@@ -483,5 +483,5 @@ a | b
|
||||||
|
]
|
||||||
});
|
});
|
||||||
- });
|
- });
|
||||||
+ });*/
|
+ });*/
|
||||||
});
|
});
|
||||||
@@ -586,3 +586,3 @@
|
|
||||||
|
@@ -587,5 +587,5 @@ a | b
|
||||||
|
});
|
||||||
|
|
||||||
- it('html sanitize', () => {
|
- it('html sanitize', () => {
|
||||||
+ /*it('html sanitize', () => {
|
+ /*it('html sanitize', () => {
|
||||||
expectInlineTokens({
|
expectInlineTokens({
|
||||||
@@ -596,3 +596,3 @@
|
md: '<div>html</div>',
|
||||||
|
@@ -597,5 +597,5 @@ a | b
|
||||||
|
]
|
||||||
});
|
});
|
||||||
- });
|
- });
|
||||||
+ });*/
|
+ });*/
|
||||||
|
|
||||||
@@ -825,3 +825,3 @@
|
it('link', () => {
|
||||||
|
@@ -909,5 +909,5 @@ a | b
|
||||||
|
});
|
||||||
|
|
||||||
- it('autolink mangle email', () => {
|
- it('autolink mangle email', () => {
|
||||||
+ /*it('autolink mangle email', () => {
|
+ /*it('autolink mangle email', () => {
|
||||||
expectInlineTokens({
|
expectInlineTokens({
|
||||||
@@ -845,3 +845,3 @@
|
md: '<test@example.com>',
|
||||||
|
@@ -929,5 +929,5 @@ a | b
|
||||||
|
]
|
||||||
});
|
});
|
||||||
- });
|
- });
|
||||||
+ });*/
|
+ });*/
|
||||||
|
|
||||||
@@ -882,3 +882,3 @@
|
it('url', () => {
|
||||||
|
@@ -966,5 +966,5 @@ a | b
|
||||||
|
});
|
||||||
|
|
||||||
- it('url mangle email', () => {
|
- it('url mangle email', () => {
|
||||||
+ /*it('url mangle email', () => {
|
+ /*it('url mangle email', () => {
|
||||||
expectInlineTokens({
|
expectInlineTokens({
|
||||||
@@ -902,3 +902,3 @@
|
md: 'test@example.com',
|
||||||
|
@@ -986,5 +986,5 @@ a | b
|
||||||
|
]
|
||||||
});
|
});
|
||||||
- });
|
- });
|
||||||
+ });*/
|
+ });*/
|
||||||
});
|
});
|
||||||
@@ -918,3 +918,3 @@
|
|
||||||
|
@@ -1002,5 +1002,5 @@ a | b
|
||||||
|
});
|
||||||
|
|
||||||
- describe('smartypants', () => {
|
- describe('smartypants', () => {
|
||||||
+ /*describe('smartypants', () => {
|
+ /*describe('smartypants', () => {
|
||||||
it('single quotes', () => {
|
it('single quotes', () => {
|
||||||
@@ -988,3 +988,3 @@
|
expectInlineTokens({
|
||||||
|
@@ -1072,5 +1072,5 @@ a | b
|
||||||
|
});
|
||||||
});
|
});
|
||||||
- });
|
- });
|
||||||
+ });*/
|
+ });*/
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -26,3 +26,6 @@ awk '/:before .content:"\\/ {sub(/[^"]+"./,""); sub(/".*/,""); print}' </z/dist/
|
|||||||
|
|
||||||
# and finally create a woff with just our icons
|
# and finally create a woff with just our icons
|
||||||
pyftsubset "$orig_woff" --unicodes-file=/z/icon.list --no-ignore-missing-unicodes --flavor=woff --with-zopfli --output-file=/z/dist/no-pk/mini-fa.woff --verbose
|
pyftsubset "$orig_woff" --unicodes-file=/z/icon.list --no-ignore-missing-unicodes --flavor=woff --with-zopfli --output-file=/z/dist/no-pk/mini-fa.woff --verbose
|
||||||
|
|
||||||
|
# scp is easier, just want basic latin
|
||||||
|
pyftsubset /z/scp.woff2 --unicodes="20-7e,ab,b7,bb,2022" --no-ignore-missing-unicodes --flavor=woff2 --output-file=/z/dist/no-pk/scp.woff2 --verbose
|
||||||
|
|||||||
@@ -166,3 +166,6 @@ chmod 755 $sfx_out.*
|
|||||||
printf "done:\n"
|
printf "done:\n"
|
||||||
printf " %s\n" "$(realpath $sfx_out)."{sh,py}
|
printf " %s\n" "$(realpath $sfx_out)."{sh,py}
|
||||||
# rm -rf *
|
# rm -rf *
|
||||||
|
|
||||||
|
# tar -tvf ../sfx/tar | sed -r 's/(.* ....-..-.. ..:.. )(.*)/\2 `` \1/' | sort | sed -r 's/(.*) `` (.*)/\2 \1/'| less
|
||||||
|
# for n in {1..9}; do tar -tf tar | grep -vE '/$' | sed -r 's/(.*)\.(.*)/\2.\1/' | sort | sed -r 's/([^\.]+)\.(.*)/\2.\1/' | tar -cT- | bzip2 -c$n | wc -c; done
|
||||||
|
|||||||
@@ -17,6 +17,14 @@
|
|||||||
[80............................................................................]
|
[80............................................................................]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
l[i]=1I;(){}o0O</> var foo = "$(`bar`)"; a's'd
|
||||||
|
```
|
||||||
|
|
||||||
|
[](#s1)
|
||||||
|
[s1](#s1)
|
||||||
|
[#s1](#s1)
|
||||||
|
|
||||||
a123456789b123456789c123456789d123456789e123456789f123456789g123456789h123456789i123456789j123456789k123456789l123456789m123456789n123456789o123456789p123456789q123456789r123456789s123456789t123456789u123456789v123456789w123456789x123456789y123456789z123456789
|
a123456789b123456789c123456789d123456789e123456789f123456789g123456789h123456789i123456789j123456789k123456789l123456789m123456789n123456789o123456789p123456789q123456789r123456789s123456789t123456789u123456789v123456789w123456789x123456789y123456789z123456789
|
||||||
|
|
||||||
<foo> bar & <span>baz</span>
|
<foo> bar & <span>baz</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user