From 5baf00de64b461f1a4d76c8bc79f6d3e44cef2dc Mon Sep 17 00:00:00 2001 From: Tsanie Lily Date: Fri, 21 Jun 2024 17:28:11 +0800 Subject: [PATCH] add: `getText` compatibility. add: `AssetSelector` and `TemplateSelector`. add: `popup-selector` style class. add: `ui.resolvePopup` function. add: `switch` in checkbox. add: `GridColumn.filterTemplate` supports. add: add `action` callback in `createIcon`. change: replace `setTimeout(..., 0)` with `requestAnimationFrame`. change: Popup result structure adjustment ({ result: any, popup: Popup }). change: complete add work order flow. change: reduce Popup title height. fix: Grid column sort in number. --- README.md | 6 + lib/app/communications/comments.js | 6 +- lib/app/communications/contact.js | 8 +- lib/app/communications/customer.js | 27 +- lib/app/communications/follower.js | 2 + lib/app/communications/internal.js | 6 +- lib/app/communications/style.scss | 2 +- lib/element.js | 8 +- lib/element/addworkorder.js | 712 ++++++++++++++++++++++++--- lib/element/assetSelector.js | 269 ++++++++++ lib/element/schedule.js | 2 + lib/element/style.scss | 199 +++++++- lib/element/templateSelector.js | 163 ++++++ lib/ui.js | 3 +- lib/ui/checkbox.d.ts | 2 + lib/ui/checkbox.js | 20 +- lib/ui/css/checkbox.scss | 7 +- lib/ui/css/common.scss | 3 +- lib/ui/css/dropdown.scss | 3 +- lib/ui/css/grid.scss | 20 +- lib/ui/css/popup.scss | 20 +- lib/ui/css/variables/definition.scss | 2 +- lib/ui/date.d.ts | 4 + lib/ui/date.js | 15 + lib/ui/dropdown.d.ts | 2 + lib/ui/dropdown.js | 4 +- lib/ui/grid/column.js | 12 +- lib/ui/grid/grid.js | 134 +++-- lib/ui/icon.d.ts | 3 +- lib/ui/icon.js | 9 +- lib/ui/popup.d.ts | 21 +- lib/ui/popup.js | 183 ++++--- package-lock.json | 254 +++++----- package.json | 6 +- 34 files changed, 1772 insertions(+), 365 deletions(-) create mode 100644 lib/element/assetSelector.js create mode 100644 lib/element/templateSelector.js diff --git a/README.md b/README.md index 59b9c74..dc89d05 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,12 @@ UI Mordern Gridview Library +## 1.0.6 +* 新增: [`col.switch`](GridColumnDefinition.html) - 列复选框样式改为 `ui-switch` + +## 1.0.5 +* 新增: [`col`.filterTemplate: (this: GridColumnDefinition, item: ValueItem) => HTMLElement](GridColumnDefinition.html) - 列头过滤项的模板函数 + ## 1.0.4 * 调整: `Dropdown` 组件支持虚模式 * 新增: `ui-switch` 样式(iOS 切换组件) diff --git a/lib/app/communications/comments.js b/lib/app/communications/comments.js index d024446..e63ee6b 100644 --- a/lib/app/communications/comments.js +++ b/lib/app/communications/comments.js @@ -1,4 +1,4 @@ -import { createElement, setTooltip, createIcon } from "../../ui"; +import { createElement, setTooltip, createIcon, requestAnimationFrame } from "../../ui"; import { r as lang, nullOrEmpty, escapeHtml, escapeEmoji } from "../../utility"; import { createBox, appendMedia, createHideMessageTitleButton, createHideMessageCommentTail } from "./lib"; @@ -12,6 +12,8 @@ export default class CustomerRecordComment { const getText = opt?.getText; if (typeof getText === 'function') { r = getText; + } else if (typeof GetTextByKey === 'function') { + r = GetTextByKey; } } @@ -179,6 +181,6 @@ export default class CustomerRecordComment { this._var.lastTop = this._var.message.scrollTop; } this._var.message.replaceChildren(...children); - setTimeout(() => this._var.message.scrollTop = keep ? this._var.lastTop : this._var.message.scrollHeight, 0); + requestAnimationFrame(() => this._var.message.scrollTop = keep ? this._var.lastTop : this._var.message.scrollHeight); } } \ No newline at end of file diff --git a/lib/app/communications/contact.js b/lib/app/communications/contact.js index 778aef3..e1d7ef3 100644 --- a/lib/app/communications/contact.js +++ b/lib/app/communications/contact.js @@ -1,4 +1,4 @@ -import { Grid, Dropdown, createElement, createCheckbox, Popup, showAlert } from "../../ui"; +import { Grid, Dropdown, createElement, createCheckbox, Popup, showAlert, requestAnimationFrame } from "../../ui"; import { isEmail, nullOrEmpty, r as lang } from "../../utility"; let r = lang; @@ -11,6 +11,8 @@ export class Contact { const getText = option?.getText; if (typeof getText === 'function') { r = getText; + } else if (typeof GetTextByKey === 'function') { + r = GetTextByKey; } } @@ -143,7 +145,7 @@ export class Contact { contactNotes }; const result = await popup.show(parent); - setTimeout(() => contactName.focus()); + requestAnimationFrame(() => contactName.focus()); return result; } @@ -204,6 +206,8 @@ export class CustomerRecordContact { const getText = option?.getText; if (typeof getText === 'function') { r = getText; + } else if (typeof GetTextByKey === 'function') { + r = GetTextByKey; } } diff --git a/lib/app/communications/customer.js b/lib/app/communications/customer.js index 01b304b..4447354 100644 --- a/lib/app/communications/customer.js +++ b/lib/app/communications/customer.js @@ -1,4 +1,4 @@ -import { Grid, GridColumn, createElement, setTooltip, createIcon, createCheckbox, createRadiobox, showAlert, showConfirm, Popup } from "../../ui"; +import { Grid, GridColumn, createElement, setTooltip, createIcon, createCheckbox, createRadiobox, showAlert, showConfirm, Popup, requestAnimationFrame } from "../../ui"; import { r as lang, nullOrEmpty, formatUrl, escapeEmoji, isEmail, isPhone } from "../../utility"; import { createBox, appendMedia, fileSupported, insertFile, getMessageSendTo, getMessageStatus, updateCustomerName, createHideMessageTitleButton, createHideMessageCommentTail } from "./lib"; import { Contact, CustomerRecordContact } from "./contact"; @@ -41,6 +41,8 @@ export default class CustomerCommunication { const getText = opt?.getText; if (typeof getText === 'function') { r = getText; + } else if (typeof GetTextByKey === 'function') { + r = GetTextByKey; } } @@ -1015,11 +1017,11 @@ export default class CustomerCommunication { { key: 'ok', text: r('P_WO_OK', 'OK') }, { key: 'cancel', text: r('P_WO_CANCEL', 'Cancel') } ] - ).then(result => { - if (result?.key === 'ok') { - const isRecord = result.popup.container.querySelector('.radio-customer-record>input').checked; + ).then(r => { + if (r.result === 'ok') { + const isRecord = r.popup.container.querySelector('.radio-customer-record>input').checked; if (typeof option.onDelete === 'function') { - option.onDelete(result.key, this, isRecord); + option.onDelete(r.result, this, isRecord); } const index = grid.source.indexOf(this); if (index >= 0) { @@ -1075,10 +1077,10 @@ export default class CustomerCommunication { showConfirm(r('P_CU_REMOVECONTACT', 'Remove Contact'), r('P_CU_REMOVEFROMWORKORDER', 'You are removing {name} from work order.\n\nDo you want to Continue?').replace('{name}', this.Name), [ { key: 'continue', text: r('P_JS_CONTINUE', 'Continue') }, { key: 'cancel', text: r('P_WO_CANCEL', 'Cancel') } - ]).then(result => { - if (result?.key === 'continue') { + ]).then(r => { + if (r.result === 'continue') { if (typeof option.onDelete === 'function') { - option.onDelete(result.key, this); + option.onDelete(r.result, this); } const index = gridWo.source.indexOf(this); if (index >= 0) { @@ -1122,14 +1124,11 @@ export default class CustomerCommunication { { key: 'skip', text: r('P_CUSTOMER_SKIPTHISSTEP', 'Skip This Step') } ] ).then(r => { - if (r == null) { - return; - } - if (r.key === 'add') { + if (r.result === 'add') { if (typeof option.onAddCompany === 'function') { option.onAddCompany.call(this); } - } else { + } else if (r.key === 'skip') { editContacts(); } }); @@ -1328,6 +1327,6 @@ export default class CustomerCommunication { this._var.lastTop = this._var.message.scrollTop; } this._var.message.replaceChildren(...children); - setTimeout(() => this._var.message.scrollTop = keep ? this._var.lastTop : this._var.message.scrollHeight, 0); + requestAnimationFrame(() => this._var.message.scrollTop = keep ? this._var.lastTop : this._var.message.scrollHeight); } } \ No newline at end of file diff --git a/lib/app/communications/follower.js b/lib/app/communications/follower.js index e15241c..db5dc7f 100644 --- a/lib/app/communications/follower.js +++ b/lib/app/communications/follower.js @@ -11,6 +11,8 @@ export default class Follower { const getText = option?.getText; if (typeof getText === 'function') { r = getText; + } else if (typeof GetTextByKey === 'function') { + r = GetTextByKey; } } diff --git a/lib/app/communications/internal.js b/lib/app/communications/internal.js index d357506..ad0122e 100644 --- a/lib/app/communications/internal.js +++ b/lib/app/communications/internal.js @@ -1,4 +1,4 @@ -import { createElement, setTooltip, createIcon } from "../../ui"; +import { createElement, setTooltip, createIcon, requestAnimationFrame } from "../../ui"; import { r as lang, nullOrEmpty, escapeHtml, escapeEmoji } from "../../utility"; import { createBox, appendMedia } from "./lib"; import { fileSupported, insertFile, getMessageSendTo, getMessageStatus, updateCustomerName, createHideMessageTitleButton, createHideMessageCommentTail } from "./lib"; @@ -19,6 +19,8 @@ export default class InternalComment { const getText = opt?.getText; if (typeof getText === 'function') { r = getText; + } else if (typeof GetTextByKey === 'function') { + r = GetTextByKey; } } @@ -336,6 +338,6 @@ export default class InternalComment { this._var.lastTop = this._var.message.scrollTop; } this._var.message.replaceChildren(...children); - setTimeout(() => this._var.message.scrollTop = keep ? this._var.lastTop : this._var.message.scrollHeight, 0); + requestAnimationFrame(() => this._var.message.scrollTop = keep ? this._var.lastTop : this._var.message.scrollHeight); } } \ No newline at end of file diff --git a/lib/app/communications/style.scss b/lib/app/communications/style.scss index d14c5d2..d058c73 100644 --- a/lib/app/communications/style.scss +++ b/lib/app/communications/style.scss @@ -122,7 +122,7 @@ >.title-functions { flex: 0 0 auto; display: flex; - padding: 4px; + padding: 0 4px; >label { margin: 0 4px; diff --git a/lib/element.js b/lib/element.js index ca4faf3..38ad117 100644 --- a/lib/element.js +++ b/lib/element.js @@ -1,8 +1,12 @@ import "./element/style.scss"; import ScheduleItem from "./element/schedule"; -import AddWorkOrder from "./element/addworkorder"; +import AddWorkOrder from "./element/addWorkorder"; +import AssetSelector from "./element/assetSelector"; +import TemplateSelector from "./element/templateSelector"; export { ScheduleItem, - AddWorkOrder + AddWorkOrder, + AssetSelector, + TemplateSelector } \ No newline at end of file diff --git a/lib/element/addworkorder.js b/lib/element/addworkorder.js index 3aab3e1..4938ab9 100644 --- a/lib/element/addworkorder.js +++ b/lib/element/addworkorder.js @@ -1,124 +1,582 @@ -import { createElement, Dropdown, Popup, validation, toDateValue, showAlert } from "../ui"; +import { createElement, Dropdown, Popup, showAlert, createIcon, DateSelector, showConfirm, Grid } from "../ui"; import { r as lang, nullOrEmpty } from "../utility"; +import AssetSelector from "./assetSelector"; let r = lang; const iconWorkOrder = 'data:image/png;base64,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'; +/** + * @private + * @param {HTMLElement} element + * @param {boolean?} display + * @returns {HTMLElement} + */ +function displayElement(element, display) { + element.style.display = display === false ? 'none' : ''; + return element; +} + +/** + * @private + * @param {HTMLInputElement} element + * @param {string} pattern + * @returns {HTMLInputElement} + */ +function patternValidation(element, pattern) { + element.pattern = pattern; + return element; +} + +/** + * @private + * @param {"mile" | "mi" | "m" | "kilometre" | "km" | "kilometres"} uom + * @returns {"Mile" | "Kilometre"} + */ +function getOdometerUnit(uom) { + if (nullOrEmpty(uom)) { + return 'Mile'; + } + switch (uom.toLowerCase()) { + case 'mile': + case 'mi': + case 'm': + return 'Mile'; + case 'kilometre': + case 'km': + case 'kilometres': + return 'Kilometre'; + default: + return 'Mile'; + } +} + export default class AddWorkOrder { _var = { option: { - isCustomerRecord: true + allowCustomer: false, + assetFullcontrol: false, + /** + * @private + * @type {(assetId: number) => Promise<{Id: number, VIN: string, DisplayName: string, OnRoad: boolean, Hide: boolean, EngineHours?: number, Odometer?: number, OdometerUOM?: string}>} + */ + requestAssetInfo: null, + /** + * @private + * @type {() => Promise<{Statuses: any[], Jobsites: any[], Codes: any[], Advisors: any[], Locations: any[], Departments: any[], OrderTypes: any[], AssetId: null}>} + */ + requestWorkOrderParams: null, + /** + * @private + * @type {(hidden: boolean, search?: string, groups?: string[], jobsites?: number[], codes?: string[]) => Promise} + */ + requestAssets: null, + /** + * @private + * @type {() => Promise} + */ + requestAddAsset: null, + /** + * @private + * @type {() => Promise<{Customer: any, Contacts: any[], Followers: any[]}>} + */ + requestCustomers: null, + /** + * @private + * @type {(assetId: number, locationId: number, departmentId: number) => Promise} + */ + requestAssignedTo: null, + /** + * @private + * @type {(assetId: number) => Promise} + */ + requestHideAsset: null, + /** + * @private + * @type {(assetId: number) => Promise} + */ + requestOpenedWorkorder: null, + zIndex: 999 }, /** * @private * @type {HTMLElement} */ - container: null + container: null, + /** + * @private + * @property {number} Id + * @property {string} VIN + * @property {string} DisplayName + * @property {boolean} OnRoad + * @property {boolean} Hide + * @property {number} [EngineHours] + * @property {number} [Odometer] + * @property {string} [OdometerUOM] + */ + asset: null, + /** + * @private + * @property {string} Id + * @property {string} Name + * @property {string} Code + */ + customer: null, + contacts: [], + followers: [], + params: { + Locations: [], + Departments: [], + Advisors: [], + OrderTypes: [], + Statuses: [], + Jobsites: [], + Codes: [] + }, + el: { + /** + * @private + * @type {HTMLTextAreaElement} + */ + textComplaint: null, + /** + * @private + * @type {Dropdown} + */ + dropWorkOrderType: null, + /** + * @private + * @type {Dropdown} + */ + dropStatus: null, + /** + * @private + * @type {DateSelector} + */ + dateCompleted: null, + /** + * @private + * @type {HTMLInputElement} + */ + inputHours: null, + /** + * @private + * @type {HTMLInputElement} + */ + inputOdometer: null, + /** + * @private + * @type {Dropdown} + */ + dropOdometerUnit: null, + /** + * @private + * @type {Dropdown} + */ + dropAssignedTo: null, + /** + * @private + * @type {Dropdown} + */ + dropAdvisor: null, + /** + * @private + * @type {Dropdown} + */ + dropLocation: null, + /** + * @private + * @type {Dropdown} + */ + dropDepartment: null + } }; + onAssetAdded; + onAssetSelected; + onSave; + constructor(opt) { opt ??= {}; this._var.option = opt; const getText = opt.getText; if (typeof getText === 'function') { r = getText; + } else if (typeof GetTextByKey === 'function') { + r = GetTextByKey; } } - get complaint() { - return this._var.container.querySelector('.wo-complaint')?.value; + async getItem() { + const title = r('P_WO_OPENWORKORDER', 'Open Work Order'); + const el = this._var.el; + let status = el.dropStatus.selected; + if (status != null) { + status = { + Status: status.Id, + StatusType: status.StatusType, + StatusName: status.Name, + StatusAutoText: status.AutoText, + StatusMessage: status.Message + }; + } else { + status = { + Status: -1 + }; + } + let machine = this._var.asset; + if (machine == null) { + showAlert(title, r('P_WO_ASSETNOTEMPTY', 'Asset cannot be empty.')).then(() => this._var.container.querySelector('.wo-asset>svg')?.focus()); + return null; + } + const item = { + Id: -1, + Description: el.textComplaint.value, + WorkOrderType: el.dropWorkOrderType.selected?.Key ?? '', + CompleteDate: el.dateCompleted.element.value, + // MeterType: + HourMeter: el.inputHours.value || -1, + Odometer: el.inputOdometer.value || -1, + OdometerUnits: el.dropOdometerUnit.selected?.value ?? 'Mile', + AssignedTo: el.dropAssignedTo.selected?.IID ?? '', + AdvisorId: el.dropAdvisor.selected?.Key ?? '', + LocationId: el.dropLocation.selected?.ID || -1, + DepartmentId: el.dropDepartment.selected?.Id || -1, + AssetID: machine.Id, + VIN: machine.VIN, + AssetName: machine.DisplayName, + WorkOrderTotalCost: -1, + HoursToComplete: -1, + OtherCost: -1, + PartsCost: -1, + TravelTimeCost: -1, + LaborCost: -1, + HourlyRate: -1, + InspectionTemplateId: -1, + ...status + }; + item.CustomerId = this._var.customer?.Id ?? -1; + item.Contacts = this._var.contacts ?? []; + item.Followers = this._var.followers ?? []; + if (nullOrEmpty(el.textComplaint?.value)) { + showAlert(title, r('P_WO_COMPLAINTREQUIRED', 'Complaint is required.')).then(() => el.textComplaint.focus()); + return null; + } + if (el.dropStatus.selected?.Completed) { + if (!el.dateCompleted.element.validity.valid) { + showAlert(title, r('P_WO_COMPLETEDDATECANNOTBEEMPTY', 'Completed Date cannot be empty.')).then(() => el.dateCompleted.element.focus()); + return null; + } + if (machine.OnRoad) { + item.MeterType = 'Odometer'; + if (nullOrEmpty(item.Odometer) || isNaN(item.Odometer) || item.Odometer < 0) { + showAlert(title, r('P_WO_ODOMETERFORMATERROR', 'Odometer format error.')).then(() => el.inputOdometer.focus()); + return null; + } + } else { + item.MeterType = 'HourMeter'; + if (nullOrEmpty(item.HourMeter) || isNaN(item.HourMeter) || item.HourMeter < 0) { + showAlert(title, r('P_WO_HOURMETERFORMATERROR', 'Hour Meter format error.')).then(() => el.inputHours.focus()); + return null; + } + } + } + return item; } - show() { + async show() { const option = this._var.option; - var title = r('P_WO_OPENWORKORDER', 'Open Work Order'); + const allowCustomer = option.allowCustomer === true; + const title = r('P_WO_OPENWORKORDER', 'Open Work Order'); + const tabIndex = Math.max.apply(null, [...document.querySelectorAll('[tabindex]')].map(e => e.tabIndex ?? 0)) + 3; + const textComplaint = createElement('textarea', textarea => { + textarea.tabIndex = tabIndex + 2; + textarea.className = 'ui-text wo-complaint'; + textarea.placeholder = r('P_WO_ENTERCOMPLAINT', 'Enter Complaint'); + }); + const baseOption = { + search: true, + textKey: 'Value', + valueKey: 'Key' + }; + const dropWorkOrderType = new Dropdown({ + tabIndex: tabIndex + 3, + input: true, + ...baseOption + }); + const dropStatus = new Dropdown({ + tabIndex: tabIndex + 5, + htmlTemplate: it => createElement('span', 'wo-color-line', + createElement('em', em => em.style.backgroundColor = it.Color), + createElement('label', label => label.innerText = it.Name) + ), + search: true, + textKey: 'Name', + valueKey: 'Id' + }); + const dateCompleted = new DateSelector({ + tabIndex: tabIndex + 6, + className: 'wo-status-closed' + }); + const inputHours = createElement('input', input => { + input.type = 'text'; + input.tabIndex = tabIndex + 7; + input.className = 'ui-input wo-hours input-hours'; + }); + const inputOdometer = createElement('input', input => { + input.type = 'text'; + input.tabIndex = tabIndex + 8; + input.className = 'ui-input wo-odometer input-odometer'; + }); + const dropOdometerUnit = new Dropdown({ + tabIndex: tabIndex + 9, + selected: 'Mile' + }); + dropOdometerUnit.source = [ + { value: 'Mile', text: GetTextByKey('P_WO_MILE', 'Mile') }, + { value: 'Kilometre', text: GetTextByKey('P_WO_KILOMETER', 'Kilometer') } + ] + const dropAssignedTo = new Dropdown({ + tabIndex: tabIndex + 10, + selected: '', + search: true, + valueKey: 'IID', + textKey: 'DisplayName' + }); + dropAssignedTo.source = [{ IID: '', DisplayName: '' }]; + const dropAdvisor = new Dropdown({ + tabIndex: tabIndex + 11, + selected: '', + ...baseOption + }); + const dropLocation = new Dropdown({ + tabIndex: tabIndex + 12, + selected: -1, + search: true, + valueKey: 'ID', + textKey: 'Name' + }); + const dropDepartment = new Dropdown({ + tabIndex: tabIndex + 13, + selected: -1, + search: true, + valueKey: 'Id', + textKey: 'Name' + }); + + // save variables + this._var.el = { + textComplaint, + dropWorkOrderType, + dropStatus, + dateCompleted, + inputHours, + inputOdometer, + dropOdometerUnit, + dropAssignedTo, + dropAdvisor, + dropLocation, + dropDepartment + } + const container = createElement('div', 'open-wo-container', createElement('div', 'open-wo-header', createElement('img', img => img.src = iconWorkOrder), createElement('h3', h3 => h3.innerText = title) ), createElement('div', 'open-wo-content', - createElement('div', 'wo-line', + createElement('div', 'wo-combined wo-asset', createElement('span', span => { span.className = 'wo-title wo-title-required'; span.innerText = r('P_WO_ASSET_COLON', 'Asset:'); + }), + createIcon('fa-light', 'search', svg => { + svg.tabIndex = tabIndex + 1; + svg.addEventListener('click', () => { + const selector = new AssetSelector({ + assetFullcontrol: option.assetFullcontrol, + requestAssets: option.requestAssets, + requestAddAsset: option.requestAddAsset, + dataSource: this._var.params + }); + selector.onSelected = async it => { + const el = this._var.el; + if (typeof option.requestAssetInfo === 'function') { + const a = await option.requestAssetInfo(it.Id); + if (a != null) { + it = a; + if (it.OnRoad) { + el.inputHours.value = ''; + el.inputOdometer.value = it.Odometer; + el.dropOdometerUnit.select(getOdometerUnit(it.OdometerUOM)); + } else { + el.inputHours.value = it.EngineHours; + el.inputOdometer.value = ''; + el.dropOdometerUnit.select('Mile'); + } + } + } + this._var.asset = it; + if (typeof this.onAssetSelected === 'function') { + this.onAssetSelected(it); + } + this._var.container.querySelector('.wo-asset-name').innerText = it.DisplayName; + // get assigned to + if (typeof option.requestAssignedTo === 'function') { + const data = await option.requestAssignedTo(it.Id, el.dropLocation.selected?.ID ?? -1, el.dropDepartment.selected?.Id ?? -1) + el.dropAssignedTo.source = [{ IID: '', DisplayName: '' }, ...data]; + el.dropStatus.onSelected(el.dropStatus.selected); + } + }; + selector.show().then(mask => mask.style.zIndex = option.zIndex ?? 999); + }); }) ), - createElement('div', 'wo-line', + createElement('span', 'wo-asset-name'), + createElement('div', 'wo-line wo-combined', createElement('span', span => { span.className = 'wo-title wo-title-required'; span.innerText = r('P_WO_COMPLAINTCOLON', 'Complaint:'); }) ), - createElement('div', 'wo-line wo-sub-line', - createElement('textarea', textarea => { - textarea.className = 'ui-text wo-complaint'; - textarea.placeholder = r('P_WO_ENTERCOMPLAINT', 'Enter Complaint'); - }) + createElement('div', div => { + div.className = 'wo-line wo-combined wo-sub-line'; + div.style.marginBottom = '2px'; + div.style.width = 'calc(100% - 10px)'; + }, + textComplaint ), - createElement('div', 'wo-line', - createElement('span', span => { - span.className = 'wo-title'; - span.innerText = r('P_WO_WORKORDERTYPE_COLON', 'Work Order Type:'); - }) - ), - createElement('div', 'wo-line wo-customer-record', + createElement('span', span => { + span.className = 'wo-title'; + span.innerText = r('P_WO_WORKORDERTYPE_COLON', 'Work Order Type:'); + }), + dropWorkOrderType.create(), + createElement('div', div => { + div.className = 'wo-combined wo-customer-record'; + if (!allowCustomer) { + displayElement(div, false); + } + }, createElement('span', span => { span.className = 'wo-title'; span.innerText = r('P_WO_COMPANYNAME_COLON', 'Company Name:'); + }), + createIcon('fa-light', 'search', svg => { + svg.tabIndex = tabIndex + 4; + svg.addEventListener('click', async () => { + if (typeof option.requestCustomers === 'function') { + popup.loading = true; + const data = await option.requestCustomers(); + popup.loading = false; + if (data != null) { + this._var.customer = data.Customer; + this._var.contacts = data.Contacts; + this._var.followers = data.Followers; + let name = data.Customer.Name; + if (!nullOrEmpty(data.Customer.Code)) { + name += ' / ' + data.Customer.Code; + } + this._var.container.querySelector('.wo-company-name').innerText = name; + } + } + }); }) ), - createElement('div', 'wo-line', - createElement('span', span => { - span.className = 'wo-title'; - span.innerText = r('P_WO_STATUS_COLON', 'Status:'); - }) + displayElement(createElement('span', 'wo-company-name'), allowCustomer), + createElement('span', span => { + span.className = 'wo-title'; + span.innerText = r('P_WO_STATUS_COLON', 'Status:'); + }), + dropStatus.create(), + createElement('span', span => { + span.className = 'wo-title wo-title-required wo-sub-line wo-status-closed'; + span.innerText = r('P_WO_COMPLETEDDATE_COLON', 'Completed Date:'); + displayElement(span, false); + }), + displayElement(dateCompleted.create(), false), + createElement('span', span => { + span.className = 'wo-title wo-title-required wo-sub-line wo-hours'; + span.innerText = r('P_WO_HOURS_COLON', 'Hours:'); + displayElement(span, false); + }), + displayElement( + patternValidation(inputHours, '\\d+\\.?\\d*'), + false ), - createElement('div', 'wo-line wo-sub-line wo-status-closed', - createElement('span', span => { - span.className = 'wo-title'; - span.innerText = r('P_WO_COMPLETEDDATE_COLON', 'Completed Date:'); - }) + createElement('span', span => { + span.className = 'wo-title wo-title-required wo-sub-line wo-odometer'; + span.innerText = r('P_WO_ODOMETER_COLON', 'Odometer:'); + displayElement(span, false); + }), + createElement('div', div => { + div.className = 'wo-combined wo-odometer'; + displayElement(div, false); + }, + patternValidation(inputOdometer, '\\d+\\.?\\d*'), + dropOdometerUnit.create() ), - createElement('div', 'wo-line wo-sub-line wo-status-closed', - createElement('span', span => { - span.className = 'wo-title'; - span.innerText = r('P_WO_HOURS_COLON', 'Hours:'); - }) - ), - createElement('div', 'wo-line wo-sub-line wo-status-closed', - createElement('span', span => { - span.className = 'wo-title'; - span.innerText = r('P_WO_ODOMETER_COLON', 'Odometer:'); - }) - ), - createElement('div', 'wo-line', - createElement('span', span => { - span.className = 'wo-title'; - span.innerText = r('P_WO_ASSIGNEDTO_COLON', 'Assigned To:'); - }) - ), - createElement('div', 'wo-line wo-customer-record', - createElement('span', span => { - span.className = 'wo-title'; - span.innerText = r('P_WO_ADVISOR_COLON', 'Advisor:'); - }) - ), - createElement('div', 'wo-line wo-customer-record', - createElement('span', span => { - span.className = 'wo-title'; - span.innerText = r('P_WO_LOCATION_COLON', 'Location:'); - }) - ), - createElement('div', 'wo-line wo-customer-record', - createElement('span', span => { - span.className = 'wo-title'; - span.innerText = r('P_WO_DEPARTMENT_COLON', 'Department:'); - }) - ) + createElement('span', span => { + span.className = 'wo-title'; + span.innerText = r('P_WO_ASSIGNEDTO_COLON', 'Assigned Tech:'); + }), + dropAssignedTo.create(), + createElement('span', span => { + span.className = 'wo-title wo-customer-record'; + span.innerText = r('P_WO_ADVISOR_COLON', 'Advisor:'); + if (!allowCustomer) { + displayElement(span, false); + } + }), + displayElement(dropAdvisor.create(), allowCustomer), + createElement('span', span => { + span.className = 'wo-title wo-customer-record'; + span.innerText = r('P_WO_LOCATION_COLON', 'Location:'); + if (!allowCustomer) { + displayElement(span, false); + } + }), + displayElement(dropLocation.create(), allowCustomer), + createElement('span', span => { + span.className = 'wo-title wo-customer-record'; + span.innerText = r('P_WO_DEPARTMENT_COLON', 'Department:'); + if (!allowCustomer) { + displayElement(span, false); + } + }), + displayElement(dropDepartment.create(), allowCustomer) ) ); + dropStatus.onSelected = item => { + if (item == null) { + return; + } + container.querySelectorAll('.wo-status-closed').forEach(it => it.style.display = item.Completed ? '' : 'none'); + if (item.Completed) { + const onRoad = this._var.asset?.OnRoad; + container.querySelectorAll('.wo-hours').forEach(it => it.style.display = onRoad ? 'none' : ''); + container.querySelectorAll('.wo-odometer').forEach(it => it.style.display = onRoad ? '' : 'none'); + } else { + container.querySelectorAll('.wo-hours').forEach(it => it.style.display = 'none'); + container.querySelectorAll('.wo-odometer').forEach(it => it.style.display = 'none'); + } + }; + dropLocation.onSelected = async loc => { + // get assigned to + const asset = this._var.asset; + if (asset != null && typeof option.requestAssignedTo === 'function') { + const data = await option.requestAssignedTo(asset.Id, loc?.ID ?? -1, this._var.el.dropDepartment.selected?.Id ?? -1) + this._var.el.dropAssignedTo.source = [{ IID: '', DisplayName: '' }, ...data]; + } + }; + dropDepartment.onSelected = async dep => { + // get assigned to + const asset = this._var.asset; + if (asset != null && typeof option.requestAssignedTo === 'function') { + const data = await option.requestAssignedTo(asset.Id, this._var.el.dropLocation.selected?.ID ?? -1, dep?.Id ?? -1) + this._var.el.dropAssignedTo.source = [{ IID: '', DisplayName: '' }, ...data]; + } + } + dateCompleted.value = new Date(); this._var.container = container; const popup = new Popup({ title, @@ -127,10 +585,78 @@ export default class AddWorkOrder { { key: 'open', text: title, - trigger: () => { - if (nullOrEmpty(this.complaint)) { - showAlert(title, r('P_WO_COMPLAINTREQUIRED', 'Complaint is required.')).then(() => container.querySelector('.wo-complaint')?.focus()); - return false; + trigger: async () => { + popup.loading = true; + try { + const item = await this.getItem(); + if (item == null) { + return false; + } + if (this._var.asset.Hide) { + if (!option.assetFullcontrol) { + await showAlert(title, r('P_WO_HIDDENCANNOTCREATE', 'The selected asset is hidden and a work order cannot be created.') + '\n\n' + r('P_WO_CONTACTTOUNHIDE', 'Please contact your Fleet Manager to Unhide the asset if you require a work order.')); + return false; + } + const next = await showConfirm(title, r('P_WO_HIDDENCANNOTCREATE', 'The selected asset is hidden and a work order cannot be created.') + '\n\n' + r('P_WO_PROMPTUNHIDE', 'Do you wish to "Un-Hide" the asset?'), [ + { key: 'unhide', text: r('P_WO_UNHIDE', 'Unhide') }, + { key: 'cancel', text: r('P_WO_CANCELWO', 'Cancel Work Order') } + ]); + if (next.result !== 'unhide') { + return false; + } + // hide + if (typeof option.requestHideAsset === 'function') { + await option.requestHideAsset(this._var.asset.Id); + this._var.asset.Hide = false; + } + } + if (typeof option.requestOpenedWorkorder === 'function') { + const wos = await option.requestOpenedWorkorder(this._var.asset.Id); + if (wos == null) { + return false; + } + if (wos.length > 0) { + const next = await new Promise(resolve => { + const popWorkorders = new Popup({ + title, + content: createElement('div', 'wo-opened-workorder', + createElement('header', header => header.innerText = r('P_WO_ASSETOPENEDWORKORDER', 'The selected asset has the following open work orders:')), + createElement('div', 'wo-grid-opened') + ), + resolve, + buttons: [ + { key: 'create', text: r('P_WO_CREATEWO', 'Create Work Order'), trigger: () => resolve('create') }, + { key: 'cancel', text: r('P_WO_CANCELWO', 'Cancel Work Order'), trigger: () => resolve('cancel') } + ] + }); + popWorkorders.show().then(mask => { + const grid = new Grid(mask.querySelector('.wo-grid-opened'), r); + grid.columns = [ + { key: 'WorkOrderNumber', caption: 'WO #', width: 100 }, + { key: 'CreateDateStr', caption: r('P_WO_CREATEDDATE', 'Created Date'), width: 120 }, + { key: 'Description', caption: r('P_WO_COMPLAINT', 'Complaint'), width: 360 } + ]; + grid.init(); + grid.source = wos.map(w => ({ + WorkOrderNumber: w.WorkOrderNumber, + CreateDateStr: { DisplayValue: w.CreateDateStr, Value: w.CreateDate }, + Description: w.Description + })); + // default focus + const button = mask.querySelector('.ui-popup-container .ui-popup-footer .ui-popup-button:last-child'); + button?.focus(); + }); + }); + if (next !== 'create') { + return false; + } + } + } + if (typeof this.onSave === 'function') { + this.onSave(item, this._var.el.dropStatus.selected); + } + } finally { + popup.loading = false; } } }, @@ -139,6 +665,48 @@ export default class AddWorkOrder { }); popup.create(); popup.rect = { width: 600 }; - return popup.show(); + const mask = await popup.show(); + mask.style.zIndex = option.zIndex ?? 999; + if (typeof option.requestWorkOrderParams === 'function') { + popup.loading = true; + const data = await option.requestWorkOrderParams() + if (!isNaN(data.AssetId) && data.AssetId > 0 && typeof option.requestAssetInfo === 'function') { + const it = await option.requestAssetInfo(data.AssetId); + if (it != null) { + if (it.OnRoad) { + inputOdometer.value = it.Odometer; + dropOdometerUnit.select(getOdometerUnit(it.OdometerUOM)); + } else { + inputHours.value = it.EngineHours; + } + this._var.asset = it; + // if (typeof this.onAssetSelected === 'function') { + // this.onAssetSelected(it); + // } + this._var.container.querySelector('.wo-asset-name').innerText = it.DisplayName; + // get assigned to + if (typeof option.requestAssignedTo === 'function') { + const data = await option.requestAssignedTo(it.Id, dropLocation.selected?.ID ?? -1, dropDepartment.selected?.Id ?? -1) + dropAssignedTo.source = [{ IID: '', DisplayName: '' }, ...data]; + // dropStatus.onSelected(dropStatus.selected); + } + } + } + popup.loading = false; + + dropWorkOrderType.source = data.OrderTypes; + dropAdvisor.source = [{ Key: '', Value: '' }, ...data.Advisors]; + dropLocation.source = [{ ID: -1, Name: '' }, ...data.Locations]; + dropDepartment.source = [{ Id: -1, Name: '' }, ...data.Departments]; + + this._var.params = data; + dropStatus.source = data.Statuses; + const defaultStatus = data.Statuses.find(s => s.DefaultOnOpen); + if (defaultStatus != null) { + dropStatus.select(defaultStatus.Id); + } + } + textComplaint.focus(); + return mask; } } \ No newline at end of file diff --git a/lib/element/assetSelector.js b/lib/element/assetSelector.js new file mode 100644 index 0000000..6851cbd --- /dev/null +++ b/lib/element/assetSelector.js @@ -0,0 +1,269 @@ +import { Dropdown, Grid, Popup, createCheckbox, createElement, createIcon } from "../ui"; +import { r as lang } from "../utility"; + +let r = lang; + +export default class AssetSelector { + _var = { + option: { + assetFullcontrol: false, + /** + * @private + * @type {(hidden: boolean, search?: string, groups?: string[], jobsites?: number[], codes?: string[]) => Promise} + */ + requestAssets: null, + /** + * @private + * @type {() => Promise} + */ + requestAddAsset: null, + /** + * @private + * @type {() => Promise<{AssetGroups: any[], Codes: any[], Jobsites: any[]}>} + */ + requestAssetParams: null, + dataSource: { + AssetGroups: [], + Codes: [], + Jobsites: [] + } + }, + /** + * @private + * @type {HTMLElement} + */ + container: null, + /** + * @private + * @type {Popup} + */ + popup: null, + el: { + /** + * @private + * @type {HTMLInputElement} + */ + inputSearch: null, + /** + * @private + * @type {HTMLLabelElement} + */ + checkHidden: null, + /** + * @private + * @type {Dropdown} + */ + dropAssetGroup: null, + /** + * @private + * @type {Dropdown} + */ + dropJobsite: null, + /** + * @private + * @type {Dropdown} + */ + dropJobsiteCode: null, + /** + * @private + * @type {Grid} + */ + grid: null + } + } + + onSelected; + + constructor(opt) { + opt ??= {}; + this._var.option = opt; + const getText = opt.getText; + if (typeof getText === 'function') { + r = getText; + } else if (typeof GetTextByKey === 'function') { + r = GetTextByKey; + } + } + + refresh() { + const requestAssets = this._var.option.requestAssets; + if (typeof requestAssets !== 'function') { + return; + } + const el = this._var.el; + this._var.popup.loading = true; + requestAssets( + el.checkHidden.querySelector('input[type="checkbox"]')?.checked, + el.inputSearch.value, + el.dropAssetGroup.selected?.Key, + el.dropJobsite.selected?.ID, + el.dropJobsiteCode.selected?.value + ).then(data => { + el.grid.source = data; + }).finally(() => this._var.popup.loading = false); + } + + select(item) { + if (typeof this.onSelected !== 'function') { + return false; + } + this.onSelected(item); + } + + async create() { + const option = this._var.option; + const title = r('P_MA_SELECTASSET', 'Select Asset'); + const tabIndex = Math.max.apply(null, [...document.querySelectorAll('[tabindex]')].map(e => e.tabIndex ?? 0)) + 3; + const inputSearch = createElement('input', input => { + input.type = 'text'; + input.placeholder = r('P_SELECTASSETS_SEARCH', 'Search'); + input.tabIndex = tabIndex + 2; + input.className = 'ui-input'; + input.addEventListener('keypress', e => { + if (e.key === 'Enter') { + this.refresh(); + } + }) + }); + const checkHidden = createCheckbox({ + tabIndex: tabIndex + 3, + label: r('P_SELECTASSETS_SHOWHIDDEN', 'Show Hidden'), + onchange: () => this.refresh() + }); + const dropAssetGroup = new Dropdown({ + tabIndex: tabIndex + 4, + search: true, + valueKey: 'Key', + textKey: 'Value' + }); + dropAssetGroup.onSelected = () => this.refresh(); + const dropJobsite = new Dropdown({ + tabIndex: tabIndex + 5, + search: true, + valueKey: 'ID', + textKey: 'Name' + }); + dropJobsite.onSelected = () => this.refresh(); + const dropJobsiteCode = new Dropdown({ + tabIndex: tabIndex + 6, + search: true + }); + dropJobsiteCode.onSelected = () => this.refresh(); + const gridContent = createElement('div', div => { + div.className = 'popup-selector-content'; + div.style.height = '400px'; + }); + const grid = new Grid(gridContent, r); + grid.columns = [ + { key: 'VIN', caption: r('P_SELECTASSETS_VIN', 'VIN'), width: 170 }, + { key: 'DisplayName', caption: r('P_SELECTASSETS_NAME', 'Name'), width: 190 }, + { key: 'MakeName', caption: r('P_SELECTASSETS_MAKE', 'Make'), width: 110, allowFilter: true }, + { key: 'ModelName', caption: r('P_SELECTASSETS_MODEL', 'Model'), width: 110, allowFilter: true }, + { key: 'TypeName', caption: r('P_SELECTASSETS_TYPE', 'Type'), width: 110, allowFilter: true }, + { key: 'AcquisitionType', caption: r('P_MA_ACQUISITIONTYPE', 'Acquisition Type'), width: 130, allowFilter: true }, + { key: 'AssetGroups', caption: r('P_MA_ASSETGROUP', 'Asset Group'), width: 150 }, + { key: 'Jobsites', caption: r('P_SELECTASSETS_JOBSITE', 'Jobsite'), width: 180, filter: it => it.Jobsites?.map(s => s.Key) } + ]; + grid.onRowDblClicked = index => { + const item = grid.source[index]; + this.select(item); + this._var.popup.close(); + }; + grid.init(); + grid.element.tabIndex = tabIndex + 7; + this._var.el = { + inputSearch, + checkHidden, + dropAssetGroup, + dropJobsite, + dropJobsiteCode, + grid + } + + const container = createElement('div', 'popup-selector', + createElement('div', 'popup-selector-header', + createElement('img', img => img.src = '../img/modules/devices.png'), + createElement('h3', h3 => h3.innerText = title), + option.assetFullcontrol ? createElement('button', button => { + button.className = 'ui-popup-button'; + button.tabIndex = tabIndex + 1; + button.innerText = r('P_MA_ADDASSET', 'Add Asset'); + button.addEventListener('click', async () => { + if (typeof option.requestAddAsset === 'function') { + this._var.popup.loading = true; + const asset = await option.requestAddAsset(); + this._var.popup.loading = false; + if (asset != null) { + this.select(asset); + this._var.popup.close(); + } + } + }); + }) : '' + ), + createElement('div', 'popup-selector-function', + createElement('div', 'search-box', + inputSearch, + createElement('span', span => { + span.addEventListener('click', () => this.refresh()); + }, + createIcon('fa-light', 'search') + ) + ), + checkHidden, + createElement('span', span => span.innerText = r('P_WO_ASSETGROUP', 'Asset Group')), + dropAssetGroup.create(), + createElement('span', span => span.innerText = r('P_WO_JOBSITE', 'Jobsite')), + dropJobsite.create(), + createElement('span', span => span.innerText = r('P_SELECTASSETS_JOBSITECODE', 'Jobsite Code')), + dropJobsiteCode.create() + ), + gridContent + ); + this._var.container = container; + const popup = new Popup({ + title, + content: container, + persistent: true, + buttons: [ + { + key: 'ok', + text: r('P_GRID_OK', 'OK'), + trigger: () => { + const item = grid.source[grid.selectedIndex]; + if (item == null) { + return false; + } + this.select(item); + } + }, + { text: r('P_WO_CANCEL', 'Cancel') } + ] + }); + this._var.popup = popup; + popup.create(); + popup.rect = { width: 1220 }; + const mask = await popup.show(); + if (option.dataSource == null) { + if (typeof option.requestAssetParams === 'function') { + popup.loading = true; + const data = await option.requestAssetParams(); + option.dataSource = data; + } else { + option.dataSource = { AssetGroups: [], Jobsites: [], Codes: [] }; + } + } + dropAssetGroup.source = [{ Key: '-1', Value: '' }, ...option.dataSource.AssetGroups]; + dropJobsite.source = [{ ID: '-1', Name: '' }, ...option.dataSource.Jobsites]; + dropJobsiteCode.source = [{ value: '-1', text: '' }, ...option.dataSource.Codes.map(c => ({ value: c, text: c }))]; + this.refresh(); + return mask; + } + + show() { + if (this._var.popup == null) { + return this.create(); + } + return this._var.popup.show(); + } +} \ No newline at end of file diff --git a/lib/element/schedule.js b/lib/element/schedule.js index 7a8bf73..943bf6d 100644 --- a/lib/element/schedule.js +++ b/lib/element/schedule.js @@ -11,6 +11,8 @@ export default class ScheduleItem { const getText = opt?.getText; if (typeof getText === 'function') { r = getText; + } else if (typeof GetTextByKey === 'function') { + r = GetTextByKey; } } diff --git a/lib/element/style.scss b/lib/element/style.scss index 103b127..3f2b371 100644 --- a/lib/element/style.scss +++ b/lib/element/style.scss @@ -1,3 +1,5 @@ +@import "../ui/css/functions/func.scss"; + .schedule-item-container { fieldset { @@ -96,6 +98,25 @@ } } +.open-wo-container, +.popup-selector { + + .ui-icon { + width: 14px; + height: 14px; + fill: rgb(123, 28, 33); + cursor: pointer; + transition: opacity .12s ease; + + &:focus, + &:active, + &:hover { + outline: none; + opacity: .4; + } + } +} + .open-wo-container { display: flex; flex-direction: column; @@ -115,28 +136,182 @@ >.open-wo-content { flex: 1 1 auto; margin: 10px; + display: grid; + grid-template-columns: minmax(130px,auto) 1fr; + grid-auto-rows: minmax(32px, auto); + align-items: center; + justify-items: start; >.wo-line { + grid-column: 1 / 3; + } + + .wo-combined { line-height: var(--settings-line-height); + display: flex; + align-items: center; - &.wo-sub-line { - margin-left: 10px; + >.ui-icon { + margin-left: 4px; } + } - >.wo-title { - &.wo-title-required { - &::after { - content: '*'; - color: var(--red-color); - } + .wo-title { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + &.wo-title-required { + &::after { + content: '*'; + color: var(--red-color); } } - >.ui-text { - width: 100%; - height: 80px; - box-sizing: border-box; + } + + .wo-sub-line { + margin-left: 10px; + } + + .wo-asset-name, + .wo-company-name { + margin-left: 6px; + max-width: 400px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .ui-input, + .ui-date-cell, + .ui-drop-wrapper { + margin-left: 4px; + } + + .ui-input { + height: 28px; + line-height: 28px; + box-sizing: border-box; + } + + .ui-input, + .ui-drop-wrapper { + min-width: 180px; + max-width: 300px; + } + + .input-odometer+.ui-drop-wrapper { + min-width: 50px; + } + + .ui-date-cell { + height: 26px; + padding: 0 4px; + + @include outborder(); + + &:invalid { + color: rgba(0, 0, 0, .3); + } + } + + .ui-text { + width: 100%; + height: 80px; + box-sizing: border-box; + } + + .wo-color-line { + display: flex; + align-items: center; + + >em { + flex: 0 0 auto; + width: 14px; + height: 14px; + border-radius: 7px; + } + + >label { + flex: 1 1 auto; + padding-left: 8px; + cursor: pointer; } } } +} + +.popup-selector { + display: flex; + flex-direction: column; + + >.popup-selector-header { + flex: 0 0 auto; + display: flex; + align-items: flex-start; + + >img { + width: 100px; + } + + >h3 { + font-size: var(--font-header-size); + font-family: var(--header-font-family); + margin: 10px; + flex: 1 1 auto; + } + } + + >.popup-selector-function { + flex: 0 0 auto; + margin: 10px; + display: flex; + align-items: center; + + >.search-box { + position: relative; + + >span { + position: absolute; + display: flex; + right: 4px; + top: calc(50% - 7px); + cursor: pointer; + } + } + + .ui-input { + width: 200px; + box-sizing: border-box; + height: 28px; + } + + .ui-drop-wrapper { + margin: 0 8px 0 4px; + width: 180px; + } + } + + >.popup-selector-content { + flex: 1 1 auto; + margin: 10px; + } +} + +.wo-opened-workorder { + display: flex; + flex-direction: column; + width: 650px; + + >header { + flex: 0 0 auto; + margin: 10px; + } + + >.wo-grid-opened { + flex: 1 1 auto; + margin: 0 10px; + height: 400px; + } } \ No newline at end of file diff --git a/lib/element/templateSelector.js b/lib/element/templateSelector.js new file mode 100644 index 0000000..39fc8a6 --- /dev/null +++ b/lib/element/templateSelector.js @@ -0,0 +1,163 @@ +import { Grid, Popup, createElement, createIcon } from "../ui"; +import { r as lang, nullOrEmpty } from "../utility"; + +let r = lang; + +export default class TemplateSelector { + _var = { + option: { + /** + * @private + * @type {(search: string) => Promise} + */ + requestTemplates: null + }, + /** + * @private + * @type {HTMLElement} + */ + container: null, + /** + * @private + * @type {Popup} + */ + popup: null, + el: { + /** + * @private + * @type {HTMLInputElement} + */ + inputSearch: null, + /** + * @private + * @type {Grid} + */ + grid: null + } + }; + + /** + * @event + * @type {(this: TemplateSelector, template: string) => void} + */ + onSelected; + + constructor(opt = {}) { + this._var.option = opt; + const getText = opt.getText; + if (typeof getText === 'function') { + r = getText; + } else if (typeof GetTextByKey === 'function') { + r = GetTextByKey; + } + } + + refresh() { + const requestTemplates = this._var.option.requestTemplates; + if (typeof requestTemplates !== 'function') { + return; + } + const el = this._var.el; + this._var.popup.loading = true; + requestTemplates(el.inputSearch.value) + .then(data => el.grid.source = data) + .finally(() => this._var.popup.loading = false); + } + + select(item) { + if (typeof this.onSelected !== 'function') { + return false; + } + this.onSelected(item); + } + + async create() { + const option = this._var.option; + const title = r('P_MODULE_INSPECTIONTEMPLATES', 'Inspection Templates'); + const tabIndex = Math.max.apply(null, [...document.querySelectorAll('[tabindex]')].map(e => e.tabIndex ?? 0)) + 3; + const inputSearch = createElement('input', input => { + input.type = 'text'; + input.placeholder = r('P_SELECTASSETS_SEARCH', 'Search'); + input.tabIndex = tabIndex + 1; + input.className = 'ui-input'; + input.addEventListener('keypress', e => e.key === 'Enter' && this.refresh()); + }); + const gridContent = createElement('div', div => { + div.className = 'popup-selector-content'; + div.style.height = '400px'; + }); + const grid = new Grid(gridContent, r); + grid.columns = [ + { + key: 'IssueId', + type: Grid.ColumnTypes.Icon, + width: 30, + resizable: false, + filter: it => nullOrEmpty(it.IssueId) ? '' : 'cubes' + }, + { key: 'Name', caption: r('P_IPT_NAME', 'Name'), width: 390 }, + { key: 'Notes', caption: r('P_IPT_NOTES', 'Notes'), width: 630 } + ]; + grid.onRowDblClicked = index => { + const item = grid.source[index]; + this.select(item); + this._var.popup.close(); + }; + grid.init(); + grid.element.tabIndex = tabIndex + 2; + this._var.el = { + inputSearch, + grid + }; + + // content + const container = createElement('div', 'popup-selector', + createElement('div', 'popup-selector-header', + createElement('h3', h3 => h3.innerText = r('P_WO_PLEASESELECTATEMPLATE', 'Please select a template.')) + ), + createElement('div', 'popup-selector-function', + createElement('div', 'search-box', + inputSearch, + createElement('span', span => { + span.addEventListener('click', () => this.refresh()); + }, + createIcon('fa-light', 'search') + ) + ) + ), + gridContent + ); + this._var.container = container; + const popup = new Popup({ + title, + content: container, + persistent: true, + buttons: [ + { + text: r('P_GRID_OK', 'OK'), + trigger: () => { + const item = grid.source[grid.selectedIndex]; + if (item == null) { + return false; + } + this.select(item); + } + }, + { text: r('P_WO_CANCEL', 'Cancel') } + ] + }); + this._var.popup = popup; + popup.create(); + popup.rect = { width: 1200 }; + const mask = await popup.show(); + this.refresh(); + return mask; + } + + show() { + if (this._var.popup == null) { + return this.create(); + } + return this._var.popup.show(); + } +} \ No newline at end of file diff --git a/lib/ui.js b/lib/ui.js index cc7b2ce..1d0588b 100644 --- a/lib/ui.js +++ b/lib/ui.js @@ -8,7 +8,7 @@ import { createTab } from "./ui/tab"; import { Dropdown } from "./ui/dropdown"; import { Grid } from "./ui/grid/grid"; import { GridColumn, GridInputColumn, GridDropdownColumn, GridCheckboxColumn, GridIconColumn, GridTextColumn, GridDateColumn } from './ui/grid/column'; -import { Popup, createPopup, showAlert, showConfirm } from "./ui/popup"; +import { Popup, createPopup, resolvePopup, showAlert, showConfirm } from "./ui/popup"; import { createPicture, createAudio, createVideo, createFile, createVideoList } from './ui/media'; import { validation, convertCssStyle } from './ui/extension'; import { createDateInput, toDateValue, getFormatter, formatDate, setDateValue, getDateValue, DateSelector } from './ui/date'; @@ -75,6 +75,7 @@ export { // popup Popup, createPopup, + resolvePopup, showAlert, showConfirm, // dateSelector diff --git a/lib/ui/checkbox.d.ts b/lib/ui/checkbox.d.ts index e79dfcc..6d93ce5 100644 --- a/lib/ui/checkbox.d.ts +++ b/lib/ui/checkbox.d.ts @@ -10,6 +10,8 @@ interface CheckboxOptions { name?: string; /** 焦点索引 */ tabIndex?: Number; + /** 是否为 switch 样式 */ + switch?: boolean; /** 样式分类,可以是 ['`fa-light`', '`fa-regular`', '`fa-solid`'] 其中之一 */ type?: string; /** 标签 */ diff --git a/lib/ui/checkbox.js b/lib/ui/checkbox.js index e415a43..616c97d 100644 --- a/lib/ui/checkbox.js +++ b/lib/ui/checkbox.js @@ -62,7 +62,7 @@ export function createRadiobox(opts = {}) { } export function createCheckbox(opts = {}) { - const container = createElement('label', 'ui-check-wrapper', + const container = createElement('label', opts.switch ? 'ui-switch' : 'ui-check-wrapper', createElement('input', input => { input.setAttribute('type', 'checkbox'); if (opts.checked === true) { @@ -86,7 +86,23 @@ export function createCheckbox(opts = {}) { if (opts.enabled === false) { container.classList.add('disabled'); } - if (opts.checkedNode != null && opts.uncheckedNode != null) { + if (opts.switch) { + const label = opts.label; + if (label instanceof Element) { + container.appendChild(label); + } else { + container.appendChild( + createElement('span', span => { + if (label != null && String(label).length > 0) { + span.innerText = label; + } + if (opts.title != null) { + span.title = opts.title; + } + }) + ); + } + } else if (opts.checkedNode != null && opts.uncheckedNode != null) { container.classList.add('ui-check-image-wrapper'); let height = opts.imageHeight; if (isNaN(height) || height <= 0) { diff --git a/lib/ui/css/checkbox.scss b/lib/ui/css/checkbox.scss index 2ea8e62..4665050 100644 --- a/lib/ui/css/checkbox.scss +++ b/lib/ui/css/checkbox.scss @@ -55,6 +55,10 @@ user-select: none; cursor: pointer; + &.disabled { + cursor: default; + } + >span:first-of-type { display: inline-flex; align-items: center; @@ -101,9 +105,10 @@ } &:disabled+span:first-of-type { + cursor: default; &::before { - opacity: .5; + opacity: .3; } } } diff --git a/lib/ui/css/common.scss b/lib/ui/css/common.scss index 3e0da0a..f07df0a 100644 --- a/lib/ui/css/common.scss +++ b/lib/ui/css/common.scss @@ -7,7 +7,8 @@ @include outborder(); - &.validation-error { + &.validation-error, + &:invalid { border-color: var(--red-color); &:focus, diff --git a/lib/ui/css/dropdown.scss b/lib/ui/css/dropdown.scss index 3ace6fd..dec15ea 100644 --- a/lib/ui/css/dropdown.scss +++ b/lib/ui/css/dropdown.scss @@ -30,7 +30,8 @@ $listMaxHeight: 210px; flex: 1 1 auto; cursor: pointer; font-size: var(--font-size); - // line-height: $headerHeight; + line-height: $headerHeight; + min-height: $headerHeight; padding: 0 6px; overflow: hidden; text-overflow: ellipsis; diff --git a/lib/ui/css/grid.scss b/lib/ui/css/grid.scss index ae6da1b..0e7dc5e 100644 --- a/lib/ui/css/grid.scss +++ b/lib/ui/css/grid.scss @@ -45,6 +45,7 @@ --header-filter-padding: 4px 26px 4px 8px; --spacing-s: 4px; --spacing-cell: 9px 4px 9px 8px; + --spacing-drop-cell: 5px 4px 5px 8px; --filter-line-height: 30px; --filter-item-padding: 0 4px; } @@ -122,8 +123,10 @@ } } - >.ui-check-wrapper { + >.ui-check-wrapper, + >.ui-switch { height: 20px; + padding: 0 4px 0 0; } >svg { @@ -398,10 +401,12 @@ @include scrollbar(); } - .ui-check-wrapper { + .ui-check-wrapper, + .ui-switch { display: inline-flex; justify-content: center; height: var(--row-height); + padding: 0 8px; .ui-check-inner { @@ -410,6 +415,14 @@ transition: none; } } + + >span:first-of-type { + + &:before, + &:after { + transition: none; + } + } } .ui-drop-span { @@ -439,7 +452,7 @@ height: 100%; >.ui-drop-text { - padding: var(--spacing-cell); + padding: var(--spacing-drop-cell); } } } @@ -708,6 +721,7 @@ .ui-popup-mask .ui-popup-container .ui-popup-footer { >.ui-sort-layout { flex: 1 1 auto; + margin-left: 8px; } } diff --git a/lib/ui/css/popup.scss b/lib/ui/css/popup.scss index 27b333f..21451f0 100644 --- a/lib/ui/css/popup.scss +++ b/lib/ui/css/popup.scss @@ -62,7 +62,7 @@ $buttonHeight: 28px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - padding: 10px 0 6px 12px; + padding: 5px 0 3px 12px; } >.ui-popup-header-title, @@ -76,7 +76,7 @@ $buttonHeight: 28px; >.ui-popup-header-icons { flex: 0 0 auto; - padding: 10px 12px 6px 0; + padding: 5px 12px 3px 0; display: flex; >svg { @@ -145,8 +145,9 @@ $buttonHeight: 28px; margin: 10px; >svg { - width: 40px; - height: 40px; + width: 30px; + height: 30px; + fill: unset; +span { padding-left: 16px; @@ -204,6 +205,10 @@ $buttonHeight: 28px; align-items: center; justify-content: flex-end; padding: 4px 10px 16px 2px; + } + + .ui-popup-body, + .ui-popup-footer { .ui-popup-button { margin-left: 12px; @@ -212,7 +217,7 @@ $buttonHeight: 28px; line-height: $buttonHeight; color: var(--title-color); border-radius: var(--corner-radius); - padding: 4px 16px; + padding: 1px 16px; box-sizing: border-box; min-width: 70px; text-align: center; @@ -227,6 +232,11 @@ $buttonHeight: 28px; } @include outline(); + + &:disabled { + opacity: .4; + cursor: default; + } } } diff --git a/lib/ui/css/variables/definition.scss b/lib/ui/css/variables/definition.scss index 9ab7be8..d27e804 100644 --- a/lib/ui/css/variables/definition.scss +++ b/lib/ui/css/variables/definition.scss @@ -38,7 +38,7 @@ --border-radius: 2px; --text-indent: 4px; --line-height: 18px; - --settings-line-height: 28px; + --settings-line-height: 32px; --font-size: .8125rem; // 13px --font-smaller-size: .75rem; // 12px diff --git a/lib/ui/date.d.ts b/lib/ui/date.d.ts index badeda1..6244980 100644 --- a/lib/ui/date.d.ts +++ b/lib/ui/date.d.ts @@ -87,6 +87,10 @@ export class DateSelector { maxDate?: string, /** 是否启用 */ enabled?: boolean, + /** 焦点索引 */ + tabIndex?: number, + /** 类名 */ + className?: string, /** * 自定义格式化函数,用于获取日期值时调用 * @param date 日期值 diff --git a/lib/ui/date.js b/lib/ui/date.js index 7f19bb2..0567904 100644 --- a/lib/ui/date.js +++ b/lib/ui/date.js @@ -1,4 +1,5 @@ import { createElement } from "../functions"; +import { isPositive, nullOrEmpty } from "../utility"; /** * 创建或转换日期选择框 @@ -344,6 +345,16 @@ export class DateSelector { * @private */ maxDate: null, + /** + * @type {number?} + * @private + */ + tabIndex: null, + /** + * @type {string?} + * @private + */ + className: null, /** * @type {DateFormatterCallback?} * @private @@ -399,6 +410,10 @@ export class DateSelector { create(element) { const opts = this._var.options; const el = createDateInput(opts.minDate, opts.maxDate, element); + isPositive(opts.tabIndex) && el.setAttribute('tabindex', opts.tabIndex); + if (!nullOrEmpty(opts.className)) { + el.classList.add(opts.className); + } if (element == null) { el.disabled = opts.enabled === false; } diff --git a/lib/ui/dropdown.d.ts b/lib/ui/dropdown.d.ts index 927c1f4..c8d383e 100644 --- a/lib/ui/dropdown.d.ts +++ b/lib/ui/dropdown.d.ts @@ -16,6 +16,8 @@ export interface DropdownOptions { valueKey?: string; /** 源码显示的关键字,默认值 `html` */ htmlKey?: string; + /** 源码显示的模板函数 */ + htmlTemplate?: (item: DropdownItem) => HTMLElement; /** 最大输入长度,默认值 `500` */ maxLength?: number; /** 是否允许多选 */ diff --git a/lib/ui/dropdown.js b/lib/ui/dropdown.js index 04633ef..e732857 100644 --- a/lib/ui/dropdown.js +++ b/lib/ui/dropdown.js @@ -130,7 +130,6 @@ export class Dropdown { onCollapsed; constructor(options = {}) { - options.searchPlaceholder ??= r('searchHolder', 'Search...'); options.textKey ??= 'text'; options.valueKey ??= 'value'; options.htmlKey ??= 'html'; @@ -139,7 +138,10 @@ export class Dropdown { const getText = options.getText; if (typeof getText === 'function') { r = getText; + } else if (typeof GetTextByKey === 'function') { + r = GetTextByKey; } + options.searchPlaceholder ??= r('searchHolder', 'Search...'); } create() { diff --git a/lib/ui/grid/column.js b/lib/ui/grid/column.js index 5f2c843..634779e 100644 --- a/lib/ui/grid/column.js +++ b/lib/ui/grid/column.js @@ -44,6 +44,14 @@ export class GridColumn { * @type {boolean} */ + /** + * 标记该类型是否支持列头批量操作 + * @member + * @name GridColumn.headerEditing + * @readonly + * @type {boolean} + */ + /** * 创建显示单元格时调用的方法 * @param {GridColumnDefinition} col - 列定义对象 @@ -579,10 +587,12 @@ export class GridCheckboxColumn extends GridColumn { /** * @ignore * @param {Function} trigger + * @param {GridColumnDefinition} col * @returns {HTMLElement} */ - static createEdit(trigger) { + static createEdit(trigger, col) { const check = createCheckbox({ + switch: col.switch, onchange: trigger }); return check; diff --git a/lib/ui/grid/grid.js b/lib/ui/grid/grid.js index 9330e64..8596e4b 100644 --- a/lib/ui/grid/grid.js +++ b/lib/ui/grid/grid.js @@ -9,11 +9,12 @@ import { setTooltip } from "../tooltip"; import { Popup, showAlert, showConfirm } from "../popup"; import { convertCssStyle } from "../extension"; import { GridColumn, GridInputColumn, GridTextColumn, GridDropdownColumn, GridCheckboxColumn, GridRadioboxColumn, GridIconColumn, GridDateColumn } from "./column"; +import { requestAnimationFrame } from '../../ui'; /** * @author Tsanie Lily * @license MIT - * @version 1.0.3 + * @version 1.0.6 */ const ScriptPath = (self.document == null ? self.location.href : self.document.currentScript?.src ?? '').replace(/ui\.min\.js\?.+$/, ''); @@ -147,6 +148,14 @@ let r = lang; * @this GridColumnDefinition */ +/** + * 行数据过滤项模板回调函数 + * @callback GridItemHtmlCallback + * @param {ValueItem} item - 行数据对象 + * @returns {HTMLElement} 返回过滤项元素对象 + * @this GridColumnDefinition + */ + /** * 行数据字符串回调函数 * @callback GridItemStringCallback @@ -250,13 +259,15 @@ let r = lang; * @property {GridItemObjectCallback} [styleFilter] - **已过时**
_根据返回值填充单元格样式(填充行列数据时读取)_ * @property {(string | GridItemStringCallback)} [background] - 设置单元格背景色(填充行列数据时读取),支持直接设置颜色字符串或调用函数返回(若赋值则忽略 [bgFilter]{@linkcode GridColumnDefinition#bgFilter}) * @property {GridItemStringCallback} [bgFilter] - **已过时**
_根据返回值设置单元格背景色_ - * @property {KeyMap} [events] - 给单元格元素附加事件(事件函数上下文为数据行对象) + * @property {boolean} [switch=false] - 复选框为 `ui-switch` 样式 `@since 1.0.6` * @property {(any | GridItemObjectCallback)} [attrs] - 根据返回值设置单元格元素的附加属性,允许直接设置对象也支持调用函数返回对象 + * @property {KeyMap} [events] - 给单元格元素附加事件(事件函数上下文为数据行对象) * @property {boolean} [allowFilter=false] - 是否允许进行列头过滤 * @property {any[]} [filterValues] - 过滤值的数组 * @property {boolean} [filterAllowNull=false] - 是否区分 `null` 与空字符串 * @property {(ValueItem[] | GridColumnFilterSourceCallback)} [filterSource] - 自定义列过滤器的数据源,支持调用函数返回数据源 * @property {boolean} [filterAsValue=false] - 列头过滤强制使用 `Value` 字段 + * @property {GridItemHtmlCallback} [filterTemplate] - 列头过滤项的模板函数 * @property {GridItemSortCallback} [sortFilter] - 自定义列排序函数 * @property {boolean} [sortAsText=false] - 按照 `DisplayValue` 排序 * @property {DropdownOptions} [dropOptions] - 列为下拉列表类型时以该值设置下拉框的参数 @@ -403,7 +414,7 @@ let r = lang; /** * 判断列是否始终编辑的回调函数 * @callback ColumnTypesEnumIsAlwaysEditing - * @param {number} type - 列类型 + * @param {number | GridColumn} type - 列类型 * @returns {boolean} 返回是否始终编辑 */ @@ -432,7 +443,9 @@ const GridColumnTypeEnum = { * 判断列是否为复选框列 * @type {ColumnTypesEnumIsAlwaysEditing} */ - isAlwaysEditing(type) { return type === 3 || type === 7 } + isAlwaysEditing(type) { + return type?.headerEditing || type === 3 || type === 7; + } }; /** @@ -1111,7 +1124,7 @@ export class Grid { * @property {GridLanguages} [langs] - 多语言资源对象 * @property {number} [virtualCount=100] - 行数大于等于该值则启用虚模式 * @property {boolean} [autoResize=true] - 未设置宽度的列自动调整列宽 - * @property {number} [rowHeight=36] - 表格行高 + * @property {number} [rowHeight=36] - 表格行高,修改后同时需要在 `.ui-grid` 所在父容器重写 `--line-height` 的值以配合显示 * @property {number} [lineHeight=18] - 文本行高(多行文本列计算高度时使用) * @property {string} [filterIcon=ellipsis-h] - 列头未过滤时的图标 * @property {string} [filteredIcon=filter] - 列头已过滤时的图标 @@ -2030,13 +2043,15 @@ export class Grid { } } source ??= [{ column: '', order: 'asc' }]; + pop.create(); + pop.rect = { width: 600, height: 460 }; pop.show(this._var.el).then(() => { - pop.container.style.cssText += 'width: 600px; height: 460px'; if (layout) { const footer = pop.container.querySelector('.ui-popup-footer'); footer.insertBefore(createCheckbox({ label: this.langs.updateLayout, className: 'ui-sort-layout', + switch: true, enabled: false }), footer.children[0]); } @@ -2462,9 +2477,9 @@ export class Grid { direction = 1; } const editing = col.sortAsText !== true; - return (a, b) => { - a = this._getItemSortProp(a.values, editing, col); - b = this._getItemSortProp(b.values, editing, col); + const comparer = (a, b) => { + a = this._getItemSortProp(a, editing, col); + b = this._getItemSortProp(b, editing, col); if (editing) { if (typeof a === 'boolean') { a = a ? 2 : 1; @@ -2473,26 +2488,30 @@ export class Grid { b = b ? 2 : 1; } if (a == null && typeof b === 'number') { - a = 0; + return (b >= 0 ? -1 : 1); } else if (typeof a === 'number' && b == null) { - b = 0; + return (a >= 0 ? 1 : -1); + } else if (a == null && b != null) { + return -1; } else if (a != null && b == null) { - return direction; - } else { - if (Array.isArray(a)) { - a = a.join(', '); - } - if (Array.isArray(b)) { - b = b.join(', '); - } - if (typeof a === 'string' && typeof b === 'string') { - a = a.toLowerCase(); - b = b.toLowerCase(); - } + return 1; + } + if (Array.isArray(a)) { + a = a.join(', '); + } + if (Array.isArray(b)) { + b = b.join(', '); + } + if (typeof a === 'string' && typeof b === 'string') { + a = a.toLowerCase(); + b = b.toLowerCase(); } } else { + if (a == null && b != null) { + return -1; + } if (a != null && b == null) { - return direction; + return 1; } if (Array.isArray(a)) { a = a.join(', '); @@ -2505,8 +2524,9 @@ export class Grid { b = b.toLowerCase(); } } - return a === b ? 0 : (a > b ? 1 : -1) * direction; + return a === b ? 0 : (a > b ? 1 : -1); }; + return (a, b) => comparer(a.values, b.values) * direction; } return (a, b) => col.sortFilter(a.values, b.values) * direction; } @@ -2670,6 +2690,7 @@ export class Grid { th.appendChild(wrapper); if (!readonly && col.enabled !== false && col.allcheck && alwaysEditing) { const check = createCheckbox({ + switch: col.switch, onchange: e => this._onColumnAllChecked(col, e.target.checked) }); wrapper.appendChild(check); @@ -3625,11 +3646,14 @@ export class Grid { /** * @private - * @param {string} tagName + * @param {HTMLElement} e * @returns {boolean} */ - _notHeader(tagName) { - return /^(input|label|layer|svg|use)$/i.test(tagName); + _notHeader(e) { + if (e.parentElement.classList.contains('ui-switch')) { + return true; + } + return /^(input|label|layer|svg|use)$/i.test(e.tagName); } /** @@ -3642,7 +3666,7 @@ export class Grid { if (!force && (this._get(col.key, 'resizing') || this._get(col.key, 'dragging'))) { return; } - if (!this._notHeader(e.target.tagName)) { + if (!this._notHeader(e.target)) { if (Array.isArray(this.sortArray) && this.sortArray.length > 0) { showConfirm(this.langs.sort, this.langs.sortArrayExists, [ { @@ -3652,8 +3676,8 @@ export class Grid { { text: this.langs.cancel } - ]).then(result => { - if (result?.key === 'yes') { + ]).then(r => { + if (r.result === 'yes') { const sortCol = this.sortArray.find(c => c.column === col.key); this.sortDirection = sortCol?.order === 'asc' ? -1 : 1; this._onDoHeaderSort(col); @@ -3790,22 +3814,27 @@ export class Grid { if (!Object.hasOwnProperty.call(dict, display)) { dict[display] = { Value: vals[i], - DisplayValue: display + DisplayValue: display, + RowItem: item.values }; } }); } else if (!Object.hasOwnProperty.call(dict, displayValue)) { dict[displayValue] = { Value: this._getItemProp(item.values, true, col), - DisplayValue: displayValue + DisplayValue: displayValue, + RowItem: item.values }; } } - const filterAsValue = col.filterAsValue; - const type = this._var.colTypes[col.key]; - const isDateColumn = type === GridDateColumn || type instanceof GridDateColumn; - array = Object.values(dict) - .sort((itemA, itemB) => { + array = Object.values(dict); + if (typeof col.sortFilter === 'function') { + array.sort((a, b) => col.sortFilter(a.RowItem, b.RowItem)); + } else { + const type = this._var.colTypes[col.key]; + const isDateColumn = type === GridDateColumn || type instanceof GridDateColumn; + const filterAsValue = col.filterAsValue; + array.sort((itemA, itemB) => { let a = itemA.Value; let b = itemB.Value; if (a instanceof Date || b instanceof Date) { @@ -3828,6 +3857,7 @@ export class Grid { } return a > b ? 1 : (a < b ? -1 : 0); }); + } } array = array.map(i => { if (Object.prototype.hasOwnProperty.call(i, 'Value') && @@ -3907,7 +3937,7 @@ export class Grid { panel.appendChild(functions); this._var.el.appendChild(panel); - setTimeout(() => panel.classList.add('active'), 0); + requestAnimationFrame(() => panel.classList.add('active')); this._var.colAttrs.__filtering = filter; filter.classList.add('hover'); } @@ -3943,24 +3973,32 @@ export class Grid { if (array.length > 12) { array = array.slice(0, 12); } - this._doFillFilterList(content, array, all); + this._doFillFilterList(col, content, array, all); list.append(holder, content); } /** * @private + * @param {GridColumnDefinition} col * @param {HTMLDivElement} content * @param {ValueItem[]} array * @param {HTMLDivElement} all */ - _doFillFilterList(content, array, all) { + _doFillFilterList(col, content, array, all) { for (let item of array) { const div = createElement('div', 'filter-item'); - const display = Object.prototype.hasOwnProperty.call(item, 'DisplayValue') ? item.DisplayValue : item; + const title = Object.prototype.hasOwnProperty.call(item, 'DisplayValue') ? item.DisplayValue : item; + let display; + if (typeof col.filterTemplate === 'function') { + display = col.filterTemplate(item); + } + if (display == null) { + display = title && String(title).replace(/( |\r\n|\n|)/g, '\u00a0'); + } div.appendChild(createCheckbox({ checked: item.__checked, - label: display && String(display).replace(/( |\r\n|\n|)/g, '\u00a0'), - title: display, + label: display, + title, onchange: e => { item.__checked = e.target.checked; all.querySelector('input').checked = ![...content.querySelectorAll('input')].some(i => !i.checked); @@ -4001,7 +4039,7 @@ export class Grid { } const content = list.querySelector('.filter-content'); content.replaceChildren(); - this._doFillFilterList(content, array, list.querySelector('.filter-all')); + this._doFillFilterList(col, content, array, list.querySelector('.filter-all')); content.style.top = `${top + rowHeight}px`; } } @@ -4012,7 +4050,7 @@ export class Grid { * @param {GridColumnDefinition} col */ _onDragStart(e, col) { - if (this._notHeader(e.target.tagName)) { + if (this._notHeader(e.target)) { return; } if (e.currentTarget.classList.contains('sticky')) { @@ -4066,7 +4104,7 @@ export class Grid { if (attr.offset == null) { delete attr.dragging; } else { - setTimeout(() => { + requestAnimationFrame(() => { delete attr.dragging; delete attr.offset; }); @@ -4116,7 +4154,7 @@ export class Grid { clearEvents(attr); const width = attr.resizing; if (width != null) { - setTimeout(() => delete attr.resizing); + requestAnimationFrame(() => delete attr.resizing); if (attr.sizing) { delete attr.sizing; delete attr.autoResize; diff --git a/lib/ui/icon.d.ts b/lib/ui/icon.d.ts index d4da461..71caad5 100644 --- a/lib/ui/icon.d.ts +++ b/lib/ui/icon.d.ts @@ -3,8 +3,9 @@ * @param type 样式分类,可以是 ['`fa-light`', '`fa-regular`', '`fa-solid`'] 其中之一 * @param id 图标 id * @param style 样式表对象 + * @param action 点击回调事件 */ -export function createIcon(type: string, id: string, style?: { [key: string]: string }): SVGSVGElement +export function createIcon(type: string, id: string, style?: { [key: string]: string } | ((icon: SVGSVGElement) => { [key: string]: string }), action?: (this: SVGSVGElement, ev: MouseEvent) => any): SVGSVGElement /** * 修改矢量图标 * @param svg 矢量图标元素 diff --git a/lib/ui/icon.js b/lib/ui/icon.js index 56511a2..f68ccaa 100644 --- a/lib/ui/icon.js +++ b/lib/ui/icon.js @@ -24,15 +24,20 @@ export function changeIcon(svg, type, id) { return svg; } -export function createIcon(type, id, style) { +export function createIcon(type, id, style, action) { const svg = document.createElementNS(svgns, 'svg'); svg.classList.add('ui-icon'); svg.appendChild(createUse(type, id)); - if (style != null) { + if (typeof style === 'function') { + style(svg); + } else if (style != null) { for (let css of Object.entries(style)) { svg.style.setProperty(css[0], css[1]); } } + if (typeof action === 'function') { + svg.addEventListener('click', action); + } return svg; } diff --git a/lib/ui/popup.d.ts b/lib/ui/popup.d.ts index 5593368..a4b6a79 100644 --- a/lib/ui/popup.d.ts +++ b/lib/ui/popup.d.ts @@ -7,6 +7,8 @@ interface PopupOptions { /** 弹出框标题,可以是文本或者 html 元素 */ title: string | HTMLElement; + /** 是否持久化显示 */ + persistent?: boolean; /** 是否包含遮罩层,默认为 `true` */ mask?: boolean; /** 遮罩层 z-index */ @@ -66,6 +68,21 @@ interface PopupOptions { export class Popup { constructor(opts?: PopupOptions); + + get container(): HTMLElement; + + get title(): string; + set title(title: string); + + get loading(): boolean; + set loading(flag: boolean); + + get rect(): { collapsed: boolean, left: number, top: number, width: number, height: number }; + set rect(r: { collapsed?: boolean, left?: number, top?: number, width?: number, height?: number }); + + close(result?: any, animation?: boolean): void; + create(): HTMLDivElement; + show(parent?: HTMLElement, hidden?: boolean): Promise | undefined; } interface PopupButton { @@ -86,12 +103,14 @@ interface PopupIconTypes { } interface PopupButtonResult { - key: string; + result: string; popup: Popup; } export function createPopup(title: string | HTMLElement, content: string | HTMLElement, ...buttons: PopupButton[]): Popup +export function resolvePopup(wrapper: string | HTMLElement, callback?: Function, removable?: boolean, zIndex?: number): Popup + export function showAlert(title: string | HTMLElement, message: string, iconType?: keyof PopupIconTypes, parent?: HTMLElement): Promise export function showConfirm(title: string | HTMLElement, content: string | HTMLElement, buttons: PopupButton[], iconType?: keyof PopupIconTypes, parent?: HTMLElement): Promise \ No newline at end of file diff --git a/lib/ui/popup.js b/lib/ui/popup.js index c4fb532..81dc242 100644 --- a/lib/ui/popup.js +++ b/lib/ui/popup.js @@ -1,9 +1,10 @@ import "./css/popup.scss"; -import { r } from "../utility/lgres"; +import { r as lang } from "../utility/lgres"; import { nullOrEmpty } from "../utility/strings"; import { global } from "../utility"; import { createElement } from "../functions"; import { createIcon, changeIcon } from "./icon"; +import { requestAnimationFrame } from "../ui"; const ResizeMods = { right: 1, @@ -51,6 +52,30 @@ export class Popup { get container() { return this._var.mask.querySelector('.ui-popup-container') } + get title() { return this._var.option.title } + set title(title) { + const element = this._var.mask?.querySelector('.ui-popup-container .ui-popup-header .ui-popup-header-title'); + if (element != null) { + element.innerText = title; + } + this._var.option.title = title; + } + + get loading() { return this._var.mask?.querySelector('.ui-popup-body>.ui-popup-loading')?.style?.visibility === 'visible' } + set loading(flag) { + let loading = this._var.mask?.querySelector('.ui-popup-body>.ui-popup-loading'); + if (loading == null) { + return; + } + if (flag === false) { + loading.style.visibility = 'hidden'; + loading.style.opacity = 0; + } else { + loading.style.visibility = 'visible'; + loading.style.opacity = 1; + } + } + get rect() { const container = this.container; if (container == null) { @@ -105,25 +130,41 @@ export class Popup { } } - close(animation = true) { + close(result = null, animation = true) { + const option = this._var.option; const mask = this._var.mask; + const doClose = () => { + if (option.persistent) { + mask.style.display = 'none'; + } else { + mask.remove(); + this._var.mask = null; + } + } if (animation) { mask.classList.add('ui-popup-active'); mask.style.opacity = 0; - setTimeout(() => { mask.remove(); }, 120); + setTimeout(() => { doClose(); }, 120); } else { - mask.remove(); + doClose(); } - if (typeof this._var.option.onMasking === 'function') { - this._var.option.onMasking.call(this, false); + if (typeof option.onMasking === 'function') { + option.onMasking.call(this, false); } - if (typeof this._var.option.resolve === 'function') { - this._var.option.resolve(); + if (typeof option.resolve === 'function') { + option.resolve.call(this, { + result, + popup: this + }); } } + /** + * 创建 Popup 面板 + * @returns {HTMLDivElement} 返回遮罩元素(顶层元素) + */ create() { - const mask = createElement('div', 'ui-popup-mask'); + const mask = createElement('div', 'ui-popup-mask ui-popup-active'); const option = this._var.option; if (option.mask === false) { mask.classList.add('ui-popup-transparent'); @@ -286,14 +327,14 @@ export class Popup { if (typeof result?.then === 'function') { result.then(r => { if (r !== false) { - this.close(); + this.close(r); } }).catch(reason => console.warn(reason)); } else if (result !== false) { - this.close(); + this.close(result); } } else { - this.close(); + this.close(b.key ?? i); } }); return button; @@ -357,24 +398,33 @@ export class Popup { return mask; } - show(parent = document.body) { + show(parent = document.body, hidden = false) { if (parent == null) { return; } - let mask = this._var.mask ?? this.create(); - // const exists = [...parent.children].filter(e => e.classList.contains('ui-popup-mask')); - const exists = parent.querySelectorAll('.ui-popup-mask'); - let zindex = 0; - for (let ex of exists) { - let z = parseInt(ex.style.zIndex); - if (!isNaN(z) && z > zindex) { - zindex = z; + let mask = this._var.mask; + if (mask == null) { + mask = this._var.mask = this.create(); + } + if (mask.parentElement == null) { + // const exists = [...parent.children].filter(e => e.classList.contains('ui-popup-mask')); + const exists = parent.querySelectorAll('.ui-popup-mask'); + let zindex = 0; + for (let ex of exists) { + let z = parseInt(global.getComputedStyle(ex).zIndex); + if (!isNaN(z) && z > zindex) { + zindex = z; + } + } + if (zindex > 0) { + mask.style.zIndex = String(zindex + 1); + } + parent.appendChild(mask); + if (hidden === true) { + mask.style.display = 'none'; + return Promise.resolve(mask); } } - if (zindex > 0) { - mask.style.zIndex = String(zindex + 1); - } - parent.appendChild(mask); if (this._var.option.mask === false) { // calculator position const container = this.container; @@ -382,29 +432,16 @@ export class Popup { container.style.top = String((parent.offsetHeight - container.offsetHeight) / 2) + 'px'; } return new Promise(resolve => { - setTimeout(() => { + mask.style.display = ''; + requestAnimationFrame(() => { + mask.classList.remove('ui-popup-active'); mask.style.opacity = 1; this.container.focus(); - resolve(mask); - }, 0); + setTimeout(() => resolve(mask), 120); + }); }); } - get loading() { return this._var.mask?.querySelector('.ui-popup-body>.ui-popup-loading')?.style?.visibility === 'visible' } - set loading(flag) { - let loading = this._var.mask?.querySelector('.ui-popup-body>.ui-popup-loading'); - if (loading == null) { - return; - } - if (flag === false) { - loading.style.visibility = 'hidden'; - loading.style.opacity = 0; - } else { - loading.style.visibility = 'visible'; - loading.style.opacity = 1; - } - } - _resize(mod, e) { if (e.buttons !== 1) { return; @@ -500,6 +537,43 @@ export function createPopup(title, content, ...buttons) { return popup; } +/** + * 解析对话框元素 + * @param {HTMLElement | string} wrapper - 解析该 `.dialog` 元素 + * @param {Function} [callback] - 关闭对话框时的回调 + * @param {boolean} [removable] - 是否可移除 + * @param {number} [zIndex] - 对话框默认 `z-index` + * @returns {Popup} 返回弹出框字典 + */ +export function resolvePopup(wrapper, callback, removable, zIndex) { + if (typeof wrapper === 'string') { + wrapper = document.querySelector(wrapper); + } + if (wrapper == null) { + return null; + } + if (!wrapper.classList.contains('dialog')) { + return null; + } + const title = wrapper.querySelector('.dialog-title>.title')?.innerText; + const content = wrapper.querySelector('.dialog-title+div'); + const buttons = [...wrapper.querySelectorAll('.dialog-func>input[type="button"]')].reverse().map(b => ({ + tabIndex: b.tabIndex, + text: b.value, + trigger: b.onclick == null ? null : (popup => (b.onclick.call(popup), false)) + })); + const popup = new Popup({ + title, + content, + persistent: !removable, + resolve: typeof callback === 'function' ? (result => callback(result)) : null, + zIndex: wrapper.zIndex ?? zIndex, + buttons + }); + popup.show(document.body, true); + return popup; +} + const iconTypes = { 'info': 'info-circle', 'information': 'info-circle', @@ -510,6 +584,7 @@ const iconTypes = { } export function showAlert(title, message, iconType = 'info', parent = document.body) { + const r = typeof GetTextByKey === 'function' ? GetTextByKey : lang; return new Promise(resolve => { const popup = new Popup({ title, @@ -519,7 +594,7 @@ export function showAlert(title, message, iconType = 'info', parent = document.b ), resolve, buttons: [ - { text: r('ok', 'OK'), trigger: resolve } + { text: r('ok', 'OK') } ] }); popup.show(parent).then(mask => { @@ -530,6 +605,7 @@ export function showAlert(title, message, iconType = 'info', parent = document.b } export function showConfirm(title, content, buttons, iconType = 'question', parent = document.body) { + const r = typeof GetTextByKey === 'function' ? GetTextByKey : lang; return new Promise(resolve => { const wrapper = createElement('div', 'message-wrapper'); if (!nullOrEmpty(iconType)) { @@ -542,34 +618,23 @@ export function showConfirm(title, content, buttons, iconType = 'question', pare title, content: wrapper, resolve, - buttons: buttons?.map(b => { + buttons: buttons?.map((b, i) => { return { text: b.text, trigger: p => { let result; if (typeof b.trigger === 'function') { result = b.trigger(p, b); - if (typeof result?.then === 'function') { - return result.then(r => { - r !== false && resolve(r); - return r; - }); - } - result !== false && resolve(result); } else { - result = { - key: b.key, - popup: p - }; - resolve(result); + result = b.key ?? i; } return result; } }; }) ?? [ - { text: r('yes', 'Yes'), trigger: p => resolve({ key: 'yes', popup: p }) }, - { text: r('no', 'No'), trigger: p => resolve({ key: 'no', popup: p }) } + { key: 'yes', text: r('yes', 'Yes') }, + { key: 'no', text: r('no', 'No') } ] }); popup.show(parent).then(mask => { diff --git a/package-lock.json b/package-lock.json index 6718dd0..8d42ba1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,28 +1,28 @@ { "name": "ui-lib", - "version": "1.0.4", + "version": "1.0.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ui-lib", - "version": "1.0.4", + "version": "1.0.5", "devDependencies": { "@mxssfd/typedoc-theme": "^1.1.3", "clean-jsdoc-theme": "^4.3.0", "docdash": "^2.0.2", "jsdoc": "^4.0.3", "postcss-preset-env": "^9.5.14", - "sass": "^1.77.4", + "sass": "^1.77.6", "typedoc": "^0.25.13", - "vite": "^5.2.12", + "vite": "^5.3.1", "vite-plugin-externals": "^0.6.2" } }, "node_modules/@babel/parser": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz", - "integrity": "sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", + "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1012,9 +1012,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ "ppc64" ], @@ -1028,9 +1028,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], @@ -1044,9 +1044,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -1060,9 +1060,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], @@ -1076,9 +1076,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -1092,9 +1092,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -1108,9 +1108,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], @@ -1124,9 +1124,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -1140,9 +1140,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -1156,9 +1156,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -1172,9 +1172,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], @@ -1188,9 +1188,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], @@ -1204,9 +1204,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], @@ -1220,9 +1220,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], @@ -1236,9 +1236,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], @@ -1252,9 +1252,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], @@ -1268,9 +1268,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -1284,9 +1284,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], @@ -1300,9 +1300,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], @@ -1316,9 +1316,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], @@ -1332,9 +1332,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], @@ -1348,9 +1348,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], @@ -1364,9 +1364,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -1698,9 +1698,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1817,9 +1817,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "version": "4.23.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", + "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", "dev": true, "funding": [ { @@ -1836,10 +1836,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", + "caniuse-lite": "^1.0.30001629", + "electron-to-chromium": "^1.4.796", "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "update-browserslist-db": "^1.0.16" }, "bin": { "browserslist": "cli.js" @@ -1865,9 +1865,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001627", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001627.tgz", - "integrity": "sha512-4zgNiB8nTyV/tHhwZrFs88ryjls/lHiqFhrxCW4qSTeuRByBVnPYpDInchOIySWknznucaf31Z4KYqjfbrecVw==", + "version": "1.0.30001636", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz", + "integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==", "dev": true, "funding": [ { @@ -2080,9 +2080,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.789", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.789.tgz", - "integrity": "sha512-0VbyiaXoT++Fi2vHGo2ThOeS6X3vgRCWrjPeO2FeIAWL6ItiSJ9BqlH8LfCXe3X1IdcG+S0iLoNaxQWhfZoGzQ==", + "version": "1.4.805", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.805.tgz", + "integrity": "sha512-8W4UJwX/w9T0QSzINJckTKG6CYpAUTqsaWcWIsdud3I1FYJcMgW9QqT1/4CBff/pP/TihWh13OmiyY8neto6vw==", "dev": true }, "node_modules/entities": { @@ -2104,9 +2104,9 @@ "dev": true }, "node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "bin": { @@ -2116,29 +2116,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/escalade": { @@ -3366,9 +3366,9 @@ } }, "node_modules/sass": { - "version": "1.77.4", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.4.tgz", - "integrity": "sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==", + "version": "1.77.6", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.6.tgz", + "integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -3467,9 +3467,9 @@ } }, "node_modules/terser": { - "version": "5.31.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.0.tgz", - "integrity": "sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==", + "version": "5.31.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.1.tgz", + "integrity": "sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -3601,12 +3601,12 @@ "dev": true }, "node_modules/vite": { - "version": "5.2.12", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.12.tgz", - "integrity": "sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.1.tgz", + "integrity": "sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==", "dev": true, "dependencies": { - "esbuild": "^0.20.1", + "esbuild": "^0.21.3", "postcss": "^8.4.38", "rollup": "^4.13.0" }, diff --git a/package.json b/package.json index d7b1184..8a9a588 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ui-lib", "private": true, - "version": "1.0.4", + "version": "1.0.6", "type": "module", "files": [ "dist" @@ -33,9 +33,9 @@ "docdash": "^2.0.2", "jsdoc": "^4.0.3", "postcss-preset-env": "^9.5.14", - "sass": "^1.77.4", + "sass": "^1.77.6", "typedoc": "^0.25.13", - "vite": "^5.2.12", + "vite": "^5.3.1", "vite-plugin-externals": "^0.6.2" } }