Fixed a lot of bugs with new widget rendering
parent
4d66f23391
commit
d43dbcacec
|
@ -133,6 +133,13 @@ export type CodeWidgetContent = {
|
|||
html?: string;
|
||||
markdown?: string;
|
||||
script?: string;
|
||||
buttons?: CodeWidgetButton[];
|
||||
};
|
||||
|
||||
export type CodeWidgetButton = {
|
||||
description: string;
|
||||
svg: string;
|
||||
invokeFunction: string;
|
||||
};
|
||||
|
||||
export type LintDiagnostic = {
|
||||
|
|
|
@ -178,6 +178,9 @@ functions:
|
|||
env: client
|
||||
panelWidget: top
|
||||
|
||||
refreshTOC:
|
||||
path: toc.ts:refreshTOC
|
||||
|
||||
lintYAML:
|
||||
path: lint.ts:lintYAML
|
||||
events:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { clientStore, editor, system } from "$sb/silverbullet-syscall/mod.ts";
|
||||
import { clientStore, codeWidget, editor, system } from "$sb/syscalls.ts";
|
||||
import { CodeWidgetContent } from "$sb/types.ts";
|
||||
import { queryObjects } from "./api.ts";
|
||||
import { LinkObject } from "./page_links.ts";
|
||||
|
@ -9,14 +9,16 @@ export async function toggleMentions() {
|
|||
let hideMentions = await clientStore.get(hideMentionsKey);
|
||||
hideMentions = !hideMentions;
|
||||
await clientStore.set(hideMentionsKey, hideMentions);
|
||||
if (!hideMentions) {
|
||||
await renderMentions();
|
||||
} else {
|
||||
await editor.dispatch({});
|
||||
}
|
||||
await codeWidget.refreshAll();
|
||||
}
|
||||
|
||||
export async function renderMentions(): Promise<CodeWidgetContent | null> {
|
||||
console.log("Hide mentions", await clientStore.get(hideMentionsKey));
|
||||
if (await clientStore.get(hideMentionsKey)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log("Stil here");
|
||||
const page = await editor.getCurrentPage();
|
||||
const linksResult = await queryObjects<LinkObject>("link", {
|
||||
// Query all links that point to this page, excluding those that are inside directives and self pointers.
|
||||
|
@ -41,6 +43,12 @@ export async function renderMentions(): Promise<CodeWidgetContent | null> {
|
|||
}
|
||||
return {
|
||||
markdown: renderedMd,
|
||||
buttons: [{
|
||||
description: "Hide",
|
||||
svg:
|
||||
`<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-eye-off"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line></svg>`,
|
||||
invokeFunction: "index.toggleMentions",
|
||||
}],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import {
|
||||
clientStore,
|
||||
codeWidget,
|
||||
editor,
|
||||
markdown,
|
||||
system,
|
||||
} from "$sb/silverbullet-syscall/mod.ts";
|
||||
import { renderToText, traverseTree, traverseTreeAsync } from "$sb/lib/tree.ts";
|
||||
import { renderToText, traverseTree } from "$sb/lib/tree.ts";
|
||||
import { CodeWidgetContent } from "$sb/types.ts";
|
||||
|
||||
const hideTOCKey = "hideTOC";
|
||||
|
@ -16,23 +16,18 @@ type Header = {
|
|||
level: number;
|
||||
};
|
||||
|
||||
let cachedTOC: string | undefined;
|
||||
|
||||
export async function toggleTOC() {
|
||||
cachedTOC = undefined;
|
||||
let hideTOC = await clientStore.get(hideTOCKey);
|
||||
hideTOC = !hideTOC;
|
||||
await clientStore.set(hideTOCKey, hideTOC);
|
||||
await renderTOC(); // This will hide it if needed
|
||||
await codeWidget.refreshAll();
|
||||
}
|
||||
|
||||
async function markdownToHtml(text: string): Promise<string> {
|
||||
return system.invokeFunction("markdown.markdownToHtml", text);
|
||||
export async function refreshTOC() {
|
||||
await codeWidget.refreshAll();
|
||||
}
|
||||
|
||||
export async function renderTOC(
|
||||
reload = false,
|
||||
): Promise<CodeWidgetContent | null> {
|
||||
export async function renderTOC(): Promise<CodeWidgetContent | null> {
|
||||
if (await clientStore.get(hideTOCKey)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -40,7 +35,7 @@ export async function renderTOC(
|
|||
const text = await editor.getText();
|
||||
const tree = await markdown.parseMarkdown(text);
|
||||
const headers: Header[] = [];
|
||||
await traverseTreeAsync(tree, async (n) => {
|
||||
traverseTree(tree, (n) => {
|
||||
if (n.type?.startsWith("ATXHeading")) {
|
||||
headers.push({
|
||||
name: n.children!.slice(1).map(renderToText).join("").trim(),
|
||||
|
@ -66,5 +61,19 @@ export async function renderTOC(
|
|||
// console.log("Markdown", renderedMd);
|
||||
return {
|
||||
markdown: renderedMd,
|
||||
buttons: [
|
||||
{
|
||||
description: "Reload",
|
||||
svg:
|
||||
`<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-refresh-cw"><polyline points="23 4 23 10 17 10"></polyline><polyline points="1 20 1 14 7 14"></polyline><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path></svg>`,
|
||||
invokeFunction: "index.refreshTOC",
|
||||
},
|
||||
{
|
||||
description: "Hide",
|
||||
svg:
|
||||
`<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-eye-off"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line></svg>`,
|
||||
invokeFunction: "index.toggleTOC",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
|
|
@ -26,11 +26,15 @@ functions:
|
|||
- editor:complete
|
||||
|
||||
refreshAllWidgets:
|
||||
path: widget.ts:refreshAll
|
||||
path: widget.ts:refreshAllWidgets
|
||||
command:
|
||||
name: "Live Queries and Templates: Refresh All"
|
||||
key: "Alt-q"
|
||||
|
||||
# Query widget buttons
|
||||
editButton:
|
||||
path: widget.ts:editButton
|
||||
|
||||
# Slash commands
|
||||
insertQuery:
|
||||
redirect: template.insertTemplateText
|
||||
|
|
|
@ -9,12 +9,12 @@ import { astToKvQuery } from "$sb/lib/parse-query.ts";
|
|||
import { jsonToMDTable, renderQueryTemplate } from "../directive/util.ts";
|
||||
import { loadPageObject, replaceTemplateVars } from "../template/template.ts";
|
||||
import { cleanPageRef, resolvePath } from "$sb/lib/resolve.ts";
|
||||
import { LintDiagnostic } from "$sb/types.ts";
|
||||
import { CodeWidgetContent, LintDiagnostic } from "$sb/types.ts";
|
||||
|
||||
export async function widget(
|
||||
bodyText: string,
|
||||
pageName: string,
|
||||
): Promise<WidgetContent> {
|
||||
): Promise<CodeWidgetContent> {
|
||||
const pageObject = await loadPageObject(pageName);
|
||||
|
||||
try {
|
||||
|
@ -72,6 +72,20 @@ export async function widget(
|
|||
|
||||
return {
|
||||
markdown: resultMarkdown,
|
||||
buttons: [
|
||||
{
|
||||
description: "Edit",
|
||||
svg:
|
||||
`<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-edit"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>`,
|
||||
invokeFunction: "query.editButton",
|
||||
},
|
||||
{
|
||||
description: "Reload",
|
||||
svg:
|
||||
`<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-refresh-cw"><polyline points="23 4 23 10 17 10"></polyline><polyline points="1 20 1 14 7 14"></polyline><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path></svg>`,
|
||||
invokeFunction: "query.refreshAllWidgets",
|
||||
},
|
||||
],
|
||||
};
|
||||
} catch (e: any) {
|
||||
return { markdown: `**Error:** ${e.message}` };
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import { codeWidget } from "$sb/syscalls.ts";
|
||||
import { codeWidget, editor } from "$sb/syscalls.ts";
|
||||
|
||||
export function refreshAll() {
|
||||
export function refreshAllWidgets() {
|
||||
codeWidget.refreshAll();
|
||||
}
|
||||
|
||||
export async function editButton(pos: number) {
|
||||
await editor.moveCursor(pos);
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ export class ServerSystem {
|
|||
),
|
||||
eventHook,
|
||||
);
|
||||
const space = new Space(this.spacePrimitives, this.ds, eventHook);
|
||||
const space = new Space(this.spacePrimitives, eventHook);
|
||||
|
||||
// Add syscalls
|
||||
this.system.registerSyscalls(
|
||||
|
|
|
@ -38,7 +38,7 @@ import { OpenPages } from "./open_pages.ts";
|
|||
import { MainUI } from "./editor_ui.tsx";
|
||||
import { cleanPageRef } from "$sb/lib/resolve.ts";
|
||||
import { SpacePrimitives } from "../common/spaces/space_primitives.ts";
|
||||
import { FileMeta, PageMeta } from "$sb/types.ts";
|
||||
import { CodeWidgetButton, FileMeta, PageMeta } from "$sb/types.ts";
|
||||
import { DataStore } from "../plugos/lib/datastore.ts";
|
||||
import { IndexedDBKvPrimitives } from "../plugos/lib/indexeddb_kv_primitives.ts";
|
||||
import { DataStoreMQ } from "../plugos/lib/mq.datastore.ts";
|
||||
|
@ -188,13 +188,7 @@ export class Client {
|
|||
// Load settings
|
||||
this.settings = await ensureSettingsAndIndex(localSpacePrimitives);
|
||||
|
||||
// Load widget cache
|
||||
this.widgetCache = new LimitedMap(
|
||||
100,
|
||||
await this.stateDataStore.get(["cache", "widgets"]) ||
|
||||
{},
|
||||
);
|
||||
|
||||
await this.loadCaches();
|
||||
// Pinging a remote space to ensure we're authenticated properly, if not will result in a redirect to auth page
|
||||
try {
|
||||
await this.httpSpacePrimitives.ping();
|
||||
|
@ -484,7 +478,6 @@ export class Client {
|
|||
|
||||
this.space = new Space(
|
||||
localSpacePrimitives,
|
||||
this.stateDataStore,
|
||||
this.eventHook,
|
||||
);
|
||||
|
||||
|
@ -1013,7 +1006,56 @@ export class Client {
|
|||
return;
|
||||
}
|
||||
|
||||
private widgetCache = new LimitedMap<WidgetCacheItem>(100);
|
||||
// Widget and image height caching
|
||||
private widgetCache = new LimitedMap<WidgetCacheItem>(100); // bodyText -> WidgetCacheItem
|
||||
private imageHeightCache = new LimitedMap<number>(100); // url -> height
|
||||
private widgetHeightCache = new LimitedMap<number>(100); // bodytext -> height
|
||||
|
||||
async loadCaches() {
|
||||
const [imageHeightCache, widgetHeightCache, widgetCache] = await this
|
||||
.stateDataStore.batchGet([["cache", "imageHeight"], [
|
||||
"cache",
|
||||
"widgetHeight",
|
||||
], ["cache", "widgets"]]);
|
||||
this.imageHeightCache = new LimitedMap(100, imageHeightCache || {});
|
||||
this.widgetHeightCache = new LimitedMap(100, widgetHeightCache || {});
|
||||
this.widgetCache = new LimitedMap(100, widgetCache || {});
|
||||
}
|
||||
|
||||
debouncedImageCacheFlush = throttle(() => {
|
||||
this.stateDataStore.set(["cache", "imageHeight"], this.imageHeightCache)
|
||||
.catch(
|
||||
console.error,
|
||||
);
|
||||
console.log("Flushed image height cache to store");
|
||||
}, 5000);
|
||||
|
||||
setCachedImageHeight(url: string, height: number) {
|
||||
this.imageHeightCache.set(url, height);
|
||||
this.debouncedImageCacheFlush();
|
||||
}
|
||||
getCachedImageHeight(url: string): number {
|
||||
return this.imageHeightCache.get(url) ?? -1;
|
||||
}
|
||||
|
||||
debouncedWidgetHeightCacheFlush = throttle(() => {
|
||||
this.stateDataStore.set(
|
||||
["cache", "widgetHeight"],
|
||||
this.widgetHeightCache.toJSON(),
|
||||
)
|
||||
.catch(
|
||||
console.error,
|
||||
);
|
||||
// console.log("Flushed widget height cache to store");
|
||||
}, 5000);
|
||||
|
||||
setCachedWidgetHeight(bodyText: string, height: number) {
|
||||
this.widgetHeightCache.set(bodyText, height);
|
||||
this.debouncedWidgetHeightCacheFlush();
|
||||
}
|
||||
getCachedWidgetHeight(bodyText: string): number {
|
||||
return this.widgetHeightCache.get(bodyText) ?? -1;
|
||||
}
|
||||
|
||||
debouncedWidgetCacheFlush = throttle(() => {
|
||||
this.stateDataStore.set(["cache", "widgets"], this.widgetCache.toJSON())
|
||||
|
@ -1023,8 +1065,8 @@ export class Client {
|
|||
console.log("Flushed widget cache to store");
|
||||
}, 5000);
|
||||
|
||||
setWidgetCache(key: string, height: number, html: string) {
|
||||
this.widgetCache.set(key, { height, html });
|
||||
setWidgetCache(key: string, cacheItem: WidgetCacheItem) {
|
||||
this.widgetCache.set(key, cacheItem);
|
||||
this.debouncedWidgetCacheFlush();
|
||||
}
|
||||
|
||||
|
@ -1036,4 +1078,5 @@ export class Client {
|
|||
type WidgetCacheItem = {
|
||||
height: number;
|
||||
html: string;
|
||||
buttons?: CodeWidgetButton[];
|
||||
};
|
||||
|
|
|
@ -57,7 +57,7 @@ export class IFrameWidget extends WidgetType {
|
|||
}
|
||||
|
||||
get estimatedHeight(): number {
|
||||
const cachedHeight = this.client.space.getCachedWidgetHeight(this.bodyText);
|
||||
const cachedHeight = this.client.getCachedWidgetHeight(this.bodyText);
|
||||
// console.log("Calling estimated height", cachedHeight);
|
||||
return cachedHeight > 0 ? cachedHeight : 150;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class InlineImageWidget extends WidgetType {
|
|||
}
|
||||
|
||||
get estimatedHeight(): number {
|
||||
const cachedHeight = this.client.space.getCachedImageHeight(this.url);
|
||||
const cachedHeight = this.client.getCachedImageHeight(this.url);
|
||||
// console.log("Estimated height requested", this.url, cachedHeight);
|
||||
return cachedHeight;
|
||||
}
|
||||
|
@ -35,11 +35,11 @@ class InlineImageWidget extends WidgetType {
|
|||
let url = this.url;
|
||||
url = resolvePath(this.client.currentPage!, url, true);
|
||||
// console.log("Creating DOM", this.url);
|
||||
const cachedImageHeight = this.client.space.getCachedImageHeight(url);
|
||||
const cachedImageHeight = this.client.getCachedImageHeight(url);
|
||||
img.onload = () => {
|
||||
// console.log("Loaded", this.url, "with height", img.height);
|
||||
if (img.height !== cachedImageHeight) {
|
||||
this.client.space.setCachedImageHeight(url, img.height);
|
||||
this.client.setCachedImageHeight(url, img.height);
|
||||
}
|
||||
};
|
||||
img.src = url;
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
import { WidgetType } from "../deps.ts";
|
||||
import type { Client } from "../client.ts";
|
||||
import type { CodeWidgetCallback } from "$sb/types.ts";
|
||||
import type { CodeWidgetButton, CodeWidgetCallback } from "$sb/types.ts";
|
||||
import { renderMarkdownToHtml } from "../../plugs/markdown/markdown_render.ts";
|
||||
import { resolveAttachmentPath } from "$sb/lib/resolve.ts";
|
||||
import { parse } from "../../common/markdown_parser/parse_tree.ts";
|
||||
import buildMarkdown from "../../common/markdown_parser/parser.ts";
|
||||
import { renderToText } from "$sb/lib/tree.ts";
|
||||
|
||||
const activeWidgets = new Set<MarkdownWidget>();
|
||||
|
||||
export class MarkdownWidget extends WidgetType {
|
||||
renderedMarkdown?: string;
|
||||
public dom?: HTMLElement;
|
||||
|
||||
constructor(
|
||||
readonly from: number | undefined,
|
||||
|
@ -27,19 +30,20 @@ export class MarkdownWidget extends WidgetType {
|
|||
if (cacheItem) {
|
||||
div.innerHTML = this.wrapHtml(
|
||||
cacheItem.html,
|
||||
this.from !== undefined,
|
||||
this.from !== undefined,
|
||||
cacheItem.buttons,
|
||||
);
|
||||
this.attachListeners(div);
|
||||
this.attachListeners(div, cacheItem.buttons);
|
||||
}
|
||||
|
||||
// Async kick-off of content renderer
|
||||
this.renderContent(div, cacheItem?.html).catch(console.error);
|
||||
|
||||
this.dom = div;
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
private async renderContent(
|
||||
async renderContent(
|
||||
div: HTMLElement,
|
||||
cachedHtml: string | undefined,
|
||||
) {
|
||||
|
@ -47,6 +51,7 @@ export class MarkdownWidget extends WidgetType {
|
|||
this.bodyText,
|
||||
this.client.currentPage!,
|
||||
);
|
||||
activeWidgets.add(this);
|
||||
if (!widgetContent) {
|
||||
div.innerHTML = "";
|
||||
// div.style.display = "none";
|
||||
|
@ -89,42 +94,30 @@ export class MarkdownWidget extends WidgetType {
|
|||
// HTML still same as in cache, no need to re-render
|
||||
return;
|
||||
}
|
||||
div.innerHTML = this.wrapHtml(
|
||||
html,
|
||||
this.from !== undefined,
|
||||
this.from !== undefined,
|
||||
);
|
||||
this.attachListeners(div);
|
||||
div.innerHTML = this.wrapHtml(html, widgetContent.buttons);
|
||||
this.attachListeners(div, widgetContent.buttons);
|
||||
|
||||
// Let's give it a tick, then measure and cache
|
||||
setTimeout(() => {
|
||||
this.client.setWidgetCache(
|
||||
this.bodyText,
|
||||
div.clientHeight,
|
||||
html,
|
||||
{ height: div.clientHeight, html, buttons: widgetContent.buttons },
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private wrapHtml(html: string, editButton = true, sourceButton = true) {
|
||||
return `
|
||||
<div class="button-bar">
|
||||
${
|
||||
sourceButton
|
||||
? `<button class="source-button" title="Show Markdown source"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-code"><polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline></svg></button>`
|
||||
: ""
|
||||
private wrapHtml(html: string, buttons?: CodeWidgetButton[]) {
|
||||
if (!buttons) {
|
||||
return html;
|
||||
}
|
||||
<button class="reload-button" title="Reload"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"></polyline><polyline points="1 20 1 14 7 14"></polyline><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path></svg></button>
|
||||
${
|
||||
editButton
|
||||
? `<button class="edit-button" title="Edit"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-edit"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg></button>`
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
${html}`;
|
||||
return `<div class="button-bar">${
|
||||
buttons.map((button, idx) =>
|
||||
`<button data-button="${idx}" title="${button.description}">${button.svg}</button> `
|
||||
).join("")
|
||||
}</div>${html}`;
|
||||
}
|
||||
|
||||
private attachListeners(div: HTMLElement) {
|
||||
private attachListeners(div: HTMLElement, buttons?: CodeWidgetButton[]) {
|
||||
div.querySelectorAll("a[data-ref]").forEach((el_) => {
|
||||
const el = el_ as HTMLElement;
|
||||
// Override default click behavior with a local navigate (faster)
|
||||
|
@ -160,20 +153,30 @@ export class MarkdownWidget extends WidgetType {
|
|||
);
|
||||
});
|
||||
|
||||
if (this.from !== undefined) {
|
||||
div.querySelector(".edit-button")!.addEventListener("click", () => {
|
||||
this.client.editorView.dispatch({
|
||||
selection: { anchor: this.from! },
|
||||
});
|
||||
this.client.focus();
|
||||
});
|
||||
div.querySelector(".source-button")!.addEventListener("click", () => {
|
||||
div.innerText = this.renderedMarkdown!;
|
||||
});
|
||||
if (!buttons) {
|
||||
buttons = [];
|
||||
}
|
||||
div.querySelector(".reload-button")!.addEventListener("click", () => {
|
||||
this.renderContent(div, undefined).catch(console.error);
|
||||
});
|
||||
|
||||
for (let i = 0; i < buttons.length; i++) {
|
||||
const button = buttons[i];
|
||||
div.querySelector(`button[data-button="${i}"]`)!.addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
this.client.system.localSyscall("system.invokeFunction", [
|
||||
button.invokeFunction,
|
||||
this.from,
|
||||
]).then((newContent: string | undefined) => {
|
||||
if (newContent) {
|
||||
div.innerText = newContent;
|
||||
}
|
||||
this.client.focus();
|
||||
}).catch(console.error);
|
||||
},
|
||||
);
|
||||
}
|
||||
// div.querySelectorAll("ul > li").forEach((el) => {
|
||||
// el.classList.add("sb-line-li-1", "sb-line-ul");
|
||||
// });
|
||||
}
|
||||
|
||||
get estimatedHeight(): number {
|
||||
|
@ -189,3 +192,25 @@ export class MarkdownWidget extends WidgetType {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function reloadAllMarkdownWidgets() {
|
||||
for (const widget of activeWidgets) {
|
||||
// Garbage collect as we go
|
||||
if (!widget.dom || !widget.dom.parentNode) {
|
||||
activeWidgets.delete(widget);
|
||||
continue;
|
||||
}
|
||||
widget.renderContent(widget.dom!, undefined).catch(console.error);
|
||||
}
|
||||
}
|
||||
|
||||
function garbageCollectWidgets() {
|
||||
for (const widget of activeWidgets) {
|
||||
if (!widget.dom || !widget.dom.parentNode) {
|
||||
// console.log("Garbage collecting widget", widget.bodyText);
|
||||
activeWidgets.delete(widget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setInterval(garbageCollectWidgets, 5000);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Decoration, EditorState, WidgetType } from "../deps.ts";
|
||||
import { Decoration, EditorState } from "../deps.ts";
|
||||
import type { Client } from "../client.ts";
|
||||
import { decoratorStateField } from "./util.ts";
|
||||
import { MarkdownWidget } from "./markdown_widget.ts";
|
||||
|
|
|
@ -149,7 +149,7 @@ export function mountIFrame(
|
|||
case "setHeight":
|
||||
iframe.height = data.height + "px";
|
||||
if (widgetHeightCacheKey) {
|
||||
client.space.setCachedWidgetHeight(
|
||||
client.setCachedWidgetHeight(
|
||||
widgetHeightCacheKey,
|
||||
data.height,
|
||||
);
|
||||
|
|
46
web/space.ts
46
web/space.ts
|
@ -11,40 +11,6 @@ import { LimitedMap } from "../common/limited_map.ts";
|
|||
const pageWatchInterval = 5000;
|
||||
|
||||
export class Space {
|
||||
imageHeightCache = new LimitedMap<number>(100); // url -> height
|
||||
widgetHeightCache = new LimitedMap<number>(100); // bodytext -> height
|
||||
|
||||
debouncedImageCacheFlush = throttle(() => {
|
||||
this.ds.set(["cache", "imageHeight"], this.imageHeightCache).catch(
|
||||
console.error,
|
||||
);
|
||||
console.log("Flushed image height cache to store");
|
||||
}, 5000);
|
||||
|
||||
setCachedImageHeight(url: string, height: number) {
|
||||
this.imageHeightCache.set(url, height);
|
||||
this.debouncedImageCacheFlush();
|
||||
}
|
||||
getCachedImageHeight(url: string): number {
|
||||
return this.imageHeightCache.get(url) ?? -1;
|
||||
}
|
||||
|
||||
debouncedWidgetCacheFlush = throttle(() => {
|
||||
this.ds.set(["cache", "widgetHeight"], this.widgetHeightCache.toJSON())
|
||||
.catch(
|
||||
console.error,
|
||||
);
|
||||
// console.log("Flushed widget height cache to store");
|
||||
}, 5000);
|
||||
|
||||
setCachedWidgetHeight(bodyText: string, height: number) {
|
||||
this.widgetHeightCache.set(bodyText, height);
|
||||
this.debouncedWidgetCacheFlush();
|
||||
}
|
||||
getCachedWidgetHeight(bodyText: string): number {
|
||||
return this.widgetHeightCache.get(bodyText) ?? -1;
|
||||
}
|
||||
|
||||
// We do watch files in the background to detect changes
|
||||
// This set of pages should only ever contain 1 page
|
||||
watchedPages = new Set<string>();
|
||||
|
@ -55,20 +21,8 @@ export class Space {
|
|||
|
||||
constructor(
|
||||
readonly spacePrimitives: SpacePrimitives,
|
||||
private ds: DataStore,
|
||||
eventHook: EventHook,
|
||||
) {
|
||||
// super();
|
||||
this.ds.batchGet([["cache", "imageHeight"], ["cache", "widgetHeight"]])
|
||||
.then(([imageCache, widgetCache]) => {
|
||||
if (imageCache) {
|
||||
this.imageHeightCache = new LimitedMap(100, imageCache);
|
||||
}
|
||||
if (widgetCache) {
|
||||
// console.log("Loaded widget cache from store", widgetCache);
|
||||
this.widgetHeightCache = new LimitedMap(100, widgetCache);
|
||||
}
|
||||
});
|
||||
eventHook.addLocalListener("page:deleted", (pageName: string) => {
|
||||
if (this.watchedPages.has(pageName)) {
|
||||
// Stop watching deleted pages already
|
||||
|
|
|
@ -451,13 +451,13 @@
|
|||
.sb-markdown-bottom-widget h1 {
|
||||
border-top-right-radius: 5px;
|
||||
border-top-left-radius: 5px;
|
||||
margin: 0;
|
||||
margin: 0 0 5px 0;
|
||||
padding: 10px !important;
|
||||
background-color: var(--editor-directive-background-color);
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.sb-markdown-top-widget {
|
||||
.sb-markdown-top-widget:has(*) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
|
@ -471,7 +471,7 @@
|
|||
overflow-y: scroll;
|
||||
border: 1px solid var(--editor-directive-background-color);
|
||||
border-radius: 5px;
|
||||
white-space: nowrap;
|
||||
white-space: wrap;
|
||||
position: relative;
|
||||
|
||||
ul,
|
||||
|
@ -482,7 +482,7 @@
|
|||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 1ch;
|
||||
// padding-left: 1ch;
|
||||
}
|
||||
|
||||
ul li::before {
|
||||
|
@ -493,7 +493,7 @@
|
|||
/* Needed to add space between the bullet and the text */
|
||||
width: 1em;
|
||||
/* Also needed for space (tweak if needed) */
|
||||
// margin-left: -1em;
|
||||
margin-left: -1em;
|
||||
}
|
||||
|
||||
h1,
|
||||
|
@ -528,27 +528,24 @@
|
|||
|
||||
.button-bar {
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
top: 6px;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
display: none;
|
||||
background: var(--editor-directive-background-color);
|
||||
padding-inline: 3px;
|
||||
padding-bottom: 1px;
|
||||
border-radius: 5px;
|
||||
|
||||
|
||||
button {
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
color: var(--root-color);
|
||||
margin-right: -8px;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-button,
|
||||
.reload-button {
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.sb-fenced-code-iframe {
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { SysCallMapping } from "../../plugos/system.ts";
|
||||
import { reloadAllMarkdownWidgets } from "../cm_plugins/markdown_widget.ts";
|
||||
import { broadcastReload } from "../components/widget_sandbox_iframe.ts";
|
||||
|
||||
export function clientCodeWidgetSyscalls(): SysCallMapping {
|
||||
return {
|
||||
"codeWidget.refreshAll": () => {
|
||||
broadcastReload();
|
||||
reloadAllMarkdownWidgets();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue