diff --git a/copyparty/web/util.js b/copyparty/web/util.js index 2f56553b..76b9c1ff 100644 --- a/copyparty/web/util.js +++ b/copyparty/web/util.js @@ -194,36 +194,40 @@ function ev(e) { // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith -if (!String.prototype.endsWith) { +if (!String.prototype.endsWith) String.prototype.endsWith = function (search, this_len) { if (this_len === undefined || this_len > this.length) { this_len = this.length; } return this.substring(this_len - search.length, this_len) === search; }; -} -if (!String.startsWith) { + +if (!String.startsWith) String.prototype.startsWith = function (s, i) { i = i > 0 ? i | 0 : 0; return this.substring(i, i + s.length) === s; }; -} -if (!Element.prototype.matches) { + +if (!String.trimEnd) + String.prototype.trimEnd = String.prototype.trimRight = function () { + return this.replace(/[ \t\r\n]+$/m, ''); + }; + +if (!Element.prototype.matches) Element.prototype.matches = Element.prototype.oMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.webkitMatchesSelector; -} -if (!Element.prototype.closest) { + +if (!Element.prototype.closest) Element.prototype.closest = function (s) { var el = this; do { if (el.matches(s)) return el; el = el.parentElement || el.parentNode; } while (el !== null && el.nodeType === 1); - } -} + }; // https://stackoverflow.com/a/950146 diff --git a/scripts/deps-docker/Dockerfile b/scripts/deps-docker/Dockerfile index 1feacec2..f55075f4 100644 --- a/scripts/deps-docker/Dockerfile +++ b/scripts/deps-docker/Dockerfile @@ -2,10 +2,10 @@ FROM alpine:3.14 WORKDIR /z ENV ver_asmcrypto=5b994303a9d3e27e0915f72a10b6c2c51535a4dc \ ver_hashwasm=4.9.0 \ - ver_marked=1.1.0 \ + ver_marked=3.0.4 \ ver_ogvjs=1.8.4 \ - ver_mde=2.14.0 \ - ver_codemirror=5.59.3 \ + ver_mde=2.15.0 \ + ver_codemirror=5.62.3 \ ver_fontawesome=5.13.0 \ ver_zopfli=1.0.3 @@ -113,7 +113,7 @@ RUN cd CodeMirror-$ver_codemirror \ COPY easymde.patch /z/ RUN cd easy-markdown-editor-$ver_mde \ && patch -p1 < /z/easymde.patch \ - && sed -ri 's`https://registry.npmjs.org/marked/-/marked-0.8.2.tgz`file:/z/nodepkgs/marked`' package-lock.json \ + && sed -ri 's`https://registry.npmjs.org/marked/-/marked-[0-9\.]+.tgz`file:/z/nodepkgs/marked`' package-lock.json \ && sed -ri 's`("marked": ")[^"]+`\1file:/z/nodepkgs/marked`' ./package.json \ && sed -ri 's`("codemirror": ")[^"]+`\1file:/z/nodepkgs/codemirror`' ./package.json \ && npm install diff --git a/scripts/deps-docker/marked-ln.patch b/scripts/deps-docker/marked-ln.patch index 42066b06..552457fd 100644 --- a/scripts/deps-docker/marked-ln.patch +++ b/scripts/deps-docker/marked-ln.patch @@ -1,15 +1,15 @@ diff --git a/src/Lexer.js b/src/Lexer.js -adds linetracking to marked.js v1.0.0 +git; +adds linetracking to marked.js v3.0.4; add data-ln="%d" to most tags, %d is the source markdown line --- a/src/Lexer.js +++ b/src/Lexer.js -@@ -49,4 +49,5 @@ function mangle(text) { +@@ -50,4 +50,5 @@ function mangle(text) { module.exports = class Lexer { constructor(options) { + this.ln = 1; // like most editors, start couting from 1 this.tokens = []; this.tokens.links = Object.create(null); -@@ -108,4 +109,15 @@ module.exports = class Lexer { +@@ -127,4 +128,15 @@ module.exports = class Lexer { } + set_ln(token, ln = this.ln) { @@ -25,122 +25,123 @@ add data-ln="%d" to most tags, %d is the source markdown line + /** * Lexing -@@ -113,10 +125,15 @@ module.exports = class Lexer { - blockTokens(src, tokens = [], top = true) { - src = src.replace(/^ +$/gm, ''); -- let token, i, l, lastToken; -+ let token, i, l, lastToken, ln; +@@ -134,7 +146,11 @@ module.exports = class Lexer { + src = src.replace(/^ +$/gm, ''); + } +- let token, lastToken, cutSrc, lastParagraphClipped; ++ let token, lastToken, cutSrc, lastParagraphClipped, ln; while (src) { + // this.ln will be bumped by recursive calls into this func; + // reset the count and rely on the outermost token's raw only + ln = this.ln; + - // newline + if (this.options.extensions + && this.options.extensions.block +@@ -142,4 +158,5 @@ module.exports = class Lexer { + if (token = extTokenizer.call({ lexer: this }, src, tokens)) { + src = src.substring(token.raw.length); ++ this.set_ln(token, ln); + tokens.push(token); + return true; +@@ -153,4 +170,5 @@ module.exports = class Lexer { if (token = this.tokenizer.space(src)) { src = src.substring(token.raw.length); -+ this.set_ln(token); // is \n if not type ++ this.set_ln(token, ln); // is \n if not type if (token.type) { tokens.push(token); -@@ -128,4 +145,5 @@ module.exports = class Lexer { - if (token = this.tokenizer.code(src, tokens)) { +@@ -162,4 +180,5 @@ module.exports = class Lexer { + if (token = this.tokenizer.code(src)) { src = src.substring(token.raw.length); -+ this.set_ln(token); - if (token.type) { - tokens.push(token); -@@ -141,4 +159,5 @@ module.exports = class Lexer { ++ this.set_ln(token, ln); + lastToken = tokens[tokens.length - 1]; + // An indented code block cannot interrupt a paragraph. +@@ -177,4 +196,5 @@ module.exports = class Lexer { if (token = this.tokenizer.fences(src)) { src = src.substring(token.raw.length); -+ this.set_ln(token); ++ this.set_ln(token, ln); tokens.push(token); continue; -@@ -148,4 +167,5 @@ module.exports = class Lexer { +@@ -184,4 +204,5 @@ module.exports = class Lexer { if (token = this.tokenizer.heading(src)) { src = src.substring(token.raw.length); -+ this.set_ln(token); ++ this.set_ln(token, ln); tokens.push(token); continue; -@@ -155,4 +175,5 @@ module.exports = class Lexer { - if (token = this.tokenizer.nptable(src)) { - src = src.substring(token.raw.length); -+ this.set_ln(token); - tokens.push(token); - continue; -@@ -162,4 +183,5 @@ module.exports = class Lexer { +@@ -191,4 +212,5 @@ module.exports = class Lexer { if (token = this.tokenizer.hr(src)) { src = src.substring(token.raw.length); -+ this.set_ln(token); ++ this.set_ln(token, ln); tokens.push(token); continue; -@@ -170,4 +192,7 @@ module.exports = class Lexer { +@@ -198,4 +220,5 @@ module.exports = class Lexer { + if (token = this.tokenizer.blockquote(src)) { src = src.substring(token.raw.length); - token.tokens = this.blockTokens(token.text, [], top); -+ // recursive call to blockTokens probably bumped this.ln, -+ // token.raw is more reliable so reset this.ln and use that + this.set_ln(token, ln); tokens.push(token); continue; -@@ -180,5 +205,9 @@ module.exports = class Lexer { - for (i = 0; i < l; i++) { - token.items[i].tokens = this.blockTokens(token.items[i].text, [], false); -+ // list entries don't bump the linecounter, so let's -+ this.ln++; - } -+ // then reset like blockquote +@@ -205,4 +228,5 @@ module.exports = class Lexer { + if (token = this.tokenizer.list(src)) { + src = src.substring(token.raw.length); + this.set_ln(token, ln); tokens.push(token); continue; -@@ -188,4 +217,5 @@ module.exports = class Lexer { +@@ -212,4 +236,5 @@ module.exports = class Lexer { if (token = this.tokenizer.html(src)) { src = src.substring(token.raw.length); -+ this.set_ln(token); ++ this.set_ln(token, ln); tokens.push(token); continue; -@@ -195,4 +225,5 @@ module.exports = class Lexer { - if (top && (token = this.tokenizer.def(src))) { +@@ -219,4 +244,5 @@ module.exports = class Lexer { + if (token = this.tokenizer.def(src)) { src = src.substring(token.raw.length); -+ this.set_ln(token); - if (!this.tokens.links[token.tag]) { - this.tokens.links[token.tag] = { -@@ -207,4 +238,5 @@ module.exports = class Lexer { ++ this.set_ln(token, ln); + lastToken = tokens[tokens.length - 1]; + if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) { +@@ -236,4 +262,5 @@ module.exports = class Lexer { if (token = this.tokenizer.table(src)) { src = src.substring(token.raw.length); -+ this.set_ln(token); ++ this.set_ln(token, ln); tokens.push(token); continue; -@@ -214,4 +246,5 @@ module.exports = class Lexer { +@@ -243,4 +270,5 @@ module.exports = class Lexer { if (token = this.tokenizer.lheading(src)) { src = src.substring(token.raw.length); -+ this.set_ln(token); ++ this.set_ln(token, ln); tokens.push(token); continue; -@@ -221,4 +254,5 @@ module.exports = class Lexer { - if (top && (token = this.tokenizer.paragraph(src))) { +@@ -263,4 +291,5 @@ module.exports = class Lexer { + } + if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) { ++ this.set_ln(token, ln); + lastToken = tokens[tokens.length - 1]; + if (lastParagraphClipped && lastToken.type === 'paragraph') { +@@ -280,4 +309,6 @@ module.exports = class Lexer { + if (token = this.tokenizer.text(src)) { src = src.substring(token.raw.length); -+ this.set_ln(token); - tokens.push(token); - continue; -@@ -228,4 +262,5 @@ module.exports = class Lexer { - if (token = this.tokenizer.text(src, tokens)) { - src = src.substring(token.raw.length); -+ this.set_ln(token); - if (token.type) { - tokens.push(token); -@@ -263,4 +298,7 @@ module.exports = class Lexer { - for (i = 0; i < l; i++) { - token = tokens[i]; -+ // this.ln is at EOF when inline() is invoked; -+ // all this affects
tags only so no biggie if it breaks -+ this.ln = token.ln || this.ln; - switch (token.type) { - case 'paragraph': -@@ -386,4 +424,6 @@ module.exports = class Lexer { ++ this.set_ln(token, ln); ++ this.ln++; + lastToken = tokens[tokens.length - 1]; + if (lastToken && lastToken.type === 'text') { +@@ -355,4 +386,5 @@ module.exports = class Lexer { + if (token = extTokenizer.call({ lexer: this }, src, tokens)) { + src = src.substring(token.raw.length); ++ this.ln = token.ln || this.ln; + tokens.push(token); + return true; +@@ -420,4 +452,6 @@ module.exports = class Lexer { if (token = this.tokenizer.br(src)) { src = src.substring(token.raw.length); + // no need to reset (no more blockTokens anyways) + token.ln = this.ln++; tokens.push(token); continue; +@@ -462,4 +496,5 @@ module.exports = class Lexer { + if (token = this.tokenizer.inlineText(cutSrc, smartypants)) { + src = src.substring(token.raw.length); ++ this.ln = token.ln || this.ln; + if (token.raw.slice(-1) !== '_') { // Track prevChar before string of ____ started + prevChar = token.raw.slice(-1); diff --git a/src/Parser.js b/src/Parser.js --- a/src/Parser.js +++ b/src/Parser.js @@ -150,17 +151,16 @@ diff --git a/src/Parser.js b/src/Parser.js + this.ln = 0; // error indicator; should always be set >=1 from tokens } -@@ -55,4 +56,9 @@ module.exports = class Parser { +@@ -64,4 +65,8 @@ module.exports = class Parser { for (i = 0; i < l; i++) { token = tokens[i]; + // take line-numbers from tokens whenever possible + // and update the renderer's html attribute with the new value + this.ln = token.ln || this.ln; + this.renderer.tag_ln(this.ln); -+ - switch (token.type) { - case 'space': { -@@ -105,7 +111,10 @@ module.exports = class Parser { + + // Run any renderer extensions +@@ -124,7 +129,10 @@ module.exports = class Parser { } - body += this.renderer.tablerow(cell); @@ -173,7 +173,7 @@ diff --git a/src/Parser.js b/src/Parser.js + out += this.renderer.tag_ln(token.ln).table(header, body); continue; } -@@ -148,8 +157,12 @@ module.exports = class Parser { +@@ -167,8 +175,12 @@ module.exports = class Parser { itemBody += this.parse(item.tokens, loose); - body += this.renderer.listitem(itemBody, task, checked); @@ -188,7 +188,7 @@ diff --git a/src/Parser.js b/src/Parser.js + out += this.renderer.tag_ln(token.ln).list(body, ordered, start); continue; } -@@ -160,5 +173,6 @@ module.exports = class Parser { +@@ -179,5 +191,6 @@ module.exports = class Parser { } case 'paragraph': { - out += this.renderer.paragraph(this.parseInline(token.tokens)); @@ -196,22 +196,14 @@ diff --git a/src/Parser.js b/src/Parser.js + out += this.renderer.tag_ln(token.ln).paragraph(t); continue; } -@@ -199,4 +213,6 @@ module.exports = class Parser { - for (i = 0; i < l; i++) { +@@ -221,4 +234,7 @@ module.exports = class Parser { token = tokens[i]; + + // another thing that only affects
and other inlines + this.ln = token.ln || this.ln; - switch (token.type) { - case 'escape': { -@@ -229,5 +245,7 @@ module.exports = class Parser { - } - case 'br': { -- out += renderer.br(); -+ // update the html attribute before writing each
, -+ // don't care about the others -+ out += renderer.tag_ln(this.ln).br(); - break; - } ++ + // Run any renderer extensions + if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) { diff --git a/src/Renderer.js b/src/Renderer.js --- a/src/Renderer.js +++ b/src/Renderer.js @@ -228,7 +220,7 @@ diff --git a/src/Renderer.js b/src/Renderer.js + code(code, infostring, escaped) { const lang = (infostring || '').match(/\S*/)[0]; -@@ -24,10 +30,10 @@ module.exports = class Renderer { +@@ -26,10 +32,10 @@ module.exports = class Renderer { if (!lang) { - return '
'
@@ -241,58 +233,69 @@ diff --git a/src/Renderer.js b/src/Renderer.js
 +    return '' + text + '\n';
 +    return '' + text + '\n';
    }
  
-@@ -73,5 +80,5 @@ module.exports = class Renderer {
+@@ -75,5 +82,5 @@ module.exports = class Renderer {
  
    listitem(text) {
 -    return '
  • ' + text + '
  • \n'; + return '' + text + '\n'; } -@@ -85,5 +92,5 @@ module.exports = class Renderer { +@@ -87,5 +94,5 @@ module.exports = class Renderer { paragraph(text) { - return '

    ' + text + '

    \n'; + return '' + text + '

    \n'; } -@@ -100,5 +107,5 @@ module.exports = class Renderer { +@@ -102,5 +109,5 @@ module.exports = class Renderer { tablerow(content) { - return '\n' + content + '\n'; + return '\n' + content + '\n'; } -@@ -125,5 +132,5 @@ module.exports = class Renderer { +@@ -127,5 +134,5 @@ module.exports = class Renderer { br() { - return this.options.xhtml ? '
    ' : '
    '; + return this.options.xhtml ? '' : ''; } -@@ -151,5 +158,5 @@ module.exports = class Renderer { +@@ -153,5 +160,5 @@ module.exports = class Renderer { } - let out = '' + text + ' { -@@ -53,3 +49,2 @@ runSpecs('Original', './original', false, { gfm: false, pedantic: true }); + const before = process.hrtime(); +@@ -53,3 +48,2 @@ runSpecs('Original', './original', false, { gfm: false, pedantic: true }); runSpecs('New', './new'); runSpecs('ReDOS', './redos'); -runSpecs('Security', './security', false, { silent: true }); // silent - do not show deprecation warning diff --git a/test/unit/Lexer-spec.js b/test/unit/Lexer-spec.js --- a/test/unit/Lexer-spec.js +++ b/test/unit/Lexer-spec.js -@@ -465,5 +465,5 @@ a | b +@@ -589,5 +589,5 @@ paragraph }); - it('sanitize', () => { + /*it('sanitize', () => { expectTokens({ md: '
    html
    ', -@@ -483,5 +483,5 @@ a | b +@@ -607,5 +607,5 @@ paragraph ] }); - }); + });*/ }); -@@ -587,5 +587,5 @@ a | b +@@ -652,5 +652,5 @@ paragraph }); - it('html sanitize', () => { + /*it('html sanitize', () => { expectInlineTokens({ md: '
    html
    ', -@@ -597,5 +597,5 @@ a | b +@@ -660,5 +660,5 @@ paragraph ] }); - }); + });*/ it('link', () => { -@@ -909,5 +909,5 @@ a | b +@@ -971,5 +971,5 @@ paragraph }); - it('autolink mangle email', () => { + /*it('autolink mangle email', () => { expectInlineTokens({ md: '', -@@ -929,5 +929,5 @@ a | b +@@ -991,5 +991,5 @@ paragraph ] }); - }); + });*/ it('url', () => { -@@ -966,5 +966,5 @@ a | b +@@ -1028,5 +1028,5 @@ paragraph }); - it('url mangle email', () => { + /*it('url mangle email', () => { expectInlineTokens({ md: 'test@example.com', -@@ -986,5 +986,5 @@ a | b +@@ -1048,5 +1048,5 @@ paragraph ] }); - }); + });*/ }); -@@ -1002,5 +1002,5 @@ a | b +@@ -1064,5 +1064,5 @@ paragraph }); - describe('smartypants', () => { + /*describe('smartypants', () => { it('single quotes', () => { expectInlineTokens({ -@@ -1072,5 +1072,5 @@ a | b +@@ -1134,5 +1134,5 @@ paragraph }); }); - }); diff --git a/srv/test.md b/srv/test.md index 05affa33..838739cf 100644 --- a/srv/test.md +++ b/srv/test.md @@ -140,12 +140,12 @@ a newline toplevel | a table | on the right | | second row | foo bar | -|| +a||a --|:-:|-: a table | big text in this | aaakbfddd second row | centred | bbb -|| +|||| --|--|-- foo