From eec9d6045ca1e6db9804e634f7840f5b4a0ea2bf Mon Sep 17 00:00:00 2001 From: Chen Lily Date: Fri, 30 Aug 2024 17:36:21 +0800 Subject: [PATCH] sync --- lib/app/communications/comments.js | 10 +-- lib/app/communications/contact.js | 52 ++++++------ lib/app/communications/customer.js | 122 ++++++++++++++--------------- lib/app/communications/follower.js | 14 ++-- lib/app/communications/internal.js | 14 ++-- lib/app/communications/lib.js | 42 +++++----- lib/element/addworkorder.js | 70 ++++++++--------- lib/element/assetSelector.js | 30 +++---- lib/element/inspectionWizard.js | 14 ++-- lib/element/schedule.js | 6 +- lib/element/signature.js | 8 +- lib/element/templateSelector.js | 10 +-- lib/ui/checkbox.js | 9 ++- lib/ui/css/dropdown.scss | 15 +++- lib/ui/css/functions/func.scss | 17 +++- lib/ui/date.js | 3 +- lib/ui/dropdown.js | 58 ++++++++++++-- lib/ui/grid/grid.js | 43 ++++++++-- lib/utility.js | 14 +++- 19 files changed, 332 insertions(+), 219 deletions(-) diff --git a/lib/app/communications/comments.js b/lib/app/communications/comments.js index e63ee6b..387936d 100644 --- a/lib/app/communications/comments.js +++ b/lib/app/communications/comments.js @@ -71,7 +71,7 @@ export default class CustomerRecordComment { createElement('div', null, createElement('div', div => { div.className = 'title-module'; - div.innerText = r('P_CR_COMMENTS', 'Comments'); + div.innerText = r('FLTL_00584', 'Comments'); }, createHideMessageTitleButton(this, 'showCommentHidden') ) @@ -97,7 +97,7 @@ export default class CustomerRecordComment { ); // enter box const enter = createElement('textarea', 'ui-text'); - enter.placeholder = r('P_CU_ENTERCOMMENTHERE', 'Enter Comment Here'); + enter.placeholder = r('FLTL_01154', 'Enter Comment Here'); enter.maxLength = this._var.option.maxLength ??= 3000; enter.addEventListener('input', () => { const val = this.text; @@ -120,8 +120,8 @@ export default class CustomerRecordComment { button.style.display = 'none'; } button.appendChild(createIcon('fa-solid', 'paper-plane')); - // setTooltip(button, r('P_M3_SENDMESSAGE', 'Send Message')); - setTooltip(button, r('P_CU_POSTNOTE', 'Post Note')); + // setTooltip(button, r('FLTL_02692', 'Send Message')); + setTooltip(button, r('FLTL_02301', 'Post Note')); button.addEventListener('click', () => { if (typeof this._var.option.onAddComment === 'function') { this._var.option.onAddComment(this.text); @@ -151,7 +151,7 @@ export default class CustomerRecordComment { } } // if (sendto !== '') { - // sendto = r('P_CU_SENDTO_COLON', 'Sent To :') + `\n${sendto}`; + // sendto = r('FLTL_02716', 'Sent To :') + `\n${sendto}`; // } div.appendChild(createElement('div', div => { div.className = 'item-poster'; diff --git a/lib/app/communications/contact.js b/lib/app/communications/contact.js index e1d7ef3..2403908 100644 --- a/lib/app/communications/contact.js +++ b/lib/app/communications/contact.js @@ -29,9 +29,9 @@ export class Contact { }); const preferences = new Dropdown({ tabIndex: tabIndex + 2 }); preferences.source = [ - { value: '0', text: r('P_CR_TEXT', 'Text') }, - { value: '1', text: r('P_CR_EMAIL', 'Email') }, - { value: '2', text: r('P_CR_PHONE', 'Phone') } + { value: '0', text: r('FLTL_02915', 'Text') }, + { value: '1', text: r('FLTL_01089', 'Email') }, + { value: '2', text: r('FLTL_02194', 'Phone') } ]; const contactEmail = createElement('input', input => { input.type = 'email'; @@ -57,7 +57,7 @@ export class Contact { const buttons = []; if (this._var.option.company) { buttons.push({ - text: c == null ? r('P_WO_ADDCONTACTRECORD', 'Add Contact Record') : r('P_WO_EDITCONTACTRECORD', 'Edit Contact Record'), + text: c == null ? r('FLTL_00100', 'Add Contact Record') : r('FLTL_01042', 'Edit Contact Record'), // tabIndex: tabIndex + 7, trigger: () => { const item = this.prepare(); @@ -73,7 +73,7 @@ export class Contact { } buttons.push( { - text: r('P_WO_WORKORDERONLY', 'Work Order Only'), + text: r('FLTL_03348', 'Work Order Only'), // tabIndex: tabIndex + 8, trigger: () => { const item = this.prepare(); @@ -88,39 +88,39 @@ export class Contact { } }, { - text: r('P_WO_CANCEL', 'Cancel'), + text: r('FLTL_00499', 'Cancel'), // tabIndex: tabIndex + 9 } ); const popup = new Popup({ onMasking: this._var.option.onMasking, - title: c == null ? r('P_CR_ADDCONTACT', 'Add Contact') : r('P_CR_EDITCONTACT', 'Edit Contact'), + title: c == null ? r('FLTL_00099', 'Add Contact') : r('FLTL_01041', 'Edit Contact'), content: createElement('div', wrapper => { wrapper.className = 'setting-wrapper'; wrapper.style.width = '500px'; }, createElement('div', 'setting-item', - createElement('span', 'setting-label setting-required', r('P_CR_CONTACTNAME_COLON', 'Contact Name:')), + createElement('span', 'setting-label setting-required', r('FLTL_00640', 'Contact Name:')), contactName ), createElement('div', 'setting-item', - createElement('span', 'setting-label', r('P_CR_CONTACTPREFERENCES_COLON', 'Contact Preferences:')), + createElement('span', 'setting-label', r('FLTL_00643', 'Contact Preferences:')), preferences.create() ), createElement('div', 'setting-item', - createElement('span', 'setting-label', r('P_CR_EMAILADDRESS_COLON', 'Email Address:')), + createElement('span', 'setting-label', r('FLTL_01092', 'Email Address:')), contactEmail ), createElement('div', 'setting-item', - createElement('span', 'setting-label', r('P_WO_MOBILE_COLON', 'Mobile:')), + createElement('span', 'setting-label', r('FLTL_01932', 'Mobile:')), contactMobile ), createElement('div', 'setting-item', - createElement('span', 'setting-label', r('P_CR_OPTOUT_COLON', 'Opt Out:')), + createElement('span', 'setting-label', r('FLTL_02089', 'Opt Out:')), checkOpt ), createElement('div', 'setting-item', - createElement('span', 'setting-label', r('P_CR_NOTES_COLON', 'Notes:')), + createElement('span', 'setting-label', r('FLTL_02017', 'Notes:')), contactNotes ) ), @@ -156,24 +156,24 @@ export class Contact { const phone = this._var.refs.contactMobile.value; const opt = this._var.refs.checkOpt.querySelector('input').checked; const notes = this._var.refs.contactNotes.value; - const title = this._var.option.contact == null ? r('P_CR_ADDCONTACT', 'Add Contact') : r('P_CR_EDITCONTACT', 'Edit Contact'); + const title = this._var.option.contact == null ? r('FLTL_00099', 'Add Contact') : r('FLTL_01041', 'Edit Contact'); if (nullOrEmpty(name)) { - showAlert(title, r('P_CR_CONTACTNAMECANNOTBEEMPTY', 'Contact Name cannot be empty.'), 'warn') + showAlert(title, r('FLTL_00639', 'Contact Name cannot be empty.'), 'warn') .then(() => this._var.refs.contactName.focus()); return null; } if ((pref == 0 || pref == 2) && nullOrEmpty(phone)) { - showAlert(title, r('P_CR_MOBILECANNOTBEEMPTY', 'Mobile cannot be empty.'), 'warn') + showAlert(title, r('FLTL_01929', 'Mobile cannot be empty.'), 'warn') .then(() => this._var.refs.contactMobile.focus()); return null; } if (pref == 1 && nullOrEmpty(email)) { - showAlert(title, r('P_CU_EMAILCANNOTBEEMPTY', 'Email cannot be empty.'), 'warn') + showAlert(title, r('FLTL_01094', 'Email cannot be empty.'), 'warn') .then(() => this._var.refs.contactEmail.focus()); return null; } if (!nullOrEmpty(email) && !isEmail(email)) { - showAlert(title, r('P_CR_EMAILISNOTAVALIDEMAILADDRESS', 'The email address is invalid.'), 'warn') + showAlert(title, r('FLTL_02952', 'The email address is invalid.'), 'warn') .then(() => this._var.refs.contactEmail.focus()); return null; } @@ -223,7 +223,7 @@ export class CustomerRecordContact { ), buttons: [ { - text: r('P_WO_OK', 'OK'), + text: r('FLTL_02057', 'OK'), key: 'ok', trigger: () => { if (typeof this._var.option.onOk === 'function') { @@ -231,7 +231,7 @@ export class CustomerRecordContact { } } }, - { text: r('P_WO_CANCEL', 'Cancel'), key: 'cancel' } + { text: r('FLTL_00499', 'Cancel'), key: 'cancel' } ] }); const result = await popup.show(parent); @@ -244,12 +244,12 @@ export class CustomerRecordContact { width: 40, // enabled: item => !nullOrEmpty(item.ID) }, - { key: 'Name', caption: r("P_CR_CONTACTNAME", "Contact Name"), width: 100 }, - { key: 'Email', caption: r("P_CR_CONTACTEMAIL", "Contact Email"), css: { 'width': 180, 'text-align': 'left' } }, - { key: 'MobilePhoneDisplayText', caption: r("P_CR_CONTACTMOBILE", "Contact Mobile"), width: 130 }, - { key: 'ContactPreferenceStr', caption: r("P_CR_CONTACTPREFERENCES", "Contact Preferences"), width: 100 }, - { key: 'OptOut', caption: r("P_CR_OPTOUT", "Opt Out"), type: Grid.ColumnTypes.Checkbox, width: 70, enabled: false, align: 'center' }, - { key: 'Notes', caption: r("P_CR_NOTES", "Notes"), width: 120 } + { key: 'Name', caption: r('FLTL_00637', 'Contact Name'), width: 100 }, + { key: 'Email', caption: r('FLTL_00633', 'Contact Email'), css: { 'width': 180, 'text-align': 'left' } }, + { key: 'MobilePhoneDisplayText', caption: r('FLTL_00636', 'Contact Mobile'), width: 130 }, + { key: 'ContactPreferenceStr', caption: r('FLTL_00642', 'Contact Preferences'), width: 100 }, + { key: 'OptOut', caption: r('FLTL_02084', 'Opt Out'), type: Grid.ColumnTypes.Checkbox, width: 70, enabled: false, align: 'center' }, + { key: 'Notes', caption: r('FLTL_02012', 'Notes'), width: 120 } ]; grid.init(); grid.source = this._var.option.contacts.sort(function (a, b) { return ((b.Text || b.Email) ? 1 : 0) - ((a.Text || a.Email) ? 1 : 0) }); diff --git a/lib/app/communications/customer.js b/lib/app/communications/customer.js index 144b399..21e24dd 100644 --- a/lib/app/communications/customer.js +++ b/lib/app/communications/customer.js @@ -215,7 +215,7 @@ export default class CustomerCommunication { let tipstr; if (c.OptOut || c.OptOut_BC || c.selected === false) { icon = 'times'; - tipstr = r('P_CU_OPTEDOUT_PROMPT', 'User has opted out of messages'); + tipstr = r('FLTL_03200', 'User has opted out of messages'); } else { switch (pref) { @@ -224,20 +224,20 @@ export default class CustomerCommunication { icon = 'times'; if (c.MobilePhoneStatus === 412) { // landline - tipstr = r('P_CU_LANDLINE', 'Landline'); + tipstr = r('FLTL_01707', 'Landline'); } } else { icon = 'comment-lines'; } - method = r('P_CU_TEXTSTO_COLON', 'Texts to:'); + method = r('FLTL_02924', 'Texts to:'); break; case '2': icon = 'phone'; - tipstr = r('P_CU_NOMESSAGE', 'No Messages Sent'); + tipstr = r('FLTL_01991', 'No Messages Sent'); break; default: icon = 'envelope'; - method = r('P_CU_EMAILSTO_COLON', 'Emails to:'); + method = r('FLTL_01109', 'Emails to:'); break; } } @@ -254,7 +254,7 @@ export default class CustomerCommunication { this._var.contacts.appendChild(item); let tip = tipstr || `${method} ${to}`; if (span.scrollWidth > span.offsetWidth) { - tip = r('P_WO_NAME_COLON', 'Name:') + ` ${c.Name}\n${tip}`; + tip = r('FLTL_01970', 'Name:') + ` ${c.Name}\n${tip}`; } setTooltip(span, tip); } @@ -315,8 +315,8 @@ export default class CustomerCommunication { if (this._var.option.customerReadonly === true) { div.style.display = 'none'; } else { - div.querySelector('.title-company-name').innerText = r('P_WO_NOCUSTOMERASSIGNED', 'No Customer Assigned'); - companyCode.innerText = ' /\n' + r('P_WO_SELECTCUSTOMER', 'Select Customer'); + div.querySelector('.title-company-name').innerText = r('FLTL_01985', 'No Customer Assigned'); + companyCode.innerText = ' /\n' + r('FLTL_02654', 'Select Customer'); companyCode.style.display = ''; } } else { @@ -337,8 +337,8 @@ export default class CustomerCommunication { const companyCode = div.querySelector('.title-company-code'); if (companyCode != null) { if (nullOrEmpty(option.companyName)) { - div.querySelector('.title-company-name').innerText = r('P_WO_NOCUSTOMERASSIGNED', 'No Customer Assigned'); - companyCode.innerText = ' /\n' + r('P_WO_SELECTCUSTOMER', 'Select Customer'); + div.querySelector('.title-company-name').innerText = r('FLTL_01985', 'No Customer Assigned'); + companyCode.innerText = ' /\n' + r('FLTL_02654', 'Select Customer'); companyCode.style.display = ''; } else { div.querySelector('.title-company-name').innerText = option.companyName; @@ -364,7 +364,7 @@ export default class CustomerCommunication { this._var.followers.replaceChildren(); if (followers?.length > 0) { this._var.container.querySelector('.follower-bar').style.display = ''; - setTooltip(this._var.buttonFollower, r('P_CU_EDITFOLLOWERS', 'Edit Followers')); + setTooltip(this._var.buttonFollower, r('FLTL_01054', 'Edit Followers')); this._var.container.querySelector('.follower-bar>.bar-list').appendChild(this._var.buttonFollower); for (let f of followers) { if (f.OptOut) { @@ -375,10 +375,10 @@ export default class CustomerCommunication { const email = String(f.Email).trim(); const tips = []; if (f.SendEmail) { - tips.push(r('P_CU_EMAILSTO_COLON', 'Emails to:') + ` ${email}`); + tips.push(r('FLTL_01109', 'Emails to:') + ` ${email}`); } if (f.SendText) { - tips.push(r('P_CU_TEXTSTO_COLON', 'Texts to:') + ` ${mpDisplay}`); + tips.push(r('FLTL_02924', 'Texts to:') + ` ${mpDisplay}`); } let icon; if (f.SendText && f.SendEmail) { @@ -402,13 +402,13 @@ export default class CustomerCommunication { ); this._var.followers.appendChild(item); if (span.scrollWidth > span.offsetWidth) { - tips.splice(0, 0, r('P_WO_NAME_COLON', 'Name:') + ` ${f.Name}`); + tips.splice(0, 0, r('FLTL_01970', 'Name:') + ` ${f.Name}`); } setTooltip(span, tips.join('\n')); } } else { this._var.container.querySelector('.follower-bar').style.display = 'none'; - setTooltip(this._var.buttonFollower, r('P_CR_ADDFOLLOWERS', 'Add Followers')); + setTooltip(this._var.buttonFollower, r('FLTL_00116', 'Add Followers')); this._var.container.querySelector('.button-edit-contacts').insertAdjacentElement('beforebegin', this._var.buttonFollower) } this._var.message.scrollTop = this._var.message.scrollHeight @@ -429,8 +429,8 @@ export default class CustomerCommunication { uncheckedNode: createIcon('fa-regular', 'ban'), onchange: function () { setTooltip(checkAutoUpdate, this.checked ? - r('P_CU_AUTOUPDATESENABLED', 'Auto Updates Enabled') : - r('P_CU_AUTOUPDATESDISABLED', 'Auto Updates Disabled')); + r('FLTL_00420', 'Auto Updates Enabled') : + r('FLTL_00419', 'Auto Updates Disabled')); } }); if (option.autoUpdatesVisible === false) { @@ -445,8 +445,8 @@ export default class CustomerCommunication { uncheckedNode: createIcon('fa-regular', 'unlink'), onchange: function () { setTooltip(checkLink, this.checked ? - r('P_WO_STATUSLINKINCLUDED', 'Status Link Included') : - r('P_WO_STATUSLINKEXCLUDED', 'Status Link Excluded')); + r('FLTL_02830', 'Status Link Included') : + r('FLTL_02829', 'Status Link Excluded')); if (typeof option.onStatusLinkChanged === 'function') { option.onStatusLinkChanged.call(This, this.checked); } @@ -460,7 +460,7 @@ export default class CustomerCommunication { createElement('div', null, createElement('div', div => { div.className = 'title-module'; - div.innerText = option.title ?? r('P_WO_CUSTOMERCOMMUNICATION', 'Customer Communication'); + div.innerText = option.title ?? r('FLTL_00732', 'Customer Communication'); }, createHideMessageTitleButton(this, 'showMessageHidden') ), @@ -472,7 +472,7 @@ export default class CustomerCommunication { createElement('span', span => { span.className = 'title-company-name'; if (nullOrEmpty(option.companyName)) { - span.innerText = r('P_WO_NOCUSTOMERASSIGNED', 'No Customer Assigned'); + span.innerText = r('FLTL_01985', 'No Customer Assigned'); } else { span.innerText = option.companyName; } @@ -482,7 +482,7 @@ export default class CustomerCommunication { if (option.customerReadonly === true) { span.style.display = 'none'; } else if (nullOrEmpty(option.companyName)) { - span.innerText = ' /\n' + r('P_WO_SELECTCUSTOMER', 'Select Customer'); + span.innerText = ' /\n' + r('FLTL_02654', 'Select Customer'); } else if (!nullOrEmpty(option.companyCode)) { span.innerText = ' / ' + option.companyCode; } else { @@ -494,7 +494,7 @@ export default class CustomerCommunication { if (option.recordReadonly) { span.style.display = 'none'; } - setTooltip(span, r('P_WO_SELECTCUSTOMER', 'Select Customer')); + setTooltip(span, r('FLTL_02654', 'Select Customer')); if (typeof option.onAddCompany === 'function') { span.addEventListener('click', () => option.onAddCompany.call(this)); } @@ -504,8 +504,8 @@ export default class CustomerCommunication { ) ), [ - setTooltip(checkAutoUpdate, r('P_CU_AUTOUPDATESENABLED', 'Auto Updates Enabled')), - setTooltip(checkLink, r('P_WO_STATUSLINKEXCLUDED', 'Status Link Excluded')) + setTooltip(checkAutoUpdate, r('FLTL_00420', 'Auto Updates Enabled')), + setTooltip(checkLink, r('FLTL_02829', 'Status Link Excluded')) ] ); // contacts @@ -514,7 +514,7 @@ export default class CustomerCommunication { this._var.followers = this._createFollowers(container, option); // enter box const enter = createElement('textarea', 'ui-text'); - enter.placeholder = r('P_CU_ENTERMESSAGEHERE', 'Enter Message Here'); + enter.placeholder = r('FLTL_01157', 'Enter Message Here'); option.maxLength ??= 3000; enter.maxLength = option.maxLength; // if (readonly === true) { @@ -586,7 +586,7 @@ export default class CustomerCommunication { div.style.display = 'none'; } }, - createElement('span', span => span.innerText = r('P_WO_NAME_COLON', 'Name:')), + createElement('span', span => span.innerText = r('FLTL_01970', 'Name:')), createElement('input', input => { input.type = 'text'; input.className = 'ui-input'; @@ -631,11 +631,11 @@ export default class CustomerCommunication { // button.style.display = 'none'; // } button.appendChild(createIcon('fa-solid', 'paper-plane')); - setTooltip(button, r('P_M3_SENDMESSAGE', 'Send Message')); + setTooltip(button, r('FLTL_02692', 'Send Message')); button.addEventListener('click', () => { const val = this.text; if (nullOrEmpty(val?.trim())) { - const p = showAlert(r('P_WO_ERROR', 'Error'), r('P_WO_PLEASEINPUTTHEMESSAGE', 'Please input the message.'), 'warn'); + const p = showAlert(r('FLTL_01165', 'Error'), r('FLTL_02233', 'Please input the message.'), 'warn'); if (typeof option.onMasking === 'function') { option.onMasking(true); p.then(() => option.onMasking(false)); @@ -678,7 +678,7 @@ export default class CustomerCommunication { button.style.display = 'none'; } button.appendChild(createIcon('fa-solid', 'user-edit')); - setTooltip(button, r('P_CU_EDITCONTACTS', 'Edit Contacts')); + setTooltip(button, r('FLTL_01043', 'Edit Contacts')); button.addEventListener('click', () => { const editContacts = () => { const pop = new Popup({ @@ -692,7 +692,7 @@ export default class CustomerCommunication { div.className = 'ui-popup-move'; div.style.flex = '1 1 auto'; }, - createElement('div', div => div.innerText = r('P_CU_EDITCONTACTS', 'Edit Contacts')), + createElement('div', div => div.innerText = r('FLTL_01043', 'Edit Contacts')), createElement('div', div => { div.className = 'title-company'; div.style.maxWidth = '540px'; @@ -760,7 +760,7 @@ export default class CustomerCommunication { }); } }); - var title = r('P_CU_SELECTFROMCUSTOMERRECORD', 'Select from Customer Record'); + var title = r('FLTL_02657', 'Select from Customer Record'); sel.show(title, container); if (typeof option.onOpenSelectCRContacts === 'function') { @@ -796,7 +796,7 @@ export default class CustomerCommunication { return false; } }); - setTooltip(button, r('P_CU_SELECTFROMCUSTOMERRECORD', 'Select from Customer Record')) + setTooltip(button, r('FLTL_02657', 'Select from Customer Record')) }), createElement('button', button => { button.style.flex = '0 0 auto'; @@ -818,7 +818,7 @@ export default class CustomerCommunication { onSave: item => { const exists = this._var.gridContact.source.some(s => s.Name === item.Name && s.MobilePhone === item.MobilePhone); if (exists) { - showAlert(r('P_CR_ADDCONTACT', 'Add Contact'), r('P_WO_CONTACTNAMEANDMOBILEUNIQUECOMBINATION', 'Contact name and contact mobile must be a unique combination.'), 'warn'); + showAlert(r('FLTL_00099', 'Add Contact'), r('FLTL_00638', 'Contact name and contact mobile must be a unique combination.'), 'warn'); return false; } if (typeof option.onSave === 'function') { @@ -852,7 +852,7 @@ export default class CustomerCommunication { }); add.show(container); }); - setTooltip(button, r('P_CR_ADDCONTACT', 'Add Contact')) + setTooltip(button, r('FLTL_00099', 'Add Contact')) }) ) }), @@ -862,7 +862,7 @@ export default class CustomerCommunication { div.style.display = 'none'; } div.style.fontWeight = 'bold'; - div.innerText = r('P_CU_CONTACTSFROMCUSTOMERRECORD', 'Contacts from Customer Record'); + div.innerText = r('FLTL_00657', 'Contacts from Customer Record'); }), createElement('div', div => { if (nullOrEmpty(option.companyName)) { @@ -875,7 +875,7 @@ export default class CustomerCommunication { }), createElement('div', div => { div.style.fontWeight = 'bold'; - div.innerText = r('P_CU_CONTACTSNOTCUSTOMERRECORD', 'Contacts not on Customer Record'); + div.innerText = r('FLTL_00659', 'Contacts not on Customer Record'); }), createElement('div', div => { div.className = 'contacts-wo'; @@ -897,7 +897,7 @@ export default class CustomerCommunication { option.onChanged([...This._var.gridContact.source, ...This._var.gridWo.source]); } }, - tooltip: item => item.selected ? r('P_CU_OPTEDIN', 'Opted In') : r('P_CU_OPTEDOUT', 'Opted Out') + tooltip: item => item.selected ? r('FLTL_02090', 'Opted In') : r('FLTL_02091', 'Opted Out') } }; const iconCol = { @@ -927,7 +927,7 @@ export default class CustomerCommunication { key: 'edit', ...buttonCol, text: 'edit', - tooltip: r('P_WO_EDIT', 'Edit'), + tooltip: r('FLTL_01032', 'Edit'), events: { onclick: function () { const edit = new Contact({ @@ -940,7 +940,7 @@ export default class CustomerCommunication { This._var.gridContact.source.some(s => s !== this && s.Name === item.Name && s.MobilePhone === item.MobilePhone) || This._var.gridWo.source.some(s => s !== this && s.Name === item.Name && s.MobilePhone === item.MobilePhone); if (exists) { - showAlert(r('P_CR_EDITCONTACT', 'Edit Contact'), r('P_WO_CONTACTNAMEANDMOBILEUNIQUECOMBINATION', 'Contact name and contact mobile must be a unique combination.'), 'warn'); + showAlert(r('FLTL_01041', 'Edit Contact'), r('FLTL_00638', 'Contact name and contact mobile must be a unique combination.'), 'warn'); return false; } if (typeof option.onSave === 'function') { @@ -993,15 +993,15 @@ export default class CustomerCommunication { key: 'delete', ...buttonCol, text: 'times', - tooltip: r('P_WO_DELETE', 'Delete'), + tooltip: r('FLTL_00791', 'Delete'), events: { onclick: function () { showConfirm( - r('P_CU_REMOVECONTACT', 'Remove Contact'), + r('FLTL_02417', 'Remove Contact'), createElement('div', null, createElement('div', div => { div.style.paddingLeft = '16px'; - div.innerText = r('P_CU_REMOVEFROM', 'Remove {name} from').replace('{name}', this.Name); + div.innerText = r('FLTL_02412', 'Remove {name} from').replace('{name}', this.Name); }), createElement('div', div => { div.style.display = 'flex'; @@ -1010,19 +1010,19 @@ export default class CustomerCommunication { }, createRadiobox({ name: 'remove-type', - label: r('P_CUSTOMERRECORD', 'Customer Record'), + label: r('FLTL_00747', 'Customer Record'), checked: true, className: 'radio-customer-record' }), createRadiobox({ name: 'remove-type', - label: r('P_WORKORDER', 'Work Order') + label: r('FLTL_03317', 'Work Order') }) ) ), [ - { key: 'ok', text: r('P_WO_OK', 'OK') }, - { key: 'cancel', text: r('P_WO_CANCEL', 'Cancel') } + { key: 'ok', text: r('FLTL_02057', 'OK') }, + { key: 'cancel', text: r('FLTL_00499', 'Cancel') } ] ).then(r => { if (r.result === 'ok') { @@ -1078,12 +1078,12 @@ export default class CustomerCommunication { key: 'delete', ...buttonCol, text: 'times', - tooltip: r('P_WO_DELETE', 'Delete'), + tooltip: r('FLTL_00791', 'Delete'), events: { onclick: function () { - 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') } + showConfirm(r('FLTL_02417', 'Remove Contact'), r('FLTL_03382', 'You are removing {name} from work order.\n\nDo you want to Continue?').replace('{name}', this.Name), [ + { key: 'continue', text: r('FLTL_00661', 'Continue') }, + { key: 'cancel', text: r('FLTL_00499', 'Cancel') } ]).then(r => { if (r.result === 'continue') { if (typeof option.onDelete === 'function') { @@ -1124,18 +1124,18 @@ export default class CustomerCommunication { }; if (nullOrEmpty(option.companyName)) { showConfirm( - r('P_CU_EDITCONTACTS', 'Edit Contacts'), - r('P_CUSTOMER_ADDCOMPANYPROMPT', 'There is no company associated with this work order. Would you like to add one?\n\nIf no company is indicated, contacts must be added as "Work Order Only".'), + r('FLTL_01043', 'Edit Contacts'), + r('FLTL_03008', 'There is no company associated with this work order. Would you like to add one?\n\nIf no company is indicated, contacts must be added as "Work Order Only".'), [ - { key: 'add', text: r('P_CUSTOMER_ADDCOMPANY', 'Add Company') }, - { key: 'skip', text: r('P_CUSTOMER_SKIPTHISSTEP', 'Skip This Step') } + { key: 'add', text: r('FLTL_00098', 'Add Company') }, + { key: 'skip', text: r('FLTL_02777', 'Skip This Step') } ] ).then(r => { if (r.result === 'add') { if (typeof option.onAddCompany === 'function') { option.onAddCompany.call(this); } - } else if (r.key === 'skip') { + } else if (r.result === 'skip') { editContacts(); } }); @@ -1147,7 +1147,7 @@ export default class CustomerCommunication { ), createElement('div', div => { div.className = 'bar-info'; - div.innerText = r('P_CR_CONTACTINFORMATION', 'Contact Information'); + div.innerText = r('FLTL_00635', 'Contact Information'); }), createElement('div', div => { if (option.contactCollapserVisible === false) { @@ -1191,12 +1191,12 @@ export default class CustomerCommunication { button.style.display = 'none'; } button.appendChild(createIcon('fa-solid', 'pen')); - setTooltip(button, r('P_CU_EDITFOLLOWERS', 'Edit Followers')); + setTooltip(button, r('FLTL_01054', 'Edit Followers')); button.addEventListener('click', () => { if (typeof option.onInitFollower === 'function') { option.onInitFollower(this._var.data.followers).then(data => { if (typeof data === 'string') { - showAlert(r('P_CUSTOMERRECORD', 'Customer Record'), data, 'warn'); + showAlert(r('FLTL_00747', 'Customer Record'), data, 'warn'); return; } const add = new Follower({ @@ -1216,7 +1216,7 @@ export default class CustomerCommunication { } } }); - var title = this._var.data.followers?.length > 0 ? r('P_CU_EDITFOLLOWERS', 'Edit Followers') : r('P_CR_ADDFOLLOWERS', 'Add Followers'); + var title = this._var.data.followers?.length > 0 ? r('FLTL_01054', 'Edit Followers') : r('FLTL_00116', 'Add Followers'); add.show(title, container); }); } @@ -1236,7 +1236,7 @@ export default class CustomerCommunication { 'border-radius': '15px', 'padding': '4px' }) - ), r('P_CU_COPIED', 'Copied')), + ), r('FLTL_00667', 'Copied')), createElement('div', 'bar-list', followers, buttonEditFollower diff --git a/lib/app/communications/follower.js b/lib/app/communications/follower.js index db5dc7f..93ff75f 100644 --- a/lib/app/communications/follower.js +++ b/lib/app/communications/follower.js @@ -24,7 +24,7 @@ export default class Follower { onMasking: this._var.option.onMasking, title, content: createElement('div', 'follower-wrapper', - createElement('div', div => div.innerText = r('P_CR_WHODOYOUWANTTORECEIVECUSTOMERNOTIFICATIONS', 'Who do you want to receive customer notifications?')), + createElement('div', div => div.innerText = r('FLTL_03300', 'Who do you want to receive customer notifications?')), createElement('input', search => { search.type = 'text'; search.tabIndex = tabIndex + 3; @@ -43,7 +43,7 @@ export default class Follower { ), buttons: [ { - text: r('P_WO_OK', 'OK'), + text: r('FLTL_02057', 'OK'), key: 'ok', trigger: () => { if (typeof this._var.option.onOk === 'function') { @@ -51,7 +51,7 @@ export default class Follower { } } }, - { text: r('P_WO_CANCEL', 'Cancel'), key: 'cancel' } + { text: r('FLTL_00499', 'Cancel'), key: 'cancel' } ] }); const result = await popup.show(parent); @@ -59,18 +59,18 @@ export default class Follower { // grid const grid = new Grid(gridContainer); grid.columns = [ - { key: 'DisplayName', caption: r('P_WO_CONTACTNAME', 'Contact Name'), width: 240 }, - { key: 'ContactTypeName', caption: r('P_WO_CONTACTTYPE', 'Contact Type'), width: 120 }, + { key: 'DisplayName', caption: r('FLTL_00637', 'Contact Name'), width: 240 }, + { key: 'ContactTypeName', caption: r('FLTL_00644', 'Contact Type'), width: 120 }, { key: 'Text', - caption: r('P_CR_TEXT', 'Text'), + caption: r('FLTL_02915', 'Text'), type: Grid.ColumnTypes.Checkbox, width: 60, enabled: item => !nullOrEmpty(item.Mobile) }, { key: 'Email', - caption: r('P_CR_EMAIL', 'Email'), + caption: r('FLTL_01089', 'Email'), type: Grid.ColumnTypes.Checkbox, width: 70, // enabled: item => !nullOrEmpty(item.ID) diff --git a/lib/app/communications/internal.js b/lib/app/communications/internal.js index 505ceee..3315350 100644 --- a/lib/app/communications/internal.js +++ b/lib/app/communications/internal.js @@ -138,7 +138,7 @@ export default class InternalComment { createElement('div', null, createElement('div', div => { div.className = 'title-module'; - div.innerText = r('P_WO_INTERNALCOMMENTS', 'Internal Comments'); + div.innerText = r('FLTL_01613', 'Internal Comments'); }, createHideMessageTitleButton(this, 'showMessageHidden') ) @@ -147,7 +147,7 @@ export default class InternalComment { const readonly = option.readonly; // enter box const enter = createElement('textarea', 'ui-text'); - enter.placeholder = r('P_CU_ENTERCOMMENTHERE', 'Enter Comment Here'); + enter.placeholder = r('FLTL_01154', 'Enter Comment Here'); enter.maxLength = option.maxLength ??= 3000; enter.addEventListener('input', () => { const val = this.text; @@ -237,7 +237,7 @@ export default class InternalComment { if (readonly === true || option.noCallLog === true) { button.style.display = 'none'; } - setTooltip(button, r('P_WO_CALLLOG', 'Call Log')); + setTooltip(button, r('FLTL_00491', 'Call Log')); button.addEventListener('click', () => { if (typeof option.onAddCallLog === 'function') { this.loading = true; @@ -252,7 +252,7 @@ export default class InternalComment { button.style.display = 'none'; } button.appendChild(createIcon('fa-solid', 'paper-plane')); - setTooltip(button, r('P_M3_SENDMESSAGE', 'Send Message')); + setTooltip(button, r('FLTL_02692', 'Send Message')); button.addEventListener('click', () => { const val = this.text; if (nullOrEmpty(val?.trim())) { @@ -272,7 +272,7 @@ export default class InternalComment { button.style.display = 'none'; } button.appendChild(createIcon('fa-solid', 'comment-alt-lines')); - setTooltip(button, r('P_CU_POSTNOTE', 'Post Note')); + setTooltip(button, r('FLTL_02301', 'Post Note')); button.addEventListener('click', () => { const val = this.text; if (nullOrEmpty(val?.trim())) { @@ -339,10 +339,10 @@ export default class InternalComment { } // if (comment.FollowUp?.length > 0) { // div.classList.add('item-sent'); - // const sendto = r('P_CU_SENDTO_COLON', 'Sent To :') + '\r\n' + comment.FollowUp.split(';').join('\r\n'); + // const sendto = r('FLTL_02716', 'Sent To :') + '\r\n' + comment.FollowUp.split(';').join('\r\n'); // content.appendChild(createElement('div', div => { // div.className = 'item-status'; - // div.innerText = r('P_WO_SENT', 'Sent'); + // div.innerText = r('FLTL_02711', 'Sent'); // setTooltip(div, sendto); // })); // } diff --git a/lib/app/communications/lib.js b/lib/app/communications/lib.js index 78e1ec9..6f31bb4 100644 --- a/lib/app/communications/lib.js +++ b/lib/app/communications/lib.js @@ -155,12 +155,12 @@ export function insertFile(container, file, r) { type = type.substring(type.lastIndexOf('.')); } if (fileSupported.indexOf(type) < 0) { - showAlert(r('P_WO_ERROR', 'Error'), r('P_CU_TYPENOTSUPPORTED', 'File type "{type}" is now not supported.').replace('{type}', type)); + showAlert(r('FLTL_01165', 'Error'), r('FLTL_01385', 'File type "{type}" is now not supported.').replace('{type}', type)); return; } const isImage = /^image\//.test(type); if (!isImage && file.size > MaxAttachmentSize.limit) { - showAlert(r('P_WO_ERROR', 'Error'), r('P_WO_ATTACHMENTSIZEEXCEEDSTHEMAXIMUMTIPS', `Attachment size exceeds the maximum allowed to be sent (${MaxAttachmentSize.text})`), 'warn'); + showAlert(r('FLTL_01165', 'Error'), r('FLTL_00407', `Attachment size exceeds the maximum allowed to be sent (${MaxAttachmentSize.text})`), 'warn'); return; } const fn = file.name; @@ -202,12 +202,12 @@ function getStatusText(status, dict) { export function getMessageStatus(comm, r, _var) { const messageStatus = { - 0: r('P_CU_PENDING', 'Pending'), - 1: r('P_WO_SENT', 'Sent'), - 5: r('P_CU_DELIVERYCONFIRMED', 'Delivery Confirmed'), - 6: r('P_CU_RESENT', 'Resent'), - 9: r('P_MA_FAILED', 'Failed'), - 9999: r('P_CU_UNKNOWN', 'Unknown') + 0: r('FLTL_02186', 'Pending'), + 1: r('FLTL_02711', 'Sent'), + 5: r('FLTL_00864', 'Delivery Confirmed'), + 6: r('FLTL_02478', 'Resent'), + 9: r('FLTL_01224', 'Failed'), + 9999: r('FLTL_03152', 'Unknown') }; const knownStatus = [0, 1, 5, 6, 9, 10, 412]; const okStatus = [1, 5, 6]; @@ -269,7 +269,7 @@ export function getMessageStatus(comm, r, _var) { if (statusUpdatable !== false) { tip.appendChild(createElement('div', b => { b.className = 'tip-function-button'; - // setTooltip(b, r('P_CU_UPDATESTATUS', 'Update Status')); + // setTooltip(b, r('FLTL_03174', 'Update Status')); b.addEventListener('click', async () => { for (let p of comm.Participator) { switch (p.Status) { @@ -292,7 +292,7 @@ export function getMessageStatus(comm, r, _var) { const gridContainer = createElement('div', 'status-grid'); const popup = new Popup({ onMasking: _var.option.onMasking, - title: r('P_CU_UPDATESTATUS', 'Update Status'), + title: r('FLTL_03174', 'Update Status'), content: createElement('div', wrapper => { wrapper.className = 'update-status-wrapper'; wrapper.style.width = '500px'; @@ -301,7 +301,7 @@ export function getMessageStatus(comm, r, _var) { ), buttons: [ { - text: r('P_WO_OK', 'OK'), + text: r('FLTL_02057', 'OK'), key: 'ok', trigger: () => { const changed = msgs.filter(m => { @@ -329,7 +329,7 @@ export function getMessageStatus(comm, r, _var) { } }, { - text: r('P_WO_CANCEL', 'Cancel'), + text: r('FLTL_00499', 'Cancel'), key: 'cancel' } ] @@ -341,22 +341,22 @@ export function getMessageStatus(comm, r, _var) { grid.columns = [ { key: 'CustomerNumber', - caption: r('P_JS_NUMBER', 'Number'), + caption: r('FLTL_02026', 'Number'), width: 150 }, /*{ key: 'customerName', - caption: r('P_WOS_CUSTOMERNAME', 'Customer Name'), + caption: r('FLTL_00742', 'Customer Name'), width: 120 },*/ { key: 'statusText', - caption: r('P_CU_CURRENTSTATUS', 'Current Status'), + caption: r('FLTL_00725', 'Current Status'), width: 155 }, { key: 'statusChanged', - caption: r('P_CU_REVISEDSTATUS', 'Revised Status'), + caption: r('FLTL_02511', 'Revised Status'), width: 155, type: Grid.ColumnTypes.Dropdown, source: [ @@ -404,7 +404,7 @@ export function getMessageSendTo(comm, contacts, followers, r) { } } if (sendto !== '') { - sendto = r('P_CU_SENDTO_COLON', 'Sent to :') + `\n${sendto}`; + sendto = r('FLTL_02716', 'Sent to :') + `\n${sendto}`; } return sendto; } @@ -432,7 +432,7 @@ export function createHideMessageTitleButton(This, optionName) { span.className = 'msgadminsetting sbutton iconnotview'; } span.style.padding = '0px 0px 0px 5px'; - setTooltip(span, option?.getText('P_WO_MESSAGEHISTORY_MANAGE', 'Manage Messages')); + setTooltip(span, option?.getText('FLTL_01860', 'Manage Messages')); span.addEventListener('click', function () { const container = This._var.container; if (!option[optionName]) { @@ -457,8 +457,8 @@ export function createHideMessageTitleButton(This, optionName) { export function createHideMessageCommentTail(This, optionName, comment, commentTime, func, hisFunc) { const option = This._var.option; - const showTooltip = option?.getText('P_WO_MESSAGEHISTORY_VISIBLE', 'Visible'); - const notShowTooltip = option?.getText('P_WO_MESSAGEHISTORY_NOTVISIBLE', 'Not Visible'); + const showTooltip = option?.getText('FLTL_03267', 'Visible'); + const notShowTooltip = option?.getText('FLTL_02006', 'Not Visible'); return createElement('div', div => { div.className = 'item-time'; div.style.display = 'flex'; @@ -498,7 +498,7 @@ export function createHideMessageCommentTail(This, optionName, comment, commentT span.className = 'msgHistory history-span-' + comment.Id; span.setAttribute('ModifyCount', comment.ModifyCount ?? 0); span.style.display = (option[optionName] && comment.ModifyCount > 0) ? '' : 'none'; - setTooltip(span, option?.getText('P_WO_MESSAGEHISTORY_HEADER', 'Hidden History')); + setTooltip(span, option?.getText('FLTL_01508', 'Hidden History')); const icon = createIcon('fa-light', 'wave-sine'); icon.style.height = '12px'; icon.style.width = '12px'; diff --git a/lib/element/addworkorder.js b/lib/element/addworkorder.js index 6ab4294..6c967bc 100644 --- a/lib/element/addworkorder.js +++ b/lib/element/addworkorder.js @@ -205,7 +205,7 @@ export default class AddWorkOrder extends OptionBase { } async getItem() { - const title = this.r('P_WO_OPENWORKORDER', 'Open Work Order'); + const title = this.r('FLTL_02078', 'Open Work Order'); const el = this._var.el; let status = el.dropStatus.selected; if (status != null) { @@ -223,7 +223,7 @@ export default class AddWorkOrder extends OptionBase { } let machine = this._var.asset; if (machine == null) { - showAlert(title, this.r('P_WO_ASSETNOTEMPTY', 'Asset cannot be empty.')).then(() => this._var.container.querySelector('.wo-asset>svg')?.focus()); + showAlert(title, this.r('FLTL_00311', 'Asset cannot be empty.')).then(() => this._var.container.querySelector('.wo-asset>svg')?.focus()); return null; } const item = { @@ -256,24 +256,24 @@ export default class AddWorkOrder extends OptionBase { item.Contacts = this._var.contacts ?? []; item.Followers = this._var.followers ?? []; if (nullOrEmpty(el.textComplaint?.value)) { - showAlert(title, this.r('P_WO_COMPLAINTREQUIRED', 'Complaint is required.')).then(() => el.textComplaint.focus()); + showAlert(title, this.r('FLTL_00602', 'Complaint is required.')).then(() => el.textComplaint.focus()); return null; } if (el.dropStatus.selected?.Completed) { if (!el.dateCompleted.element.validity.valid) { - showAlert(title, this.r('P_WO_COMPLETEDDATECANNOTBEEMPTY', 'Completed Date cannot be empty.')).then(() => el.dateCompleted.element.focus()); + showAlert(title, this.r('FLTL_00613', '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, this.r('P_WO_ODOMETERFORMATERROR', 'Odometer format error.')).then(() => el.inputOdometer.focus()); + showAlert(title, this.r('FLTL_02044', '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, this.r('P_WO_HOURMETERFORMATERROR', 'Hour Meter format error.')).then(() => el.inputHours.focus()); + showAlert(title, this.r('FLTL_01516', 'Hour Meter format error.')).then(() => el.inputHours.focus()); return null; } } @@ -284,12 +284,12 @@ export default class AddWorkOrder extends OptionBase { async show() { const option = this._option; const allowCustomer = option.allowCustomer === true; - const title = this.r('P_WO_OPENWORKORDER', 'Open Work Order'); + const title = this.r('FLTL_02078', '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 = this.r('P_WO_ENTERCOMPLAINT', 'Enter Complaint'); + textarea.placeholder = this.r('FLTL_01155', 'Enter Complaint'); }); const baseOption = { search: true, @@ -330,8 +330,8 @@ export default class AddWorkOrder extends OptionBase { selected: 'Mile' }); dropOdometerUnit.source = [ - { value: 'Mile', text: GetTextByKey('P_WO_MILE', 'Mile') }, - { value: 'Kilometre', text: GetTextByKey('P_WO_KILOMETER', 'Kilometer') } + { value: 'Mile', text: this.r('FLTL_01922', 'Mile') }, + { value: 'Kilometre', text: this.r('FLTL_01694', 'Kilometer') } ] const dropAssignedTo = new Dropdown({ tabIndex: tabIndex + 10, @@ -385,7 +385,7 @@ export default class AddWorkOrder extends OptionBase { createElement('div', 'wo-combined wo-asset', createElement('span', span => { span.className = 'wo-title wo-title-required'; - span.innerText = this.r('P_WO_ASSET_COLON', 'Asset:'); + span.innerText = this.r('FLTL_00361', 'Asset:'); }), createIcon('fa-light', 'search', svg => { svg.tabIndex = tabIndex + 1; @@ -430,16 +430,16 @@ export default class AddWorkOrder extends OptionBase { } }; popup = new Popup({ - title: this.r('P_MA_SELECTASSET', 'Select Asset'), + title: this.r('FLTL_02645', 'Select Asset'), content: selector.create(), persistent: true, buttons: [ { key: 'ok', - text: this.r('P_GRID_OK', 'OK'), + text: this.r('FLTL_02057', 'OK'), trigger: () => selector.select() }, - { text: this.r('P_WO_CANCEL', 'Cancel') } + { text: this.r('FLTL_00499', 'Cancel') } ] }); this._var.assetSelectorPopup = popup; @@ -458,7 +458,7 @@ export default class AddWorkOrder extends OptionBase { createElement('div', 'wo-line wo-combined', createElement('span', span => { span.className = 'wo-title wo-title-required'; - span.innerText = this.r('P_WO_COMPLAINTCOLON', 'Complaint:'); + span.innerText = this.r('FLTL_00603', 'Complaint:'); }) ), createElement('div', div => { @@ -470,7 +470,7 @@ export default class AddWorkOrder extends OptionBase { ), createElement('span', span => { span.className = 'wo-title'; - span.innerText = this.r('P_WO_WORKORDERTYPE_COLON', 'Work Order Type:'); + span.innerText = this.r('FLTL_03359', 'Work Order Type:'); }), dropWorkOrderType.create(), createElement('div', div => { @@ -481,7 +481,7 @@ export default class AddWorkOrder extends OptionBase { }, createElement('span', span => { span.className = 'wo-title'; - span.innerText = this.r('P_WO_COMPANYNAME_COLON', 'Company Name:'); + span.innerText = this.r('FLTL_00598', 'Company Name:'); }), createIcon('fa-light', 'search', svg => { svg.tabIndex = tabIndex + 4; @@ -507,18 +507,18 @@ export default class AddWorkOrder extends OptionBase { displayElement(createElement('span', 'wo-company-name'), allowCustomer), createElement('span', span => { span.className = 'wo-title'; - span.innerText = this.r('P_WO_STATUS_COLON', 'Status:'); + span.innerText = this.r('FLTL_02834', 'Status:'); }), dropStatus.create(), createElement('span', span => { span.className = 'wo-title wo-title-required wo-sub-line wo-status-closed'; - span.innerText = this.r('P_WO_COMPLETEDDATE_COLON', 'Completed Date:'); + span.innerText = this.r('FLTL_00617', '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 = this.r('P_WO_HOURS_COLON', 'Hours:'); + span.innerText = this.r('FLTL_01530', 'Hours:'); displayElement(span, false); }), displayElement( @@ -527,7 +527,7 @@ export default class AddWorkOrder extends OptionBase { ), createElement('span', span => { span.className = 'wo-title wo-title-required wo-sub-line wo-odometer'; - span.innerText = this.r('P_WO_ODOMETER_COLON', 'Odometer:'); + span.innerText = this.r('FLTL_02054', 'Odometer:'); displayElement(span, false); }), createElement('div', div => { @@ -539,12 +539,12 @@ export default class AddWorkOrder extends OptionBase { ), createElement('span', span => { span.className = 'wo-title'; - span.innerText = this.r('P_WO_ASSIGNEDTO_COLON', 'Assigned Tech:'); + span.innerText = this.r('FLTL_00382', 'Assigned Tech:'); }), dropAssignedTo.create(), createElement('span', span => { span.className = 'wo-title wo-customer-record'; - span.innerText = this.r('P_WO_ADVISOR_COLON', 'Advisor:'); + span.innerText = this.r('FLTL_00199', 'Advisor:'); if (!allowCustomer) { displayElement(span, false); } @@ -552,7 +552,7 @@ export default class AddWorkOrder extends OptionBase { displayElement(dropAdvisor.create(), allowCustomer), createElement('span', span => { span.className = 'wo-title wo-customer-record'; - span.innerText = this.r('P_WO_LOCATION_COLON', 'Location:'); + span.innerText = this.r('FLTL_01796', 'Location:'); if (!allowCustomer) { displayElement(span, false); } @@ -560,7 +560,7 @@ export default class AddWorkOrder extends OptionBase { displayElement(dropLocation.create(), allowCustomer), createElement('span', span => { span.className = 'wo-title wo-customer-record'; - span.innerText = this.r('P_WO_DEPARTMENT_COLON', 'Department:'); + span.innerText = this.r('FLTL_00869', 'Department:'); if (!allowCustomer) { displayElement(span, false); } @@ -616,12 +616,12 @@ export default class AddWorkOrder extends OptionBase { } if (this._var.asset.Hide) { if (!option.assetFullcontrol) { - await showAlert(title, this.r('P_WO_HIDDENCANNOTCREATE', 'The selected asset is hidden and a work order cannot be created.') + '\n\n' + this.r('P_WO_CONTACTTOUNHIDE', 'Please contact your Fleet Manager to Unhide the asset if you require a work order.')); + await showAlert(title, this.r('FLTL_02992', 'The selected asset is hidden and a work order cannot be created.') + '\n\n' + this.r('FLTL_02213', 'Please contact your Fleet Manager to Unhide the asset if you require a work order.')); return false; } - const next = await showConfirm(title, this.r('P_WO_HIDDENCANNOTCREATE', 'The selected asset is hidden and a work order cannot be created.') + '\n\n' + this.r('P_WO_PROMPTUNHIDE', 'Do you wish to "Un-Hide" the asset?'), [ - { key: 'unhide', text: this.r('P_WO_UNHIDE', 'Unhide') }, - { key: 'cancel', text: this.r('P_WO_CANCELWO', 'Cancel Work Order') } + const next = await showConfirm(title, this.r('FLTL_02992', 'The selected asset is hidden and a work order cannot be created.') + '\n\n' + this.r('FLTL_00999', 'Do you wish to "Un-Hide" the asset?'), [ + { key: 'unhide', text: this.r('FLTL_03136', 'Unhide') }, + { key: 'cancel', text: this.r('FLTL_00502', 'Cancel Work Order') } ]); if (next.result !== 'unhide') { return false; @@ -642,21 +642,21 @@ export default class AddWorkOrder extends OptionBase { const popWorkorders = new Popup({ title, content: createElement('div', 'wo-opened-workorder', - createElement('header', header => header.innerText = this.r('P_WO_ASSETOPENEDWORKORDER', 'The selected asset has the following open work orders:')), + createElement('header', header => header.innerText = this.r('FLTL_02991', 'The selected asset has the following open work orders:')), createElement('div', 'wo-grid-opened') ), resolve, buttons: [ - { key: 'create', text: this.r('P_WO_CREATEWO', 'Create Work Order'), trigger: () => resolve('create') }, - { key: 'cancel', text: this.r('P_WO_CANCELWO', 'Cancel Work Order'), trigger: () => resolve('cancel') } + { key: 'create', text: this.r('FLTL_00700', 'Create Work Order'), trigger: () => resolve('create') }, + { key: 'cancel', text: this.r('FLTL_00502', 'Cancel Work Order'), trigger: () => resolve('cancel') } ] }); popWorkorders.show().then(mask => { const grid = new Grid(mask.querySelector('.wo-grid-opened'), this.r); grid.columns = [ { key: 'WorkOrderNumber', caption: 'WO #', width: 100 }, - { key: 'CreateDateStr', caption: this.r('P_WO_CREATEDDATE', 'Created Date'), width: 120 }, - { key: 'Description', caption: this.r('P_WO_COMPLAINT', 'Complaint'), width: 360 } + { key: 'CreateDateStr', caption: this.r('FLTL_00703', 'Created Date'), width: 120 }, + { key: 'Description', caption: this.r('FLTL_00600', 'Complaint'), width: 360 } ]; grid.init(); grid.source = wos.map(w => ({ @@ -682,7 +682,7 @@ export default class AddWorkOrder extends OptionBase { } } }, - { text: this.r('P_WO_CANCEL', 'Cancel') } + { text: this.r('FLTL_00499', 'Cancel') } ] }); popup.create(); diff --git a/lib/element/assetSelector.js b/lib/element/assetSelector.js index 88bb806..24422f8 100644 --- a/lib/element/assetSelector.js +++ b/lib/element/assetSelector.js @@ -80,7 +80,7 @@ export default class AssetSelector extends OptionBase { super(opt); } - get title() { return this.r('P_MA_SELECTASSET', 'Select Asset') } + get title() { return this.r('FLTL_02645', 'Select Asset') } get currentAsset() { return this._var.el.grid.currentItem } @@ -126,7 +126,7 @@ export default class AssetSelector extends OptionBase { 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 = this.r('P_SELECTASSETS_SEARCH', 'Search'); + input.placeholder = this.r('FLTL_02606', 'Search'); input.tabIndex = tabIndex + 2; input.className = 'ui-input'; input.addEventListener('keypress', e => { @@ -137,7 +137,7 @@ export default class AssetSelector extends OptionBase { }); const checkHidden = createCheckbox({ tabIndex: tabIndex + 3, - label: this.r('P_SELECTASSETS_SHOWHIDDEN', 'Show Hidden'), + label: this.r('FLTL_02768', 'Show Hidden'), onchange: () => this.refresh() }); if (option.ignoreHidden) { @@ -168,14 +168,14 @@ export default class AssetSelector extends OptionBase { }); const grid = new Grid(gridContent, this.r); grid.columns = [ - { key: 'VIN', caption: this.r('P_SELECTASSETS_VIN', 'VIN'), width: 170 }, - { key: 'DisplayName', caption: this.r('P_SELECTASSETS_NAME', 'Name'), width: 190 }, - { key: 'MakeName', caption: this.r('P_SELECTASSETS_MAKE', 'Make'), width: 110, allowFilter: true }, - { key: 'ModelName', caption: this.r('P_SELECTASSETS_MODEL', 'Model'), width: 110, allowFilter: true }, - { key: 'TypeName', caption: this.r('P_SELECTASSETS_TYPE', 'Type'), width: 110, allowFilter: true }, - { key: 'AcquisitionType', caption: this.r('P_MA_ACQUISITIONTYPE', 'Acquisition Type'), width: 130, allowFilter: true }, - { key: 'AssetGroups', caption: this.r('P_MA_ASSETGROUP', 'Asset Group'), width: 150 }, - { key: 'Jobsites', caption: this.r('P_SELECTASSETS_JOBSITE', 'Jobsite'), width: 180, filter: it => it.Jobsites?.map(s => s.Key) } + { key: 'VIN', caption: this.r('FLTL_03260', 'VIN'), width: 170 }, + { key: 'DisplayName', caption: this.r('FLTL_01966', 'Name'), width: 190 }, + { key: 'MakeName', caption: this.r('FLTL_01832', 'Make'), width: 110, allowFilter: true }, + { key: 'ModelName', caption: this.r('FLTL_01933', 'Model'), width: 110, allowFilter: true }, + { key: 'TypeName', caption: this.r('FLTL_03112', 'Type'), width: 110, allowFilter: true }, + { key: 'AcquisitionType', caption: this.r('FLTL_00072', 'Acquisition Type'), width: 130, allowFilter: true }, + { key: 'AssetGroups', caption: this.r('FLTL_00318', 'Asset Group'), width: 150 }, + { key: 'Jobsites', caption: this.r('FLTL_01666', 'Jobsite'), width: 180, filter: it => it.Jobsites?.map(s => s.Key) } ]; grid.onRowDblClicked = index => { const item = grid.source[index]; @@ -202,7 +202,7 @@ export default class AssetSelector extends OptionBase { option.assetFullcontrol ? createElement('button', button => { button.className = 'ui-popup-button'; button.tabIndex = tabIndex + 1; - button.innerText = this.r('P_MA_ADDASSET', 'Add Asset'); + button.innerText = this.r('FLTL_00091', 'Add Asset'); button.addEventListener('click', async () => { if (typeof option.requestAddAsset === 'function') { this.loading(true); @@ -228,11 +228,11 @@ export default class AssetSelector extends OptionBase { ) ), checkHidden, - createElement('span', span => span.innerText = this.r('P_WO_ASSETGROUP', 'Asset Group')), + createElement('span', span => span.innerText = this.r('FLTL_00318', 'Asset Group')), dropAssetGroup.create(), - createElement('span', span => span.innerText = this.r('P_WO_JOBSITE', 'Jobsite')), + createElement('span', span => span.innerText = this.r('FLTL_01666', 'Jobsite')), dropJobsite.create(), - createElement('span', span => span.innerText = this.r('P_SELECTASSETS_JOBSITECODE', 'Jobsite Code')), + createElement('span', span => span.innerText = this.r('FLTL_01669', 'Jobsite Code')), dropJobsiteCode.create() ), gridContent diff --git a/lib/element/inspectionWizard.js b/lib/element/inspectionWizard.js index adfcc6d..a574cc8 100644 --- a/lib/element/inspectionWizard.js +++ b/lib/element/inspectionWizard.js @@ -85,23 +85,23 @@ export default class InspectionWizard extends OptionBase { templateSelector.create() ]; const popup = new Popup({ - title: this.r('ADDINSPECTION', 'Add Inspection'), + title: this.r('FLTL_00121', 'Add Inspection'), content: createElement('div', null, ...this._var.containers), persistent: true, buttons: [ { - text: this.r('BACK', 'Back'), + text: this.r('FLTL_00447', 'Back'), trigger: () => { this._changePage(0); return false; } }, { - text: this.r('NEXT', 'Next'), + text: this.r('FLTL_01973', 'Next'), trigger: () => { const asset = assetSelector.currentAsset; if (asset == null) { - showAlert(assetSelector.title, this.r('P_SELECTASSETS_SELECTASSET', 'Please select an Asset.')); + showAlert(assetSelector.title, this.r('FLTL_02269', 'Please select an Asset.')); return false; } this._var.asset = asset; @@ -112,18 +112,18 @@ export default class InspectionWizard extends OptionBase { } }, { - text: this.r('P_GRID_OK', 'OK'), + text: this.r('FLTL_02057', 'OK'), trigger: () => { const template = templateSelector.currentTemplate; if (template == null) { - showAlert(templateSelector.title, this.r('P_WO_PLEASESELECTATEMPLATE', 'Please select a template.')); + showAlert(templateSelector.title, this.r('FLTL_02261', 'Please select a template.')); return false; } this._var.template = template; this._select(); } }, - { text: this.r('P_WO_CANCEL', 'Cancel') } + { text: this.r('FLTL_00499', 'Cancel') } ] }); this._var.popup = popup; diff --git a/lib/element/schedule.js b/lib/element/schedule.js index 8d361da..9f45731 100644 --- a/lib/element/schedule.js +++ b/lib/element/schedule.js @@ -161,7 +161,7 @@ export default class ScheduleItem extends OptionBase { }), validation( createElement('input', i => { i.type = 'text', i.className = 'ui-input schedule-id-occur-once', i.maxLength = 5 }), - /^([01][0-9]|[2][0-3]):[0-5][0-9]$/ + /^([1-9]|[01][0-9]|[2][0-3]):([1-9]|[0-5][0-9])$/ ) ), createElement('div', 'schedule-item-line schedule-item-line-occur-every', @@ -182,14 +182,14 @@ export default class ScheduleItem extends OptionBase { createElement('span', span => span.innerText = 'Starting at'), validation( createElement('input', i => { i.type = 'text', i.className = 'ui-input schedule-id-occur-starting', i.maxLength = 5 }), - /^([01][0-9]|[2][0-3]):[0-5][0-9]$/ + /^([1-9]|[01][0-9]|[2][0-3]):([1-9]|[0-5][0-9])$/ ) ), createElement('div', 'scheldule-item-line', createElement('span', span => span.innerText = 'Ending at'), validation( createElement('input', i => { i.type = 'text', i.className = 'ui-input schedule-id-occur-ending', i.maxLength = 5 }), - /^([01][0-9]|[2][0-3]):[0-5][0-9]$/ + /^([1-9]|[01][0-9]|[2][0-3]):([1-9]|[0-5][0-9])$/ ) ) ) diff --git a/lib/element/signature.js b/lib/element/signature.js index 29ee623..a22a8f5 100644 --- a/lib/element/signature.js +++ b/lib/element/signature.js @@ -37,7 +37,7 @@ export default class Signature extends OptionBase { async show() { const popup = new Popup({ - title: this.r('P_IPT_SIGNATURE', 'Signature'), + title: this.r('FLTL_02770', 'Signature'), content: this._var.canvas = createElement('canvas', canvas => { canvas.style.width = '100%'; canvas.style.height = '100%'; @@ -56,7 +56,7 @@ export default class Signature extends OptionBase { }, buttons: [ { - text: this.r('P_GRID_OK', 'OK'), + text: this.r('FLTL_02057', 'OK'), trigger: () => { if (this._var.allPoints.length === 0) { return false; @@ -65,14 +65,14 @@ export default class Signature extends OptionBase { } }, { - text: this.r('P_GRID_RESET', 'Reset'), + text: this.r('FLTL_02479', 'Reset'), trigger: () => { const ctx = this._var.canvas.getContext('2d'); ctx.clearRect(0, 0, this._var.canvas.width, this._var.canvas.height); return false } }, - { text: this.r('P_WO_CANCEL', 'Cancel') } + { text: this.r('FLTL_00499', 'Cancel') } ] }); this._var.popup = popup; diff --git a/lib/element/templateSelector.js b/lib/element/templateSelector.js index e0b8457..64a6bd2 100644 --- a/lib/element/templateSelector.js +++ b/lib/element/templateSelector.js @@ -50,7 +50,7 @@ export default class TemplateSelector extends OptionBase { this.refresh(); } - get title() { return this.r('P_MODULE_INSPECTIONTEMPLATES', 'Inspection Templates') } + get title() { return this.r('FLTL_01604', 'Inspection Templates') } get currentTemplate() { return this._var.el.grid.currentItem } @@ -83,7 +83,7 @@ export default class TemplateSelector extends OptionBase { 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 = this.r('P_SELECTASSETS_SEARCH', 'Search'); + input.placeholder = this.r('FLTL_02606', 'Search'); input.tabIndex = tabIndex + 1; input.className = 'ui-input'; input.addEventListener('keypress', e => e.key === 'Enter' && this.refresh()); @@ -102,8 +102,8 @@ export default class TemplateSelector extends OptionBase { resizable: false, filter: it => nullOrEmpty(it.IssueId) ? '' : 'cubes' }, - { key: 'Name', caption: this.r('P_IPT_NAME', 'Name'), width: 390 }, - { key: 'Notes', caption: this.r('P_IPT_NOTES', 'Notes'), width: 630 } + { key: 'Name', caption: this.r('FLTL_01966', 'Name'), width: 390 }, + { key: 'Notes', caption: this.r('FLTL_02012', 'Notes'), width: 630 } ]; grid.onRowDblClicked = index => { const item = grid.source[index]; @@ -122,7 +122,7 @@ export default class TemplateSelector extends OptionBase { // content const container = createElement('div', 'popup-selector', createElement('div', 'popup-selector-header', - createElement('h3', h3 => h3.innerText = this.r('P_WO_PLEASESELECTATEMPLATE', 'Please select a template.')) + createElement('h3', h3 => h3.innerText = this.r('FLTL_02261', 'Please select a template.')) ), createElement('div', 'popup-selector-function', createElement('div', 'search-box', diff --git a/lib/ui/checkbox.js b/lib/ui/checkbox.js index 616c97d..ccb1e9c 100644 --- a/lib/ui/checkbox.js +++ b/lib/ui/checkbox.js @@ -3,6 +3,10 @@ import { createElement } from "../functions"; import { createIcon } from "./icon"; function fillCheckbox(container, type = 'fa-regular', label, tabindex = -1, charactor = 'check', title) { + const checkIcon = createIcon(type, charactor); + checkIcon.classList.add('ui-check-icon'); + const indeterminateIcon = createIcon(type, 'grip-lines'); + indeterminateIcon.classList.add('ui-indeterminate-icon') container.appendChild( createElement('layer', layer => { layer.className = 'ui-check-inner'; @@ -18,7 +22,7 @@ function fillCheckbox(container, type = 'fa-regular', label, tabindex = -1, char if (tabindex >= 0) { layer.tabIndex = tabindex; } - }, createIcon(type, charactor)) + }, checkIcon, indeterminateIcon) ); if (label instanceof Element) { container.appendChild(label); @@ -68,6 +72,9 @@ export function createCheckbox(opts = {}) { if (opts.checked === true) { input.checked = true; } + if (opts.indeterminate === true) { + input.indeterminate = true; + } if (opts.enabled === false) { input.disabled = true; } diff --git a/lib/ui/css/dropdown.scss b/lib/ui/css/dropdown.scss index dec15ea..bd47f93 100644 --- a/lib/ui/css/dropdown.scss +++ b/lib/ui/css/dropdown.scss @@ -185,9 +185,20 @@ $listMaxHeight: 210px; background-color: var(--hover-bg-color); } - >.ui-check-wrapper { - height: $dropItemHeight; + >.li-wrapper { display: flex; + align-items: center; + + >.ui-expandor { + width: 12px; + height: 12px; + display: flex; + } + + >.ui-check-wrapper { + height: $dropItemHeight; + display: flex; + } } } } diff --git a/lib/ui/css/functions/func.scss b/lib/ui/css/functions/func.scss index ffb424c..fd01fa0 100644 --- a/lib/ui/css/functions/func.scss +++ b/lib/ui/css/functions/func.scss @@ -92,7 +92,22 @@ border-color: var(--link-color); background-color: var(--link-color); - >svg { + >.ui-check-icon { + transform: scale(1); + opacity: 1; + } + } + + &:indeterminate+.ui-check-inner { + border-color: var(--secondary-color); + background-color: var(--secondary-color); + + >.ui-check-icon { + transform: scale(0); + opacity: 0; + } + + >.ui-indeterminate-icon { transform: scale(1); opacity: 1; } diff --git a/lib/ui/date.js b/lib/ui/date.js index 0567904..5967faf 100644 --- a/lib/ui/date.js +++ b/lib/ui/date.js @@ -178,6 +178,7 @@ export function getFormatter(date, utc) { * @param {Date | number | string} date - 需要格式化的日期值,支持的格式如下: * * * `"2024-01-26"` + * * `"2024/1/26"` * * `"2024-01-26T00:00:00"` * * `"1/26/2024"` * * `"638418240000000000"` @@ -214,7 +215,7 @@ export function formatDate(date, formatter) { if (isNaN(date)) { let e = /^(\d{4})-(\d{2})-(\d{2})/.exec(date); if (e == null) { - e = /^(\d{4})\/(\d{2})\/(\d{2})/.exec(date); + e = /^(\d{4})\/(\d{1,2})\/(\d{1,2})/.exec(date); } if (e != null) { date = new Date(e[1], parseInt(e[2]) - 1, e[3]); diff --git a/lib/ui/dropdown.js b/lib/ui/dropdown.js index 9e5694a..645ea98 100644 --- a/lib/ui/dropdown.js +++ b/lib/ui/dropdown.js @@ -302,7 +302,14 @@ export class Dropdown { if (!Array.isArray(list)) { return; } - this._var.source = list; + const valuekey = this._var.options.valueKey; + function reduceItems(list, id, level = 0) { + if (!Array.isArray(list)) { + return []; + } + return list.reduce((array, item) => [...array, { __p: id, __level: level, ...item }, ...reduceItems(item.children, item[valuekey], level + 1)], []); + } + this._var.source = reduceItems(list); if (this._expanded) { setTimeout(() => this._dropdown(), 120); } @@ -422,6 +429,7 @@ export class Dropdown { const search = createElement('div', 'ui-drop-search'); const input = createElement('input'); input.type = 'text'; + input.className = 'ui-input'; isPositive(options.tabIndex) && input.setAttribute('tabindex', options.tabIndex); !nullOrEmpty(options.searchPlaceholder) && input.setAttribute('placeholder', options.searchPlaceholder); input.addEventListener('input', e => { @@ -579,7 +587,14 @@ export class Dropdown { } if (multiselect) { const selected = selectedlist.some(s => String(getValue(s, valuekey, textkey)) === val); - item.__checked = allchecked || selected; + if (allchecked || selected) { + item.__checked = 1; + } else { + const indeterminate = selectedlist.some(s => this._contains(String(getValue(s, valuekey, textkey)), item, valuekey, textkey)); + if (indeterminate) { + item.__checked = 2; + } + } } }); if (source.length > 20) { @@ -592,6 +607,20 @@ export class Dropdown { } } + _contains(it, item, valuekey, textkey) { + if (item.children?.length > 0) { + for (let t of item.children) { + if (it === getValue(t, valuekey, textkey)) { + return true; + } + if (this._contains(it, t, valuekey, textkey)) { + return true; + } + } + } + return false; + } + _dofilllist(content, array) { const multiselect = this.multiSelect; const valuekey = this._var.options.valueKey; @@ -608,6 +637,18 @@ export class Dropdown { const li = createElement('li'); li.dataset.value = val; li.title = item[textkey]; + if (item.__level > 0) { + li.style.marginLeft = `${item.__level * 24}px`; + } + const wrapper = createElement('span', 'li-wrapper', + createElement('span', span => { + // events + span.className = 'ui-expandor'; + }, + createIcon('fa-light', 'caret-down') + ) + ); + li.appendChild(wrapper); let label; let html; if (typeof template === 'function') { @@ -628,20 +669,21 @@ export class Dropdown { } const box = createCheckbox({ label, - checked: item.__checked, + checked: item.__checked === 1, + indeterminate: item.__checked === 2, customAttributes: { 'class': 'dataitem', 'data-value': val }, onchange: e => this._triggerselect(e.target, item) }); - li.appendChild(box); + wrapper.appendChild(box); } else { if (label == null) { - li.innerText = item[textkey]; - } else { - li.appendChild(label); + label = createElement('span'); + label.innerHTML = item[textkey]; } + wrapper.appendChild(label); if (selected != null && String(selected[valuekey]) === val) { scrolled = DropdownItemHeight * i; li.classList.add('selected'); @@ -664,7 +706,7 @@ export class Dropdown { boxes.forEach(box => box.checked = allchecked); list = []; } else { - item.__checked = checkbox.checked; + item.__checked = checkbox.indeterminate ? 2 : checkbox.checked ? 1 : 0; const all = this._var.container.querySelector('input[isall="1"]'); if (checkbox.checked) { const source = this.source; diff --git a/lib/ui/grid/grid.js b/lib/ui/grid/grid.js index 047f79b..39e7775 100644 --- a/lib/ui/grid/grid.js +++ b/lib/ui/grid/grid.js @@ -1431,12 +1431,21 @@ export class Grid { e.stopPropagation(); } }); - grid.addEventListener('mousedown', e => { + grid.addEventListener('mousedown', async e => { if (e.target === this._var.el) { if (e.offsetX < 0 || e.offsetX > e.target.clientWidth || e.offsetY < 0 || e.offsetY > e.target.clientHeight) { // except scroll bars return; } + if (typeof this.willSelect === 'function') { + let result = this.willSelect(-1, -1); + if (result instanceof Promise) { + result = await result; + } + if (!result) { + return; + } + } // cancel selections const selectedIndexes = this._var.selectedIndexes; if (selectedIndexes?.length > 0) { @@ -1525,7 +1534,7 @@ export class Grid { holder.classList.remove('active'); this._clearHolder(holder); } - return this._onRowClicked(e, row, col); + this._onRowClicked(e, row, col); }); holder.addEventListener('dblclick', e => this._onRowDblClicked(e)); wrapper.appendChild(holder); @@ -2107,6 +2116,7 @@ export class Grid { // FIXME: 清除缓存会导致选中状态下动态数据源下拉列表显示为空 // delete it.source; it.values = item; + this._var.colAttrs.__filtered = false; if (this.sortArray?.length > 0) { this.sort(); } else if (this.sortIndex >= 0) { @@ -2148,6 +2158,7 @@ export class Grid { this._var.source.push(newIt); } } + this._var.colAttrs.__filtered = false; if (this.sortArray?.length > 0) { this.sort(true); } else if (this.sortIndex >= 0) { @@ -2195,6 +2206,7 @@ export class Grid { this._var.source.push(...items); } } + this._var.colAttrs.__filtered = false; if (this.sortArray?.length > 0) { this.sort(true); } else if (this.sortIndex >= 0) { @@ -3926,6 +3938,8 @@ export class Grid { return String(displayValue).toLowerCase().includes(key); }); this._fillFilterList(col, itemlist, items, itemall); + this._set(col.key, 'filterTop', -1); + itemlist.dispatchEvent(new Event('scroll')); }); } // function @@ -4405,12 +4419,9 @@ export class Grid { * @param {number} index * @param {number} colIndex */ - _onRowClicked(e, index, colIndex) { + _afterRowChanged(e, index, colIndex) { const startIndex = this._var.startIndex; const selectedIndex = startIndex + index; - if (typeof this.willSelect === 'function' && !this.willSelect(selectedIndex, colIndex)) { - return; - } // multi-select let flag = false; const selectedIndexes = this._var.selectedIndexes; @@ -4471,6 +4482,26 @@ export class Grid { } } + /** + * @private + * @param {MouseEvent} e + * @param {number} index + * @param {number} colIndex + */ + async _onRowClicked(e, index, colIndex) { + if (typeof this.willSelect === 'function') { + const selectedIndex = this._var.startIndex + index; + let result = this.willSelect(selectedIndex, colIndex); + if (result instanceof Promise) { + result = await result; + } + if (!result) { + return; + } + } + this._afterRowChanged(e, index, colIndex); + } + /** * @private * @param {MouseEvent} e diff --git a/lib/utility.js b/lib/utility.js index ca03be1..180f5c2 100644 --- a/lib/utility.js +++ b/lib/utility.js @@ -53,19 +53,24 @@ function isPhone(text) { return false; } -function verifyPassword(password, min) { +function getPasswordStrength(password) { if (password == null || typeof password !== 'string') { - return false; + return 0; } if (password.length < 8) { - return false; + return 0; } - min ??= 3; let secure = 0; if (/[0-9]/.test(password)) { secure++ } if (/[a-z]/.test(password)) { secure++ } if (/[A-Z]/.test(password)) { secure++ } if (/[^0-9a-zA-Z]/.test(password)) { secure++ } + return secure; +} + +function verifyPassword(password, min) { + min ??= 3; + const secure = getPasswordStrength(password); return secure >= min; } @@ -100,6 +105,7 @@ export { truncate, isEmail, isPhone, + getPasswordStrength, verifyPassword, domLoad } \ No newline at end of file