From bfafe34d5c79f30f274c66709775ed8b13a016c5 Mon Sep 17 00:00:00 2001 From: Hsieh Chin Fan Date: Thu, 10 Oct 2024 11:51:57 +0800 Subject: docs(jsdoc): update jsdoc --- src/Layout.mjs | 26 ++++++++++++++++------- src/MenuItem.mjs | 36 ++++++++++++++++++++++++-------- src/dumbymap.mjs | 18 +++++++++------- src/editor.mjs | 63 ++++++++++++++++++++++++++++++++++++++++++-------------- 4 files changed, 103 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/Layout.mjs b/src/Layout.mjs index 5236475..7b14926 100644 --- a/src/Layout.mjs +++ b/src/Layout.mjs @@ -2,13 +2,17 @@ import PlainDraggable from 'plain-draggable' import { onRemove, animateRectTransition } from './utils' /** - * Layout. Basic class for layout + * Basic class for layout */ export class Layout { /** - * constructor. + * Creates a new Layout instance * - * @param {} options + * @param {Object} options - The options for the layout + * @param {string} options.name - The name of the layout + * @param {Function} [options.enterHandler] - Handler called when entering the layout + * @param {Function} [options.leaveHandler] - Handler called when leaving the layout + * @throws {Error} If the layout name is not provided */ constructor (options = {}) { if (!options.name) throw Error('Layout name is not given') @@ -18,7 +22,9 @@ export class Layout { } /** - * valueOf. + * Returns the name of the layout + * + * @returns {string} The name of the layout */ valueOf = () => this.name } @@ -35,9 +41,12 @@ export class SideBySide extends Layout { name = 'side-by-side' /** - * enterHandler. + * Handler called when entering the Side-By-Side layout * - * @param {} + * @param {Object} options - The options object + * @param {HTMLElement} options.container - The main container element + * @param {HTMLElement} options.htmlHolder - The HTML content holder + * @param {HTMLElement} options.showcase - The showcase element */ enterHandler = ({ container, htmlHolder, showcase }) => { const bar = document.createElement('div') @@ -71,9 +80,10 @@ export class SideBySide extends Layout { } /** - * leaveHandler. + * Handler called when leaving the Side-By-Side layout * - * @param {} + * @param {Object} options - The options object + * @param {HTMLElement} options.container - The main container element */ leaveHandler = ({ container }) => { container.querySelector('.bar')?.remove() diff --git a/src/MenuItem.mjs b/src/MenuItem.mjs index 0fea539..8b54539 100644 --- a/src/MenuItem.mjs +++ b/src/MenuItem.mjs @@ -1,15 +1,28 @@ import { shiftByWindow } from './utils.mjs' /** - * Item. Basic Element for menu item + * @typedef {Object} RefLink + * @property {string} ref -- name of link + * @property {string} link -- content of link + * @property {string|null} title -- title of link + */ + +/** + * Basic Element for menu item * * @extends {window.HTMLDivElement} */ export class Item extends window.HTMLDivElement { /** - * constructor. + * Creates a new Item instance * - * @param {Object} + * @param {Object} options - The options for the item + * @param {string} [options.text] - The text content of the item + * @param {string} [options.innerHTML] - The HTML content of the item + * @param {string} [options.title] - The title attribute for the item + * @param {Function} [options.onclick] - The click event handler + * @param {string} [options.style] - The CSS style string + * @param {string[]} [options.className] - Additional CSS classes */ constructor ({ text, innerHTML, title, onclick, style, className }) { super() @@ -30,15 +43,18 @@ export class Item extends window.HTMLDivElement { window.customElements.define('menu-item', Item, { extends: 'div' }) /** - * Folder. Basic Element for menu item, it generate submenu on hover + * Basic Element for menu item that generates a submenu on hover * * @extends {window.HTMLDivElement} */ export class Folder extends window.HTMLDivElement { /** - * constructor. + * Creates a new Folder instance * - * @param {} + * @param {Object} options - The options for the folder + * @param {string} [options.text] - The text content of the folder + * @param {string} [options.innerHTML] - The HTML content of the folder + * @param {Item[]} options.items - The submenu items */ constructor ({ text, innerHTML, items }) { super() @@ -67,9 +83,11 @@ export class Folder extends window.HTMLDivElement { window.customElements.define('menu-folder', Folder, { extends: 'div' }) /** - * pickMapItem. + * Creates a menu item for picking a map * - * @param {Function[]} options.utils + * @param {Object} options - The options object + * @param {Object} options.utils - Utility functions + * @returns {Folder} A Folder instance for picking a map */ export const pickMapItem = ({ utils }) => new Folder({ @@ -372,7 +390,7 @@ export const restoreCamera = map => * addRefLink. replace selected text into markdown link by reference style links * * @param {CodeMirror} cm - * @param {Object[]} refLinks -- object for { ref, link } + * @param {RefLink[]} refLinks */ export const addRefLink = (cm, refLinks) => new Folder({ diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs index ac8392c..b01c73e 100644 --- a/src/dumbymap.mjs +++ b/src/dumbymap.mjs @@ -26,10 +26,11 @@ const defaultLayouts = [ const mapCache = {} /** - * markdown2HTML. + * Converts Markdown content to HTML and prepares it for DumbyMap rendering * - * @param {HTMLElement} container -- Target Element to include generated HTML contents - * @param {String} mdContent -- Texts in Markdown + * @param {HTMLElement} container - Target Element to include generated HTML contents + * @param {string} mdContent - Texts in Markdown format + * @returns {Object} An object representing the DumbyMap instance */ export const markdown2HTML = (container, mdContent) => { /** Prepare Elements for Container */ @@ -106,11 +107,12 @@ export const markdown2HTML = (container, mdContent) => { } /** - * generateMaps. + * Generates maps based on the provided configuration * - * @param {HTMLElement} container -- Target Element contains HTML contents - * @param {Number} options.delay -- delay of map generation, milliseconds - * @return {Object} dumbymap -- Include and Elements and Methods about managing contents + * @param {HTMLElement} container - The container element for the maps + * @param {Object} options - Configuration options + * @param {number} [options.delay=1000] - Delay before rendering maps (in milliseconds) + * @param {Function} options.mapCallback - Callback function to be called after map rendering */ export const generateMaps = (container, { layouts = [], delay, renderCallback } = {}) => { /** Prepare Contaner/HTML Holder/Showcase */ @@ -509,4 +511,4 @@ export const generateMaps = (container, { layouts = [], delay, renderCallback } ) return Object.seal(dumbymap) -} +} \ No newline at end of file diff --git a/src/editor.mjs b/src/editor.mjs index 8cb7045..5c65af4 100644 --- a/src/editor.mjs +++ b/src/editor.mjs @@ -1,5 +1,4 @@ /* global EasyMDE */ -/* eslint no-undef: "error" */ import { markdown2HTML, generateMaps } from './dumbymap' import { defaultAliases, parseConfigsFromYaml } from 'mapclay' import * as menuItem from './MenuItem' @@ -7,18 +6,41 @@ import { addAnchorByPoint } from './dumbyUtils.mjs' import { shiftByWindow } from './utils.mjs' import LeaderLine from 'leader-line' +/** + * @typedef {Object} RefLink + * @property {string} ref -- name of link + * @property {string} link -- content of link + * @property {string|null} title -- title of link + */ + // Set up Containers {{{ /** Variables about dumbymap and editor **/ const url = new URL(window.location) const context = document.querySelector('[data-mode]') const dumbyContainer = document.querySelector('.DumbyMap') +dumbyContainer.dataset.scrollLine = '' const textArea = document.querySelector('.editor textarea') let dumbymap -const refLinkPattern = /\[([^\x5B\x5D]+)\]:\s+(.+)/ +/** Variables about Reference Style Links in Markdown */ +const refLinkPattern = /\[([^\x5B\x5D]+)\]:\s+(\S+)(\s["'](\S+)["'])?/ let refLinks = [] + +/** + * Validates if the given anchor name is unique + * + * @param {string} anchorName - The anchor name to validate + * @returns {boolean} True if the anchor name is unique, false otherwise + */ const validateAnchorName = anchorName => !refLinks.find(obj => obj.ref === anchorName) + +/** + * Appends a reference link to the CodeMirror instance + * + * @param {CodeMirror} cm - The CodeMirror instance + * @param {RefLink} refLink - The reference link to append + */ const appendRefLink = (cm, refLink) => { const { ref, link, title } = refLink let refLinkString = `\n[${ref}]: ${link} "${title ?? ''}"` @@ -46,7 +68,7 @@ new window.MutationObserver(() => { attributeOldValue: true, }) /** - * toggleEditing: toggle editing mode + * Toggles the editing mode */ const toggleEditing = () => { const mode = context.dataset.mode @@ -236,12 +258,15 @@ const editor = new EasyMDE({ /** CodeMirror Instance **/ const cm = editor.codemirror -/** Ref Links **/ +/** + * getRefLinks from contents of editor + * @return {RefLink[]} refLinks + */ const getRefLinks = () => editor.value() .split('\n') .map(line => { - const [, ref, link] = line.match(refLinkPattern) ?? [] - return { ref, link } + const [, ref, link,, title] = line.match(refLinkPattern) ?? [] + return { ref, link, title } }) .filter(({ ref, link }) => ref && link) @@ -284,8 +309,12 @@ if (url.searchParams.get('content') === 'tutorial') { // }}} // Set up logic about editor content {{{ -/** Sync scroll from HTML to CodeMirror **/ -const htmlOnScroll = (ele) => () => { +/** + * updateScrollLine. Update data attribute by scroll on given element + * + * @param {HTMLElement} ele + */ +const updateScrollLine = (ele) => () => { if (textArea.dataset.scrollLine) return const threshold = ele.scrollTop + window.innerHeight / 2 + 30 @@ -300,14 +329,14 @@ const htmlOnScroll = (ele) => () => { const offset = (line.offsetTop + block.offsetTop - ele.scrollTop) if (linenumber) { - dumbyContainer.dataset.scrollLine = linenumber + '/' + offset + ele.closest('[data-scroll-line]').dataset.scrollLine = linenumber + '/' + offset } } new window.MutationObserver(() => { clearTimeout(dumbyContainer.timer) dumbyContainer.timer = setTimeout( - () => delete dumbyContainer.dataset.scrollLine, + () => { dumbyContainer.dataset.scrollLine = '' }, 50, ) @@ -324,7 +353,11 @@ new window.MutationObserver(() => { attributeFilter: ['data-scroll-line'], }) -const setScrollLine = () => { +/** + * updateScrollLineByCodeMirror. + * @param {CodeMirror} cm + */ +const updateCMScrollLine = (cm) => { if (dumbyContainer.dataset.scrollLine) return const lineNumber = cm.getCursor()?.line ?? @@ -332,14 +365,14 @@ const setScrollLine = () => { textArea.dataset.scrollLine = lineNumber } cm.on('scroll', () => { - if (cm.hasFocus()) setScrollLine() + if (cm.hasFocus()) updateCMScrollLine(cm) }) /** Sync scroll from CodeMirror to HTML **/ new window.MutationObserver(() => { clearTimeout(textArea.timer) textArea.timer = setTimeout( - () => delete textArea.dataset.scrollLine, + () => { textArea.dataset.scrollLine = '' }, 1000, ) @@ -486,7 +519,7 @@ const updateDumbyMap = (callback = null) => { dumbymap = generateMaps(dumbyContainer) // Set onscroll callback const htmlHolder = dumbymap.htmlHolder - htmlHolder.onscroll = htmlOnScroll(htmlHolder) + htmlHolder.onscroll = updateScrollLine(htmlHolder) // Set oncontextmenu callback dumbymap.utils.setContextMenu(menuForEditor) @@ -497,7 +530,7 @@ updateDumbyMap() // Re-render HTML by editor content cm.on('change', (_, change) => { updateDumbyMap(() => { - setScrollLine() + updateCMScrollLine(cm) }) addClassToCodeLines() completeForCodeBlock(change) -- cgit v1.2.3-70-g09d2