Page MenuHomeSealhub

markdown-textarea.stimulus.ts
No OneTemporary

markdown-textarea.stimulus.ts

/* eslint-disable @typescript-eslint/no-misused-promises */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Controller } from "stimulus";
import type { default as simplemde } from "simplemde";
const CSS_ID = "simplemde-css";
const JS_ID = "simplemde-js";
declare const SimpleMDE: simplemde;
export default class MarkdownTextarea extends Controller<HTMLTextAreaElement> {
sm: simplemde;
checkboxHandler: (this: HTMLElement, ev: Event) => any;
resizeObserver: ResizeObserver;
intersectionObserver: IntersectionObserver;
mdeStarted = false;
addCSS() {
const tag = document.querySelector(`head #${CSS_ID}`);
if (!tag) {
const link = document.createElement("link");
link.setAttribute("rel", "stylesheet");
link.setAttribute("type", "text/css");
link.setAttribute("id", CSS_ID);
link.setAttribute("href", "/dist/simplemde.min.css");
document.head.appendChild(link);
}
}
async addJS() {
return new Promise<void>((resolve, reject) => {
const once_loaded = (e: MouseEvent) => {
(e.target as HTMLScriptElement).setAttribute("loaded", "true");
resolve();
};
try {
const tag = document.querySelector(`head #${JS_ID}`);
if (!tag) {
const script = document.createElement("script");
script.setAttribute("id", JS_ID);
script.setAttribute("src", "/dist/simplemde.min.js");
script.addEventListener("load", once_loaded);
document.head.appendChild(script);
} else {
if (tag.getAttribute("loaded") == "true") {
resolve();
} else {
tag.addEventListener("load", once_loaded);
}
}
} catch (e) {
reject(e);
}
});
}
handleResize() {
this.sm.codemirror.refresh();
}
async connect() {
console.log("Markdown connect!", this.element);
if (this.element.parentNode?.querySelector(".editor-toolbar")) {
//already loaded, quit;
return;
}
this.addCSS();
await this.addJS();
const component_block = this.isInsideComponentBlock();
// some offloading of starting the MDE, because it is slow on Chrome
if (component_block) {
if (this.isHiddenBlock()) {
const handler = () => {
this.getCheckboxThatShowsBlock()?.removeEventListener(
"change",
handler
);
setTimeout(() => this.init(), 1);
};
this.getCheckboxThatShowsBlock()?.addEventListener(
"change",
handler
);
} else {
await this.init();
}
} else {
await this.init();
}
}
async startMDE() {
if (this.mdeStarted) {
return;
}
this.sm = new (SimpleMDE as any)({
element: this.element,
autoDownloadFontAwesome: false,
spellChecker: false,
hideIcons: ["image", "preview", "side-by-side"],
status: ["words"],
autosave: { enabled: false },
forceSync: true, // for autosubmit to work
initialValue: this.element.value,
}) as simplemde;
// this.element.closest(".grow-wrap").setAttribute("data-turbo-permanent", "");
this.sm.codemirror.on("change", () => {
this.element.dispatchEvent(new Event("input"));
});
this.setupRefreshOnShow();
this.resizeObserver = new ResizeObserver(() => {
this.sm.codemirror.refresh();
});
const wrapper = (this.sm as any).element.closest(
".grow-wrap"
) as HTMLDivElement;
this.resizeObserver.observe(wrapper);
document.addEventListener(
"turbo:before-morph-element",
function (event: BeforeUnloadEvent) {
const target = event.target as HTMLDivElement;
// disallow morphing, but allow removing
if (
target == wrapper &&
(event as any).detail.newElement !== undefined
) {
event.preventDefault();
}
}
);
this.mdeStarted = true;
}
async init() {
this.intersectionObserver = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.intersectionRatio > 0.2) {
this.startMDE();
}
});
},
{
root: this.element.closest(".component-arguments"),
rootMargin: "0px",
threshold: 0.25,
}
);
this.intersectionObserver.observe(this.element);
}
isHiddenBlock() {
return !this.getCheckboxThatShowsBlock()?.checked;
}
isInsideComponentBlock(): false | HTMLDivElement {
return this.element.closest(".jdd-editor__component-block") as
| HTMLDivElement
| false;
}
getCheckboxThatShowsBlock(): HTMLInputElement | null {
const block = this.isInsideComponentBlock();
if (!block) {
return null;
}
return block.querySelector(".component-collapse-toggle");
}
setupRefreshOnShow() {
this.checkboxHandler = (e) => {
const target = e.target as HTMLInputElement;
if (target.checked) {
this.sm.codemirror.refresh();
}
};
this.getCheckboxThatShowsBlock()?.addEventListener(
"change",
this.checkboxHandler
);
}
disconnect() {
console.log("disconnecting", this.element);
this.getCheckboxThatShowsBlock()?.removeEventListener(
"change",
this.checkboxHandler
);
this.element
.closest(".grow-wrap")
?.removeAttribute("data-turbo-permanent");
this.resizeObserver?.unobserve((this.sm as any).element as HTMLElement);
this.sm.toTextArea();
}
}

File Metadata

Mime Type
text/x-java
Expires
Fri, Nov 28, 15:09 (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1075932
Default Alt Text
markdown-textarea.stimulus.ts (5 KB)

Event Timeline