From e14b76b7c4474533c99ab78d8c98e3211bb0266a Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Sat, 31 Jan 2026 01:07:19 +0100 Subject: [PATCH] move to headless-mde --- .../js/controllers/mdeditor_controller.js | 28 ++++++++----------- cmd/web/package.json | 1 + cmd/web/webpack.config.js | 8 ++++++ cmd/web/yarn.lock | 5 ++++ 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/cmd/web/client/js/controllers/mdeditor_controller.js b/cmd/web/client/js/controllers/mdeditor_controller.js index b3055d5..e6a36d8 100644 --- a/cmd/web/client/js/controllers/mdeditor_controller.js +++ b/cmd/web/client/js/controllers/mdeditor_controller.js @@ -1,9 +1,5 @@ import { Controller } from "@hotwired/stimulus" -import { bootstrapTextareaMarkdown } from "textarea-markdown-editor/dist/bootstrap"; - -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} +import { bootstrapTextareaMarkdown } from "@can3p/headless-mde/headless"; export default class extends Controller { static values = { @@ -15,8 +11,6 @@ export default class extends Controller { const { trigger, dispose, cursor } = bootstrapTextareaMarkdown(textarea, { options: { enableLinkPasteExtension: false, - enablePrefixWrappingExtension: true, - customPrefixWrapping: ['*'], } }); @@ -115,7 +109,8 @@ export default class extends Controller { } } - const uploadFiles = async(files) => { + const uploadFiles = (files) => { + textarea.focus(); this.element.classList.add("mdeditor--loading") let promises = []; @@ -126,11 +121,12 @@ export default class extends Controller { if (cursor.position.line.text) { cursor.insert('\n'); // wrap to next line if some line is not empty } + const loadingPlaceholder = `[uploading (${file.name})...${Math.random()}]`; - cursor.insert('\n' + loadingPlaceholder + '\n'); + cursor.insertAndScrollIntoView(loadingPlaceholder); - let prom = uploadFile(file).then((resultUrl) => { - textarea.value = cursor.value.replace(loadingPlaceholder, `![${file.name}](${resultUrl})`) + let prom = uploadFile(file).then((url) => { + cursor.replace(loadingPlaceholder, `![${file.name}](${url})`); }).catch((e) => { console.log("image upload failure:" , e) }); @@ -138,11 +134,11 @@ export default class extends Controller { promises.push(prom) } - htmx.trigger(textarea, "change") - - await Promise.all(promises) - upload.value = null; - this.element.classList.remove("mdeditor--loading") + Promise.all(promises).then(() => { + htmx.trigger(textarea, "change") + upload.value = null; + this.element.classList.remove("mdeditor--loading") + }) } const handler = async () => { diff --git a/cmd/web/package.json b/cmd/web/package.json index 1ba8501..db2a244 100644 --- a/cmd/web/package.json +++ b/cmd/web/package.json @@ -9,6 +9,7 @@ "private": true, "license": "unlicensed", "dependencies": { + "@can3p/headless-mde": "^0.0.4", "@justinribeiro/lite-youtube": "^1.5.0", "bootstrap": "^5.3.2", "bootstrap-icons": "^1.11.3", diff --git a/cmd/web/webpack.config.js b/cmd/web/webpack.config.js index 765e133..f3d32c3 100644 --- a/cmd/web/webpack.config.js +++ b/cmd/web/webpack.config.js @@ -69,6 +69,14 @@ module.exports = (env, argv) => { // custom loaders configuration module: { rules: [ + { + test: /\.m?js$/, + include: /node_modules\/@can3p\/headless-mde/, + resolve: { + fullySpecified: false, + }, + }, + // styles loader { test: /\.(sa|sc|c)ss$/, diff --git a/cmd/web/yarn.lock b/cmd/web/yarn.lock index 78ab910..8fde040 100644 --- a/cmd/web/yarn.lock +++ b/cmd/web/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@can3p/headless-mde@^0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@can3p/headless-mde/-/headless-mde-0.0.4.tgz#b45c0c00db5fafe660426673e7301cc9a70dab83" + integrity sha512-m3L7mbuYQrBDIR0CLxqvRL6sQ+CZKaVFIihkvRZ8/XAEZOExgPqgunPQjTNibGOE3g+qskhIEpCJGkU5vi1qUw== + "@discoveryjs/json-ext@^0.5.0": version "0.5.7" resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"