web: clickable links in terminal rows and dashboard messages (issue #233)
This commit is contained in:
parent
4b51c198d5
commit
15e44955a8
5 changed files with 82 additions and 8 deletions
|
|
@ -213,6 +213,9 @@ details.row > pre.diff-body .diff-ctx { color: var(--fg); }
|
|||
border-radius: 0;
|
||||
}
|
||||
.live .row .md a { color: var(--cyan); text-decoration: underline; }
|
||||
/* Auto-linkified bare URLs in plain rows + tool-body blocks (issue #233). */
|
||||
.live .row a { color: var(--cyan); text-decoration: underline; }
|
||||
.live .row a:hover { color: var(--fg); }
|
||||
.live .row .md strong { color: inherit; font-weight: bold; }
|
||||
.live .row .md em { color: inherit; font-style: italic; }
|
||||
.live .row .md ul, .live .row .md ol { margin: 0.2em 0 0.2em 1.4em; padding: 0; }
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@
|
|||
clearPlaceholder();
|
||||
const e = document.createElement('div');
|
||||
e.className = 'row ' + (cls || '') + (currentNoAnim ? ' no-anim' : '');
|
||||
e.textContent = text;
|
||||
e.appendChild(linkify(text));
|
||||
log.appendChild(e);
|
||||
afterAppend();
|
||||
return e;
|
||||
|
|
@ -127,7 +127,7 @@
|
|||
d.appendChild(s);
|
||||
const pre = document.createElement('pre');
|
||||
pre.className = 'tool-body';
|
||||
pre.textContent = body;
|
||||
pre.appendChild(linkify(body));
|
||||
d.appendChild(pre);
|
||||
log.appendChild(d);
|
||||
afterAppend();
|
||||
|
|
@ -158,7 +158,7 @@
|
|||
|
||||
function api(extra) {
|
||||
return Object.assign({
|
||||
row, details, detailsDiff, placeholder,
|
||||
row, details, detailsDiff, placeholder, linkify,
|
||||
fromHistory: false,
|
||||
}, extra || {});
|
||||
}
|
||||
|
|
@ -296,5 +296,49 @@
|
|||
return { row, details, detailsDiff, placeholder, ready };
|
||||
}
|
||||
|
||||
window.HiveTerminal = { create };
|
||||
// Build a DocumentFragment from `text`, turning bare http(s) URLs into
|
||||
// clickable links that open in a new tab. Non-URL text stays as plain
|
||||
// text nodes — no innerHTML, so this is XSS-safe. Trailing sentence
|
||||
// punctuation is kept out of the link. (issue #233)
|
||||
const LINKIFY_URL_RE = /https?:\/\/[^\s<>"']+/g;
|
||||
function linkify(text) {
|
||||
const str = text == null ? '' : String(text);
|
||||
const frag = document.createDocumentFragment();
|
||||
if (str.indexOf('://') === -1) { // fast path: no URLs
|
||||
if (str) frag.appendChild(document.createTextNode(str));
|
||||
return frag;
|
||||
}
|
||||
let last = 0;
|
||||
let m;
|
||||
LINKIFY_URL_RE.lastIndex = 0;
|
||||
while ((m = LINKIFY_URL_RE.exec(str)) !== null) {
|
||||
let url = m[0];
|
||||
// Don't swallow trailing punctuation that's really sentence text.
|
||||
const trail = url.match(/[.,;:!?)\]}'"]+$/);
|
||||
const tail = trail ? trail[0] : '';
|
||||
if (tail) url = url.slice(0, -tail.length);
|
||||
if (m.index > last) {
|
||||
frag.appendChild(document.createTextNode(str.slice(last, m.index)));
|
||||
}
|
||||
if (!url.slice(url.indexOf('://') + 3)) {
|
||||
// Nothing past the scheme — not a real URL, emit verbatim.
|
||||
frag.appendChild(document.createTextNode(m[0]));
|
||||
} else {
|
||||
const a = document.createElement('a');
|
||||
a.href = url; // regex only matches https?:// — safe
|
||||
a.textContent = url;
|
||||
a.target = '_blank';
|
||||
a.rel = 'noopener noreferrer';
|
||||
frag.appendChild(a);
|
||||
if (tail) frag.appendChild(document.createTextNode(tail));
|
||||
}
|
||||
last = m.index + m[0].length;
|
||||
}
|
||||
if (last < str.length) {
|
||||
frag.appendChild(document.createTextNode(str.slice(last)));
|
||||
}
|
||||
return frag;
|
||||
}
|
||||
|
||||
window.HiveTerminal = { create, linkify };
|
||||
})();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue