UNPKG

test-isc

Version:

An Ionic component similar to Ionic Select, that allows to search items, including async search, group, add, edit, delete items, and much more.

1,129 lines (1,122 loc) 75.4 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); const index = require('./index-366d4dde.js'); require('./ionic-global-53907587.js'); const ionicSelectable_interfaces_component = require('./ionic-selectable.interfaces.component-7f9cbc0a.js'); require('./utils-7ad8ea36.js'); const index$1 = require('./index-14b758b3.js'); require('./helpers-41dfb43a.js'); require('./animation-34a434a2.js'); require('./index-69bad4f5.js'); require('./ios.transition-d0eaafea.js'); require('./md.transition-deadd839.js'); require('./cubic-bezier-f3b34d27.js'); require('./index-ea0ef88d.js'); require('./index-4b7e4228.js'); require('./hardware-back-button-8c2f48d2.js'); require('./index-1ceca8b8.js'); const overlays = require('./overlays-2201b17c.js'); const findItemLabel = (componentElement) => { const itemElement = componentElement.closest('ion-item'); if (itemElement) { return itemElement.querySelector('ion-label'); } return null; }; const findItem = (componentEl) => { const itemEl = componentEl.closest('ion-item'); return itemEl; }; const addRippleEffectElement = (componentElement) => { const itemElement = componentElement.closest('ion-item'); const itemNative = itemElement.shadowRoot.querySelector('div.item-native'); if (itemNative) { const ionRipple = itemNative.ownerDocument.createElement('ion-ripple-effect'); itemNative.appendChild(ionRipple); } }; const hostContext = (selector, element) => { return element.closest(selector) !== null; }; const renderHiddenInput = (always, container, name, value, disabled) => { if (always || hasShadowDom(container)) { let input = container.querySelector('input.aux-input'); if (!input) { input = container.ownerDocument.createElement('input'); input.type = 'hidden'; input.classList.add('aux-input'); container.appendChild(input); } input.disabled = disabled; input.name = name; input.value = value || ''; } }; const hasShadowDom = (element) => { return !!element.shadowRoot && !!element.attachShadow; }; const ionicSelectableIosComponentCss = ":host{--font-family:var(--ion-font-family, inherit)}:host{--placeholder-color:currentColor;--placeholder-opacity:0.33;padding-left:var(--padding-start);padding-right:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:-ms-flexbox;display:flex;position:relative;-ms-flex-align:center;align-items:center;font-family:var(--font-family, inherit);overflow:hidden;z-index:var(--z-index-item-input)}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){:host{padding-left:unset;padding-right:unset;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end)}}:host(.in-item){position:static;max-width:45%}:host(.ionic-selectable-is-disabled){opacity:0.4;pointer-events:none}:host(.ion-focused) button{border:2px solid #5e9ed6}:host(.item-multiple-inputs){position:relative}:host(.item-label-stacked),:host(.item-label-floating){--padding-start:0;-ms-flex-item-align:stretch;align-self:stretch;width:100%;max-width:100%}button{left:0;top:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;position:absolute;width:100%;height:100%;border:0;background:transparent;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;outline:none}[dir=rtl] button,:host-context([dir=rtl]) button{left:unset;right:unset;right:0}button::-moz-focus-inner{border:0}.ionic-selectable-placeholder{color:var(--placeholder-color);opacity:var(--placeholder-opacity)}.ionic-selectable-text{-ms-flex:1;flex:1;min-width:16px;font-size:inherit;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ionic-selectable-icon{position:relative;opacity:0.33}.ionic-selectable-icon-inner{left:5px;top:50%;margin-top:-3px;position:absolute;width:0;height:0;border-top:5px solid;border-right:5px solid transparent;border-left:5px solid transparent;color:currentColor;pointer-events:none}[dir=rtl] .ionic-selectable-icon-inner,:host-context([dir=rtl]) .ionic-selectable-icon-inner{left:unset;right:unset;right:5px}.ionic-selectable-icon-template{-ms-flex-item-align:center;align-self:center;margin-left:5px}:host{--padding-top:var(--item-ios-padding-top, 10px);--padding-end:10px;--padding-bottom:var(--item-ios-padding-bottom, 10px);--padding-start:var(--item-ios-padding-start, 20px)}:host(.item-label-stacked),:host(.item-label-floating){--padding-top:8px;--padding-bottom:8px;--padding-start:0}.ionic-selectable-icon{width:12px;height:18px}"; const ionicSelectableMdComponentCss = ":host{--font-family:var(--ion-font-family, inherit)}:host{--placeholder-color:currentColor;--placeholder-opacity:0.33;padding-left:var(--padding-start);padding-right:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:-ms-flexbox;display:flex;position:relative;-ms-flex-align:center;align-items:center;font-family:var(--font-family, inherit);overflow:hidden;z-index:var(--z-index-item-input)}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){:host{padding-left:unset;padding-right:unset;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end)}}:host(.in-item){position:static;max-width:45%}:host(.ionic-selectable-is-disabled){opacity:0.4;pointer-events:none}:host(.ion-focused) button{border:2px solid #5e9ed6}:host(.item-multiple-inputs){position:relative}:host(.item-label-stacked),:host(.item-label-floating){--padding-start:0;-ms-flex-item-align:stretch;align-self:stretch;width:100%;max-width:100%}button{left:0;top:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;position:absolute;width:100%;height:100%;border:0;background:transparent;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;outline:none}[dir=rtl] button,:host-context([dir=rtl]) button{left:unset;right:unset;right:0}button::-moz-focus-inner{border:0}.ionic-selectable-placeholder{color:var(--placeholder-color);opacity:var(--placeholder-opacity)}.ionic-selectable-text{-ms-flex:1;flex:1;min-width:16px;font-size:inherit;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ionic-selectable-icon{position:relative;opacity:0.33}.ionic-selectable-icon-inner{left:5px;top:50%;margin-top:-3px;position:absolute;width:0;height:0;border-top:5px solid;border-right:5px solid transparent;border-left:5px solid transparent;color:currentColor;pointer-events:none}[dir=rtl] .ionic-selectable-icon-inner,:host-context([dir=rtl]) .ionic-selectable-icon-inner{left:unset;right:unset;right:5px}.ionic-selectable-icon-template{-ms-flex-item-align:center;align-self:center;margin-left:5px}:host{--padding-top:var(--item-md-padding-top, 10px);--padding-end:0;--padding-bottom:var(--item-md-padding-bottom, 11px);--padding-start:var(--item-md-padding-start, 16px)}:host(.item-label-stacked),:host(.item-label-floating){--padding-top:8px;--padding-bottom:8px;--padding-start:0}.ionic-selectable-icon{width:19px;height:19px}"; const IonicSelectableComponent = class { constructor(hostRef) { index.registerInstance(this, hostRef); this.id = this.element.id ? this.element.id : `ionic-selectable-${nextId++}`; this.isInited = false; this.isRendered = false; this.isChangeInternal = false; this.groups = []; this.filteredGroups = []; this.hasFilteredItems = false; this.hasObjects = false; this.hasGroups = false; this.footerButtonsCount = 0; this.isSearching = false; this.isAddItemTemplateVisible = false; this.isFooterVisible = true; this.itemToAdd = null; this.selectedItems = []; this.valueItems = []; this.itemsToConfirm = []; /** * Determines whether Modal is opened. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#isopened). * * @default false * @readonly * @memberof IonicSelectableComponent */ this.isOpened = false; /** * Determines whether the component is disabled. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#isdisabled). * * @default false * @memberof IonicSelectableComponent */ this.isDisabled = false; /** * Close button text. * The field is only applicable to **iOS** platform, on **Android** only Cross icon is displayed. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#closebuttontext). * * @default 'Cancel' * @memberof IonicSelectableComponent */ this.closeButtonText = 'Cancel'; /** * Close button slot. [Ionic slots](https://ionicframework.com/docs/api/buttons) are supported. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#closebuttonslot). * * @default 'start' * @memberof IonicSelectableComponent */ this.closeButtonSlot = 'start'; /** * Item icon slot. [Ionic slots](https://ionicframework.com/docs/api/item) are supported. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#itemiconslot). * * @default 'start' * @memberof IonicSelectableComponent */ this.itemIconSlot = 'start'; /** * Confirm button text. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#confirmbuttontext). * * @default 'OK' * @memberof IonicSelectableComponent */ this.confirmButtonText = 'OK'; /** * Clear button text. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#clearbuttontext). * * @default 'Clear' * @memberof IonicSelectableComponent */ this.clearButtonText = 'Clear'; /** * Add button text. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#addbuttontext). * * @default 'Add' * @memberof IonicSelectableComponent */ this.addButtonText = 'Add'; /** * The name of the control, which is submitted with the form data. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#name). * * @default null * @memberof IonicSelectableComponent */ this.name = this.id; /** * Determines whether multiple items can be selected. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#ismultiple). * * @default false * @memberof IonicSelectableComponent */ this.isMultiple = false; /** * The value of the component. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#value). * * @default null * @memberof IonicSelectableComponent */ this.value = null; /** * Is set to true, the value will be extracted from the itemValueField of the objects. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#shouldStoreItemValue). * * @default false * @memberof IonicSelectableComponent */ this.shouldStoreItemValue = false; /** * A list of items. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#items). * * @default [] * @memberof IonicSelectableComponent */ this.items = []; /** * A list of items to disable. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#disableditems). * * @default [] * @memberof IonicSelectableComponent */ this.disabledItems = []; /** * Item property to use as a unique identifier, e.g, `'id'`. * **Note**: `items` should be an object array. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#itemvaluefield). * * @default null * @memberof IonicSelectableComponent */ this.itemValueField = null; /** * Item property to display, e.g, `'name'`. * **Note**: `items` should be an object array. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#itemtextfield). * * @default null * @memberof IonicSelectableComponent */ this.itemTextField = null; /** * Modal CSS class. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#modalcssclass). * * @default null * @memberof IonicSelectableComponent */ this.modalCssClass = null; /** * Modal enter animation. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#modalenteranimation). * * @default null * @memberof IonicSelectableComponent */ this.modalEnterAnimation = null; /** * Modal leave animation. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#modalleaveanimation). * * @default null * @memberof IonicSelectableComponent */ this.modalLeaveAnimation = null; /** * Text of [Ionic Label](https://ionicframework.com/docs/api/label). * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#label). * * @readonly * @default null * @memberof IonicSelectableComponent */ this.titleText = null; /** * * Group property to use as a unique identifier to group items, e.g. `'country.id'`. * **Note**: `items` should be an object array. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#groupvaluefield). * * @default null * @memberof IonicSelectableComponent */ this.groupValueField = null; /** * Group property to display, e.g. `'country.name'`. * **Note**: `items` should be an object array. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#grouptextfield). * * @default null * @memberof IonicSelectableComponent */ this.groupTextField = null; /** * Determines whether Ionic [InfiniteScroll](https://ionicframework.com/docs/api/infinite-scroll) is enabled. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#hasinfinitescroll). * * @default false * @memberof IonicSelectableComponent */ this.hasInfiniteScroll = false; /** * The threshold distance from the bottom of the content to call the infinite output event when scrolled. * Use the value 100px when the scroll is within 100 pixels from the bottom of the page. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#infinite-scroll). * * @default '100px' * @memberof IonicSelectableComponent */ this.infiniteScrollThreshold = '100px'; /** * Determines whether Ionic [VirtualScroll](https://ionicframework.com/docs/api/virtual-scroll) is enabled. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#hasvirtualscroll). * * @default false * @memberof IonicSelectableComponent */ this.hasVirtualScroll = false; /** * See Ionic VirtualScroll [approxHeaderHeight](https://ionicframework.com/docs/api/virtual-scroll). * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#virtualscrollheaderfn). * * @default 30 * @memberof IonicSelectableComponent */ this.virtualScrollApproxHeaderHeight = 30; /** * See Ionic VirtualScroll [approxItemHeight](https://ionicframework.com/docs/api/virtual-scroll). * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#virtualscrollheaderfn). * * @default 45 * @memberof IonicSelectableComponent */ this.virtualScrollApproxItemHeight = 45; /** * Determines whether Confirm button is visible for single selection. * By default Confirm button is visible only for multiple selection. * **Note**: It is always true for multiple selection and cannot be changed. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#hasconfirmbutton). * * @default false * @memberof IonicSelectableComponent */ this.hasConfirmButton = false; /** * Determines whether to allow adding items. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#canadditem). * * @default false * @memberof IonicSelectableComponent */ this.canAddItem = false; /** * Determines whether to show Clear button. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#canclear). * @default false * @memberof IonicSelectableComponent */ // Pending - @HostBinding('class.ionic-selectable-can-clear') this.canClear = false; /** * Determines whether to show [Searchbar](https://ionicframework.com/docs/api/searchbar). * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#cansearch). * * @default false * @memberof IonicSelectableComponent */ this.canSearch = false; /** * Determines the search is delegate to event, and not handled internally. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#cansearch). * * @default false * @memberof IonicSelectableComponent */ this.shouldDelegateSearchToEvent = false; /** * How long, in milliseconds, to wait to filter items or to trigger `onSearch` event after each keystroke. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#searchdebounce). * * @default 250 * @memberof IonicSelectableComponent */ this.searchDebounce = 250; /** * A placeholder for [Searchbar](https://ionicframework.com/docs/api/searchbar). * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#searchplaceholder). * * @default 'Search' * @memberof IonicSelectableComponent */ this.searchPlaceholder = 'Search'; /** * Text in [Searchbar](https://ionicframework.com/docs/api/searchbar). * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#searchtext). * * @default '' * @memberof IonicSelectableComponent */ this.searchText = ''; /** * Text to display when no items have been found during search. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#searchfailtext). * * @default 'No items found.' * @memberof IonicSelectableComponent */ this.searchFailText = 'No items found.'; /** * Determines whether Searchbar should receive focus when Modal is opened. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#shouldfocussearchbar). * * @default false * @memberof IonicSelectableComponent */ this.shouldFocusSearchbar = false; /** * Set the cancel button icon of the [Searchbar](https://ionicframework.com/docs/api/searchbar). * Only applies to md mode. Defaults to "arrow-back-sharp". * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#hassearchtext). * * @default 'arrow-back-sharp' * @memberof IonicSelectableComponent */ this.searchCancelButtonIcon = 'arrow-back-sharp'; /** * Set the the cancel button text of the [Searchbar](https://ionicframework.com/docs/api/searchbar). * Only applies to ios mode. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#hassearchtext). * * @default 'Cancel' * @memberof IonicSelectableComponent */ this.searchCancelButtonText = 'Cancel'; /** * Set the clear icon of the [Searchbar](https://ionicframework.com/docs/api/searchbar). * Defaults to "close-circle" for ios and "close-sharp" for md. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#hassearchtext). * * @memberof IonicSelectableComponent */ this.searchClearIcon = index$1.getMode() === 'ios' ? 'close-circle' : 'close-sharp'; /** * A hint to the browser for which keyboard to display. * Possible values: "none", "text", "tel", "url", "email", "numeric", "decimal", and "search". * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#hassearchtext). * @default 'none' * @memberof IonicSelectableComponent */ this.searchInputmode = 'none'; /** * The icon to use as the search icon in the [Searchbar](https://ionicframework.com/docs/api/searchbar). * Defaults to "search-outline" in ios mode and "search-sharp" in md mode. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#hassearchtext). * @default 'none' * @memberof IonicSelectableComponent */ this.searchIcon = index$1.getMode() === 'ios' ? 'search-outline' : 'search-sharp'; /** * Sets the behavior for the cancel button of the [Searchbar](https://ionicframework.com/docs/api/searchbar). * Defaults to "never". * Setting to "focus" shows the cancel button on focus. * Setting to "never" hides the cancel button. * Setting to "always" shows the cancel button regardless of focus state. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#hassearchtext). * @default 'none' * @memberof IonicSelectableComponent */ this.searchShowCancelButton = 'never'; /** * Determines whether Confirm button is enabled. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#isconfirmbuttonenabled). * * @default true * @memberof IonicSelectableComponent */ this.isConfirmButtonEnabled = true; /** * Header color. [Ionic colors](https://ionicframework.com/docs/theming/advanced#colors) are supported. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#headercolor). * * @default null * @memberof IonicSelectableComponent */ this.headerColor = null; /** * Group color. [Ionic colors](https://ionicframework.com/docs/theming/advanced#colors) are supported. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#groupcolor). * * @default null * @memberof IonicSelectableComponent */ this.groupColor = null; /** * See Ionic VirtualScroll [headerFn](https://ionicframework.com/docs/api/virtual-scroll). * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#virtualscrollheaderfn). * * @memberof IonicSelectableComponent */ this.virtualScrollHeaderFn = () => null; this.onClick = async () => { this.setFocus(); this.open(); }; this.onFocus = () => { this.focused.emit(); }; this.onBlur = () => { this.blurred.emit(); }; this.infiniteScrolled = index.createEvent(this, "infiniteScrolled", 7); this.searching = index.createEvent(this, "searching", 7); this.searchFailed = index.createEvent(this, "searchFailed", 7); this.searchSuccessed = index.createEvent(this, "searchSuccessed", 7); this.itemAdding = index.createEvent(this, "itemAdding", 7); this.cleared = index.createEvent(this, "cleared", 7); this.changed = index.createEvent(this, "changed", 7); this.itemsChanged = index.createEvent(this, "itemsChanged", 7); this.selected = index.createEvent(this, "selected", 7); this.opened = index.createEvent(this, "opened", 7); this.closed = index.createEvent(this, "closed", 7); this.focused = index.createEvent(this, "focused", 7); this.blurred = index.createEvent(this, "blurred", 7); this.ionStyle = index.createEvent(this, "ionStyle", 7); } onShouldStoreItemValueChanged(value) { if (!value && !this.hasObjects) { throw new Error(`If items contains primitive elements, shouldStoreItemValue must be null or true: ${this.element.id}`); } } onItemValueFieldChanged(value) { if (this.hasObjects && this.isNullOrWhiteSpace(value)) { throw new Error(`If items contains object elements, itemValueField must be non null or non whitespace : ${this.element.id}`); } else if (!this.hasObjects && !this.isNullOrWhiteSpace(value)) { throw new Error(`If items contains primitive elements, itemValueField must be null: ${this.element.id}`); } } onItemTextFieldChanged(value) { if (this.hasObjects && this.isNullOrWhiteSpace(value)) { throw new Error(`If items contains object elements, itemTextField must be non null or non whitespace : ${this.element.id}`); } else if (!this.hasObjects && !this.isNullOrWhiteSpace(value)) { throw new Error(`If items contains primitive elements, itemTextField must be null: ${this.element.id}`); } } onItemsChanged(value) { this.setItems(value); } onDisabledChanged() { this.emitStyle(); } onValueChanged(newValue) { if (!this.isChangeInternal) { this.emitStyle(); if (this.isInited) { this.setValue(newValue, false); } } this.isChangeInternal = false; } onSearchTextChanged(newValue) { if (!this.isChangeInternal) { if (this.isOpened) { this.startSearch(); this.filterItems(newValue, false); this.endSearch(); } } this.isChangeInternal = false; } onIsMultipleChanged() { this.countFooterButtons(); } onDisabledItemsChanged() { var _a; (_a = this.selectableModalComponent) === null || _a === void 0 ? void 0 : _a.update(); } async connectedCallback() { this.emitStyle(); } componentWillLoad() { this.setItems(this.items); this.setValue(this.value); this.countFooterButtons(); this.isInited = true; } /** * Determines whether any item has been selected. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#hasvalue). * * @returns A boolean determining whether any item has been selected. * @memberof IonicSelectableComponent */ async hasValue() { return this.parseValue() !== ''; } /** * Opens Modal. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#open). * * @returns Promise that resolves when Modal has been opened. * @memberof IonicSelectableComponent */ async open() { if (this.isDisabled || this.isOpened) { return Promise.reject(`IonicSelectable is disabled or already opened: ${this.element.id}`); } const label = findItemLabel(this.element); if (label && !this.titleText) { this.titleText = label.textContent; } const modalOptions = { component: 'ionic-selectable-modal', componentProps: { selectableComponent: this }, backdropDismiss: this.shouldBackdropClose, }; if (this.modalCssClass) { modalOptions.cssClass = this.modalCssClass; } if (this.modalEnterAnimation) { modalOptions.enterAnimation = this.modalEnterAnimation; } if (this.modalLeaveAnimation) { modalOptions.leaveAnimation = this.modalLeaveAnimation; } this.filterItems(this.searchText); this.modalElement = await overlays.modalController.create(modalOptions); await this.modalElement.present(); this.isOpened = true; this.setFocus(); this.whatchModalEvents(); this.emitOpened(); return Promise.resolve(); } /** * Closes Modal. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#close). * * @returns Promise that resolves when Modal has been closed. * @memberof IonicSelectableComponent */ async close() { if (this.isDisabled || !this.isOpened) { return Promise.reject(`IonicSelectable is disabled or already closed: ${this.element.id}`); } await this.modalElement.dismiss(); this.itemToAdd = null; this.hideAddItemTemplate(); if (!this.shouldDelegateSearchToEvent) { this.setHasSearchText(''); } this.emitClosed(); return Promise.resolve(); } /** * Return a list of items that are selected and awaiting confirmation by user, when he has clicked Confirm button. * After the user has clicked Confirm button items to confirm are cleared. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#itemstoconfirm). * * @returns a promise whit de list of items that are selected and awaiting confirmation by user * @memberof IonicSelectableComponent */ async getItemsToConfirm() { return this.itemsToConfirm; } /** * Confirms selected items by updating value. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#confirm). * * @memberof IonicSelectableComponent */ async confirm() { if (this.isMultiple) { this.setValue(this.selectedItems); } else if (this.hasConfirmButton || (this.hasTemplateRender && this.hasTemplateRender('footer'))) { this.setValue(this.selectedItems[0] || null); } } /** * Clears value. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#clear). * * @memberof IonicSelectableComponent */ async clear() { this.clearItems(); } /** * Enables infinite scroll. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#enableinfinitescroll). * * @memberof IonicSelectableComponent */ async enableInfiniteScroll() { if (!this.hasInfiniteScroll) { return; } this.selectableModalComponent.infiniteScrollElement.disabled = false; } /** * Disables infinite scroll. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#disableinfinitescroll). * * @memberof IonicSelectableComponent */ async disableInfiniteScroll() { if (!this.hasInfiniteScroll) { return; } this.selectableModalComponent.infiniteScrollElement.disabled = true; } /** * Ends infinite scroll. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#endinfinitescroll). * * @memberof IonicSelectableComponent */ async endInfiniteScroll() { if (!this.hasInfiniteScroll) { return; } this.selectableModalComponent.infiniteScrollElement.complete(); this.setItems(this.items); } /** * Scrolls to the top of Modal content. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#scrolltotop). * * @returns Promise that resolves when scroll has been completed. * @memberof IonicSelectableComponent */ async scrollToTop() { if (!this.isOpened) { return Promise.reject(`IonicSelectable content cannot be scrolled: ${this.element.id}`); } await this.selectableModalComponent.contentElement.scrollToTop(); return Promise.resolve(); } /** * Scrolls to the bottom of Modal content. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#scrolltobottom). * * @returns Promise that resolves when scroll has been completed. * @memberof IonicSelectableComponent */ async scrollToBottom() { if (!this.isOpened) { return Promise.reject(`IonicSelectable content cannot be scrolled: ${this.element.id}`); } await this.selectableModalComponent.contentElement.scrollToBottom(); return Promise.resolve(); } /** * Starts search process by showing Loading spinner. * Use it together with `onSearch` event to indicate search start. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#startsearch). * * @memberof IonicSelectableComponent */ async startSearch() { if (this.isDisabled) { return; } this.showLoading(); } /** * Ends search process by hiding Loading spinner and refreshing items. * Use it together with `onSearch` event to indicate search end. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#endsearch). * * @memberof IonicSelectableComponent */ async endSearch() { if (this.isDisabled) { return; } this.hideLoading(); // Refresh items manually. // Pending - this.setItems(this.items); this.emitOnSearchSuccessedOrFailed(this.hasFilteredItems); } /** * Shows Loading spinner. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#showloading). * * @memberof IonicSelectableComponent */ async showLoading() { var _a; if (this.isDisabled) { return; } this.isSearching = true; (_a = this.selectableModalComponent) === null || _a === void 0 ? void 0 : _a.update(); } /** * Hides Loading spinner. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#hideloading). * * @memberof IonicSelectableComponent */ async hideLoading() { var _a; if (this.isDisabled) { return; } this.isSearching = false; (_a = this.selectableModalComponent) === null || _a === void 0 ? void 0 : _a.update(); } /** * Adds item. * **Note**: If you want an item to be added to the original array as well use two-way data binding syntax on `[(items)]` field. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#additem). * * @param item Item to add. * @returns Promise that resolves when item has been added. * @memberof IonicSelectableComponent */ async addItem(item) { // Adding item triggers onItemsChange. // Return a promise that resolves when onItemsChange finishes. // We need a promise or user could do something after item has been added, // e.g. use search() method to find the added item. this.items.push(item); this.setItems(this.items); return Promise.resolve(); } /** * Deletes item. * **Note**: If you want an item to be deleted from the original array as well use two-way data binding syntax on `[(items)]` field. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#deleteitem). * * @param item Item to delete. * @returns Promise that resolves when item has been deleted. * @memberof IonicSelectableComponent */ async deleteItem(item) { let hasValueChanged = false; // Remove deleted item from selected items. if (this.selectedItems) { this.selectedItems = this.selectedItems.filter((_item) => this.getItemValue(item) !== this.getStoredItemValue(_item)); } // Remove deleted item from value. if (this.value) { if (this.isMultiple) { const values = this.value.filter((value) => { return value.id !== item.id; }); if (values.length !== this.value.length) { this.value = values; hasValueChanged = true; } } else { if (item === this.value) { this.value = null; hasValueChanged = true; } } } if (hasValueChanged) { this.emitChanged(); } // Remove deleted item from list. const items = this.items.filter((_item) => { return _item.id !== item.id; }); // Refresh items on parent component. // Pending - this.itemsChange.emit(items); // Refresh list. this.setItems(items); return Promise.resolve(); } /** * Selects or deselects all or specific items. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#toggleitems). * * @param isSelect Determines whether to select or deselect items. * @param [items] Items to toggle. If items are not set all items will be toggled. * @memberof IonicSelectableComponent */ async toggleItems(isSelect, items) { var _a; if (isSelect) { const hasItems = items && items.length; let itemsToToggle = this.groups.reduce((allItems, group) => { return allItems.concat(group.items); }, []); // Don't allow to select all items in single mode. if (!this.isMultiple && !hasItems) { itemsToToggle = []; } // Toggle specific items. if (hasItems) { itemsToToggle = itemsToToggle.filter((itemToToggle) => { return (items.find((item) => { return this.getItemValue(itemToToggle) === this.getItemValue(item); }) !== undefined); }); // Take the first item for single mode. if (!this.isMultiple) { itemsToToggle.splice(0, 1); } } itemsToToggle.forEach((item) => { this.addSelectedItem(item); }); } else { const hasItems = items && items.length; if (hasItems) { items.forEach((item) => { this.deleteSelectedItem(item); }); } else { this.selectedItems = []; } (_a = this.selectableModalComponent) === null || _a === void 0 ? void 0 : _a.update(); } this.itemsToConfirm = [...this.selectedItems]; } /** * Shows `ionicSelectableAddItemTemplate`. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#showadditemtemplate). * * @memberof IonicSelectableComponent */ async showAddItemTemplate() { this.toggleAddItemTemplate(true); } /** * Hides `ionicSelectableAddItemTemplate`. * See more on [GitHub](https://github.com/eakoriakin/ionic-selectable/wiki/Documentation#hideadditemtemplate). * * @memberof IonicSelectableComponent */ async hideAddItemTemplate() { // Clean item to add as it's no longer needed once Add Item Modal has been closed. this.itemToAdd = null; this.toggleAddItemTemplate(false); } clearItems() { var _a; this.setValue(null); (_a = this.selectableModalComponent) === null || _a === void 0 ? void 0 : _a.update(); this.emitCleared(); } closeModal() { this.close(); } addItemClick() { if (this.hasTemplateRender && this.hasTemplateRender('addItem')) { this.showAddItemTemplate(); } else { this.emitItemAdding(); } } onSearchbarValueChanged(event) { this.startSearch(); this.filterItems(event.detail.value); this.endSearch(); } isItemSelected(item) { return (this.selectedItems.find((selectedItem) => { return this.getItemValue(item) === this.getStoredItemValue(selectedItem); }) !== undefined); } isItemDisabled(item) { if (!this.disabledItems) { return; } return this.disabledItems.some((_item) => { return this.getItemValue(_item) === this.getItemValue(item); }); } selectItem(item) { const isItemSelected = this.isItemSelected(item); if (this.isMultiple) { if (isItemSelected) { this.deleteSelectedItem(item); } else { this.addSelectedItem(item); } this.itemsToConfirm = [...this.selectedItems]; // Emit onSelect event after setting items to confirm so they could be used inside the event. this.emitSelected(item, !isItemSelected); } else { if (this.hasConfirmButton /* || this.footerTemplate*/) { // Don't close Modal and keep track on items to confirm. // When footer template is used it's up to developer to close Modal. this.selectedItems = []; if (isItemSelected) { this.deleteSelectedItem(item); } else { this.addSelectedItem(item); } this.itemsToConfirm = [...this.selectedItems]; // Emit onSelect event after setting items to confirm so they could be used inside the event. this.emitSelected(item, !isItemSelected); } else { if (!isItemSelected) { this.selectedItems = []; this.addSelectedItem(item); // Emit onSelect before onChange. this.emitSelected(item, true); this.setValue(item); } this.close(); } } } confirmSelection() { this.confirm(); this.close(); } getMoreItems() { this.emitIonInfiniteScrolled(); } setValue(value, isChangeInternal = true) { var _a; this.isChangeInternal = isChangeInternal; if (value) { // If type is string convert to object value = typeof value === 'string' ? JSON.parse(value.replace(/\'/gi, '"')) : value; const isArray = Array.isArray(value); if (!isArray) { value = [value]; } if (this.isMultiple && !isArray) { throw new Error(`If isMultiple is set to true, value must be array: ${this.element.id}`); } if (!this.isMultiple && isArray) { throw new Error(`If isMultiple is set to false, value must be object: ${this.element.id}`); } this.valueItems = []; value.forEach((_item) => { if (this.shouldStoreItemValue && typeof _item === 'object') { throw new Error(`If shouldStoreItemValue is set to true, value must be primitive: ${this.element.id}`); } else if (!this.shouldStoreItemValue && typeof _item !== 'object') { throw new Error(`If shouldStoreItemValue is set to false, value must be object: ${this.element.id}`); } const itemFind = this.items.find((item) => this.getItemValue(item) === this.getStoredItemValue(_item)); if (itemFind) { this.valueItems.push(this.getItem(itemFind)); } }); if (!this.isMultiple) { this.valueItems = this.valueItems.pop(); this.selectedItems = [this.valueItems]; } else { this.selectedItems = [...this.valueItems]; } if (this.isChangeInternal) { this.value = this.valueItems; } } else { this.valueItems = []; this.selectedItems = []; if (this.isChangeInternal) { this.value = this.isMultiple ? [] : null; } } this.itemsToConfirm = []; if (this.isOpened) { (_a = this.selectableModalComponent) === null || _a === void 0 ? void 0 : _a.update(); } if (this.isInited) { this.emitChanged(); } } setItems(items) { var _a, _b; if (!Array.isArray(items)) { throw new Error(`items must be array: ${this.element.id}`); } this.items.forEach((item) => { if (typeof item === 'object') { this.hasObjects = true; } }); // If items contains primitive elements, isValuePrimitive is set to true if (!this.hasObjects) { this.shouldStoreItemValue = true; } this.onItemValueFieldChanged(this.itemValueField); this.onItemTextFieldChanged(this.itemTextField); this.onShouldStoreItemValueChanged(this.shouldStoreItemValue); // Grouping is supported for objects only. // Ionic VirtualScroll has it's own implementation of grouping. this.hasGroups = Boolean(this.hasObjects && (this.groupValueField || this.groupTextField) && !this.hasVirtualScroll); /* It's important to have an empty starting group with empty items (groups[0].items), * because we bind to it when using VirtualScroll. * See https://github.com/eakoriakin/ionic-selectable/issues/70. */ let groups = [ { items: items || [], }, ]; if (items && items.length) { if (this.hasGroups) { groups = []; items.forEach((item) => { const groupValue = this.getPropertyValue(item, this.groupValueField || this.groupTextField); const group = groups.find((_group) => _group.value === groupValue); if (group) { group.items.push(item); } else { groups.push({ value: groupValue, text: this.getPropertyValue(item, this.groupTextField), items: [item], }); } }); } } this.groups = groups; this.filteredGroups = this.groups; this.hasFilteredItems = !this.areGroupsEmpty(this.filteredGroups); if (this.hasVirtualScroll) { // Rerender Virtual Scroll List After Adding New Data (_a = this.selectableModalComponent) === null || _a === void 0 ? void 0 : _a.virtualScrollElement.checkEnd(); } (_b = this.selectableModalComponent) === null || _b === void 0 ? void 0 : _b.update(); if (this.isInited) { this.emitItemsChanged(); } } filterItems(searchText, isChangeInternal = true) { var _a; this.isChangeInternal = isChangeInternal; this.setHasSearchText(searchText); if (this.shouldDelegateSearchToEvent) { // Delegate filtering to the event. this.emitSearching(); } else { // Default filtering. let groups = [];