From a38af7577b03339dafb13937ae5690e8af82cbcb Mon Sep 17 00:00:00 2001 From: Tsanie Date: Tue, 30 Jan 2024 17:28:18 +0800 Subject: [PATCH] change to jsdoc --- jsdoc-date.json | 22 ++ jsdoc.json | 23 ++ lib/ui/css/grid.scss | 1 + lib/ui/date.d.ts | 4 +- lib/ui/date.js | 114 ++++++++- lib/ui/dropdown.js | 21 ++ lib/ui/grid/column.js | 81 ++++++ lib/ui/grid/grid.d.ts | 5 +- lib/ui/grid/grid.js | 581 +++++++++++++++++++++++++++++++++++++++--- package-lock.json | 531 ++++++++++++++++++++++++++++++++++++++ package.json | 7 +- 11 files changed, 1347 insertions(+), 43 deletions(-) create mode 100644 jsdoc-date.json create mode 100644 jsdoc.json diff --git a/jsdoc-date.json b/jsdoc-date.json new file mode 100644 index 0000000..cf6e989 --- /dev/null +++ b/jsdoc-date.json @@ -0,0 +1,22 @@ +{ + "source": { + "include": ["lib/ui/date.js"], + "includePattern": "\\.js$", + "exclude": [] + }, + "plugins": ["plugins/markdown"], + "opts": { + "encoding": "utf8", + "destination": "./jsdoc/date", + "recurse": true, + "verbose": false, + "template": "node_modules/docdash", + "theme_opts": { + "default_theme": "light" + } + }, + "markdown": { + "hardwrap": false, + "idInHeadings": true + } +} \ No newline at end of file diff --git a/jsdoc.json b/jsdoc.json new file mode 100644 index 0000000..81092f5 --- /dev/null +++ b/jsdoc.json @@ -0,0 +1,23 @@ +{ + "source": { + "include": ["lib/ui/grid", "README.md"], + "includePattern": "\\.js$", + "exclude": [] + }, + "plugins": ["plugins/markdown"], + "opts": { + "encoding": "utf8", + "readme": "./README.md", + "destination": "./jsdoc/grid", + "recurse": true, + "verbose": false, + "template": "node_modules/docdash", + "theme_opts": { + "default_theme": "light" + } + }, + "markdown": { + "hardwrap": false, + "idInHeadings": true + } +} \ No newline at end of file diff --git a/lib/ui/css/grid.scss b/lib/ui/css/grid.scss index 5c492aa..eb08683 100644 --- a/lib/ui/css/grid.scss +++ b/lib/ui/css/grid.scss @@ -599,6 +599,7 @@ >.ui-sort-panel-grid { flex: 1 1 auto; position: relative; + height: calc(100% - 30px); } } } diff --git a/lib/ui/date.d.ts b/lib/ui/date.d.ts index e5e3715..fd93895 100644 --- a/lib/ui/date.d.ts +++ b/lib/ui/date.d.ts @@ -66,7 +66,7 @@ export class DateSelector { * // 控制台会输出:dateFrom.value = '2024-01-30', formatted: '1/30/2024' * ``` */ - static resolve(dom?: HTMLElement, trigger?: (date: Date) => void): HTMLElement; + static resolve(dom?: HTMLElement, trigger?: (this: DateSelector, date: Date) => void): HTMLElement; /** * 日期选择框构造函数 @@ -122,5 +122,5 @@ export class DateSelector { * @param date 日期值,或者经自定义参数中格式化函数格式后的值 * @eventProperty */ - onDateChanged?: (date: Date | any) => void; + onDateChanged?: (this: DateSelector, date: Date | any) => void; } \ No newline at end of file diff --git a/lib/ui/date.js b/lib/ui/date.js index 018efd2..c7542e2 100644 --- a/lib/ui/date.js +++ b/lib/ui/date.js @@ -1,5 +1,12 @@ import { createElement } from "../functions"; +/** + * 创建或转换日期选择框 + * @param {string} [min] - 最小可选日期 + * @param {string} [max] - 最大可选日期 + * @param {HTMLInputElement} [element] - 转换该元素为日期选择框 + * @returns {HTMLInputElement} 返回创建或转换的日期选择框 + */ export function createDateInput(min, max, element) { let date; if (element instanceof HTMLInputElement) { @@ -39,6 +46,17 @@ function resolveDate(s) { return new Date(s); } +/** + * 格式化日期为 M/d/yyyy 格式的字符串 + * @param {Date | number | string} date - 需要格式化的日期值,支持的格式如下: + * + * * `"2024-01-26"` + * * `"2024-01-26T00:00:00"` + * * `"1/26/2024"` + * * `"638418240000000000"` + * * `new Date('2024-01-26')` + * @returns {string} 返回格式化后的日期字符串 + */ export function formatDate(date) { date = resolveDate(date); if (date instanceof Date && !isNaN(date)) { @@ -47,13 +65,18 @@ export function formatDate(date) { return ''; } +/** + * 设置显示日期 + * @param {HTMLElement} element - 要设置显示日期的元素 + * @param {Date | number | string} val - 日期值,支持格式参见 {@linkcode formatDate} + */ export function setDateValue(element, val) { if (element.tagName === 'INPUT') { if (val === '') { element.value = ''; } else if (isNaN(val)) { - if (/^\d{4}-\d{2}-\d{2}$/.test(val)) { - element.value = val; + if (/^\d{4}-\d{2}-\d{2}/.test(val)) { + element.value = String(val).substring(0, 10); } else if (/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(val)) { element.value = toDateValue(new Date(val)); } else { @@ -70,6 +93,19 @@ export function setDateValue(element, val) { } } +/** + * 自定义日期格式化回调函数 + * @callback DateFormatterCallback + * @param {Date} date - 日期值 + * @returns {any} 返回格式化后的结果 + */ + +/** + * 从日期选择框获取日期值 + * @param {HTMLInputElement} element - 要获取的日期选择框 + * @param {DateFormatterCallback} [formatter] - 自定义格式化函数,传入参数为 `Date` 类型 + * @returns {string | any} 默认返回日期 `ticks` 的字符串 + */ export function getDateValue(element, formatter) { const date = element?.valueAsDate; if (date instanceof Date && !isNaN(date)) { @@ -85,19 +121,47 @@ export function getDateValue(element, formatter) { return ''; } +/** + * 日期选中触发的回调函数 + * @callback DateSelectedCallback + * @param {Date} date - 修改后的日期值 + * @this DateSelector + */ + +/** + * 日期选择框类 + * @class + */ export class DateSelector { _var = { - parent: null, options: null }; + /** + * 日期发生变化时触发的事件 + * @event + * @type {DateSelectedCallback} + */ onDateChanged; + /** + * 日期选择框构造函数 + * @constructor + * @param {object} [opts] - 日期选择框初始化参数 + * @param {boolean} [opts.enabled] - 是否可用 + * @param {string} [opts.minDate] - 最小可选择日期 + * @param {string} [opts.maxDate] - 最大可选择日期 + * @param {DateFormatterCallback} [opts.valueFormatter] - 自定义格式化函数 + */ constructor(opts) { - opts ??= {}; - this._var.options = opts; + this._var.options = opts ?? {}; } + /** + * 创建或转换日期选择框元素 + * @param {HTMLInputElement} [element] - 转换该元素为日期选择框 + * @returns {HTMLInputElement} 返回创建或转换的日期选择元素 + */ create(element) { const opts = this._var.options; const el = createDateInput(opts.minDate, opts.maxDate, element); @@ -117,24 +181,45 @@ export class DateSelector { return el; } + /** + * 获取日期选择框元素 + * @readonly + * @type {HTMLInputElement} + */ get element() { return this._var.el } + /** + * 获取或设置日期选择框是否启用 + * @type {boolean} + */ get enabled() { return !this._var.el.disabled } set enabled(flag) { this._var.el.disabled = flag === false; } + /** + * 获取格式化的日期值,或设置日期值,支持的格式参见 {@linkcode formatDate} + * @type {string | any} + */ get value() { return this._getDate(this._var.el.valueAsDate) } set value(val) { setDateValue(this._var.el, val); } + /** + * 获取或设置最小可选择日期 + * @type {string} + */ get minDate() { return this._var.el.min } set minDate(date) { this._var.el.min = date; this._var.options.minDate = date; } + /** + * 获取或设置最大可选择日期 + * @type {string} + */ get maxDate() { return this._var.el.max } set maxDate(date) { this._var.el.max = date; @@ -155,6 +240,25 @@ export class DateSelector { return null; } + /** + * 把父容器下所有匹配 `input[data-type="date"]` 的元素修改为统一的日期选择框

+ * 解析的属性为 `id`, `class`, `data-min`, `data-max`, `disabled` + * @static + * @param {HTMLElement} [dom=document.body] 父元素 + * @param {DateSelectedCallback} trigger 日期设置事件触发函数(上下文为触发设置日期的 `DateSelector` 实例) + * @example HTML + * + * @example 解析父容器 + * // 解析 document.body 下所有符合条件的元素,转换为日期选择框,第二个参数可选 + * DateSelector.resolve(document.body, function (date) { + * console.log(`element(#${this.element.id}), date changed to: ${formatDate(date)}`); + * // 当日期选择改变时,控制台将会输出:element(#dateFrom), date changed to: 1/30/2024 + * }); + * @example 其他地方调用时 + * const value = document.querySelector('#dateFrom').value; + * console.log(`dateFrom.value = '${value}', formatted: '${formatDate(value)}'`); + * // 控制台会输出:dateFrom.value = '2024-01-30', formatted: '1/30/2024' + */ static resolve(dom = document.body, trigger) { const dates = dom.querySelectorAll('input[data-type="date"]'); for (let dat of dates) { diff --git a/lib/ui/dropdown.js b/lib/ui/dropdown.js index 58e27ba..8bd72a2 100644 --- a/lib/ui/dropdown.js +++ b/lib/ui/dropdown.js @@ -82,6 +82,27 @@ function filterSource(searchkeys, textkey, key, source) { return source; } +/** + * 下拉列表参数对象 + * @typedef DropdownOptions + * @property {string} [textKey=text] - 文本关键字 + * @property {string} [valueKey=value] - 值关键字 + * @property {string} [htmlKey=html] - 源码显示的关键字 + * @property {number} [maxLength=500] - 最大输入长度 + * @property {boolean} [multiSelect] - 是否允许多选 + * @property {string} [selected] - 选中值 + * @property {string[]} [selectedList] - 选中的数组 + * @property {boolean} [disabled] - 是否禁用 + * @property {boolean} [input] - 是否支持输入 + * @property {boolean} [search] - 是否支持搜索 + * @property {string[]} [searchKeys] - 搜索的关键字数组 + * @property {string} [searchPlaceholder] - 搜索提示文本,默认值取语言资源 `searchHolder` "Search..." + * @property {number} [tabIndex] - 焦点索引 + * @property {string} [placeholder] - 输入框的提示文本 + * @property {boolean} [slideFixed] - 是否固定为向下展开 + * @property {HTMLElement} [wrapper] - 父元素,默认添加到头元素之后 + */ + export class Dropdown { _var = {}; // _var.options; diff --git a/lib/ui/grid/column.js b/lib/ui/grid/column.js index 8a00887..7af4691 100644 --- a/lib/ui/grid/column.js +++ b/lib/ui/grid/column.js @@ -7,15 +7,71 @@ import { Dropdown } from "../dropdown"; import { convertCssStyle } from "../extension"; import { createDateInput, formatDate, setDateValue, getDateValue } from "../date"; +/** + * 列定义基类 + * @class + */ export class GridColumn { + /** + * 创建显示单元格时调用的方法 + * @param {GridColumnDefinition} col - 列定义对象 + * @returns {HTMLElement} 返回创建的单元格元素 + * @virtual + */ static create() { return createElement('span'); } + /** + * 创建编辑单元格时调用的方法 + * + * 元素修改后设置行包装对象的 `__editing` 后,支持在离开编辑状态时及时触发 [leaveEdit]{@linkcode GridColumn.leaveEdit} 方法
+ * 更多例子参考代码中 {@linkcode GridDropdownColumn} 的实现。 + * @param {Function} trigger - 编辑事件回调函数,`e` 参数会传递给 [getValue]{@linkcode GridColumn.getValue} 方法 + * @param {GridColumnDefinition} col - 列定义对象 + * @param {HTMLElement} container - 父容器元素 + * @param {GridItemWrapper} vals - 行包装对象,其 `values` 属性为行数据对象 + * @returns {HTMLElement} 返回创建的编辑状态的单元格元素 + * @virtual + */ + static createEdit() { } + + /** + * 创建列头时调用的方法 + * @param {GridColumnDefinition} col - 列定义对象 + * @returns {HTMLElement} 返回创建的列头元素 + * @virtual + */ + static createCaption() { } + + /** + * 设置单元格值时调用的方法 + * @param {HTMLElement} element - 单元格元素 + * @param {(string | boolean | number)} val - 待设置的单元格值 + * @param {GridItemWrapper} vals - 行包装对象 + * @param {GridColumnDefinition} col - 列定义对象 + * @param {Grid} grid - Grid 对象 + * @virtual + */ static setValue(element, val) { element.innerText = val; } + /** + * 获取编辑状态单元格值时调用的方法 + * @param {any} `e` 由 [createEdit]{@linkcode GridColumn.createEdit} 方法中 `trigger` 函数传递来的对象 + * @param {GridColumnDefinition} col - 列定义对象 + * @returns {(string | boolean | number)} 返回单元格的值 + * @virtual + */ + static getValue() { } + + /** + * 设置单元格样式时调用的方法 + * @param {HTMLElement} element - 单元格元素 + * @param {object} style - 样式对象 + * @virtual + */ static setStyle(element, style) { // for (let css of Object.entries(style)) { // element.style.setProperty(css[0], css[1]); @@ -23,6 +79,12 @@ export class GridColumn { element.style.cssText = convertCssStyle(style); } + /** + * 设置单元格可用性时调用的方法 + * @param {HTMLElement} element - 单元格元素 + * @param {boolean} enabled - 启用值,为 `false` 时代表禁用 + * @virtual + */ static setEnabled(element, enabled) { const tooltip = element.querySelector('.ui-tooltip-wrapper'); if (tooltip != null) { @@ -30,10 +92,29 @@ export class GridColumn { } } + /** + * 单元格离开编辑元素时触发,需要由行包装对象的 `__editing` 来确定是否触发。 + * @param {HTMLElement} element - 单元格元素 + * @param {HTMLElement} container - 父容器元素 + * @virtual + */ + static leaveEdit() { } + static toString() { return '[object Column]' } } +/** + * 单行文本列 + * @extends GridColumn + */ export class GridInputColumn extends GridColumn { + /** + * 设置该类型是否支持触发 [onInputEnded]{@linkcode GridColumnDefinition.onInputEnded} 方法
+ * 该属性返回 `true` 后,在任意事件中修改行包装对象的 `__editing` 值,则会在行列元素变动时及时触发 [onInputEnded]{@linkcode GridColumnDefinition.onInputEnded} 方法,避免例如文本框还未触发 `onchange` 事件就被移除元素而导致的问题
+ * 更多例子参考代码中 {@linkcode GridInputColumn} 的实现 + * @readonly + * @type {boolean} + */ static get editing() { return true }; static createEdit(trigger, col, _wrapper, vals) { diff --git a/lib/ui/grid/grid.d.ts b/lib/ui/grid/grid.d.ts index 3522076..50743ec 100644 --- a/lib/ui/grid/grid.d.ts +++ b/lib/ui/grid/grid.d.ts @@ -2,11 +2,11 @@ import { GridColumnDefinition } from "./column" /** * 单元格点击回调函数 * - * @callback cellClickedCallback * @param {number} index - 点击的行索引 * @param {number} colIndex - 点击的列索引 * @returns {boolean} 返回 `false` 则取消事件冒泡 */ +declare function cellClickedCallback(index: number, colIndex: number): boolean; /** 列数据接口 */ interface GridItem { @@ -159,10 +159,9 @@ export class Grid { willSelect?: (index: number, colIndex: number) => boolean; /** * 单元格单击时触发,colIndex 为 -1 则表示点击的是行的空白处,返回 false 则取消事件冒泡 - * @property {cellClickedCallback} * @eventProperty */ - cellClicked?: (index: number, colIndex: number) => boolean; + cellClicked?: typeof cellClickedCallback; /** * 选中行发生变化时触发的事件 diff --git a/lib/ui/grid/grid.js b/lib/ui/grid/grid.js index 0cd2ce9..3291823 100644 --- a/lib/ui/grid/grid.js +++ b/lib/ui/grid/grid.js @@ -35,7 +35,7 @@ function indexOfParent(target) { return Array.prototype.indexOf.call(target.parentElement.children, target); } -const ColumnTypes = { +const ColumnTypeDefs = { 0: GridColumn, 1: GridInputColumn, 2: GridDropdownColumn, @@ -47,6 +47,246 @@ const ColumnTypes = { let r = lang; +/** + * 行数据接口 + * @typedef {object} GridItem + * @property {any} Value - 值 + * @property {string} DisplayValue - 显示值 + */ + +/** + * 行数据包装接口 + * @typedef GridItemWrapper + * @property {object} values - 真实数据对象 + * @property {(GridItem | any)} values.[key]] 数据属性 + * @property {object} source - 下拉数据源缓存对象 + * @property {GridSourceItem[]} source.[key]] 数据源 + */ + +/** + * 下拉框数据源接口 + * @typedef {object} GridSourceItem + * @property {string} value - 值 + * @property {string} text - 显示文本 + */ + +/** + * 行数据可用性回调函数 + * @callback GridItemBooleanCallback + * @param {GridItem} item - 行数据对象 + * @returns {boolean} 返回是否可用 + * @this GridColumnDefinition + */ + +/** + * 行数据过滤回调函数 + * @callback GridItemFilterCallback + * @param {GridItem} item - 行数据对象 + * @param {boolean} editing - 是否处于编辑状态 + * @param {HTMLElement} [body] - Grid 控件的 `` 部分 + * @this GridColumnDefinition + */ + +/** + * 行数据处理回调函数 + * @callback GridItemObjectCallback + * @param {GridItem} item - 行数据对象 + * @returns {object} 返回任意对象 + * @this GridColumnDefinition + */ + +/** + * 行数据字符串回调函数 + * @callback GridItemStringCallback + * @param {GridItem} item - 行数据对象 + * @returns {string} 返回字符串 + * @this GridColumnDefinition + */ + +/** + * 列过滤器数据源回调函数 + * @callback GridColumnFilterSourceCallback + * @param {GridColumnDefinition} col - 列定义对象 + * @returns {GridItem[]} 返回过滤器的数据数组 + * @this Grid + */ + +/** + * 行数据排序回调函数 + * @callback GridItemSortCallback + * @param {GridItem} a - 对比行数据1 + * @param {GridItem} b - 对比行数据2 + * @returns {number} 返回大小对比结果 + */ + +/** + * 下拉列表数据源回调函数 + * @callback GridDropdownSourceCallback + * @param {GridItem} item - 行数据对象 + * @returns {GridSourceItem[]} 行下拉列表数据源 + */ + +/** + * 列头复选框改变时的回调函数 + * @callback GridColumnCheckedCallback + * @param {GridColumnDefinition} col - 列定义对象 + * @param {boolean} flag - 是否选中 + * @this Grid + */ + +/** + * 单元格发生变化时的回调函数 + * @callback GridCellChangedCallback + * @param {GridItem} item - 行数据对象 + * @param {(boolean | string | number)} value - 修改后的值 + * @param {(boolean | string | number)} oldValue - 修改前的值 + * @param {any} [e] - 列修改事件传递过来的任意对象 + * @this Grid + */ + +/** + * 文本单元格输入完成时的回调函数 + * @callback GridCellInputEndedCallback + * @param {GridColumnDefinition} col - 列定义对象 + * @param {string} value - 修改后的文本框值 + * @this Grid + */ + +/** + * 列过滤点 `OK` 时的回调函数 + * @callback GridColumnFilterOkCallback + * @param {GridColumnDefinition} col - 列定义对象 + * @param {GridItem[]} selected - 选中的过滤项 + * @this Grid + */ + +/** + * 列过滤后的回调函数 + * @callback GridColumnFilteredCallback + * @param {GridColumnDefinition} col - 列定义对象 + * @this Grid + */ + +/** + * 下拉框列表展开时的回调函数 + * @callback GridColumnDropExpandedCallback + * @param {GridItem} item - 行数据对象 + * @param {Dropdown} drop - 拉框对象 + * @this GridColumnDefinition + */ + +/** + * 列定义接口 + * @typedef {object} GridColumnDefinition + * @property {string} key - 列关键字,默认以该关键字从行数据中提取单元格值,行数据的关键字属性值里包含 DisplayValue 则优先显示此值 + * @property {(GridColumnTypeEnum | GridColumn)} [type=Grid.ColumnTypes.Common] - 列的类型,可以为 {@linkcode GridColumn} 的子类,或者内置类型 {@linkcode GridColumnTypeEnum} + * @property {string} [caption] - 列标题文本 + * @property {object} [captionStyle] - 列标题的元素样式 + * @property {number} [width] - 大于 0 则设置为该宽度,否则根据列内容自动调整列宽 + * @property {("left" |"center" | "right")} [align=left] 列对齐方式 + * @property {(boolean | string | GridItemBooleanCallback)} [enabled] - 列是否可用(可编辑),允许以下类型 + * + * * `boolean` 则直接使用该值 + * * `string` 则以该值为关键字从行数据中取值作为判断条件 + * * `(item: GridItem) => boolean` 则调用该函数(上下文为列定义对象),以返回值作为判断条件 + * @property {GridItemFilterCallback} [filter] - 单元格取值采用该函数返回的值 + * @property {string} [text] - 单元格以该值填充内容,忽略filter与关键字属性 + * @property {boolean} [visible=true] - 列是否可见 + * @property {boolean} [resizable=true] - 列是否允许调整宽度 + * @property {boolean} [sortable=true] - 列是否允许排序 + * @property {boolean} [orderable=true] - 列是否允许重排顺序 + * @property {boolean} [allcheck=false] - 列为复选框类型时是否在列头增加全选复选框 + * @property {object} [css] - 单元格css样式对象(仅在重建行元素时读取) + * @property {GridItemObjectCallback} [styleFilter] - 根据返回值填充单元格样式(填充行列数据时读取) + * @property {GridItemStringCallback} [bgFilter] - 根据返回值设置单元格背景色 + * @property {object} [events] - 给单元格元素附加事件(事件函数上下文为数据行对象) + * @property {Function} events.[event]] - 事件回调函数 + * @property {(object | GridItemObjectCallback)} [attrs] - 根据返回值设置单元格元素的附加属性,允许直接设置对象也支持函数返回对象 + * @property {boolean} [allowFilter=false] - 是否允许进行列头过滤 + * @property {(GridItem[] | GridColumnFilterSourceCallback)} [filterSource] - 自定义列过滤器的数据源(函数上下文为Grid) + * @property {GridItemSortCallback} [sortFilter] - 自定义列排序函数 + * @property {DropdownOptions} [dropOptions] - 列为下拉列表类型时以该值设置下拉框的参数 + * @property {(GridSourceItem[] | GridDropdownSourceCallback | Promise)} [source] - 列为下拉列表类型时以该值设置下拉列表数据源,支持函数返回,也支持返回异步对象 + * @property {boolean} [sourceCache=false] - 下拉列表数据源是否缓存结果(即行数据未发生变化时仅从source属性获取一次值) + * @property {("fa-light" | "fa-regular" | "fa-solid")} [iconType=fa-light] - 列为图标类型时以该值设置图标样式(函数上下文为列定义对象) + * @property {(string | GridItemStringCallback)} [iconClassName] - 列为图标类型时以该值作为单元格元素的额外样式类型(函数上下文为列定义对象) + * @property {string} [dateMin] - 列为日期类型时以该值作为最小可选日期值 + * @property {string} [dateMax] - 列为日期类型时以该值作为最大可选日期值 + * @property {DateFormatterCallback} [dateValueFormatter] - 列为日期类型时自定义日期格式化函数 + * @property {(string | GridItemStringCallback)} [tooltip] - 以返回值额外设置单元格的tooltip(函数上下文为列定义对象) + * @property {GridColumnCheckedCallback} [onAllChecked] - 列头复选框改变时触发 + * @property {GridColumnDefinition} onAllChecked.col - 列定义对象 + * @property {boolean} onAllChecked.flag - 是否选中 + * @property {GridCellChangedCallback} [onChanged] - 单元格发生变化时触发 + * @property {GridCellInputEndedCallback} [onInputEnded] - 文本单元格在输入完成时触发的事件 + * @property {GridColumnFilterOkCallback} [onFilterOk] - 列过滤点击 `OK` 时触发的事件 + * @property {GridColumnFilteredCallback} [onFiltered] - 列过滤后触发的事件 + * @property {GridColumnDropExpandedCallback} [onDropExpanded] - 列为下拉框类型时在下拉列表展开时触发的事件 + */ + +/** + * 判断复选框列的回调函数 + * @callback ColumnTypesEnumIsCheckbox + * @param {number} type - 列类型 + * @returns {boolean} 返回是否为复选框列 + */ + +/** + * 列类型枚举 + * @enum {number} + */ +const GridColumnTypeEnum = { + /** 0 - 通用列(只读) */ + Common: 0, + /** 1 - 单行文本列 */ + Input: 1, + /** 2 - 下拉选择列 */ + Dropdown: 2, + /** 3 - 复选框列 */ + Checkbox: 3, + /** 4 - 图标列 */ + Icon: 4, + /** 5 - 多行文本列 */ + Text: 5, + /** 6 - 日期选择列 */ + Date: 6, + /** + * 判断列是否为复选框列 + * @type {ColumnTypesEnumIsCheckbox} + */ + isCheckbox(type) { return type === 3 } +}; + +/** + * 列排序枚举 + * @enum {number} + */ +const GridColumnDirection = { + /** -1 - 倒序 */ + Descending: -1, + /** 1 - 升序 */ + Ascending: 1 +}; + +/** + * 列排序定义接口 + * @typedef GridColumnSortDefinition + * @property {string} column - 排序列的关键字 + * @property {("asc" | "desc")} order - 升序或降序 + */ + +/** + * 多语言文本资源回调函数 + * @callback GridLanguageCallback + * @param {string} id - 资源 ID + * @param {string} [def] - 默认资源 + * @returns 返回获取的多语言资源 + */ + +/** + * Grid 控件基础类 + * @class + */ export class Grid { _var = { selectedColumnIndex: -1, @@ -74,44 +314,189 @@ export class Grid { // _var.colAttrs = {}; // _var.vtable = []; + /** + * 列定义的数组 + * @type {GridColumnDefinition[]} + */ columns = []; + /** + * 多语言资源对象 + * @type {object} + * @property {string} [all=( All )] + * @property {string} [ok=OK] + * @property {string} [reset=Reset] + * @property {string} [cancel=Cancel] + * @property {string} [null=( Null )] + * @property {string} [addLevel=Add Level] + * @property {string} [deleteLevel=Delete Level] + * @property {string} [copyLevel=Copy Level] + * @property {string} [asc=Ascending] + * @property {string} [desc=Descending] + * @property {string} [column=Column] + * @property {string} [order=Order] + * @property {string} [sort=Sort] + * @property {string} [requirePrompt=All sort criteria must have a column specified. Check the selected sort criteria and try again.] + * @property {string} [duplicatePrompt={column} is being sorted more than once. Delete the duplicate sort criteria and try again.] + */ langs = {}; + /** + * 行数大于等于该值则启用虚模式 + * @type {number} + * @default 100 + */ virtualCount = 100; + /** + * 表格行高 + * @type {number} + * @default 36 + */ rowHeight = 36; + /** + * 文本行高 + * @type {number} + * @default 24 + */ lineHeight = 24; + /** + * 列表底部留出额外的空白行 + * @type {number} + * @default 0 + */ extraRows = 0; + /** + * 过滤条件列表的行高 + * @type {number} + * @default 30 + */ filterRowHeight = 30; + /** + * 列表高度值,为 0 时列表始终显示全部内容(自增高),为非数字或者小于 0 则根据容器高度来确定虚模式的渲染行数 + * @type {number | null} + */ height; + /** + * 列表是否为只读 + * @type {boolean} + */ readonly; + /** + * 是否允许多选 + * @type {boolean} + * @default false + */ multiSelect = false; + /** + * 为 `false` 时只有点击在单元格内才会选中行 + * @type {boolean} + * @default true + */ fullrowClick = true; + /** + * 单元格 tooltip 是否禁用 + * @type {boolean} + * @default false + */ tooltipDisabled = false; + /** + * 列头是否显示 + * @type {boolean} + * @default true + */ headerVisible = true; + /** + * 监听事件的窗口载体 + * @type {(Window | HTMLElement)} + * @default window + */ window = global; + /** + * 排序列的索引 + * @type {number} + * @default -1 + */ sortIndex = -1; - sortDirection = 1; + /** + * 排序方式,正数升序,负数倒序 + * @type {GridColumnDirection} + * @default GridColumnDirection.Ascending + */ + sortDirection = GridColumnDirection.Ascending; + /** + * 排序列数组 + * @type {GridColumnSortDefinition[]} + * @default null + */ sortArray = null; + /** + * 即将选中行时触发 + * @event + * @param {number} index - 即将选中的行索引 + * @param {number} colIndex - 即将选中的列索引 + * @returns {boolean} 返回 `false`、`null`、`undefined`、`0` 等则取消选中动作 + */ willSelect; + /** + * 单元格单击时触发,colIndex 为 -1 则表示点击的是行的空白处 + * @event + * @param {number} index - 点击的行索引 + * @param {number} colIndex - 点击的列索引 + * @returns {boolean} 返回 false 则取消事件冒泡 + */ cellClicked; + /** + * 选中行发生变化时触发的事件 + * @event + * @param {number} index - 选中的行索引 + */ onSelectedRowChanged; + /** + * 单元格双击时触发的事件,colIndex 为 -1 则表示点击的是行的空白处 + * @event + * @param {number} index - 双击的行索引 + * @param {number} colIndex - 双击的列索引 + */ onCellDblClicked; + /** + * 行双击时触发的事件 + * @event + * @param {number} index - 双击的行索引 + */ onRowDblClicked; + /** + * 列发生变化时触发的事件 + * @event + * @param {("reorder" | "resize" | "sort")} type - 事件类型 + * + * * "reorder" 为发生列重排事件,此时 value 为目标列索引 + * * "resize" 为发生列宽调整事件,此时 value 为列宽度值 + * * "sort" 为发生列排序事件,此时 value 为 1(升序)或 -1(倒序) + * @param {number} colIndex - 发生变化事件的列索引 + * @param {number | GridColumnDirection} value - 变化的值 + */ onColumnChanged; + /** + * 列滚动时触发的事件 + * @event + * @param {Event} e - 滚动事件对象 + */ onBodyScrolled; - static ColumnTypes = { - Common: 0, - Input: 1, - Dropdown: 2, - Checkbox: 3, - Icon: 4, - Text: 5, - Date: 6, - isCheckbox(type) { return type === 3 } - }; + /** + * 列类型枚举 + * @readonly + * @type {GridColumnTypeEnum} + */ + static get ColumnTypes() { return GridColumnTypeEnum } + /** + * + * @param {(string | HTMLElement)} container Grid 控件所在的父容器,可以是 string 表示选择器,也可以是 HTMLElement 对象 + * Grid 控件构造函数 + * _构造时可以不进行赋值,但是调用 init 函数时则必须进行赋值_ + * @param {GridLanguageCallback} [getText] 获取多语言文本的函数代理 + */ constructor(container, getText) { this._var.parent = typeof container === 'string' ? document.querySelector(container) : container; if (typeof getText === 'function') { @@ -123,21 +508,31 @@ export class Grid { reset: r('reset', 'Reset'), cancel: r('cancel', 'Cancel'), null: r('null', '( Null )'), - addLevel: r('', 'Add level'), - deleteLevel: r('', 'Delete level'), - copyLevel: r('', 'Copy level'), - asc: r('', 'Ascending'), - desc: r('', 'Descending'), - column: r('', 'Column'), - order: r('', 'Order'), - sort: r('', 'Sort'), - requirePrompt: r('', 'Column required.'), - duplicatePrompt: r('', 'Column duplicated: "{column}"') + addLevel: r('addLevel', 'Add level'), + deleteLevel: r('deleteLevel', 'Delete level'), + copyLevel: r('copyLevel', 'Copy level'), + asc: r('asc', 'Ascending'), + desc: r('desc', 'Descending'), + column: r('column', 'Column'), + order: r('order', 'Order'), + sort: r('sort', 'Sort'), + requirePrompt: r('requirePrompt', 'All sort criteria must have a column specified. Check the selected sort criteria and try again.'), + duplicatePrompt: r('duplicatePrompt', '{column} is being sorted more than once. Delete the duplicate sort criteria and try again.') }; } + /** + * 获取 Grid 的页面元素 + * @readonly + * @type {HTMLDivElement} + */ get element() { return this._var.el } + /** + * 获取当前 Grid 是否已发生改变 + * @readonly + * @type {boolean} + */ get changed() { const source = this._var.source; if (source == null) { @@ -146,8 +541,17 @@ export class Grid { return source.find(r => r.__changed) != null; } + /** + * 返回所有数据的数据(未过滤) + * @readonly + * @type {GridItem[]} + */ get allSource() { return this._var.source?.map(s => s.values) } + /** + * 获取已过滤的数据数组,或者设置数据并刷新列表 + * @type {GridItem[]} + */ get source() { return this._var.currentSource?.map(s => s.values) } set source(list) { if (this._var.el == null) { @@ -166,6 +570,11 @@ export class Grid { this._refreshSource(list); } + /** + * 设置单行数据 + * @param {number} index - 行索引 + * @param {GridItem} item - 待设置的行数据对象 + */ setItem(index, item) { if (this._var.currentSource == null) { throw new Error('no source'); @@ -174,9 +583,21 @@ export class Grid { // clear dropdown source cache delete it.source; it.values = item; - this.refresh(); + if (this.sortIndex >= 0) { + this.sortColumn(); + } else if (this.sortArray?.length > 0) { + this.sort(); + } else { + this.refresh(); + } } + /** + * 添加行数据 + * @param {GridItem} item - 待添加的行数据值 + * @param {number} [index] - 待添加的行索引 + * @returns {GridItem} 返回已添加的行数据 + */ addItem(item, index) { if (this._var.currentSource == null) { throw new Error('no source'); @@ -199,10 +620,22 @@ export class Grid { this._var.source.push(newIt); } } - this.reload(); + if (this.sortIndex >= 0) { + this.sortColumn(); + } else if (this.sortArray?.length > 0) { + this.sort(); + } else { + this.reload(); + } return item; } + /** + * 批量添加行数据 + * @param {GridItem[]} array - 待添加的行数据数组 + * @param {number} [index] - 待添加的行索引 + * @returns {GridItem[]} 返回已添加的行数据数组 + */ addItems(array, index) { if (this._var.currentSource == null) { throw new Error('no source'); @@ -230,10 +663,21 @@ export class Grid { this._var.source.push(...items); } } - this.reload(); + if (this.sortIndex >= 0) { + this.sortColumn(); + } else if (this.sortArray?.length > 0) { + this.sort(); + } else { + this.reload(); + } return array; } + /** + * 删除行数据 + * @param {number} index - 待删除的行索引 + * @returns {GridItem} 返回已删除的行数据 + */ removeItem(index) { if (this._var.currentSource == null) { throw new Error('no source'); @@ -257,6 +701,11 @@ export class Grid { return it.values; } + /** + * 批量删除行数据 + * @param {number[]} [indexes] - 待删除的行索引数组,未传值时删除所有行 + * @returns {GridItem[]} 返回已删除的行数据数组 + */ removeItems(indexes) { if (this._var.currentSource == null) { throw new Error('no source'); @@ -334,8 +783,18 @@ export class Grid { this.resize(); } + /** + * 获取当前是否为虚模式状态 + * @readonly + * @type {boolean} + */ get virtual() { return this._var.currentSource?.length > this.virtualCount } + /** + * 获取当前排序的列关键字,为 null 则当前无排序列 + * @readonly + * @type {string | null} + */ get sortKey() { if (this.columns == null) { return null; @@ -348,6 +807,10 @@ export class Grid { return Array.prototype.slice.call(this._var.refs.body.children); } + /** + * 获取或设置当前选中的行索引的数组,设置后会刷新列表 + * @type {number[]} + */ get selectedIndexes() { return this._var.selectedIndexes } set selectedIndexes(indexes) { const startIndex = this._var.startIndex; @@ -368,8 +831,17 @@ export class Grid { } } + /** + * 获取当前选中行的索引,为 -1 则当前没有选中行 + * @readonly + * @type {number} + */ get selectedIndex() { return (this._var.selectedIndexes && this._var.selectedIndexes[0]) ?? -1 } + /** + * 获取或设置 Grid 当前的加载状态 + * @type {boolean} + */ get loading() { return this._var.refs.loading?.style?.visibility === 'visible' } set loading(flag) { if (this._var.refs.loading == null) { @@ -384,6 +856,10 @@ export class Grid { } } + /** + * 获取或设置 Grid 当前滚动的偏移量 + * @type {number} + */ get scrollTop() { return this._var.el?.scrollTop; } set scrollTop(top) { if (this._var.el == null) { @@ -393,6 +869,10 @@ export class Grid { this.reload(true); } + /** + * 初始化Grid控件 + * @param {HTMLElement} [container=.ctor#container] - 父容器元素,若未传值则采用构造方法中传入的父容器元素 + */ init(container = this._var.parent) { this._var.el = null; this._var.refs = {}; @@ -488,15 +968,28 @@ export class Grid { } } + /** + * 设置数据列表,该方法为 [source]{@linkcode Grid#source} 属性的语法糖 + * @param {GridItem[]} source - 待设置的数据列表 + */ setData(source) { this.source = source; } + /** + * 滚动到指定行的位置 + * @param {number} index - 待滚动至的行索引 + */ scrollToIndex(index) { const top = this._scrollToTop(index * (this.rowHeight + 1), true); this._var.el.scrollTop = top; } + /** + * 调整 Grid 元素的大小,一般需要在宽度变化时(如页面大小发生变化时)调用 + * @param {boolean} [force] - 是否强制 [reload]{@linkcode Grid#reload},默认只有待渲染的行数发生变化时才会调用 + * @param {boolean} [keep] - 是否保持当前滚动位置 + */ resize(force, keep) { if (this._var.rendering || this._var.el == null) { return; @@ -518,6 +1011,10 @@ export class Grid { this._var.bodyClientWidth = body.clientWidth; } + /** + * 重新计算需要渲染的行,并载入元素,一般需要在高度变化时调用 + * @param {boolean} [keep] - 是否保持当前滚动位置 + */ reload(keep) { const filtered = this.columns.some(c => c.filterValues != null); if ((filtered ^ this._var.colAttrs.__filtered) === 1) { @@ -552,6 +1049,9 @@ export class Grid { this.refresh(); } + /** + * 重新填充Grid单元格数据 + */ refresh() { if (this._var.refs.body == null) { throw new Error('body has not been created.'); @@ -575,6 +1075,9 @@ export class Grid { } } + /** + * 把所有行重置为未修改的状态 + */ resetChange() { if (this._var.source == null) { return; @@ -608,6 +1111,10 @@ export class Grid { return (a, b) => col.sortFilter(a.values, b.values) * direction; } + /** + * 根据当前排序字段进行列排序 + * @param {boolean} [reload] - 为 `true` 则在列排序后调用 [reload]{@linkcode Grid#reload} 方法 + */ sortColumn(reload) { const index = this.sortIndex; const col = this.columns[index]; @@ -642,6 +1149,10 @@ export class Grid { } } + /** + * 根据当前排序列数组进行多列排序 + * @param {boolean} [reload] - 为 `true` 则在多列排序后调用 [reload]{@linkcode Grid#reload} 方法 + */ sort(reload) { const sortArray = this.sortArray; if (sortArray == null || sortArray.length === 0) { @@ -689,11 +1200,17 @@ export class Grid { }); } + /** + * 清除列头复选框的选中状态 + */ clearHeaderCheckbox() { const boxes = this._var.refs.header.querySelectorAll('.ui-check-wrapper>input'); boxes.forEach(box => box.checked = false); } + /** + * 显示多列排序设置面板 + */ showSortPanel() { const content = createElement('div', 'ui-sort-panel-content'); const buttonWrapper = createElement('div', 'ui-sort-panel-buttons'); @@ -811,7 +1328,7 @@ export class Grid { key: 'column', caption: this.langs.column, width: 270, - type: Grid.ColumnTypes.Dropdown, + type: GridColumnTypeEnum.Dropdown, dropOptions: { textKey: 'caption', valueKey: 'key' @@ -824,7 +1341,7 @@ export class Grid { key: 'order', caption: this.langs.order, width: 150, - type: Grid.ColumnTypes.Dropdown, + type: GridColumnTypeEnum.Dropdown, source: [ { value: 'asc', text: this.langs.asc }, { value: 'desc', text: this.langs.desc } @@ -915,13 +1432,13 @@ export class Grid { continue; } // style - const isCheckbox = Grid.ColumnTypes.isCheckbox(col.type); + const isCheckbox = GridColumnTypeEnum.isCheckbox(col.type); let type = this._var.colTypes[col.key]; if (type == null) { if (isNaN(col.type)) { type = col.type; } else { - type = ColumnTypes[col.type]; + type = ColumnTypeDefs[col.type]; } type ??= GridColumn; this._var.colTypes[col.key] = type; @@ -1097,7 +1614,7 @@ export class Grid { if (style !== '') { cell.style.cssText = style; } - if (Grid.ColumnTypes.isCheckbox(col.type)) { + if (GridColumnTypeEnum.isCheckbox(col.type)) { cell.appendChild(GridCheckboxColumn.createEdit(e => this._onRowChanged(e, exists + i, col, e.target.checked, cell))); // this._var.colTypes[col.key] = GridCheckboxColumn; } else { @@ -1106,7 +1623,7 @@ export class Grid { if (isNaN(col.type)) { type = col.type; } else { - type = ColumnTypes[col.type]; + type = ColumnTypeDefs[col.type]; } type ??= GridColumn; this._var.colTypes[col.key] = type; @@ -1184,7 +1701,7 @@ export class Grid { const bgColor = col.bgFilter(item); cell.style.backgroundColor = bgColor ?? ''; } - const isCheckbox = Grid.ColumnTypes.isCheckbox(col.type); + const isCheckbox = GridColumnTypeEnum.isCheckbox(col.type); const type = isCheckbox ? GridCheckboxColumn : this._var.colTypes[col.key] ?? GridColumn; let element; if (!isCheckbox && typeof type.createEdit === 'function') { diff --git a/package-lock.json b/package-lock.json index 40764eb..68a7af7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,9 @@ "version": "0.0.1", "devDependencies": { "@mxssfd/typedoc-theme": "^1.1.3", + "clean-jsdoc-theme": "^4.2.17", + "docdash": "^2.0.2", + "jsdoc": "^4.0.2", "postcss-preset-env": "^9.3.0", "sass": "^1.70.0", "typedoc": "^0.25.7", @@ -16,6 +19,18 @@ "vite-plugin-externals": "^0.6.2" } }, + "node_modules/@babel/parser": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", + "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@csstools/cascade-layer-name-parser": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-1.0.7.tgz", @@ -1281,6 +1296,76 @@ "node": ">=12" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsdoc/salty": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.7.tgz", + "integrity": "sha512-mh8LbS9d4Jq84KLw8pzho7XC2q2/IJGiJss3xwRoLD1A+EE16SjN4PfaG4jRCzKegTFLlN0Zd8SdUPE6XdoPFg==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v12.0.0" + } + }, "node_modules/@mxssfd/typedoc-theme": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@mxssfd/typedoc-theme/-/typedoc-theme-1.1.3.tgz", @@ -1468,6 +1553,28 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, + "node_modules/@types/linkify-it": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", + "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", + "dev": true + }, + "node_modules/@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "dev": true, + "dependencies": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", + "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", + "dev": true + }, "node_modules/acorn": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", @@ -1499,6 +1606,12 @@ "node": ">= 8" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/autoprefixer": { "version": "10.4.17", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.17.tgz", @@ -1551,6 +1664,12 @@ "node": ">=8" } }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -1604,6 +1723,22 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001580", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001580.tgz", @@ -1624,6 +1759,18 @@ } ] }, + "node_modules/catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -1651,6 +1798,44 @@ "fsevents": "~2.3.2" } }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-jsdoc-theme": { + "version": "4.2.17", + "resolved": "https://registry.npmjs.org/clean-jsdoc-theme/-/clean-jsdoc-theme-4.2.17.tgz", + "integrity": "sha512-5SbJNXcQHUXd7N13g+3OpGFiBQdxz36xwEP3p1r1vbo/apLcDRtugaFdUZ56H6Rvlb68Q33EChoBkajSlnD11w==", + "dev": true, + "dependencies": { + "@jsdoc/salty": "^0.2.4", + "fs-extra": "^10.1.0", + "html-minifier-terser": "^7.2.0", + "klaw-sync": "^6.0.0", + "lodash": "^4.17.21", + "showdown": "^2.1.0" + }, + "peerDependencies": { + "jsdoc": ">=3.x <=4.x" + } + }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/css-blank-pseudo": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-6.0.1.tgz", @@ -1753,12 +1938,40 @@ "node": ">=4" } }, + "node_modules/docdash": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/docdash/-/docdash-2.0.2.tgz", + "integrity": "sha512-3SDDheh9ddrwjzf6dPFe1a16M6ftstqTNjik2+1fx46l24H9dD2osT2q9y+nBEC1wWz4GIqA48JmicOLQ0R8xA==", + "dev": true, + "dependencies": { + "@jsdoc/salty": "^0.2.1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.645", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.645.tgz", "integrity": "sha512-EeS1oQDCmnYsRDRy2zTeC336a/4LZ6WKqvSaM1jLocEk5ZuyszkQtCpsqvuvaIXGOUjwtvF6LTcS8WueibXvSw==", "dev": true }, + "node_modules/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-module-lexer": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.4.1.tgz", @@ -1812,6 +2025,15 @@ "node": ">=6" } }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1883,6 +2105,39 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, + "node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, + "node_modules/html-minifier-terser/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/immutable": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", @@ -1931,6 +2186,44 @@ "node": ">=0.12.0" } }, + "node_modules/js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "dev": true, + "dependencies": { + "xmlcreate": "^2.0.4" + } + }, + "node_modules/jsdoc": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", + "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.15", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^12.2.3", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^12.3.2", + "markdown-it-anchor": "^8.4.1", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/jsonc-parser": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", @@ -1949,6 +2242,48 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, + "node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/lunr": { "version": "2.3.9", "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", @@ -1964,6 +2299,32 @@ "sourcemap-codec": "^1.4.8" } }, + "node_modules/markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", + "dev": true, + "peerDependencies": { + "@types/markdown-it": "*", + "markdown-it": "*" + } + }, "node_modules/marked": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", @@ -1976,6 +2337,12 @@ "node": ">= 12" } }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true + }, "node_modules/minimatch": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", @@ -1991,6 +2358,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -2009,6 +2388,16 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", @@ -2033,6 +2422,26 @@ "node": ">=0.10.0" } }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -2760,6 +3169,24 @@ "node": ">=8.10.0" } }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/requizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", + "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, "node_modules/rollup": { "version": "4.9.6", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.6.tgz", @@ -2821,6 +3248,40 @@ "vscode-textmate": "^8.0.0" } }, + "node_modules/showdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/showdown/-/showdown-2.1.0.tgz", + "integrity": "sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==", + "dev": true, + "dependencies": { + "commander": "^9.0.0" + }, + "bin": { + "showdown": "bin/showdown.js" + }, + "funding": { + "type": "individual", + "url": "https://www.paypal.me/tiviesantos" + } + }, + "node_modules/showdown/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -2830,6 +3291,16 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/sourcemap-codec": { "version": "1.4.8", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", @@ -2837,6 +3308,42 @@ "deprecated": "Please use @jridgewell/sourcemap-codec instead", "dev": true }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz", + "integrity": "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2849,6 +3356,12 @@ "node": ">=8.0" } }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/typedoc": { "version": "0.25.7", "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.7.tgz", @@ -2884,6 +3397,18 @@ "node": ">=14.17" } }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -3013,6 +3538,12 @@ "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", "dev": true + }, + "node_modules/xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "dev": true } } } diff --git a/package.json b/package.json index 1ec841f..b860176 100644 --- a/package.json +++ b/package.json @@ -23,10 +23,15 @@ "scripts": { "dev": "vite", "build": "node ./vite.build.js && typedoc", - "doc": "typedoc" + "doc": "typedoc", + "jsdoc": "jsdoc -c jsdoc.json", + "jsdoc-date": "jsdoc -c jsdoc-date.json" }, "devDependencies": { "@mxssfd/typedoc-theme": "^1.1.3", + "clean-jsdoc-theme": "^4.2.17", + "docdash": "^2.0.2", + "jsdoc": "^4.0.2", "postcss-preset-env": "^9.3.0", "sass": "^1.70.0", "typedoc": "^0.25.7",