11import Quill from "https://esm.sh/quill@2.0.3" ;
22import { toMarkdown as mdastUtilToMarkdown } from "https://esm.sh/mdast-util-to-markdown@2.1.2" ;
33
4+ /**
5+ * @typedef {Object } QuillAttributes
6+ * @property {boolean } [bold] - Whether the text is bold.
7+ * @property {boolean } [italic] - Whether the text is italic.
8+ * @property {string } [link] - URL if the text is a link.
9+ * @property {number } [header] - Header level (1-3).
10+ * @property {string } [list] - List type ('ordered' or 'bullet').
11+ * @property {boolean } [blockquote] - Whether the text is in a blockquote.
12+ * @property {string } [code-block] - Code language if in a code block.
13+ * @property {string } [alt] - Alt text for images.
14+ */
15+
16+ /**
17+ * @typedef {Object } QuillOperation
18+ * @property {string|Object } [insert] - Content to insert (string or object with image URL).
19+ * @property {number } [delete] - Number of characters to delete.
20+ * @property {number } [retain] - Number of characters to retain.
21+ * @property {QuillAttributes } [attributes] - Formatting attributes.
22+ */
23+
24+ /**
25+ * @typedef {Object } QuillDelta
26+ * @property {Array<QuillOperation> } ops - Array of operations in the delta.
27+ */
28+
429/**
530 * Converts Quill Delta object to a Markdown string using mdast.
6- * @param {object } delta - Quill Delta object (https://quilljs.com/docs/delta/).
31+ * @param {QuillDelta } delta - Quill Delta object (https://quilljs.com/docs/delta/).
732 * @returns {string } - Markdown representation.
833 */
934function deltaToMarkdown ( delta ) {
@@ -26,6 +51,11 @@ function deltaToMarkdown(delta) {
2651 }
2752}
2853
54+ /**
55+ * Extracts plain text from a Quill Delta object.
56+ * @param {QuillDelta } delta - Quill Delta object.
57+ * @returns {string } - Plain text extracted from the delta.
58+ */
2959function extractPlainTextFromDelta ( delta ) {
3060 try {
3161 return delta . ops
@@ -60,7 +90,7 @@ function createAndReplaceTextarea(textarea) {
6090
6191/**
6292 * Returns the toolbar options array configured for Markdown compatibility.
63- * @returns {Array } - Quill toolbar options.
93+ * @returns {Array<Array<any>> } - Quill toolbar options.
6494 */
6595function getMarkdownToolbarOptions ( ) {
6696 return [
@@ -75,7 +105,7 @@ function getMarkdownToolbarOptions() {
75105/**
76106 * Initializes a Quill editor instance on a given div.
77107 * @param {HTMLDivElement } editorDiv - The div element for the editor.
78- * @param {Array } toolbarOptions - The toolbar configuration.
108+ * @param {Array<Array<any>> } toolbarOptions - The toolbar configuration.
79109 * @param {string } initialValue - The initial content for the editor.
80110 * @returns {Quill } - The initialized Quill instance.
81111 */
@@ -94,9 +124,10 @@ function initializeQuillEditor(editorDiv, toolbarOptions, initialValue) {
94124
95125/**
96126 * Attaches a submit event listener to the form to update the hidden textarea.
97- * @param {HTMLFormElement } form - The form containing the editor.
127+ * @param {HTMLFormElement|null } form - The form containing the editor.
98128 * @param {HTMLTextAreaElement } textarea - The original (hidden) textarea.
99129 * @param {Quill } quill - The Quill editor instance.
130+ * @returns {void }
100131 */
101132function updateTextareaOnSubmit ( form , textarea , quill ) {
102133 if ( ! form ) {
@@ -113,13 +144,23 @@ function updateTextareaOnSubmit(form, textarea, quill) {
113144 } ) ;
114145}
115146
147+ /**
148+ * Loads the Quill CSS stylesheet.
149+ * @returns {void }
150+ */
116151function loadQuillStylesheet ( ) {
117152 const link = document . createElement ( "link" ) ;
118153 link . rel = "stylesheet" ;
119154 link . href = "https://esm.sh/quill@2.0.3/dist/quill.snow.css" ;
120155 document . head . appendChild ( link ) ;
121156}
122157
158+ /**
159+ * Handles errors during editor initialization.
160+ * @param {HTMLTextAreaElement } textarea - The textarea that failed initialization.
161+ * @param {Error } error - The error that occurred.
162+ * @returns {void }
163+ */
123164function handleEditorInitError ( textarea , error ) {
124165 console . error ( "Failed to initialize Quill for textarea:" , textarea , error ) ;
125166 textarea . style . display = "" ;
@@ -129,6 +170,12 @@ function handleEditorInitError(textarea, error) {
129170 textarea . parentNode . insertBefore ( errorMsg , textarea . nextSibling ) ;
130171}
131172
173+ /**
174+ * Sets up a single editor for a textarea.
175+ * @param {HTMLTextAreaElement } textarea - The textarea to replace with an editor.
176+ * @param {Array<Array<any>> } toolbarOptions - The toolbar configuration.
177+ * @returns {boolean } - Whether the setup was successful.
178+ */
132179function setupSingleEditor ( textarea , toolbarOptions ) {
133180 if ( textarea . dataset . quillInitialized === "true" ) {
134181 return false ;
@@ -152,6 +199,10 @@ function setupSingleEditor(textarea, toolbarOptions) {
152199 }
153200}
154201
202+ /**
203+ * Initializes Quill editors for all textareas in the document.
204+ * @returns {void }
205+ */
155206function initializeEditors ( ) {
156207 loadQuillStylesheet ( ) ;
157208
@@ -177,9 +228,30 @@ function initializeEditors() {
177228}
178229
179230// MDAST conversion functions
231+ /**
232+ * @typedef {Object } MdastNode
233+ * @property {string } type - The type of the node.
234+ * @property {Array<MdastNode> } [children] - Child nodes.
235+ * @property {string } [value] - Text value for text nodes.
236+ * @property {string } [url] - URL for link and image nodes.
237+ * @property {string } [title] - Title for image nodes.
238+ * @property {string } [alt] - Alt text for image nodes.
239+ * @property {number } [depth] - Depth for heading nodes.
240+ * @property {boolean } [ordered] - Whether the list is ordered.
241+ * @property {boolean } [spread] - Whether the list is spread.
242+ * @property {string } [lang] - Language for code blocks.
243+ */
244+
245+ /**
246+ * Converts a Quill Delta to a MDAST (Markdown Abstract Syntax Tree).
247+ * @param {QuillDelta } delta - The Quill Delta to convert.
248+ * @returns {MdastNode } - The root MDAST node.
249+ */
180250function deltaToMdast ( delta ) {
181251 const mdast = createRootNode ( ) ;
252+ /** @type {MdastNode|null } */
182253 let currentParagraph = null ;
254+ /** @type {MdastNode|null } */
183255 let currentList = null ;
184256 let textBuffer = "" ;
185257
@@ -239,24 +311,42 @@ function deltaToMdast(delta) {
239311 return mdast ;
240312}
241313
314+ /**
315+ * Creates a root MDAST node.
316+ * @returns {MdastNode } - The root node.
317+ */
242318function createRootNode ( ) {
243319 return {
244320 type : "root" ,
245321 children : [ ] ,
246322 } ;
247323}
248324
325+ /**
326+ * Creates a paragraph MDAST node.
327+ * @returns {MdastNode } - The paragraph node.
328+ */
249329function createParagraphNode ( ) {
250330 return {
251331 type : "paragraph" ,
252332 children : [ ] ,
253333 } ;
254334}
255335
336+ /**
337+ * Checks if an operation is an image insertion.
338+ * @param {Object } op - The operation to check.
339+ * @returns {boolean } - Whether the operation is an image insertion.
340+ */
256341function isImageInsert ( op ) {
257342 return typeof op . insert === "object" && op . insert . image ;
258343}
259344
345+ /**
346+ * Creates an image MDAST node.
347+ * @param {Object } op - The operation containing the image.
348+ * @returns {MdastNode } - The image node.
349+ */
260350function createImageNode ( op ) {
261351 return {
262352 type : "image" ,
@@ -266,6 +356,12 @@ function createImageNode(op) {
266356 } ;
267357}
268358
359+ /**
360+ * Creates a text MDAST node with optional formatting.
361+ * @param {string } text - The text content.
362+ * @param {Object } attributes - The formatting attributes.
363+ * @returns {MdastNode } - The formatted text node.
364+ */
269365function createTextNode ( text , attributes ) {
270366 let node = {
271367 type : "text" ,
@@ -291,13 +387,28 @@ function createTextNode(text, attributes) {
291387 return node ;
292388}
293389
390+ /**
391+ * Wraps a node with a formatting container.
392+ * @param {MdastNode } node - The node to wrap.
393+ * @param {string } type - The type of container.
394+ * @returns {MdastNode } - The wrapped node.
395+ */
294396function wrapNodeWith ( node , type ) {
295397 return {
296398 type : type ,
297399 children : [ node ] ,
298400 } ;
299401}
300402
403+ /**
404+ * Processes a line break in the Delta.
405+ * @param {MdastNode } mdast - The root MDAST node.
406+ * @param {MdastNode|null } currentParagraph - The current paragraph being built.
407+ * @param {Object } attributes - The attributes for the line.
408+ * @param {string } textBuffer - The text buffer for the current line.
409+ * @param {MdastNode|null } currentList - The current list being built.
410+ * @returns {void }
411+ */
301412function processLineBreak (
302413 mdast ,
303414 currentParagraph ,
@@ -323,6 +434,13 @@ function processLineBreak(
323434 }
324435}
325436
437+ /**
438+ * Handles an empty line with special attributes.
439+ * @param {MdastNode } mdast - The root MDAST node.
440+ * @param {Object } attributes - The attributes for the line.
441+ * @param {MdastNode|null } currentList - The current list being built.
442+ * @returns {void }
443+ */
326444function handleEmptyLineWithAttributes ( mdast , attributes , currentList ) {
327445 if ( attributes [ "code-block" ] ) {
328446 mdast . children . push ( createEmptyCodeBlock ( attributes ) ) ;
@@ -334,6 +452,11 @@ function handleEmptyLineWithAttributes(mdast, attributes, currentList) {
334452 }
335453}
336454
455+ /**
456+ * Creates an empty code block MDAST node.
457+ * @param {Object } attributes - The attributes for the code block.
458+ * @returns {MdastNode } - The code block node.
459+ */
337460function createEmptyCodeBlock ( attributes ) {
338461 return {
339462 type : "code" ,
@@ -343,6 +466,10 @@ function createEmptyCodeBlock(attributes) {
343466 } ;
344467}
345468
469+ /**
470+ * Creates an empty list item MDAST node.
471+ * @returns {MdastNode } - The list item node.
472+ */
346473function createEmptyListItem ( ) {
347474 return {
348475 type : "listItem" ,
@@ -351,13 +478,24 @@ function createEmptyListItem() {
351478 } ;
352479}
353480
481+ /**
482+ * Creates an empty blockquote MDAST node.
483+ * @returns {MdastNode } - The blockquote node.
484+ */
354485function createEmptyBlockquote ( ) {
355486 return {
356487 type : "blockquote" ,
357488 children : [ { type : "paragraph" , children : [ ] } ] ,
358489 } ;
359490}
360491
492+ /**
493+ * Processes a header line break.
494+ * @param {MdastNode } mdast - The root MDAST node.
495+ * @param {string } textBuffer - The text buffer for the current line.
496+ * @param {Object } attributes - The attributes for the line.
497+ * @returns {void }
498+ */
361499function processHeaderLineBreak ( mdast , textBuffer , attributes ) {
362500 const lines = textBuffer . split ( "\n" ) ;
363501
@@ -386,6 +524,13 @@ function processHeaderLineBreak(mdast, textBuffer, attributes) {
386524 }
387525}
388526
527+ /**
528+ * Processes a code block line break.
529+ * @param {MdastNode } mdast - The root MDAST node.
530+ * @param {string } textBuffer - The text buffer for the current line.
531+ * @param {Object } attributes - The attributes for the line.
532+ * @returns {void }
533+ */
389534function processCodeBlockLineBreak ( mdast , textBuffer , attributes ) {
390535 mdast . children . push ( {
391536 type : "code" ,
@@ -395,6 +540,13 @@ function processCodeBlockLineBreak(mdast, textBuffer, attributes) {
395540 } ) ;
396541}
397542
543+ /**
544+ * Ensures a list exists in the MDAST.
545+ * @param {MdastNode } mdast - The root MDAST node.
546+ * @param {Object } attributes - The attributes for the line.
547+ * @param {MdastNode|null } currentList - The current list being built.
548+ * @returns {MdastNode } - The list node.
549+ */
398550function ensureList ( mdast , attributes , currentList ) {
399551 if ( ! currentList || currentList . ordered !== ( attributes . list === "ordered" ) ) {
400552 const newList = {
@@ -409,6 +561,14 @@ function ensureList(mdast, attributes, currentList) {
409561 return currentList ;
410562}
411563
564+ /**
565+ * Processes a list line break.
566+ * @param {MdastNode } mdast - The root MDAST node.
567+ * @param {MdastNode } currentParagraph - The current paragraph being built.
568+ * @param {Object } attributes - The attributes for the line.
569+ * @param {MdastNode|null } currentList - The current list being built.
570+ * @returns {void }
571+ */
412572function processListLineBreak (
413573 mdast ,
414574 currentParagraph ,
@@ -426,6 +586,12 @@ function processListLineBreak(
426586 list . children . push ( listItem ) ;
427587}
428588
589+ /**
590+ * Processes a blockquote line break.
591+ * @param {MdastNode } mdast - The root MDAST node.
592+ * @param {MdastNode } currentParagraph - The current paragraph being built.
593+ * @returns {void }
594+ */
429595function processBlockquoteLineBreak ( mdast , currentParagraph ) {
430596 mdast . children . push ( {
431597 type : "blockquote" ,
@@ -435,5 +601,3 @@ function processBlockquoteLineBreak(mdast, currentParagraph) {
435601
436602// Main execution
437603document . addEventListener ( "DOMContentLoaded" , initializeEditors ) ;
438-
439- export { deltaToMdast } ;
0 commit comments