From dbd3b03ec842c446488135853ed380f5a75adb27 Mon Sep 17 00:00:00 2001 From: Hsieh Chin Fan Date: Fri, 4 Oct 2024 13:38:08 +0800 Subject: docs: add jsdoc --- src/Layout.mjs | 57 +++++++++++++++++++++++++++++++++++++ src/MenuItem.mjs | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/dumbyUtils.mjs | 28 +++++++++++++++++- src/dumbymap.mjs | 19 +++++++++++-- src/editor.mjs | 83 +++++++++++++++++++++++++++++++++++++++++++++++------- src/utils.mjs | 5 ++++ 6 files changed, 255 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/Layout.mjs b/src/Layout.mjs index 3c4ea3d..6bb6282 100644 --- a/src/Layout.mjs +++ b/src/Layout.mjs @@ -1,7 +1,15 @@ import PlainDraggable from 'plain-draggable' import { onRemove, animateRectTransition } from './utils' +/** + * Layout. Basic class for layout + */ export class Layout { + /** + * constructor. + * + * @param {} options + */ constructor (options = {}) { if (!options.name) throw Error('Layout name is not given') this.name = options.name @@ -9,12 +17,28 @@ export class Layout { this.leaveHandler = options.leaveHandler } + /** + * valueOf. + */ valueOf = () => this.name } +/** + * Side-By-Side Layout, HTML content and Showcase show on left/right side + * + * @extends {Layout} + */ export class SideBySide extends Layout { + /** + * @type {} + */ name = 'side-by-side' + /** + * enterHandler. + * + * @param {} + */ enterHandler = ({ container, htmlHolder, showcase }) => { const bar = document.createElement('div') bar.className = 'bar' @@ -46,20 +70,43 @@ export class SideBySide extends Layout { onRemove(bar, () => draggable.remove()) } + /** + * leaveHandler. + * + * @param {} + */ leaveHandler = ({ container }) => { container.querySelector('.bar')?.remove() } } +/** + * Overlay Layout, Showcase occupies viewport, and HTML content becomes draggable blocks + * + * @extends {Layout} + */ export class Overlay extends Layout { + /** + * @type {} + */ name = 'overlay' + /** + * saveLeftTopAsData. + * + * @param {} element + */ saveLeftTopAsData = element => { const { left, top } = element.getBoundingClientRect() element.setAttribute('data-left', left) element.setAttribute('data-top', top) } + /** + * addDraggable. + * + * @param {} element + */ addDraggable = element => { // Make sure current element always on top const siblings = Array.from( @@ -119,6 +166,11 @@ export class Overlay extends Layout { }) } + /** + * enterHandler. + * + * @param {} + */ enterHandler = ({ htmlHolder, blocks }) => { // FIXME It is weird rect from this method and this scope are different... blocks.forEach(this.saveLeftTopAsData) @@ -197,6 +249,11 @@ export class Overlay extends Layout { }) } + /** + * leaveHandler. + * + * @param {} + */ leaveHandler = ({ htmlHolder, blocks }) => { const resumeFromDraggable = block => { const draggableContainer = block.closest('.draggable-block') diff --git a/src/MenuItem.mjs b/src/MenuItem.mjs index fe0bd99..864bc05 100644 --- a/src/MenuItem.mjs +++ b/src/MenuItem.mjs @@ -1,6 +1,16 @@ import { shiftByWindow } from './utils.mjs' +/** + * Item. Basic Element for menu item + * + * @extends {window.HTMLDivElement} + */ export class Item extends window.HTMLDivElement { + /** + * constructor. + * + * @param {} + */ constructor ({ text, innerHTML, onclick, style, className, onmouseover }) { super() this.innerHTML = innerHTML ?? text @@ -18,7 +28,17 @@ 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 + * + * @extends {window.HTMLDivElement} + */ export class Folder extends window.HTMLDivElement { + /** + * constructor. + * + * @param {} + */ constructor ({ text, innerHTML, items }) { super() this.innerHTML = innerHTML ?? text @@ -44,6 +64,11 @@ export class Folder extends window.HTMLDivElement { } window.customElements.define('menu-folder', Folder, { extends: 'div' }) +/** + * pickMapItem. + * + * @param {Function[]} options.utils + */ export const pickMapItem = ({ utils }) => new Folder({ innerHTML: 'Maps(Tab)', @@ -59,6 +84,12 @@ export const pickMapItem = ({ utils }) => ) }) +/** + * pickBlockItem. + * + * @param {HTMLElement[]} options.blocks + * @param {Function[]} options.utils + */ export const pickBlockItem = ({ blocks, utils }) => new Folder({ innerHTML: 'Blocks(n/p)', @@ -92,6 +123,12 @@ export const pickBlockItem = ({ blocks, utils }) => ) }) +/** + * pickLayoutItem. + * + * @param {HTEMElement} options.container + * @param {String[]} options.layouts + */ export const pickLayoutItem = ({ container, layouts }) => new Folder({ innerHTML: 'Layouts(x)', @@ -115,6 +152,12 @@ export const pickLayoutItem = ({ container, layouts }) => ] }) +/** + * addGeoLink. + * + * @param {Function[]} options.utils + * @param {Range} range + */ export const addGeoLink = ({ utils }, range) => new Item({ text: 'Add GeoLink', @@ -138,7 +181,17 @@ export const addGeoLink = ({ utils }, range) => } }) +/** + * Suggestion. Menu Item for editor suggestion + * + * @extends {Item} + */ export class Suggestion extends Item { + /** + * constructor. + * + * @param {} + */ constructor ({ text, replace, cm }) { super({ text }) this.replace = replace @@ -165,6 +218,13 @@ export class Suggestion extends Item { } window.customElements.define('menu-item-suggestion', Suggestion, { extends: 'div' }) +/** + * renderResults. return a menu item for reporting render results + * + * @param {Object} options.modal -- Ojbect of plain-modal + * @param {HTMLElement} options.modalContent + * @param {HTMLElement} map -- Rendered map element + */ export const renderResults = ({ modal, modalContent }, map) => new Item({ text: 'Render Results', @@ -215,6 +275,13 @@ export const renderResults = ({ modal, modalContent }, map) => } }) +/** + * printObject. Generate
in parent element based on Ojbect properties + * + * @param {Object} obj + * @param {HTMLElement} parentElement + * @param {String} name + */ function printObject (obj, parentElement, name = null) { // Create
and inside const detailsEle = document.createElement('details') @@ -255,12 +322,22 @@ function printObject (obj, parentElement, name = null) { } } +/** + * toggleBlockFocus. Menu Item for toggling focus on a block + * + * @param {HTMLElement} block + */ export const toggleBlockFocus = block => new Item({ text: 'Toggle Focus', onclick: () => block.classList.toggle('focus') }) +/** + * toggleMapFocus. Menu Item for toggling focus on a map + * + * @param {HTMLElement} map + */ export const toggleMapFocus = map => new Item({ text: 'Toggle Focus', diff --git a/src/dumbyUtils.mjs b/src/dumbyUtils.mjs index b0845bd..5182a8f 100644 --- a/src/dumbyUtils.mjs +++ b/src/dumbyUtils.mjs @@ -1,5 +1,10 @@ import LeaderLine from 'leader-line' +/** + * focusNextMap. + * + * @param {Boolean} reverse -- focus previous map + */ export function focusNextMap (reverse = false) { const renderedList = this.utils.renderedMaps() const index = renderedList.findIndex(e => e.classList.contains('focus')) @@ -10,6 +15,11 @@ export function focusNextMap (reverse = false) { nextMap.scrollIntoView({ behavior: 'smooth' }) } +/** + * focusNextBlock. + * + * @param {Boolean} reverse -- focus previous block + */ export function focusNextBlock (reverse = false) { const blocks = this.blocks.filter(b => b.checkVisibility({ @@ -27,7 +37,12 @@ export function focusNextBlock (reverse = false) { scrollToBlock(nextBlock) } -// Consider block is bigger then viewport height +/** + * scrollToBlock. Smoothly scroll to target block. + * If block is bigger than viewport, then pick strategy wisely. + * + * @param {HTMLElement} block -- Scroll to this element + */ export const scrollToBlock = block => { const parentRect = block.parentElement.getBoundingClientRect() const scrollBlock = @@ -37,10 +52,18 @@ export const scrollToBlock = block => { block.scrollIntoView({ behavior: 'smooth', block: scrollBlock }) } +/** + * focusDelay. Delay of throttle, value changes by cases + */ export function focusDelay () { return window.window.getComputedStyle(this.showcase).display === 'none' ? 50 : 300 } +/** + * switchToNextLayout. + * + * @param {Boolean} reverse -- Switch to previous one + */ export function switchToNextLayout (reverse = false) { const layouts = this.layouts const currentLayoutName = this.container.getAttribute('data-layout') @@ -54,6 +77,9 @@ export function switchToNextLayout (reverse = false) { this.container.setAttribute('data-layout', nextLayout.name) } +/** + * removeBlockFocus. + */ export function removeBlockFocus () { this.blocks.forEach(b => b.classList.remove('focus')) } diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs index 0c6f0be..744d216 100644 --- a/src/dumbymap.mjs +++ b/src/dumbymap.mjs @@ -21,6 +21,12 @@ const layouts = [ ] const mapCache = {} +/** + * markdown2HTML. + * + * @param {HTMLElement} container -- Target Element to include generated HTML contents + * @param {String} mdContent -- Texts in Markdown + */ export const markdown2HTML = (container, mdContent) => { // Render: Markdown -> HTML {{{ container.replaceChildren() @@ -83,7 +89,7 @@ export const markdown2HTML = (container, mdContent) => { state.tokens.push(new state.Token('dumby_block_close', '', -1)) }) - const contentWithToc = '${toc}\n\n\n' + mdContent // eslint-disable-line + const contentWithToc = '${toc}\n\n\n' + mdContent htmlHolder.innerHTML = md.render(contentWithToc) // TODO Do this in markdown-it @@ -96,6 +102,13 @@ export const markdown2HTML = (container, mdContent) => { return container // }}} } + +/** + * generateMaps. + * + * @param {HTMLElement} container -- Target Element contains HTML contents + * @param {Object} dumbymap -- Include and Elements and Methods about managing contents + */ export const generateMaps = (container, { delay, mapCallback }) => { container.classList.add('Dumby') container.removeAttribute('data-layout') @@ -159,7 +172,7 @@ export const generateMaps = (container, { delay, mapCallback }) => { const isAnchorPointedBy = link => anchor => { const mapContainer = anchor.closest('.mapclay') const isTarget = !link.targets || link.targets.includes(mapContainer.id) - return anchor.title === link.url.pathname && isTarget + return anchor.title === link.url.searchParams.get('text') && isTarget } const isAnchorVisible = anchor => { @@ -366,7 +379,7 @@ export const generateMaps = (container, { delay, mapCallback }) => { mapCallback?.call(this, mapElement) const markers = geoLinks .filter(link => !link.targets || link.targets.includes(mapElement.id)) - .map(link => ({ xy: link.xy, title: link.url.pathname })) + .map(link => ({ xy: link.xy, title: link.url.searchParams.get('text') })) // FIXME Here may cause error // Add markers with Geolinks diff --git a/src/editor.mjs b/src/editor.mjs index 36f0fdc..e9ee84a 100644 --- a/src/editor.mjs +++ b/src/editor.mjs @@ -23,6 +23,9 @@ new window.MutationObserver(() => { attributeFilter: ['data-mode'], attributeOldValue: true }) +/** + * toggle editing mode + */ const toggleEditing = () => { const mode = context.getAttribute('data-mode') context.setAttribute('data-mode', mode === 'editing' ? '' : 'editing') @@ -128,6 +131,11 @@ const editor = new EasyMDE({ const cm = editor.codemirror +/** + * get state of website from hash string + * + * @param {String} hash + */ const getStateFromHash = hash => { const hashValue = hash.substring(1) const stateString = decodeURIComponent(hashValue) @@ -138,6 +146,11 @@ const getStateFromHash = hash => { } } +/** + * get editor content from hash string + * + * @param {} hash + */ const getContentFromHash = hash => { const state = getStateFromHash(hash) return state.content @@ -154,7 +167,13 @@ if (contentFromHash) { } // }}} // Set up logic about editor content {{{ -const afterMapRendered = _ => { +/** + * afterMapRendered. Callback of map rendered + * + * @param {HTEMLElement} map + */ +const afterMapRendered = map => { + console.info(map) // mapHolder.oncontextmenu = (event) => { // event.preventDefault() // const lonLat = mapHolder.renderer.unproject([event.x, event.y]) @@ -164,7 +183,9 @@ const afterMapRendered = _ => { markdown2HTML(HtmlContainer, editor.value()) dumbymap = generateMaps(HtmlContainer, afterMapRendered) -// Quick hack to style lines inside code block +/** + * addClassToCodeLines. Quick hack to style lines inside code block + */ const addClassToCodeLines = () => { const lines = cm.getLineHandle(0).parent.lines let insideCodeBlock = false @@ -180,6 +201,11 @@ const addClassToCodeLines = () => { } addClassToCodeLines() +/** + * completeForCodeBlock. + * + * @param {Object} change -- codemirror change object + */ const completeForCodeBlock = change => { const line = change.to.line if (change.origin === '+input') { @@ -234,6 +260,9 @@ const completeForCodeBlock = change => { // } // })() +/** + * update content of HTML about Dumbymap + */ const updateDumbyMap = () => { markdown2HTML(HtmlContainer, editor.value()) // TODO Test if generate maps intantly is OK with map cache @@ -309,7 +338,11 @@ fetch(defaultApply) }) .catch(err => console.warn(`Fail to get aliases from ${defaultApply}`, err)) // }}} -// FUNCTION: Check if current token is inside code block {{{ +/** + * insideCodeblockForMap. Check if current token is inside code block {{{ + * + * @param {} anchor + */ const insideCodeblockForMap = anchor => { const token = cm.getTokenAt(anchor) const insideCodeBlock = @@ -330,7 +363,11 @@ const insideCodeblockForMap = anchor => { return false } // }}} -// FUNCTION: Get Renderer by cursor position in code block {{{ +/** + * getLineWithRenderer. Get Renderer by cursor position in code block {{{ + * + * @param {Object} anchor -- Codemirror Anchor Object + */ const getLineWithRenderer = anchor => { const currentLine = anchor.line if (!cm.getLine) return null @@ -365,7 +402,12 @@ const getLineWithRenderer = anchor => { return null } // }}} -// FUNCTION: Return suggestions for valid options {{{ +/** + * getSuggestionsForOptions. Return suggestions for valid options {{{ + * + * @param {Boolean} optionTyped + * @param {Object[]} validOptions + */ const getSuggestionsForOptions = (optionTyped, validOptions) => { let suggestOptions = [] @@ -389,7 +431,11 @@ const getSuggestionsForOptions = (optionTyped, validOptions) => { ) } // }}} -// FUNCTION: Return suggestion for example of option value {{{ +/** + * getSuggestionFromMapOption. Return suggestion for example of option value {{{ + * + * @param {Object} option + */ const getSuggestionFromMapOption = option => { if (!option.example) return null @@ -404,7 +450,11 @@ const getSuggestionFromMapOption = option => { }) } // }}} -// FUNCTION: Return suggestions from aliases {{{ +/** + * getSuggestionsFromAliases. Return suggestions from aliases {{{ + * + * @param {Object} option + */ const getSuggestionsFromAliases = option => Object.entries(aliasesForMapOptions[option.valueOf()] ?? {})?.map(record => { const [alias, value] = record @@ -416,7 +466,11 @@ const getSuggestionsFromAliases = option => }) }) ?? [] // }}} -// FUCNTION: Handler for map codeblock {{{ +/** + * handleTypingInCodeBlock. Handler for map codeblock {{{ + * + * @param {Object} anchor -- Codemirror Anchor Object + */ const handleTypingInCodeBlock = anchor => { const text = cm.getLine(anchor.line) if (text.match(/^\s\+$/) && text.length % 2 !== 0) { @@ -429,7 +483,11 @@ const handleTypingInCodeBlock = anchor => { } } // }}} -// FUNCTION: get suggestions by current input {{{ +/** + * getSuggestions. Get suggestions by current input {{{ + * + * @param {Object} anchor -- Codemirror Anchor Object + */ const getSuggestions = anchor => { const text = cm.getLine(anchor.line) @@ -543,7 +601,12 @@ const getSuggestions = anchor => { return [] } // }}} -// {{{ FUNCTION: Show element about suggestions +/** + * addSuggestions. Show element about suggestions {{{ + * + * @param {Object} anchor -- Codemirror Anchor Object + * @param {Suggestion[]} suggestions + */ const addSuggestions = (anchor, suggestions) => { if (suggestions.length === 0) { menu.style.display = 'none' diff --git a/src/utils.mjs b/src/utils.mjs index c9a2457..ffd8978 100644 --- a/src/utils.mjs +++ b/src/utils.mjs @@ -88,6 +88,11 @@ export function throttle (func, delay) { } } +/** + * shiftByWindow. make sure HTMLElement inside viewport + * + * @param {HTMLElement} element + */ export const shiftByWindow = element => { const rect = element.getBoundingClientRect() const offsetX = window.innerWidth - rect.left - rect.width -- cgit v1.2.3-70-g09d2