From 53ba798235cc6f00df318b8aa4c4f34068f36cc9 Mon Sep 17 00:00:00 2001
From: Benjamin Young
Date: Fri, 15 Aug 2025 11:59:30 -0400
Subject: [PATCH 1/7] Load JSON-LD from hash fragments.
Supports `startTab` and `json-ld` (for the document).
---
playground/next/editor.bundle.js | 310 +++++++++++++++++++++----------
playground/next/editor.mjs | 7 +
playground/next/index.html | 2 +-
3 files changed, 217 insertions(+), 102 deletions(-)
diff --git a/playground/next/editor.bundle.js b/playground/next/editor.bundle.js
index 6ff237b5..8e6ac79a 100644
--- a/playground/next/editor.bundle.js
+++ b/playground/next/editor.bundle.js
@@ -4253,6 +4253,34 @@
return name
}
+ function crelt() {
+ var elt = arguments[0];
+ if (typeof elt == "string") elt = document.createElement(elt);
+ var i = 1, next = arguments[1];
+ if (next && typeof next == "object" && next.nodeType == null && !Array.isArray(next)) {
+ for (var name in next) if (Object.prototype.hasOwnProperty.call(next, name)) {
+ var value = next[name];
+ if (typeof value == "string") elt.setAttribute(name, value);
+ else if (value != null) elt[name] = value;
+ }
+ i++;
+ }
+ for (; i < arguments.length; i++) add(elt, arguments[i]);
+ return elt
+ }
+
+ function add(elt, child) {
+ if (typeof child == "string") {
+ elt.appendChild(document.createTextNode(child));
+ } else if (child == null) ; else if (child.nodeType != null) {
+ elt.appendChild(child);
+ } else if (Array.isArray(child)) {
+ for (var i = 0; i < child.length; i++) add(elt, child[i]);
+ } else {
+ throw new RangeError("Unsupported child node: " + child)
+ }
+ }
+
function getSelection(root) {
let target;
// Browsers differ on whether shadow roots have a getSelection
@@ -6668,8 +6696,7 @@
let handler = state.facet(exceptionSink);
if (handler.length)
handler[0](exception);
- else if (window.onerror)
- window.onerror(String(exception), context, undefined, undefined, exception);
+ else if (window.onerror && window.onerror(String(exception), context, undefined, undefined, exception)) ;
else if (context)
console.error(context + ":", exception);
else
@@ -6677,11 +6704,23 @@
}
const editable = /*@__PURE__*/Facet.define({ combine: values => values.length ? values[0] : true });
let nextPluginID = 0;
- const viewPlugin = /*@__PURE__*/Facet.define();
+ const viewPlugin = /*@__PURE__*/Facet.define({
+ combine(plugins) {
+ return plugins.filter((p, i) => {
+ for (let j = 0; j < i; j++)
+ if (plugins[j].plugin == p.plugin)
+ return false;
+ return true;
+ });
+ }
+ });
/**
View plugins associate stateful values with a view. They can
influence the way the content is drawn, and are notified of things
- that happen in the view.
+ that happen in the view. They optionally take an argument, in
+ which case you need to call [`of`](https://codemirror.net/6/docs/ref/#view.ViewPlugin.of) to create
+ an extension for the plugin. When the argument type is undefined,
+ you can use the plugin instance as an extension directly.
*/
class ViewPlugin {
constructor(
@@ -6705,7 +6744,14 @@
this.create = create;
this.domEventHandlers = domEventHandlers;
this.domEventObservers = domEventObservers;
- this.extension = buildExtensions(this);
+ this.baseExtensions = buildExtensions(this);
+ this.extension = this.baseExtensions.concat(viewPlugin.of({ plugin: this, arg: undefined }));
+ }
+ /**
+ Create an extension for this plugin with the given argument.
+ */
+ of(arg) {
+ return this.baseExtensions.concat(viewPlugin.of({ plugin: this, arg }));
}
/**
Define a plugin from a constructor function that creates the
@@ -6714,7 +6760,7 @@
static define(create, spec) {
const { eventHandlers, eventObservers, provide, decorations: deco } = spec || {};
return new ViewPlugin(nextPluginID++, create, eventHandlers, eventObservers, plugin => {
- let ext = [viewPlugin.of(plugin)];
+ let ext = [];
if (deco)
ext.push(decorations.of(view => {
let pluginInst = view.plugin(plugin);
@@ -6730,7 +6776,7 @@
editor view as argument.
*/
static fromClass(cls, spec) {
- return ViewPlugin.define(view => new cls(view), spec);
+ return ViewPlugin.define((view, arg) => new cls(view, arg), spec);
}
}
class PluginInstance {
@@ -6738,18 +6784,19 @@
this.spec = spec;
// When starting an update, all plugins have this field set to the
// update object, indicating they need to be updated. When finished
- // updating, it is set to `false`. Retrieving a plugin that needs to
+ // updating, it is set to `null`. Retrieving a plugin that needs to
// be updated with `view.plugin` forces an eager update.
this.mustUpdate = null;
// This is null when the plugin is initially created, but
// initialized on the first update.
this.value = null;
}
+ get plugin() { return this.spec && this.spec.plugin; }
update(view) {
if (!this.value) {
if (this.spec) {
try {
- this.value = this.spec.create(view);
+ this.value = this.spec.plugin.create(view, this.spec.arg);
}
catch (e) {
logException(view.state, e, "CodeMirror plugin crashed");
@@ -7705,8 +7752,7 @@
closestRect = rect;
closestX = dx;
closestY = dy;
- let side = dy ? (y < rect.top ? -1 : 1) : dx ? (x < rect.left ? -1 : 1) : 0;
- closestOverlap = !side || (side > 0 ? i < rects.length - 1 : i > 0);
+ closestOverlap = !dx ? true : x < rect.left ? i > 0 : i < rects.length - 1;
}
if (dx == 0) {
if (y > rect.bottom && (!aboveRect || aboveRect.bottom < rect.bottom)) {
@@ -7882,13 +7928,24 @@
// line before. This is used to detect such a result so that it can be
// ignored (issue #401).
function isSuspiciousSafariCaretResult(node, offset, x) {
- let len;
+ let len, scan = node;
if (node.nodeType != 3 || offset != (len = node.nodeValue.length))
return false;
- for (let next = node.nextSibling; next; next = next.nextSibling)
- if (next.nodeType != 1 || next.nodeName != "BR")
+ for (;;) { // Check that there is no content after this node
+ let next = scan.nextSibling;
+ if (next) {
+ if (next.nodeName == "BR")
+ break;
return false;
- return textRange(node, len - 1, len).getBoundingClientRect().left > x;
+ }
+ else {
+ let parent = scan.parentNode;
+ if (!parent || parent.nodeName == "DIV")
+ break;
+ scan = parent;
+ }
+ }
+ return textRange(node, len - 1, len).getBoundingClientRect().right > x;
}
// Chrome will move positions between lines to the start of the next line
function isSuspiciousChromeCaretResult(node, offset, x) {
@@ -8607,16 +8664,16 @@
return result[type] || (result[type] = { observers: [], handlers: [] });
}
for (let plugin of plugins) {
- let spec = plugin.spec;
- if (spec && spec.domEventHandlers)
- for (let type in spec.domEventHandlers) {
- let f = spec.domEventHandlers[type];
+ let spec = plugin.spec, handlers = spec && spec.plugin.domEventHandlers, observers = spec && spec.plugin.domEventObservers;
+ if (handlers)
+ for (let type in handlers) {
+ let f = handlers[type];
if (f)
record(type).handlers.push(bindHandler(plugin.value, f));
}
- if (spec && spec.domEventObservers)
- for (let type in spec.domEventObservers) {
- let f = spec.domEventObservers[type];
+ if (observers)
+ for (let type in observers) {
+ let f = observers[type];
if (f)
record(type).observers.push(bindHandler(plugin.value, f));
}
@@ -9311,7 +9368,7 @@
heightForLine(length) {
if (!this.lineWrapping)
return this.lineHeight;
- let lines = 1 + Math.max(0, Math.ceil((length - this.lineLength) / (this.lineLength - 5)));
+ let lines = 1 + Math.max(0, Math.ceil((length - this.lineLength) / Math.max(1, this.lineLength - 5)));
return lines * this.lineHeight;
}
setDoc(doc) { this.doc = doc; return this; }
@@ -10281,7 +10338,7 @@
refresh = true;
if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
let { lineHeight, charWidth, textHeight } = view.docView.measureTextSize();
- refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, textHeight, contentWidth / charWidth, lineHeights);
+ refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, textHeight, Math.max(5, contentWidth / charWidth), lineHeights);
if (refresh) {
view.docView.minWidth = 0;
result |= 16 /* UpdateFlag.Geometry */;
@@ -10806,13 +10863,16 @@
display: "flex",
height: "100%",
boxSizing: "border-box",
- insetInlineStart: 0,
- zIndex: 200
+ zIndex: 200,
},
+ ".cm-gutters-before": { insetInlineStart: 0 },
+ ".cm-gutters-after": { insetInlineEnd: 0 },
"&light .cm-gutters": {
backgroundColor: "#f5f5f5",
color: "#6c6c6c",
- borderRight: "1px solid #ddd"
+ border: "0px solid #ddd",
+ "&.cm-gutters-before": { borderRightWidth: "1px" },
+ "&.cm-gutters-after": { borderLeftWidth: "1px" },
},
"&dark .cm-gutters": {
backgroundColor: "#333338",
@@ -10862,6 +10922,21 @@
backgroundColor: "#333338",
color: "white"
},
+ ".cm-dialog": {
+ padding: "2px 19px 4px 6px",
+ position: "relative",
+ "& label": { fontSize: "80%" },
+ },
+ ".cm-dialog-close": {
+ position: "absolute",
+ top: "3px",
+ right: "4px",
+ backgroundColor: "inherit",
+ border: "none",
+ font: "inherit",
+ fontSize: "14px",
+ padding: "0"
+ },
".cm-tab": {
display: "inline-block",
overflow: "hidden",
@@ -10988,7 +11063,7 @@
else
this.flush();
});
- if (window.EditContext && view.constructor.EDIT_CONTEXT !== false &&
+ if (window.EditContext && browser.android && view.constructor.EDIT_CONTEXT !== false &&
// Chrome <126 doesn't support inverted selections in edit context (#1392)
!(browser.chrome && browser.chrome_version < 126)) {
this.editContext = new EditContextManager(view);
@@ -12174,8 +12249,8 @@
*/
plugin(plugin) {
let known = this.pluginMap.get(plugin);
- if (known === undefined || known && known.spec != plugin)
- this.pluginMap.set(plugin, known = this.plugins.find(p => p.spec == plugin) || null);
+ if (known === undefined || known && known.plugin != plugin)
+ this.pluginMap.set(plugin, known = this.plugins.find(p => p.plugin == plugin) || null);
return known && known.update(this).value;
}
/**
@@ -12999,6 +13074,8 @@
else if (isChar && (event.altKey || event.metaKey || event.ctrlKey) &&
// Ctrl-Alt may be used for AltGr on Windows
!(browser.windows && event.ctrlKey && event.altKey) &&
+ // Alt-combinations on macOS tend to be typed characters
+ !(browser.mac && event.altKey && !event.ctrlKey) &&
(baseName = base[event.keyCode]) && baseName != name) {
if (runFor(scopeObj[prefix + modifiers(baseName, event, true)])) {
handled = true;
@@ -13578,7 +13655,7 @@
updateRange(view, deco, updateFrom, updateTo) {
for (let r of view.visibleRanges) {
let from = Math.max(r.from, updateFrom), to = Math.min(r.to, updateTo);
- if (to > from) {
+ if (to >= from) {
let fromLine = view.state.doc.lineAt(from), toLine = fromLine.to < to ? view.state.doc.lineAt(to) : fromLine;
let start = Math.max(r.from, fromLine.from), end = Math.min(r.to, toLine.to);
if (this.boundary) {
@@ -14824,7 +14901,8 @@
lineMarkerChange: null,
initialSpacer: null,
updateSpacer: null,
- domEventHandlers: {}
+ domEventHandlers: {},
+ side: "before"
};
const activeGutters = /*@__PURE__*/Facet.define();
/**
@@ -14832,7 +14910,7 @@
determined by their extension priority.
*/
function gutter(config) {
- return [gutters(), activeGutters.of(Object.assign(Object.assign({}, defaults$1), config))];
+ return [gutters(), activeGutters.of({ ...defaults$1, ...config })];
}
const unfixGutters = /*@__PURE__*/Facet.define({
combine: values => values.some(x => x)
@@ -14856,15 +14934,20 @@
const gutterView = /*@__PURE__*/ViewPlugin.fromClass(class {
constructor(view) {
this.view = view;
+ this.domAfter = null;
this.prevViewport = view.viewport;
this.dom = document.createElement("div");
- this.dom.className = "cm-gutters";
+ this.dom.className = "cm-gutters cm-gutters-before";
this.dom.setAttribute("aria-hidden", "true");
this.dom.style.minHeight = (this.view.contentHeight / this.view.scaleY) + "px";
this.gutters = view.state.facet(activeGutters).map(conf => new SingleGutterView(view, conf));
- for (let gutter of this.gutters)
- this.dom.appendChild(gutter.dom);
this.fixed = !view.state.facet(unfixGutters);
+ for (let gutter of this.gutters) {
+ if (gutter.config.side == "after")
+ this.getDOMAfter().appendChild(gutter.dom);
+ else
+ this.dom.appendChild(gutter.dom);
+ }
if (this.fixed) {
// FIXME IE11 fallback, which doesn't support position: sticky,
// by using position: relative + event handlers that realign the
@@ -14874,6 +14957,17 @@
this.syncGutters(false);
view.scrollDOM.insertBefore(this.dom, view.contentDOM);
}
+ getDOMAfter() {
+ if (!this.domAfter) {
+ this.domAfter = document.createElement("div");
+ this.domAfter.className = "cm-gutters cm-gutters-after";
+ this.domAfter.setAttribute("aria-hidden", "true");
+ this.domAfter.style.minHeight = (this.view.contentHeight / this.view.scaleY) + "px";
+ this.domAfter.style.position = this.fixed ? "sticky" : "";
+ this.view.scrollDOM.appendChild(this.domAfter);
+ }
+ return this.domAfter;
+ }
update(update) {
if (this.updateGutters(update)) {
// Detach during sync when the viewport changed significantly
@@ -14884,18 +14978,26 @@
this.syncGutters(vpOverlap < (vpB.to - vpB.from) * 0.8);
}
if (update.geometryChanged) {
- this.dom.style.minHeight = (this.view.contentHeight / this.view.scaleY) + "px";
+ let min = (this.view.contentHeight / this.view.scaleY) + "px";
+ this.dom.style.minHeight = min;
+ if (this.domAfter)
+ this.domAfter.style.minHeight = min;
}
if (this.view.state.facet(unfixGutters) != !this.fixed) {
this.fixed = !this.fixed;
this.dom.style.position = this.fixed ? "sticky" : "";
+ if (this.domAfter)
+ this.domAfter.style.position = this.fixed ? "sticky" : "";
}
this.prevViewport = update.view.viewport;
}
syncGutters(detach) {
let after = this.dom.nextSibling;
- if (detach)
+ if (detach) {
this.dom.remove();
+ if (this.domAfter)
+ this.domAfter.remove();
+ }
let lineClasses = RangeSet.iter(this.view.state.facet(gutterLineClass), this.view.viewport.from);
let classSet = [];
let contexts = this.gutters.map(gutter => new UpdateContext(gutter, this.view.viewport, -this.view.documentPadding.top));
@@ -14929,8 +15031,11 @@
}
for (let cx of contexts)
cx.finish();
- if (detach)
+ if (detach) {
this.view.scrollDOM.insertBefore(this.dom, after);
+ if (this.domAfter)
+ this.view.scrollDOM.appendChild(this.domAfter);
+ }
}
updateGutters(update) {
let prev = update.startState.facet(activeGutters), cur = update.state.facet(activeGutters);
@@ -14959,8 +15064,12 @@
if (gutters.indexOf(g) < 0)
g.destroy();
}
- for (let g of gutters)
- this.dom.appendChild(g.dom);
+ for (let g of gutters) {
+ if (g.config.side == "after")
+ this.getDOMAfter().appendChild(g.dom);
+ else
+ this.dom.appendChild(g.dom);
+ }
this.gutters = gutters;
}
return change;
@@ -14969,15 +15078,18 @@
for (let view of this.gutters)
view.destroy();
this.dom.remove();
+ if (this.domAfter)
+ this.domAfter.remove();
}
}, {
provide: plugin => EditorView.scrollMargins.of(view => {
let value = view.plugin(plugin);
if (!value || value.gutters.length == 0 || !value.fixed)
return null;
+ let before = value.dom.offsetWidth * view.scaleX, after = value.domAfter ? value.domAfter.offsetWidth * view.scaleX : 0;
return view.textDirection == Direction.LTR
- ? { left: value.dom.offsetWidth * view.scaleX }
- : { right: value.dom.offsetWidth * view.scaleX };
+ ? { left: before, right: after }
+ : { right: before, left: after };
})
});
function asArray(val) { return (Array.isArray(val) ? val : [val]); }
@@ -15219,7 +15331,8 @@
let max = formatNumber(update.view, maxLineNumber(update.view.state.doc.lines));
return max == spacer.number ? spacer : new NumberMarker(max);
},
- domEventHandlers: state.facet(lineNumberConfig).domEventHandlers
+ domEventHandlers: state.facet(lineNumberConfig).domEventHandlers,
+ side: "before"
}));
/**
Create a line number gutter extension.
@@ -18485,8 +18598,8 @@
const indentService = /*@__PURE__*/Facet.define();
/**
Facet for overriding the unit by which indentation happens. Should
- be a string consisting either entirely of the same whitespace
- character. When not set, this defaults to 2 spaces.
+ be a string consisting entirely of the same whitespace character.
+ When not set, this defaults to 2 spaces.
*/
const indentUnit = /*@__PURE__*/Facet.define({
combine: values => {
@@ -18655,7 +18768,8 @@
let inner = ast.resolveInner(pos, -1).resolve(pos, 0).enterUnfinishedNodesBefore(pos);
if (inner != stack.node) {
let add = [];
- for (let cur = inner; cur && !(cur.from == stack.node.from && cur.type == stack.node.type); cur = cur.parent)
+ for (let cur = inner; cur && !(cur.from < stack.node.from || cur.to > stack.node.to ||
+ cur.from == stack.node.from && cur.type == stack.node.type); cur = cur.parent)
add.push(cur);
for (let i = add.length - 1; i >= 0; i--)
stack = { node: add[i], next: stack };
@@ -18969,6 +19083,8 @@
return Decoration.none;
},
update(folded, tr) {
+ if (tr.isUserEvent("delete"))
+ tr.changes.iterChangedRanges((fromA, toA) => folded = clearTouchedFolds(folded, fromA, toA));
folded = folded.map(tr.changes);
for (let e of tr.effects) {
if (e.is(foldEffect) && !foldExists(folded, e.value.from, e.value.to)) {
@@ -18983,17 +19099,8 @@
}
}
// Clear folded ranges that cover the selection head
- if (tr.selection) {
- let onSelection = false, { head } = tr.selection.main;
- folded.between(head, head, (a, b) => { if (a < head && b > head)
- onSelection = true; });
- if (onSelection)
- folded = folded.update({
- filterFrom: head,
- filterTo: head,
- filter: (a, b) => b <= head || a >= head
- });
- }
+ if (tr.selection)
+ folded = clearTouchedFolds(folded, tr.selection.main.head);
return folded;
},
provide: f => EditorView.decorations.from(f),
@@ -19015,6 +19122,16 @@
return Decoration.set(ranges, true);
}
});
+ function clearTouchedFolds(folded, from, to = from) {
+ let touched = false;
+ folded.between(from, to, (a, b) => { if (a < to && b > from)
+ touched = true; });
+ return !touched ? folded : folded.update({
+ filterFrom: from,
+ filterTo: to,
+ filter: (a, b) => a >= to || b <= from
+ });
+ }
function findFold(state, from, to) {
var _a;
let found = null;
@@ -19187,7 +19304,7 @@
to fold or unfold the line).
*/
function foldGutter(config = {}) {
- let fullConfig = Object.assign(Object.assign({}, foldGutterDefaults), config);
+ let fullConfig = { ...foldGutterDefaults, ...config };
let canFold = new FoldMarker(fullConfig, true), canUnfold = new FoldMarker(fullConfig, false);
let markers = ViewPlugin.fromClass(class {
constructor(view) {
@@ -19222,7 +19339,9 @@
initialSpacer() {
return new FoldMarker(fullConfig, false);
},
- domEventHandlers: Object.assign(Object.assign({}, domEventHandlers), { click: (view, line, event) => {
+ domEventHandlers: {
+ ...domEventHandlers,
+ click: (view, line, event) => {
if (domEventHandlers.click && domEventHandlers.click(view, line, event))
return true;
let folded = findFold(view.state, line.from, line.to);
@@ -19236,7 +19355,8 @@
return true;
}
return false;
- } })
+ }
+ }
}),
codeFolding()
];
@@ -19921,7 +20041,7 @@
advance() {
let context = ParseContext.get();
let parseEnd = this.stoppedAt == null ? this.to : Math.min(this.to, this.stoppedAt);
- let end = Math.min(parseEnd, this.chunkStart + 2048 /* C.ChunkSize */);
+ let end = Math.min(parseEnd, this.chunkStart + 512 /* C.ChunkSize */);
if (context)
end = Math.min(end, context.viewport.to);
while (this.parsedPos < end)
@@ -20027,7 +20147,7 @@
length: this.parsedPos - this.chunkStart,
nodeSet,
topID: 0,
- maxBufferLength: 2048 /* C.ChunkSize */,
+ maxBufferLength: 512 /* C.ChunkSize */,
reused: this.chunkReused
});
tree = new Tree(tree.type, tree.children, tree.positions, tree.length, [[this.lang.stateAfter, this.lang.streamParser.copyState(this.state)]]);
@@ -21576,34 +21696,6 @@
*/
const indentWithTab = { key: "Tab", run: indentMore, shift: indentLess };
- function crelt() {
- var elt = arguments[0];
- if (typeof elt == "string") elt = document.createElement(elt);
- var i = 1, next = arguments[1];
- if (next && typeof next == "object" && next.nodeType == null && !Array.isArray(next)) {
- for (var name in next) if (Object.prototype.hasOwnProperty.call(next, name)) {
- var value = next[name];
- if (typeof value == "string") elt.setAttribute(name, value);
- else if (value != null) elt[name] = value;
- }
- i++;
- }
- for (; i < arguments.length; i++) add(elt, arguments[i]);
- return elt
- }
-
- function add(elt, child) {
- if (typeof child == "string") {
- elt.appendChild(document.createTextNode(child));
- } else if (child == null) ; else if (child.nodeType != null) {
- elt.appendChild(child);
- } else if (Array.isArray(child)) {
- for (var i = 0; i < child.length; i++) add(elt, child[i]);
- } else {
- throw new RangeError("Unsupported child node: " + child)
- }
- }
-
const basicNormalize = typeof String.prototype.normalize == "function"
? x => x.normalize("NFKD") : x => x;
/**
@@ -22533,14 +22625,16 @@
next = query.nextMatch(state, next.from, next.to);
effects.push(EditorView.announce.of(state.phrase("replaced match on line $", state.doc.lineAt(from).number) + "."));
}
+ let changeSet = view.state.changes(changes);
if (next) {
- let off = changes.length == 0 || changes[0].from >= match.to ? 0 : match.to - match.from - replacement.length;
- selection = EditorSelection.single(next.from - off, next.to - off);
+ selection = EditorSelection.single(next.from, next.to).map(changeSet);
effects.push(announceMatch(view, next));
effects.push(state.facet(searchConfigFacet).scrollToMatch(selection.main, view));
}
view.dispatch({
- changes, selection, effects,
+ changes: changeSet,
+ selection,
+ effects,
userEvent: "input.replace"
});
return true;
@@ -28587,7 +28681,7 @@
const { blockQuote, commentString, lineWidth } = ctx.options;
// 1. Block can't end in whitespace unless the last line is non-empty.
// 2. Strings consisting of only whitespace are best rendered explicitly.
- if (!blockQuote || /\n[\t ]+$/.test(value) || /^\s*$/.test(value)) {
+ if (!blockQuote || /\n[\t ]+$/.test(value)) {
return quotedString(value, ctx);
}
const indent = ctx.indent ||
@@ -36134,7 +36228,7 @@
*
* @author Dan Kogai (https://github.com/dankogai)
*/
- const version = '3.7.7';
+ const version = '3.7.8';
/**
* @deprecated use lowercase `version`.
*/
@@ -36288,17 +36382,24 @@
if (!b64re.test(asc))
throw new TypeError('malformed base64.');
asc += '=='.slice(2 - (asc.length & 3));
- let u24, bin = '', r1, r2;
+ let u24, r1, r2;
+ let binArray = []; // use array to avoid minor gc in loop
for (let i = 0; i < asc.length;) {
u24 = b64tab[asc.charAt(i++)] << 18
| b64tab[asc.charAt(i++)] << 12
| (r1 = b64tab[asc.charAt(i++)]) << 6
| (r2 = b64tab[asc.charAt(i++)]);
- bin += r1 === 64 ? _fromCC(u24 >> 16 & 255)
- : r2 === 64 ? _fromCC(u24 >> 16 & 255, u24 >> 8 & 255)
- : _fromCC(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255);
+ if (r1 === 64) {
+ binArray.push(_fromCC(u24 >> 16 & 255));
+ }
+ else if (r2 === 64) {
+ binArray.push(_fromCC(u24 >> 16 & 255, u24 >> 8 & 255));
+ }
+ else {
+ binArray.push(_fromCC(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255));
+ }
}
- return bin;
+ return binArray.join('');
};
/**
* does what `window.atob` of web browsers do.
@@ -39864,6 +39965,13 @@ ${O$2.repeat(r.depth)}}`:r.close="}";break}case f$4.TAG:e+=String(i),e+=a(f$4.PO
'@context': this.doc['@context']
};
setEditorValue(this.contextEditor, this.contextDoc);
+ },
+ gatherHash() {
+ const url = new URL(window.location);
+ const hash = new URLSearchParams(url.hash.slice(1));
+ this.doc = JSON.parse(hash.get('json-ld') || {});
+ setEditorValue(this.mainEditor, this.doc);
+ this.outputTab = hash.get('startTab').slice(4);
}
}).mount();
diff --git a/playground/next/editor.mjs b/playground/next/editor.mjs
index 587e7541..80e013f2 100644
--- a/playground/next/editor.mjs
+++ b/playground/next/editor.mjs
@@ -538,5 +538,12 @@ window.app = createApp({
'@context': this.doc['@context']
};
setEditorValue(this.contextEditor, this.contextDoc);
+ },
+ gatherHash() {
+ const url = new URL(window.location);
+ const hash = new URLSearchParams(url.hash.slice(1));
+ this.doc = JSON.parse(hash.get('json-ld') || {});
+ setEditorValue(this.mainEditor, this.doc);
+ this.outputTab = hash.get('startTab').slice(4);
}
}).mount();
diff --git a/playground/next/index.html b/playground/next/index.html
index 9814eb2f..7074f9f9 100644
--- a/playground/next/index.html
+++ b/playground/next/index.html
@@ -29,7 +29,7 @@
Shift+Tab
) to navigate out of the editor.
-
+