diff --git a/package-lock.json b/package-lock.json index 103233952..e5944f332 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,7 +65,6 @@ "katex": "0.16.21", "leaflet": "1.9.4", "leaflet-gpx": "2.1.2", - "mark.js": "8.11.1", "marked": "15.0.7", "mermaid": "11.6.0", "mime-types": "3.0.1", @@ -88,7 +87,6 @@ "tmp": "0.2.3", "turndown": "7.2.0", "unescape": "1.0.1", - "vanilla-js-wheel-zoom": "9.0.4", "ws": "8.18.1", "xml2js": "0.6.2", "yauzl": "3.2.0" @@ -173,6 +171,7 @@ "jsdoc": "4.0.4", "knockout": "3.5.1", "lorem-ipsum": "2.0.8", + "mark.js": "8.11.1", "mind-elixir": "4.4.3", "mini-css-extract-plugin": "2.9.2", "nodemon": "3.1.9", @@ -183,6 +182,7 @@ "rimraf": "6.0.1", "sass": "1.86.0", "sass-loader": "16.0.5", + "script-loader": "0.7.2", "split.js": "1.6.5", "supertest": "7.1.0", "svg-pan-zoom": "3.6.2", @@ -193,6 +193,7 @@ "typedoc": "0.28.1", "typescript": "5.8.2", "typescript-eslint": "8.28.0", + "vanilla-js-wheel-zoom": "9.0.4", "vitest": "3.0.9", "webpack": "5.98.0", "webpack-cli": "6.0.1", @@ -15232,6 +15233,7 @@ "version": "8.11.1", "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "dev": true, "license": "MIT" }, "node_modules/markdown-it": { @@ -18034,6 +18036,12 @@ "node": ">=0.6" } }, + "node_modules/raw-loader": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-0.5.1.tgz", + "integrity": "sha512-sf7oGoLuaYAScB4VGr0tzetsYlS8EJH6qnTCfQ/WVEa89hALQ4RQfCKt5xCyPQKPDUbVUAIP1QsxAwfAjlDp7Q==", + "dev": true + }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -19095,6 +19103,16 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/script-loader": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/script-loader/-/script-loader-0.7.2.tgz", + "integrity": "sha512-UMNLEvgOAQuzK8ji8qIscM3GIrRCWN6MmMXGD4SD5l6cSycgGsCo0tX5xRnfQcoghqct0tjHjcykgI1PyBE2aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "raw-loader": "~0.5.1" + } + }, "node_modules/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", @@ -21492,6 +21510,7 @@ "version": "9.0.4", "resolved": "https://registry.npmjs.org/vanilla-js-wheel-zoom/-/vanilla-js-wheel-zoom-9.0.4.tgz", "integrity": "sha512-OjmS9ihEKBCRw2OQ7IiIdQGXdC5gTEEmtcAWZcPeNAJaYiS61KCd02Z72YMtIoXLGN5TZP+wliBMylLAsr6wow==", + "dev": true, "license": "MIT" }, "node_modules/vary": { diff --git a/package.json b/package.json index 6cf645049..72c59aaa9 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,6 @@ "katex": "0.16.21", "leaflet": "1.9.4", "leaflet-gpx": "2.1.2", - "mark.js": "8.11.1", "marked": "15.0.7", "mermaid": "11.6.0", "mime-types": "3.0.1", @@ -147,7 +146,6 @@ "tmp": "0.2.3", "turndown": "7.2.0", "unescape": "1.0.1", - "vanilla-js-wheel-zoom": "9.0.4", "ws": "8.18.1", "xml2js": "0.6.2", "yauzl": "3.2.0" @@ -229,6 +227,7 @@ "jsdoc": "4.0.4", "knockout": "3.5.1", "lorem-ipsum": "2.0.8", + "mark.js": "8.11.1", "mind-elixir": "4.4.3", "mini-css-extract-plugin": "2.9.2", "nodemon": "3.1.9", @@ -239,6 +238,7 @@ "rimraf": "6.0.1", "sass": "1.86.0", "sass-loader": "16.0.5", + "script-loader": "0.7.2", "split.js": "1.6.5", "supertest": "7.1.0", "svg-pan-zoom": "3.6.2", @@ -249,6 +249,7 @@ "typedoc": "0.28.1", "typescript": "5.8.2", "typescript-eslint": "8.28.0", + "vanilla-js-wheel-zoom": "9.0.4", "vitest": "3.0.9", "webpack": "5.98.0", "webpack-cli": "6.0.1", diff --git a/src/public/app/services/content_renderer.ts b/src/public/app/services/content_renderer.ts index a1999cffe..0bf7bca28 100644 --- a/src/public/app/services/content_renderer.ts +++ b/src/public/app/services/content_renderer.ts @@ -15,7 +15,7 @@ import { loadElkIfNeeded, postprocessMermaidSvg } from "./mermaid.js"; import { normalizeMimeTypeForCKEditor } from "./mime_type_definitions.js"; import renderDoc from "./doc_renderer.js"; import { t } from "i18next"; -import type { Mermaid } from "mermaid"; +import WheelZoom from 'vanilla-js-wheel-zoom'; let idCounter = 1; @@ -150,13 +150,19 @@ function renderImage(entity: FNote | FAttachment, $renderedContent: JQuery { - WZoom.create(`#${$img.attr("id")}`, { - maxScale: 50, - speed: 1.3, - zoomOnClick: false - }); - }); + const initZoom = async () => { + const element = document.querySelector(`#${$img.attr("id")}`); + if (element) { + WheelZoom.create(`#${$img.attr("id")}`, { + maxScale: 50, + speed: 1.3, + zoomOnClick: false + }); + } else { + requestAnimationFrame(initZoom); + } + }; + initZoom(); } imageContextMenuService.setupContextMenu($img); diff --git a/src/public/app/services/library_loader.ts b/src/public/app/services/library_loader.ts index 129dca688..cbc8771cb 100644 --- a/src/public/app/services/library_loader.ts +++ b/src/public/app/services/library_loader.ts @@ -42,23 +42,11 @@ const CODE_MIRROR: Library = { css: ["node_modules/codemirror/lib/codemirror.css", "node_modules/codemirror/addon/lint/lint.css"] }; -const CALENDAR_WIDGET: Library = { - css: ["stylesheets/calendar.css"] -}; - const KATEX: Library = { js: ["node_modules/katex/dist/katex.min.js", "node_modules/katex/dist/contrib/mhchem.min.js", "node_modules/katex/dist/contrib/auto-render.min.js"], css: ["node_modules/katex/dist/katex.min.css"] }; -const WHEEL_ZOOM: Library = { - js: ["node_modules/vanilla-js-wheel-zoom/dist/wheel-zoom.min.js"] -}; - -const MARKJS: Library = { - js: ["node_modules/mark.js/dist/jquery.mark.es6.min.js"] -}; - const HIGHLIGHT_JS: Library = { js: () => { const mimeTypes = mimeTypesService.getMimeTypes(); @@ -85,10 +73,6 @@ const HIGHLIGHT_JS: Library = { } }; -const LEAFLET: Library = { - css: ["node_modules/leaflet/dist/leaflet.css"] -}; - async function requireLibrary(library: Library) { if (library.css) { library.css.map((cssUrl) => requireCss(cssUrl)); @@ -174,10 +158,6 @@ export default { loadHighlightingTheme, CKEDITOR, CODE_MIRROR, - CALENDAR_WIDGET, KATEX, - WHEEL_ZOOM, - MARKJS, - HIGHLIGHT_JS, - LEAFLET + HIGHLIGHT_JS }; diff --git a/src/public/app/types.d.ts b/src/public/app/types.d.ts index da0ad927a..0228c3756 100644 --- a/src/public/app/types.d.ts +++ b/src/public/app/types.d.ts @@ -132,13 +132,6 @@ declare global { var renderMathInElement: (element: HTMLElement, options: { trust: boolean; }) => void; - var WZoom = { - create(selector: string, opts: { - maxScale: number; - speed: number; - zoomOnClick: boolean - }) - }; interface CKCodeBlockLanguage { language: string; label: string; diff --git a/src/public/app/widgets/buttons/calendar.ts b/src/public/app/widgets/buttons/calendar.ts index 131d176bf..11e9092bc 100644 --- a/src/public/app/widgets/buttons/calendar.ts +++ b/src/public/app/widgets/buttons/calendar.ts @@ -1,5 +1,4 @@ import { t } from "../../services/i18n.js"; -import libraryLoader from "../../services/library_loader.js"; import utils from "../../services/utils.js"; import dateNoteService from "../../services/date_notes.js"; import server from "../../services/server.js"; @@ -9,6 +8,7 @@ import toastService from "../../services/toast.js"; import options from "../../services/options.js"; import { Dropdown } from "bootstrap"; import type { EventData } from "../../components/app_context.js"; +import "../../../stylesheets/calendar.css"; const MONTHS = [ t("calendar.january"), @@ -188,7 +188,6 @@ export default class CalendarWidget extends RightDropdownButtonWidget { } async dropdownShown() { - await libraryLoader.requireLibrary(libraryLoader.CALENDAR_WIDGET); this.init(appContext.tabManager.getActiveContextNote()?.getOwnedLabelValue("dateNote") ?? null); } diff --git a/src/public/app/widgets/find_in_html.ts b/src/public/app/widgets/find_in_html.ts index d1e9a93db..bc63d78ce 100644 --- a/src/public/app/widgets/find_in_html.ts +++ b/src/public/app/widgets/find_in_html.ts @@ -1,7 +1,6 @@ // ck-find-result and ck-find-result_selected are the styles ck-editor // uses for highlighting matches, use the same one on CodeMirror // for consistency -import libraryLoader from "../services/library_loader.js"; import utils from "../services/utils.js"; import appContext from "../components/app_context.js"; import type FindWidget from "./find.js"; @@ -23,7 +22,7 @@ export default class FindInHtml { } async performFind(searchTerm: string, matchCase: boolean, wholeWord: boolean) { - await libraryLoader.requireLibrary(libraryLoader.MARKJS); + await import("script-loader!mark.js/dist/jquery.mark.min.js"); const $content = await this.parent?.noteContext?.getContentElement(); diff --git a/src/public/app/widgets/geo_map.ts b/src/public/app/widgets/geo_map.ts index fabefcdc9..699d71a51 100644 --- a/src/public/app/widgets/geo_map.ts +++ b/src/public/app/widgets/geo_map.ts @@ -1,5 +1,6 @@ import type { Map } from "leaflet"; -import library_loader from "../services/library_loader.js"; +import L from "leaflet"; +import "leaflet/dist/leaflet.css"; import NoteContextAwareWidget from "./note_context_aware_widget.js"; const TPL = `\ @@ -21,7 +22,7 @@ const TPL = `\
`; -export type Leaflet = typeof import("leaflet"); +export type Leaflet = typeof L; export type InitCallback = (L: Leaflet) => void; export default class GeoMapWidget extends NoteContextAwareWidget { @@ -40,23 +41,18 @@ export default class GeoMapWidget extends NoteContextAwareWidget { this.$container = this.$widget.find(".geo-map-container"); - library_loader.requireLibrary(library_loader.LEAFLET).then(async () => { - const L = (await import("leaflet")).default; - - const map = L.map(this.$container[0], { - worldCopyJump: true - }); - - this.map = map; - if (this.initCallback) { - this.initCallback(L); - } - - L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", { - attribution: '© OpenStreetMap contributors', - detectRetina: true - }).addTo(map); + const map = L.map(this.$container[0], { + worldCopyJump: true }); - } + this.map = map; + if (this.initCallback) { + this.initCallback(L); + } + + L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", { + attribution: '© OpenStreetMap contributors', + detectRetina: true + }).addTo(map); + } } diff --git a/src/public/app/widgets/type_widgets/image.ts b/src/public/app/widgets/type_widgets/image.ts index e235abaef..e082fd003 100644 --- a/src/public/app/widgets/type_widgets/image.ts +++ b/src/public/app/widgets/type_widgets/image.ts @@ -1,10 +1,10 @@ import utils from "../../services/utils.js"; import TypeWidget from "./type_widget.js"; -import libraryLoader from "../../services/library_loader.js"; import imageContextMenuService from "../../menus/image_context_menu.js"; import imageService from "../../services/image.js"; import type FNote from "../../entities/fnote.js"; import type { EventData } from "../../components/app_context.js"; +import WheelZoom from 'vanilla-js-wheel-zoom'; const TPL = `
@@ -54,13 +54,19 @@ class ImageTypeWidget extends TypeWidget { this.$imageWrapper = this.$widget.find(".note-detail-image-wrapper"); this.$imageView = this.$widget.find(".note-detail-image-view").attr("id", `image-view-${utils.randomString(10)}`); - libraryLoader.requireLibrary(libraryLoader.WHEEL_ZOOM).then(() => { - WZoom.create(`#${this.$imageView.attr("id")}`, { - maxScale: 50, - speed: 1.3, - zoomOnClick: false - }); - }); + const initZoom = async () => { + const element = document.querySelector(`#${this.$imageView.attr("id")}`); + if (element) { + WheelZoom.create(`#${this.$imageView.attr("id")}`, { + maxScale: 50, + speed: 1.3, + zoomOnClick: false + }); + } else { + requestAnimationFrame(initZoom); + } + }; + initZoom(); imageContextMenuService.setupContextMenu(this.$imageView); diff --git a/src/public/app/widgets/view_widgets/list_or_grid_view.ts b/src/public/app/widgets/view_widgets/list_or_grid_view.ts index 56ee00b86..1c70d791a 100644 --- a/src/public/app/widgets/view_widgets/list_or_grid_view.ts +++ b/src/public/app/widgets/view_widgets/list_or_grid_view.ts @@ -2,7 +2,6 @@ import linkService from "../../services/link.js"; import contentRenderer from "../../services/content_renderer.js"; import froca from "../../services/froca.js"; import attributeRenderer from "../../services/attribute_renderer.js"; -import libraryLoader from "../../services/library_loader.js"; import treeService from "../../services/tree.js"; import utils from "../../services/utils.js"; import type FNote from "../../entities/fnote.js"; @@ -216,7 +215,7 @@ class ListOrGridView extends ViewMode { const highlightedTokens = this.parentNote.highlightedTokens || []; if (highlightedTokens.length > 0) { - await libraryLoader.requireLibrary(libraryLoader.MARKJS); + await import("script-loader!mark.js/dist/jquery.mark.min.js"); const regex = highlightedTokens.map((token) => utils.escapeRegExp(token)).join("|"); @@ -269,12 +268,12 @@ class ListOrGridView extends ViewMode { i === this.page ? $("").text(i).css("text-decoration", "underline").css("font-weight", "bold") : $('') - .text(i) - .attr("title", `Page of ${startIndex} - ${endIndex}`) - .on("click", () => { - this.page = i; - this.renderList(); - }), + .text(i) + .attr("title", `Page of ${startIndex} - ${endIndex}`) + .on("click", () => { + this.page = i; + this.renderList(); + }), "   " ); } else if (lastPrinted) { diff --git a/src/routes/assets.ts b/src/routes/assets.ts index f5cf33612..70cd4de8f 100644 --- a/src/routes/assets.ts +++ b/src/routes/assets.ts @@ -73,10 +73,6 @@ async function register(app: express.Application) { app.use(`/${assetPath}/node_modules/eslint/bin/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/eslint/bin/"))); - app.use(`/${assetPath}/node_modules/vanilla-js-wheel-zoom/dist/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/vanilla-js-wheel-zoom/dist/"))); - - app.use(`/${assetPath}/node_modules/mark.js/dist/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/mark.js/dist/"))); - // Deprecated, https://www.npmjs.com/package/autocomplete.js?activeTab=readme app.use(`/${assetPath}/node_modules/autocomplete.js/dist/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/autocomplete.js/dist/"))); @@ -91,8 +87,6 @@ async function register(app: express.Application) { app.use(`/${assetPath}/node_modules/codemirror/keymap/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/codemirror/keymap/"))); app.use(`/${assetPath}/node_modules/@highlightjs/cdn-assets/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/@highlightjs/cdn-assets/"))); - - app.use(`/${assetPath}/node_modules/leaflet/dist/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/leaflet/dist/"))); } export default { diff --git a/src/types.d.ts b/src/types.d.ts index 671408321..f1d67c904 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -30,3 +30,5 @@ declare module "is-animated" { function isAnimated(buffer: Buffer): boolean; export default isAnimated; } + +declare module "script-loader!mark.js/dist/jquery.mark.min.js"; diff --git a/webpack.config.ts b/webpack.config.ts index 92bb2337b..bfafd6036 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -66,7 +66,10 @@ const config: Configuration = { loader: miniCssExtractPlugin.loader }, { - loader: "css-loader" + loader: "css-loader", + options: { + esModule: true + } }, { loader: "postcss-loader", @@ -109,6 +112,9 @@ const config: Configuration = { ".js": [".js", ".ts"], ".cjs": [".cjs", ".cts"], ".mjs": [".mjs", ".mts"] + }, + alias: { + stylesheets: path.resolve(rootDir, "src/public/stylesheets") } }, devtool: "nosources-source-map",