@discoveryjs/discovery
Version:
Frontend framework for rapid data (JSON) analysis, shareable serverless reports and dashboards
135 lines (134 loc) • 4.04 kB
JavaScript
import { createElement } from "../../core/utils/dom.js";
import { copyText } from "../../core/utils/copy-text.js";
import { getParamsFromContext } from "./params.js";
function quote(str) {
return str.replace(/\\/g, "\\\\").replace(/\t/g, "\\t").replace(/\r/g, "\\r").replace(/\n/g, "\\n").replace(/'/g, "\\'");
}
function exportStateAsJson(pageParams) {
const { title, query, view } = pageParams;
const res = { title, query, view };
return `{
${Object.keys(res).reduce(
(props, k) => typeof res[k] === "string" ? props.concat(` ${k}: '${quote(res[k])}'`) : props,
[]
).join(",\n")}
}`;
}
function toDate(value) {
if (value && (typeof value === "number" || typeof value === "string")) {
const date = new Date(value);
return !isNaN(Number(date)) ? date : null;
}
return value instanceof Date ? value : null;
}
function formatDate(value) {
const date = toDate(value);
if (date) {
return date.toISOString().replace(/^(\d{4})-(\d{2})-(\d{2})T([\d:]+).*/, "$3/$2/$1 $4 UTC");
}
return null;
}
export default function(host, updateParams) {
let titleInputEl;
let dataDateTimeEl;
let viewDateTimeEl;
let noeditToggleEl;
const shareOptionsPopup = new host.view.Popup({
render: (popupEl, _, hide) => host.view.render(popupEl, {
view: "menu",
data: () => [
{
text: "Copy page permalink",
disabled: !host.action.has("permalink"),
action: async () => copyText(await host.action.call("permalink", host.pageHash))
},
{
text: "Copy page hash",
action: () => copyText(host.pageHash)
},
{
text: "Copy page as JSON",
action: () => copyText(exportStateAsJson(host.pageParams))
}
],
onClick(item) {
hide();
item.action();
}
})
});
const actionsPanel = createElement("div", "discovery-actions", [
noeditToggleEl = createElement("button", {
class: "edit-mode discovery-hidden-in-dzen",
title: "Toggle edit mode",
onclick() {
this.blur();
updateParams({
noedit: !host.pageParams.noedit
});
}
}),
createElement("button", {
class: "share",
title: "Sharing",
onclick() {
this.blur();
shareOptionsPopup.show(this);
}
}),
createElement("button", {
class: "toggle-fullscreen",
title: "Toggle full page mode",
onclick() {
this.blur();
updateParams({
dzen: !host.pageParams.dzen
});
}
})
]);
const updateHeaderTitle = (target) => {
target.parentNode.dataset.title = target.value || target.placeholder;
};
const headerEl = createElement("div", "discovery-header", [
createElement("div", { class: "discovery-header-text", "data-title": "\xA0" }, [
titleInputEl = createElement("input", {
class: "discovery-hidden-in-dzen",
placeholder: "Untitled discovery",
oninput() {
updateHeaderTitle(this);
},
onchange() {
updateHeaderTitle(this);
updateParams({
title: this.value
}, true);
},
onkeypress(e) {
if (e.key === "Enter") {
this.blur();
}
}
}),
createElement("span", "timestamp", [
dataDateTimeEl = createElement("span", null, " "),
viewDateTimeEl = createElement("span")
])
])
]);
return {
el: [
actionsPanel,
headerEl
],
render(data, context) {
const { title, noedit } = getParamsFromContext(context);
const createdAt = formatDate(context?.datasets?.[0]?.resource?.createdAt);
titleInputEl.value = title || "";
updateHeaderTitle(titleInputEl);
noeditToggleEl.classList.toggle("disabled", noedit);
dataDateTimeEl.innerText = createdAt ? "Data collected at " + createdAt + " | " : "";
viewDateTimeEl.innerText = "Rendered at " + formatDate(/* @__PURE__ */ new Date());
}
};
}