Code widget refactor
This commit is contained in:
parent
4ef857acf4
commit
d8318c4ad7
10
plug-api/silverbullet-syscall/code_widget.ts
Normal file
10
plug-api/silverbullet-syscall/code_widget.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import type { CodeWidgetContent } from "$sb/types.ts";
|
||||||
|
import { syscall } from "./syscall.ts";
|
||||||
|
|
||||||
|
export function render(
|
||||||
|
lang: string,
|
||||||
|
body: string,
|
||||||
|
pageName: string,
|
||||||
|
): Promise<CodeWidgetContent> {
|
||||||
|
return syscall("codeWidget.render", lang, body, pageName);
|
||||||
|
}
|
@ -7,3 +7,4 @@ export * as sync from "./sync.ts";
|
|||||||
export * as debug from "./debug.ts";
|
export * as debug from "./debug.ts";
|
||||||
export * as language from "./language.ts";
|
export * as language from "./language.ts";
|
||||||
export * as handlebars from "./handlebars.ts";
|
export * as handlebars from "./handlebars.ts";
|
||||||
|
export * as codeWidget from "./code_widget.ts";
|
||||||
|
@ -120,6 +120,7 @@ export type ObjectQuery = Omit<Query, "prefix">;
|
|||||||
// Code widget stuff
|
// Code widget stuff
|
||||||
export type CodeWidgetCallback = (
|
export type CodeWidgetCallback = (
|
||||||
bodyText: string,
|
bodyText: string,
|
||||||
|
pageName: string,
|
||||||
) => Promise<CodeWidgetContent>;
|
) => Promise<CodeWidgetContent>;
|
||||||
|
|
||||||
export type CodeWidgetContent = {
|
export type CodeWidgetContent = {
|
||||||
|
@ -6,7 +6,7 @@ import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
|
|||||||
import { extractAttributes } from "$sb/lib/attribute.ts";
|
import { extractAttributes } from "$sb/lib/attribute.ts";
|
||||||
import { indexObjects } from "./api.ts";
|
import { indexObjects } from "./api.ts";
|
||||||
|
|
||||||
type PageObject = ObjectValue<
|
export type PageObject = ObjectValue<
|
||||||
// The base is PageMeta, but we override lastModified to be a string
|
// The base is PageMeta, but we override lastModified to be a string
|
||||||
Omit<PageMeta, "lastModified"> & {
|
Omit<PageMeta, "lastModified"> & {
|
||||||
lastModified: string; // indexing it as a string
|
lastModified: string; // indexing it as a string
|
||||||
@ -14,6 +14,10 @@ type PageObject = ObjectValue<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
export async function indexPage({ name, tree }: IndexTreeEvent) {
|
export async function indexPage({ name, tree }: IndexTreeEvent) {
|
||||||
|
if (name.startsWith("_")) {
|
||||||
|
// Don't index pages starting with _
|
||||||
|
return;
|
||||||
|
}
|
||||||
const pageMeta = await space.getPageMeta(name);
|
const pageMeta = await space.getPageMeta(name);
|
||||||
let pageObj: PageObject = {
|
let pageObj: PageObject = {
|
||||||
ref: name,
|
ref: name,
|
||||||
|
@ -24,7 +24,7 @@ async function init() {
|
|||||||
const body = widget.innerText;
|
const body = widget.innerText;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await syscall("widget.render", lang, body);
|
const result = await syscall("codeWidget.render", lang, body, pageName);
|
||||||
const iframe = document.createElement("iframe");
|
const iframe = document.createElement("iframe");
|
||||||
iframe.src = "about:blank";
|
iframe.src = "about:blank";
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import { renderMarkdownToHtml } from "./markdown_render.ts";
|
|||||||
|
|
||||||
export async function markdownContentWidget(
|
export async function markdownContentWidget(
|
||||||
markdownText: string,
|
markdownText: string,
|
||||||
|
pageName: string,
|
||||||
): Promise<WidgetContent> {
|
): Promise<WidgetContent> {
|
||||||
// Parse markdown to a ParseTree
|
// Parse markdown to a ParseTree
|
||||||
const mdTree = await markdown.parseMarkdown(markdownText);
|
const mdTree = await markdown.parseMarkdown(markdownText);
|
||||||
@ -12,16 +13,17 @@ export async function markdownContentWidget(
|
|||||||
const html = renderMarkdownToHtml(mdTree, { smartHardBreak: true });
|
const html = renderMarkdownToHtml(mdTree, { smartHardBreak: true });
|
||||||
return {
|
return {
|
||||||
html: await wrapHTML(html),
|
html: await wrapHTML(html),
|
||||||
script: await prepareJS(markdownText),
|
script: await prepareJS(markdownText, pageName),
|
||||||
// And add back the markdown text so we can render it in a different way if desired
|
// And add back the markdown text so we can render it in a different way if desired
|
||||||
markdown: markdownText,
|
markdown: markdownText,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function prepareJS(originalMarkdown: string) {
|
export async function prepareJS(pageName: string, originalMarkdown: string) {
|
||||||
const iframeJS = await asset.readAsset("assets/markdown_widget.js");
|
const iframeJS = await asset.readAsset("assets/markdown_widget.js");
|
||||||
return `
|
return `
|
||||||
const panelHtml = ${JSON.stringify(panelHtml)};
|
const panelHtml = ${JSON.stringify(panelHtml)};
|
||||||
|
const pageName = ${JSON.stringify(pageName)};
|
||||||
const originalMarkdown = ${JSON.stringify(originalMarkdown)};
|
const originalMarkdown = ${JSON.stringify(originalMarkdown)};
|
||||||
${iframeJS}
|
${iframeJS}
|
||||||
`;
|
`;
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
import type { WidgetContent } from "$sb/app_event.ts";
|
import type { WidgetContent } from "$sb/app_event.ts";
|
||||||
import { editor, events, language, space, system } from "$sb/syscalls.ts";
|
import { events, language, space, system } from "$sb/syscalls.ts";
|
||||||
import { parseTreeToAST } from "$sb/lib/tree.ts";
|
import { parseTreeToAST } from "$sb/lib/tree.ts";
|
||||||
import { astToKvQuery } from "$sb/lib/parse-query.ts";
|
import { astToKvQuery } from "$sb/lib/parse-query.ts";
|
||||||
import { jsonToMDTable, renderTemplate } from "../directive/util.ts";
|
import { jsonToMDTable, renderTemplate } from "../directive/util.ts";
|
||||||
import { replaceTemplateVars } from "../template/template.ts";
|
import { replaceTemplateVars } from "../template/template.ts";
|
||||||
import { parse } from "../../common/markdown_parser/parse_tree.ts";
|
|
||||||
|
|
||||||
export async function widget(bodyText: string): Promise<WidgetContent> {
|
export async function widget(
|
||||||
const pageMeta = await space.getPageMeta(await editor.getCurrentPage());
|
bodyText: string,
|
||||||
|
pageName: string,
|
||||||
|
): Promise<WidgetContent> {
|
||||||
|
const pageMeta = await space.getPageMeta(pageName);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const queryAST = parseTreeToAST(
|
const queryAST = parseTreeToAST(
|
||||||
|
@ -29,9 +29,10 @@ import { DenoKvPrimitives } from "../plugos/lib/deno_kv_primitives.ts";
|
|||||||
import { DataStore } from "../plugos/lib/datastore.ts";
|
import { DataStore } from "../plugos/lib/datastore.ts";
|
||||||
import { dataStoreSyscalls } from "../plugos/syscalls/datastore.ts";
|
import { dataStoreSyscalls } from "../plugos/syscalls/datastore.ts";
|
||||||
import { DataStoreMQ } from "../plugos/lib/mq.datastore.ts";
|
import { DataStoreMQ } from "../plugos/lib/mq.datastore.ts";
|
||||||
import { language } from "@codemirror/language";
|
|
||||||
import { languageSyscalls } from "../common/syscalls/language.ts";
|
import { languageSyscalls } from "../common/syscalls/language.ts";
|
||||||
import { handlebarsSyscalls } from "../common/syscalls/handlebars.ts";
|
import { handlebarsSyscalls } from "../common/syscalls/handlebars.ts";
|
||||||
|
import { codeWidgetSyscalls } from "../web/syscalls/code_widget.ts";
|
||||||
|
import { CodeWidgetHook } from "../web/hooks/code_widget.ts";
|
||||||
|
|
||||||
const fileListInterval = 30 * 1000; // 30s
|
const fileListInterval = 30 * 1000; // 30s
|
||||||
|
|
||||||
@ -72,6 +73,10 @@ export class ServerSystem {
|
|||||||
|
|
||||||
this.system.addHook(new MQHook(this.system, mq));
|
this.system.addHook(new MQHook(this.system, mq));
|
||||||
|
|
||||||
|
const codeWidgetHook = new CodeWidgetHook();
|
||||||
|
|
||||||
|
this.system.addHook(codeWidgetHook);
|
||||||
|
|
||||||
this.spacePrimitives = new EventedSpacePrimitives(
|
this.spacePrimitives = new EventedSpacePrimitives(
|
||||||
new PlugSpacePrimitives(
|
new PlugSpacePrimitives(
|
||||||
this.baseSpacePrimitives,
|
this.baseSpacePrimitives,
|
||||||
@ -94,6 +99,7 @@ export class ServerSystem {
|
|||||||
handlebarsSyscalls(),
|
handlebarsSyscalls(),
|
||||||
dataStoreSyscalls(this.ds),
|
dataStoreSyscalls(this.ds),
|
||||||
debugSyscalls(),
|
debugSyscalls(),
|
||||||
|
codeWidgetSyscalls(codeWidgetHook),
|
||||||
markdownSyscalls(buildMarkdown([])), // Will later be replaced with markdown extensions
|
markdownSyscalls(buildMarkdown([])), // Will later be replaced with markdown extensions
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -403,7 +403,7 @@ export class Client {
|
|||||||
this.eventHook.addLocalListener("file:listed", (fileList: FileMeta[]) => {
|
this.eventHook.addLocalListener("file:listed", (fileList: FileMeta[]) => {
|
||||||
this.ui.viewDispatch({
|
this.ui.viewDispatch({
|
||||||
type: "pages-listed",
|
type: "pages-listed",
|
||||||
pages: fileList.filter((f) => f.name.endsWith(".md")).map(
|
pages: fileList.filter(this.space.isListedPage).map(
|
||||||
fileMetaToPageMeta,
|
fileMetaToPageMeta,
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
@ -36,7 +36,7 @@ import { DataStore } from "../plugos/lib/datastore.ts";
|
|||||||
import { MessageQueue } from "../plugos/lib/mq.ts";
|
import { MessageQueue } from "../plugos/lib/mq.ts";
|
||||||
import { languageSyscalls } from "../common/syscalls/language.ts";
|
import { languageSyscalls } from "../common/syscalls/language.ts";
|
||||||
import { handlebarsSyscalls } from "../common/syscalls/handlebars.ts";
|
import { handlebarsSyscalls } from "../common/syscalls/handlebars.ts";
|
||||||
import { widgetSyscalls } from "./syscalls/widget.ts";
|
import { codeWidgetSyscalls } from "./syscalls/code_widget.ts";
|
||||||
|
|
||||||
export class ClientSystem {
|
export class ClientSystem {
|
||||||
commandHook: CommandHook;
|
commandHook: CommandHook;
|
||||||
@ -143,7 +143,7 @@ export class ClientSystem {
|
|||||||
assetSyscalls(this.system),
|
assetSyscalls(this.system),
|
||||||
yamlSyscalls(),
|
yamlSyscalls(),
|
||||||
handlebarsSyscalls(),
|
handlebarsSyscalls(),
|
||||||
widgetSyscalls(this.client),
|
codeWidgetSyscalls(this.codeWidgetHook),
|
||||||
languageSyscalls(),
|
languageSyscalls(),
|
||||||
this.client.syncMode
|
this.client.syncMode
|
||||||
// In sync mode handle locally
|
// In sync mode handle locally
|
||||||
|
@ -27,7 +27,7 @@ class IFrameWidget extends WidgetType {
|
|||||||
const iframe = createWidgetSandboxIFrame(
|
const iframe = createWidgetSandboxIFrame(
|
||||||
this.editor,
|
this.editor,
|
||||||
this.bodyText,
|
this.bodyText,
|
||||||
this.codeWidgetCallback(this.bodyText),
|
this.codeWidgetCallback(this.bodyText, this.editor.currentPage!),
|
||||||
(message) => {
|
(message) => {
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case "blur":
|
case "blur":
|
||||||
@ -38,16 +38,18 @@ class IFrameWidget extends WidgetType {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case "reload":
|
case "reload":
|
||||||
this.codeWidgetCallback(this.bodyText).then(
|
this.codeWidgetCallback(this.bodyText, this.editor.currentPage!)
|
||||||
(widgetContent: WidgetContent) => {
|
.then(
|
||||||
iframe.contentWindow!.postMessage({
|
(widgetContent: WidgetContent) => {
|
||||||
type: "html",
|
iframe.contentWindow!.postMessage({
|
||||||
html: widgetContent.html,
|
type: "html",
|
||||||
script: widgetContent.script,
|
html: widgetContent.html,
|
||||||
theme: document.getElementsByTagName("html")[0].dataset.theme,
|
script: widgetContent.script,
|
||||||
});
|
theme:
|
||||||
},
|
document.getElementsByTagName("html")[0].dataset.theme,
|
||||||
);
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -23,9 +23,12 @@ export class CodeWidgetHook implements Hook<CodeWidgetT> {
|
|||||||
if (!functionDef.codeWidget) {
|
if (!functionDef.codeWidget) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
this.codeWidgetCallbacks.set(functionDef.codeWidget, (bodyText) => {
|
this.codeWidgetCallbacks.set(
|
||||||
return plug.invoke(name, [bodyText]);
|
functionDef.codeWidget,
|
||||||
});
|
(bodyText, pageName) => {
|
||||||
|
return plug.invoke(name, [bodyText, pageName]);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,24 @@
|
|||||||
import { CodeWidgetContent } from "$sb/types.ts";
|
import { CodeWidgetContent } from "$sb/types.ts";
|
||||||
import { SysCallMapping } from "../../plugos/system.ts";
|
import { SysCallMapping } from "../../plugos/system.ts";
|
||||||
import { Client } from "../client.ts";
|
import { CodeWidgetHook } from "../hooks/code_widget.ts";
|
||||||
|
|
||||||
export function widgetSyscalls(
|
export function codeWidgetSyscalls(
|
||||||
client: Client,
|
codeWidgetHook: CodeWidgetHook,
|
||||||
): SysCallMapping {
|
): SysCallMapping {
|
||||||
return {
|
return {
|
||||||
"widget.render": (
|
"codeWidget.render": (
|
||||||
_ctx,
|
_ctx,
|
||||||
lang: string,
|
lang: string,
|
||||||
body: string,
|
body: string,
|
||||||
|
pageName: string,
|
||||||
): Promise<CodeWidgetContent> => {
|
): Promise<CodeWidgetContent> => {
|
||||||
const langCallback = client.system.codeWidgetHook.codeWidgetCallbacks.get(
|
const langCallback = codeWidgetHook.codeWidgetCallbacks.get(
|
||||||
lang,
|
lang,
|
||||||
);
|
);
|
||||||
if (!langCallback) {
|
if (!langCallback) {
|
||||||
throw new Error(`Code widget ${lang} not found`);
|
throw new Error(`Code widget ${lang} not found`);
|
||||||
}
|
}
|
||||||
return langCallback(body);
|
return langCallback(body, pageName);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user