From f75461db5282976955d50e0e1e025a18c7fd6280 Mon Sep 17 00:00:00 2001 From: Jan-Stefan Janetzky Date: Sun, 17 Mar 2024 16:42:17 +0100 Subject: [PATCH] dynamic css provider for setting changes (blacksmithgu#2270) --- src/main.ts | 26 +++++++++++++++++++ src/util/style-provider.ts | 53 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 src/util/style-provider.ts diff --git a/src/main.ts b/src/main.ts index 9b600fae..ff94fcae 100644 --- a/src/main.ts +++ b/src/main.ts @@ -29,11 +29,14 @@ import { import { DataviewInit } from "ui/markdown"; import { inlinePlugin } from "./ui/lp-render"; import { Extension } from "@codemirror/state"; +import { StyleProvider } from "util/style-provider"; export default class DataviewPlugin extends Plugin { /** Plugin-wide default settings. */ public settings: DataviewSettings; + private customStyles: StyleProvider; + /** The index that stores all dataview data. */ public index: FullIndex; /** External-facing plugin API. */ @@ -53,6 +56,11 @@ export default class DataviewPlugin extends Plugin { }) ); + this.customStyles = new StyleProvider(`${this.manifest.name}@${this.manifest.version}`); + + // Set up settings listeners. + this.updateSettingListeners(this.settings); + // Set up automatic (intelligent) view refreshing that debounces. this.updateRefreshSettings(); @@ -174,6 +182,7 @@ export default class DataviewPlugin extends Plugin { } public onunload() { + this.customStyles.detach(); console.log(`Dataview: version ${this.manifest.version} unloaded.`); } @@ -287,8 +296,25 @@ export default class DataviewPlugin extends Plugin { } } + private updateSettingListeners(settings: Partial) { + for (const [key, value] of Object.entries(settings)) { + switch (key) { + case "dataviewJsKeyword": + this.customStyles.setStyle( + "codeblock scrolling during inline-edit", + `div.block-language-${value} { + overflow-x: auto; + }` + ); + // TODO: add support for syntax highlighting during inline editing + break; + } + } + } + /** Update plugin settings. */ async updateSettings(settings: Partial) { + this.updateSettingListeners(settings); Object.assign(this.settings, settings); this.updateRefreshSettings(); await this.saveData(this.settings); diff --git a/src/util/style-provider.ts b/src/util/style-provider.ts new file mode 100644 index 00000000..2fc1e267 --- /dev/null +++ b/src/util/style-provider.ts @@ -0,0 +1,53 @@ +export class StyleProvider { + private node: HTMLStyleElement; + private styles: Map; + private waiting: boolean; + private css: string; + + constructor(name: string) { + this.node = document.createElement("style"); + this.node.setAttribute("type", "text/css"); + this.node.setAttribute("data-style-provider", name); + this.styles = new Map(); + this.waiting = false; + this.css = ""; + this.attach(); + } + + attach() { + document.head.appendChild(this.node); + } + + detach() { + this.node.parentNode?.removeChild(this.node); + } + + setStyle(name: string, style: string) { + const old = this.styles.get(name); + if (old === style) return; + this.styles.set(name, style); + this.updateStyles(); + } + + removeStyle(name: string) { + this.styles.delete(name); + this.updateStyles(); + } + + private updateStyles() { + this.css = ""; + for (const [name, style] of this.styles) { + this.css += `/* ${name}: */\n${style}\n\n`; + } + this.queueUpdate(); + } + + private queueUpdate = () => { + if (this.waiting) return; + this.waiting = true; + requestAnimationFrame(() => { + this.waiting = false; + this.node.textContent = this.css.trimEnd(); + }); + }; +}