From 3962c2bb0435484b60a3e408e4738d792e249a53 Mon Sep 17 00:00:00 2001
From: buli <137736985@qq.com>
Date: 星期一, 05 六月 2023 11:09:55 +0800
Subject: [PATCH] LEX CommunityNewCmp
---
force-app/main/default/lwc/lexLookup/lexLookup.js | 493 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 493 insertions(+), 0 deletions(-)
diff --git a/force-app/main/default/lwc/lexLookup/lexLookup.js b/force-app/main/default/lwc/lexLookup/lexLookup.js
new file mode 100644
index 0000000..7d2ef23
--- /dev/null
+++ b/force-app/main/default/lwc/lexLookup/lexLookup.js
@@ -0,0 +1,493 @@
+import { LightningElement, api, track } from 'lwc';
+import { NavigationMixin } from 'lightning/navigation';
+
+const SEARCH_DELAY = 300; // Wait 300 ms after user stops typing then, peform search
+
+const KEY_ARROW_UP = 38;
+const KEY_ARROW_DOWN = 40;
+const KEY_ENTER = 13;
+
+const VARIANT_LABEL_STACKED = 'label-stacked';
+const VARIANT_LABEL_INLINE = 'label-inline';
+const VARIANT_LABEL_HIDDEN = 'label-hidden';
+
+const REGEX_SOSL_RESERVED = /(\?|&|\||!|\{|\}|\[|\]|\(|\)|\^|~|\*|:|"|\+|-|\\)/g;
+const REGEX_EXTRA_TRAP = /(\$|\\)/g;
+
+export default class LexLookup extends NavigationMixin(LightningElement) {
+ // Public properties
+ @api variant = VARIANT_LABEL_STACKED;
+ @api label = '';
+ @api required = false;
+ @api disabled = false;
+ @api placeholder = '';
+ @api isMultiEntry = false;
+ @api scrollAfterNItems = null;
+ @api newRecordOptions = [];
+ @api minSearchTermLength = 2;
+ @api isDisabledForDealerText = false;
+ @api accountValue = '';
+
+ // Template properties
+ searchResultsLocalState = [];
+ loading = false;
+
+ // Private properties
+ _errors = [];
+ _hasFocus = false;
+ _isDirty = false;
+ _searchTerm = '';
+ _cleanSearchTerm;
+ _cancelBlur = false;
+ _searchThrottlingTimeout;
+ _searchResults = [];
+ _defaultSearchResults = [];
+ _curSelection = [];
+ _focusedResultIndex = null;
+
+
+
+
+
+ // PUBLIC FUNCTIONS AND GETTERS/SETTERS
+ @api
+ set selection(initialSelection) {
+ if (initialSelection) {
+ this._curSelection = Array.isArray(initialSelection) ? initialSelection : [initialSelection];
+ this.processSelectionUpdate(false);
+ }
+ }
+
+ get selection() {
+ return this._curSelection;
+ }
+
+ @api
+ set errors(errors) {
+ this._errors = errors;
+ // Blur component if errors are passed
+ if (this._errors?.length > 0) {
+ this.blur();
+ }
+ }
+
+ get errors() {
+ return this._errors;
+ }
+
+ @api
+ get validity() {
+ return { valid: !this._errors || this._errors.length === 0 };
+ }
+
+ @api
+ get value() {
+ return this.getSelection();
+ }
+
+ @api
+ setSearchResults(results) {
+ // Reset the spinner
+ this.loading = false;
+ // Clone results before modifying them to avoid Locker restriction
+ let resultsLocal = JSON.parse(JSON.stringify(results));
+ // Remove selected items from search results
+ const selectedIds = this._curSelection.map((sel) => sel.id);
+ resultsLocal = resultsLocal.filter((result) => selectedIds.indexOf(result.id) === -1);
+ // Format results
+ const cleanSearchTerm = this._searchTerm.replace(REGEX_SOSL_RESERVED, '.?').replace(REGEX_EXTRA_TRAP, '\\$1');
+ const regex = new RegExp(`(${cleanSearchTerm})`, 'gi');
+ this._searchResults = resultsLocal.map((result) => {
+ // Format title and subtitle
+ if (this._searchTerm.length > 0) {
+ result.titleFormatted = result.title
+ ? result.title.replace(regex, '<strong>$1</strong>')
+ : result.title;
+ result.subtitleFormatted = result.subtitle
+ ? result.subtitle.replace(regex, '<strong>$1</strong>')
+ : result.subtitle;
+ } else {
+ result.titleFormatted = result.title;
+ result.subtitleFormatted = result.subtitle;
+ }
+ // Add icon if missing
+ if (typeof result.icon === 'undefined') {
+ result.icon = 'standard:default';
+ }
+ return result;
+ });
+ // Add local state and dynamic class to search results
+ this._focusedResultIndex = null;
+ const self = this;
+ this.searchResultsLocalState = this._searchResults.map((result, i) => {
+ return {
+ result,
+ state: {},
+ get classes() {
+ let cls = 'slds-media slds-media_center slds-listbox__option slds-listbox__option_entity';
+ if (result.subtitleFormatted) {
+ cls += ' slds-listbox__option_has-meta';
+ }
+ if (self._focusedResultIndex === i) {
+ cls += ' slds-has-focus';
+ }
+ return cls;
+ }
+ };
+ });
+ }
+
+ @api
+ getSelection() {
+ console.log('get selection:' +this._curSelection);
+ return this._curSelection;
+ }
+
+ @api
+ setDefaultResults(results) {
+ this._defaultSearchResults = [...results];
+ if (this._searchResults.length === 0) {
+ this.setSearchResults(this._defaultSearchResults);
+ }
+ }
+
+ @api
+ blur() {
+ this.template.querySelector('input')?.blur();
+ }
+
+ connectedCallback(){
+ console.log('LexLookup accountValue = ' + this.accountValue);
+ console.log('isDisabledForDealerText = ' + this.isDisabledForDealerText);
+ }
+
+ // INTERNAL FUNCTIONS
+ updateSearchTerm(newSearchTerm) {
+ this._searchTerm = newSearchTerm;
+
+ // Compare clean new search term with current one and abort if identical
+ const newCleanSearchTerm = newSearchTerm.trim().replace(REGEX_SOSL_RESERVED, '?').toLowerCase();
+ if (this._cleanSearchTerm === newCleanSearchTerm) {
+ return;
+ }
+
+ // Save clean search term
+ this._cleanSearchTerm = newCleanSearchTerm;
+
+ // Ignore search terms that are too small after removing special characters
+ if (newCleanSearchTerm.replace(/\?/g, '').length < this.minSearchTermLength) {
+ this.setSearchResults(this._defaultSearchResults);
+ return;
+ }
+
+ // Apply search throttling (prevents search if user is still typing)
+ if (this._searchThrottlingTimeout) {
+ clearTimeout(this._searchThrottlingTimeout);
+ }
+ // eslint-disable-next-line @lwc/lwc/no-async-operation
+ this._searchThrottlingTimeout = setTimeout(() => {
+ // Send search event if search term is long enougth
+ if (this._cleanSearchTerm.length >= this.minSearchTermLength) {
+ // Display spinner until results are returned
+ this.loading = true;
+
+ const searchEvent = new CustomEvent('search', {
+ detail: {
+ searchTerm: this._cleanSearchTerm,
+ rawSearchTerm: newSearchTerm,
+ selectedIds: this._curSelection.map((element) => element.id)
+ }
+ });
+ this.dispatchEvent(searchEvent);
+ }
+ this._searchThrottlingTimeout = null;
+ }, SEARCH_DELAY);
+ }
+
+ isSelectionAllowed() {
+ if (this.isMultiEntry) {
+ return true;
+ }
+ return !this.hasSelection();
+ }
+
+ hasSelection() {
+ return this._curSelection.length > 0;
+ }
+
+ processSelectionUpdate(isUserInteraction) {
+ // Reset search
+ this._cleanSearchTerm = '';
+ this._searchTerm = '';
+ this.setSearchResults([...this._defaultSearchResults]);
+ // Indicate that component was interacted with
+ this._isDirty = isUserInteraction;
+ // Blur input after single select lookup selection
+ if (!this.isMultiEntry && this.hasSelection()) {
+ this._hasFocus = false;
+ }
+ // If selection was changed by user, notify parent components
+ if (isUserInteraction) {
+ const selectedIds = this._curSelection.map((sel) => sel.id);
+ this.dispatchEvent(new CustomEvent('selectionchange', { detail: selectedIds }));
+ }
+ }
+
+ // EVENT HANDLING
+
+ handleInput(event) {
+ // Prevent action if selection is not allowed
+ if (!this.isSelectionAllowed()) {
+ return;
+ }
+ this.updateSearchTerm(event.target.value);
+ }
+
+ handleKeyDown(event) {
+ if (this._focusedResultIndex === null) {
+ this._focusedResultIndex = -1;
+ }
+ if (event.keyCode === KEY_ARROW_DOWN) {
+ // If we hit 'down', select the next item, or cycle over.
+ this._focusedResultIndex++;
+ if (this._focusedResultIndex >= this._searchResults.length) {
+ this._focusedResultIndex = 0;
+ }
+ event.preventDefault();
+ } else if (event.keyCode === KEY_ARROW_UP) {
+ // If we hit 'up', select the previous item, or cycle over.
+ this._focusedResultIndex--;
+ if (this._focusedResultIndex < 0) {
+ this._focusedResultIndex = this._searchResults.length - 1;
+ }
+ event.preventDefault();
+ } else if (event.keyCode === KEY_ENTER && this._hasFocus && this._focusedResultIndex >= 0) {
+ // If the user presses enter, and the box is open, and we have used arrows,
+ // treat this just like a click on the listbox item
+ const selectedId = this._searchResults[this._focusedResultIndex].id;
+ console.log('selectedid:'+selectedId);
+ this.template.querySelector(`[data-recordid="${selectedId}"]`).click();
+ event.preventDefault();
+ }
+ }
+
+ handleResultClick(event) {
+ const recordId = event.currentTarget.dataset.recordid;
+
+ // Save selection
+ const selectedItem = this._searchResults.find((result) => result.id === recordId);
+ if (!selectedItem) {
+ return;
+ }
+ const newSelection = [...this._curSelection];
+ newSelection.push(selectedItem);
+ this._curSelection = newSelection;
+
+ // Process selection update
+ this.processSelectionUpdate(true);
+ }
+
+ handleComboboxMouseDown(event) {
+ const mainButton = 0;
+ if (event.button === mainButton) {
+ this._cancelBlur = true;
+ }
+ }
+
+ handleComboboxMouseUp() {
+ this._cancelBlur = false;
+ // Re-focus to text input for the next blur event
+ this.template.querySelector('input').focus();
+ }
+
+ handleFocus() {
+ // Prevent action if selection is not allowed
+ if (!this.isSelectionAllowed()) {
+ return;
+ }
+ this._hasFocus = true;
+ this._focusedResultIndex = null;
+ }
+
+ handleBlur() {
+ // Prevent action if selection is either not allowed or cancelled
+ if (!this.isSelectionAllowed() || this._cancelBlur) {
+ return;
+ }
+ const blurEvent = new CustomEvent('blur', {
+ detail: {}
+ });
+ this.dispatchEvent(blurEvent);
+ this._hasFocus = false;
+ if(!this.hasSelection()){
+ this._searchTerm = '';
+ }
+ }
+
+ handleRemoveSelectedItem(event) {
+ if (this.disabled) {
+ return;
+ }
+ const recordId = event.currentTarget.name;
+ this._curSelection = this._curSelection.filter((item) => item.id !== recordId);
+ // Process selection update
+ this.processSelectionUpdate(true);
+ }
+
+ handleClearSelection() {
+ this._curSelection = [];
+ this._hasFocus = false;
+ this.accountValue = '';
+ // Process selection update
+ this.processSelectionUpdate(true);
+ }
+
+ handleNewRecordClick(event) {
+ const objectApiName = event.currentTarget.dataset.sobject;
+ const selection = this.newRecordOptions.find((option) => option.value === objectApiName);
+
+ const preNavigateCallback = selection.preNavigateCallback
+ ? selection.preNavigateCallback
+ : () => Promise.resolve();
+ preNavigateCallback(selection).then(() => {
+ this[NavigationMixin.Navigate]({
+ type: 'standard__objectPage',
+ attributes: {
+ objectApiName,
+ actionName: 'new'
+ },
+ state: {
+ defaultFieldValues: selection.defaults
+ }
+ });
+ });
+ }
+
+ // STYLE EXPRESSIONS
+
+ get isSingleEntry() {
+ return !this.isMultiEntry;
+ }
+
+ get isListboxOpen() {
+ const isSearchTermValid = this._cleanSearchTerm && this._cleanSearchTerm.length >= this.minSearchTermLength;
+ return (
+ this._hasFocus &&
+ this.isSelectionAllowed() &&
+ (isSearchTermValid || this.hasResults || this.newRecordOptions?.length > 0)
+ );
+ }
+
+ get hasResults() {
+ return this._searchResults.length > 0;
+ }
+
+ get getFormElementClass() {
+ return this.variant === VARIANT_LABEL_INLINE
+ ? 'slds-form-element slds-form-element_horizontal'
+ : 'slds-form-element';
+ }
+
+ get getLabelClass() {
+ return this.variant === VARIANT_LABEL_HIDDEN
+ ? 'slds-form-element__label slds-assistive-text'
+ : 'slds-form-element__label';
+ }
+
+ get getContainerClass() {
+ let css = 'slds-combobox_container ';
+ if (this._errors.length > 0) {
+ css += 'has-custom-error';
+ }
+ return css;
+ }
+
+ get getDropdownClass() {
+ let css = 'slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click ';
+ if (this.isListboxOpen) {
+ css += 'slds-is-open';
+ }
+ return css;
+ }
+
+ get getInputClass() {
+ let css = 'slds-input slds-combobox__input has-custom-height ';
+ if (this._hasFocus && this.hasResults) {
+ css += 'slds-has-focus ';
+ }
+ if (this._errors.length > 0 || (this._isDirty && this.required && !this.hasSelection())) {
+ css += 'has-custom-error ';
+ }
+ if (!this.isMultiEntry) {
+ css += 'slds-combobox__input-value ' + (this.hasSelection() ? 'has-custom-border' : '');
+ }
+ return css;
+ }
+
+ get getComboboxClass() {
+ let css = 'slds-combobox__form-element slds-input-has-icon ';
+ if (this.isMultiEntry) {
+ css += 'slds-input-has-icon_right';
+ } else {
+ css += this.hasSelection() ? 'slds-input-has-icon_left-right' : 'slds-input-has-icon_right';
+ }
+ return css;
+ }
+
+ get getSearchIconClass() {
+ let css = 'slds-input__icon slds-input__icon_right ';
+ if (!this.isMultiEntry) {
+ css += this.hasSelection() ? 'slds-hide' : '';
+ }
+ return css;
+ }
+
+ get getClearSelectionButtonClass() {
+ return (
+ 'slds-button slds-button_icon slds-input__icon slds-input__icon_right ' +
+ (this.hasSelection() ? '' : 'slds-hide')
+ );
+ }
+
+ get getSelectIconName() {
+ if(this._curSelection[0])
+ console.log('this._curSelection[0].icon = ' + this._curSelection[0].icon);
+ return this.hasSelection() ? this._curSelection[0].icon : 'standard:default';
+ }
+
+ get getSelectIconClass() {
+ return 'slds-combobox__input-entity-icon ' + (this.hasSelection() ? '' : 'slds-hide');
+ }
+
+ get getInputValue() {
+ if (this.isMultiEntry) {
+ return this._searchTerm;
+ }
+ if(this.accountValue != ''){
+ return this.accountValue;
+ }
+ return this.hasSelection() ? this._curSelection[0].title : this._searchTerm;
+ }
+
+ get getInputTitle() {
+ if (this.isMultiEntry) {
+ return '';
+ }
+ return this.hasSelection() ? this._curSelection[0].title : '';
+ }
+
+ get getListboxClass() {
+ return (
+ 'slds-dropdown ' +
+ (this.scrollAfterNItems ? `slds-dropdown_length-with-icon-${this.scrollAfterNItems} ` : '') +
+ 'slds-dropdown_fluid'
+ );
+ }
+
+ get isInputReadonly() {
+ if (this.isMultiEntry) {
+ return false;
+ }
+ return this.hasSelection();
+ }
+}
\ No newline at end of file
--
Gitblit v1.9.1