@discoveryjs/discovery
Version:
Frontend framework for rapid data (JSON) analysis, shareable serverless reports and dashboards
207 lines (206 loc) • 7.45 kB
JavaScript
import { debounce } from "../../core/utils/debounce.js";
import { createElement } from "../../core/utils/dom.js";
import { escapeHtml } from "../../core/utils/html.js";
import { jsonStringifyAsJavaScript } from "../../core/utils/json.js";
import { contextWithoutEditorParams, getParamsFromContext } from "./params.js";
import { getUsageRenderConfig } from "../views-showcase/view-usage-render.js";
export const defaultViewSource = "{\n view: 'struct',\n expanded: 1\n}";
const defaultViewPresets = [
{
name: "Table",
content: jsonStringifyAsJavaScript({
view: "table"
})
},
{
name: "Auto-link list",
content: jsonStringifyAsJavaScript({
view: "ol",
item: "auto-link"
})
},
{
name: "Signature",
content: jsonStringifyAsJavaScript({
view: "signature",
expanded: 2
})
},
{
name: "Text render",
content: jsonStringifyAsJavaScript({
view: "text-render",
content: [
"table"
]
})
}
];
function createPresetTab(name, content, updateParams) {
return createElement("div", {
class: "discovery-editor-tab",
onclick: () => updateParams({
view: content
// JSON.stringify(content, null, 4)
})
}, name || "Untitled preset");
}
export default function(host, updateParams) {
const ViewEditorClass = host.view.ViewEditor;
const viewPresets = defaultViewPresets;
let lastView = {};
let availableViewsEl;
let availableViewsTextEl;
let availableViewsListEl;
let viewModeTabsEls;
let viewLiveEditEl;
const viewEditor = new ViewEditorClass().on(
"change",
(value) => viewLiveEditEl.checked && updateParams({ view: value }, true)
);
const viewEditorButtonsEl = createElement("div", "buttons");
const viewEditorFormEl = createElement("div", "form view-editor-form", [
createElement("div", "view-editor-form-header", [
createElement("div", "discovery-editor-tabs view-mode", viewModeTabsEls = ["Default", "Custom"].map(
(viewMode) => createElement(
"div",
{
class: "discovery-editor-tab",
"data-mode": viewMode.toLowerCase(),
onclick() {
if (!this.classList.contains("active")) {
updateParams({
view: viewMode === "Default" ? void 0 : defaultViewSource,
viewEditorHidden: false
}, true);
} else {
updateParams({
viewEditorHidden: !viewEditorFormEl.classList.contains("hide-editor")
}, true);
}
}
},
viewMode === "Custom" ? [viewMode, createElement("span", "show-view-editor-toggle")] : viewMode
)
)),
/* availablePresetListEl = */
createElement("div", "discovery-editor-tabs presets", viewPresets.map(
({ name, content }) => createPresetTab(name, content, updateParams)
)),
createElement("div", "view-editor-form-header-links", '<a href="#views-showcase" class="view-link">Views showcase</a>')
]),
createElement("div", "view-editor-form-content", [
createElement("button", {
class: "view-button formatting",
title: "Prettify (input should be a JSON)",
onclick() {
viewEditor.focus();
try {
const currentText = viewEditor.getValue().trim();
const json = new Function("return 0," + currentText)();
updateParams({
view: jsonStringifyAsJavaScript(json)
});
} catch (e) {
host.logger.error("View editor prettify failed:", e);
}
}
}),
viewEditor.el,
createElement("div", "editor-toolbar", [
availableViewsEl = createElement("div", "view-expand", [
createElement("div", {
class: "header",
onclick() {
availableViewsEl.classList.toggle("expanded");
availableViewsListEl.classList.toggle("visible");
}
}, [
availableViewsTextEl = createElement("div", "header-content"),
createElement("div", "trigger")
]),
availableViewsListEl = createElement("div", "view-editor-view-list")
]),
createElement("label", "view-checkbox", [
viewLiveEditEl = createElement("input", {
class: "live-update",
type: "checkbox",
checked: true,
onchange() {
if (this.checked) {
updateParams({ view: viewEditor.getValue() }, true);
}
}
}),
createElement("span", "view-checkbox__label", "build on input")
]),
viewEditorButtonsEl
])
])
]);
host.view.render(viewEditorButtonsEl, {
view: "button-primary",
content: 'text:"Build"',
onClick() {
lastView = {};
updateParams({
view: viewEditor.getValue()
}, true);
host.scheduleRender("page");
}
});
new host.view.Popup({
className: "view-editor-view-list-hint",
hoverTriggers: ".view-editor-view-list .item.with-usage",
// hoverPin: 'trigger-click',
render(popupEl, triggerEl) {
host.view.render(
popupEl,
getUsageRenderConfig(host),
host.view.get(triggerEl?.textContent),
{}
);
}
});
availableViewsTextEl.textContent = `Available ${[...host.view.entries].filter(([, view]) => view.options.usage).length} views`;
const updateAvailableViewList = () => availableViewsListEl.innerHTML = '<a href="#views-showcase" class="view-link">Views showcase</a><br><br>' + [...host.view.entries].sort().map(([name, view]) => `<div><a class="item view-link${view.options.usage ? " with-usage" : ""}" ${view.options.usage ? 'href="#views-showcase:' + name + '"' : ""}>${name}</a></div>`).join("");
updateAvailableViewList();
host.view.on("define", debounce(updateAvailableViewList, 100));
return {
el: viewEditorFormEl,
render(data, context, discoveryContentEl) {
const viewContext = contextWithoutEditorParams(context, lastView.context);
const params = getParamsFromContext(context);
const viewMode = typeof params.view === "string" ? "custom" : "default";
const viewEditorHidden = viewMode === "default" || params.viewEditorHidden === true;
let pageView = params.view;
let view = null;
viewEditor.setValue(pageView);
viewEditorFormEl.classList.toggle("hide-editor", viewEditorHidden);
viewModeTabsEls.forEach(
(el) => el.classList.toggle("active", el.dataset.mode === viewMode)
);
if (!pageView && viewMode === "default") {
pageView = defaultViewSource;
}
if (lastView.view !== pageView || lastView.data !== data || lastView.context !== viewContext) {
discoveryContentEl.innerHTML = "";
try {
view = Function("return " + (pageView ? "0," + pageView : "null"))();
host.view.render(discoveryContentEl, view, data, viewContext);
} catch (e) {
host.view.render(discoveryContentEl, (el) => {
el.className = "discovery-error render-error";
el.innerHTML = escapeHtml(String(e)) + "<br>(see details in console)";
host.logger.error(e);
});
}
lastView = {
data,
context: viewContext,
view: pageView
};
}
}
};
}