mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 17:12:13 -06:00
editor performance
This commit is contained in:
parent
d7d1c3685c
commit
da3f68c363
|
@ -83,6 +83,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;
|
||||||
|
@ -239,7 +240,7 @@ blink {
|
||||||
}
|
}
|
||||||
#mn.undocked {
|
#mn.undocked {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
padding: 1.2em 0 1em 1em;
|
padding: 1.7em 0 1.5em 1em;
|
||||||
box-shadow: 0 0 .5em rgba(0, 0, 0, 0.3);
|
box-shadow: 0 0 .5em rgba(0, 0, 0, 0.3);
|
||||||
background: #f7f7f7;
|
background: #f7f7f7;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,30 @@ 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 : ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// add navbar
|
// add navbar
|
||||||
(function () {
|
(function () {
|
||||||
var n = document.location + '';
|
var n = document.location + '';
|
||||||
|
@ -28,17 +48,105 @@ function hesc(txt) {
|
||||||
dom_nav.innerHTML = nav.join('');
|
dom_nav.innerHTML = nav.join('');
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
// 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) {
|
function convert_markdown(md_text) {
|
||||||
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;
|
||||||
|
|
||||||
// todo-lists (should probably be a marked extension)
|
// todo-lists (should probably be a marked extension)
|
||||||
var nodes = dom_pre.getElementsByTagName('input');
|
var 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 +166,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 +186,45 @@ 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, dom_pre, 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 manip_nodes_dyn = dom_pre.getElementsByTagName('*');
|
var manip_nodes_dyn = dom_pre.getElementsByTagName('*');
|
||||||
var manip_nodes = [];
|
var manip_nodes = [];
|
||||||
|
@ -97,7 +233,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];
|
||||||
|
@ -110,23 +246,7 @@ function init_toc() {
|
||||||
lv--;
|
lv--;
|
||||||
}
|
}
|
||||||
|
|
||||||
var orig_id = elm.getAttribute('id');
|
html.push('<li>' + elm.innerHTML + '</li>');
|
||||||
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 + '">' +
|
|
||||||
elm.innerHTML + '</a>';
|
|
||||||
|
|
||||||
html.push('<li>' + ahref + '</li>');
|
|
||||||
elm.innerHTML = ahref;
|
|
||||||
|
|
||||||
if (anchor != null)
|
if (anchor != null)
|
||||||
anchors.push(anchor);
|
anchors.push(anchor);
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
}
|
}
|
||||||
#mw {
|
#mw {
|
||||||
left: calc(100% - 57em);
|
left: calc(100% - 57em);
|
||||||
|
overflow-y: auto;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,7 +24,7 @@
|
||||||
}
|
}
|
||||||
#mw.preview,
|
#mw.preview,
|
||||||
#mtw.editor {
|
#mtw.editor {
|
||||||
z-index: 3;
|
z-index: 5;
|
||||||
}
|
}
|
||||||
#mtw.single,
|
#mtw.single,
|
||||||
#mw.single {
|
#mw.single {
|
||||||
|
|
|
@ -18,11 +18,6 @@ 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 = [];
|
var map_src = [];
|
||||||
var map_pre = [];
|
var map_pre = [];
|
||||||
|
@ -62,8 +57,10 @@ function genmap(dom) {
|
||||||
// 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);
|
||||||
|
|
||||||
|
@ -77,16 +74,22 @@ var nlines = 0;
|
||||||
map_src = genmap(dom_ref);
|
map_src = genmap(dom_ref);
|
||||||
map_pre = genmap(dom_pre);
|
map_pre = genmap(dom_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
@ -296,7 +299,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');
|
||||||
|
@ -366,7 +369,7 @@ function setsel(s) {
|
||||||
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);
|
||||||
try {
|
try {
|
||||||
dom_src.oninput();
|
draw_md();
|
||||||
}
|
}
|
||||||
catch (ex) { }
|
catch (ex) { }
|
||||||
}
|
}
|
||||||
|
@ -426,7 +429,7 @@ 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);
|
m = /^[ \t>+-]*(\* )?([0-9]+\. +)?/.exec(ln);
|
||||||
|
|
||||||
s.pre = s.md.substring(0, s.car) + '\n' + m[0];
|
s.pre = s.md.substring(0, s.car) + '\n' + m[0];
|
||||||
s.sel = '';
|
s.sel = '';
|
||||||
|
@ -561,7 +564,7 @@ action_stack = (function () {
|
||||||
dom_src.value = ref;
|
dom_src.value = ref;
|
||||||
dom_src.setSelectionRange(state.cursor, state.cursor);
|
dom_src.setSelectionRange(state.cursor, state.cursor);
|
||||||
ignore = true; // all browsers
|
ignore = true; // all browsers
|
||||||
dom_src.oninput();
|
draw_md();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,6 +580,10 @@ action_stack = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function undo() {
|
function undo() {
|
||||||
|
if (redos.length == 0) {
|
||||||
|
clearTimeout(sched_timer);
|
||||||
|
push();
|
||||||
|
}
|
||||||
return apply(undos, redos);
|
return apply(undos, redos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue