Remove deprecated scripts for adding head-matter to wt_config.xml, including Python and Bash implementations, to streamline configuration management.
This commit is contained in:
297
client/node_modules/@vueform/multiselect/src/Multiselect.d.ts
generated
vendored
Normal file
297
client/node_modules/@vueform/multiselect/src/Multiselect.d.ts
generated
vendored
Normal file
@@ -0,0 +1,297 @@
|
||||
import { VNode, defineComponent } from 'vue';
|
||||
|
||||
interface ClassList {
|
||||
assist: string;
|
||||
caret: Array<string>;
|
||||
clear: string;
|
||||
clearIcon: string;
|
||||
container: Array<string>;
|
||||
dropdown: Array<string>;
|
||||
fakeInput: string;
|
||||
group: string;
|
||||
groupLabel: (g: any) => any;
|
||||
groupOptions: string;
|
||||
inifinite: string;
|
||||
inifiniteSpinner: string;
|
||||
multipleLabel: string;
|
||||
noOptions: string;
|
||||
noResults: string;
|
||||
option: (o:any, g:any) => any;
|
||||
options: Array<string>;
|
||||
placeholder: string;
|
||||
search: string;
|
||||
singleLabel: string;
|
||||
singleLabelText: string;
|
||||
spacer: string;
|
||||
spinner: string;
|
||||
tag: Array<string>
|
||||
tagDisabled: string;
|
||||
tagRemove: string;
|
||||
tagRemoveIcon: string;
|
||||
tags: string;
|
||||
tagsSearch: string;
|
||||
tagsSearchCopy: string;
|
||||
tagsSearchWrapper: string;
|
||||
wrapper: string;
|
||||
}
|
||||
|
||||
interface MultiselectProps {
|
||||
modelValue?: any;
|
||||
value?: any;
|
||||
mode?: 'single' | 'multiple' | 'tags';
|
||||
options?: any[] | object | Function;
|
||||
searchable?: boolean;
|
||||
valueProp?: string;
|
||||
trackBy?: string | string[];
|
||||
label?: string;
|
||||
placeholder?: string | null;
|
||||
multipleLabel?: any; // Function
|
||||
disabled?: boolean;
|
||||
max?: number;
|
||||
limit?: number;
|
||||
loading?: boolean;
|
||||
id?: string;
|
||||
caret?: boolean;
|
||||
maxHeight?: string | number;
|
||||
noOptionsText?: string | object;
|
||||
noResultsText?: string | object;
|
||||
canDeselect?: boolean;
|
||||
canClear?: boolean;
|
||||
clearOnSearch?: boolean;
|
||||
clearOnSelect?: boolean;
|
||||
delay?: number;
|
||||
filterResults?: boolean;
|
||||
minChars?: number;
|
||||
resolveOnLoad?: boolean;
|
||||
appendNewTag?: boolean;
|
||||
appendNewOption?: boolean;
|
||||
createTag?: boolean;
|
||||
createOption?: boolean;
|
||||
addTagOn?: string[];
|
||||
addOptionOn?: string[];
|
||||
hideSelected?: boolean;
|
||||
showOptions?: boolean;
|
||||
object?: boolean;
|
||||
required?: boolean;
|
||||
openDirection?: 'top' | 'bottom';
|
||||
nativeSupport?: boolean;
|
||||
classes?: object;
|
||||
strict?: boolean;
|
||||
closeOnSelect?: boolean;
|
||||
closeOnDeselect?: boolean;
|
||||
autocomplete?: string;
|
||||
groups?: boolean;
|
||||
groupLabel?: string;
|
||||
groupOptions?: string;
|
||||
groupHideEmpty?: boolean;
|
||||
groupSelect?: boolean;
|
||||
inputType?: string;
|
||||
attrs?: object;
|
||||
onCreate?: Function;
|
||||
searchStart?: boolean;
|
||||
reverse?: boolean;
|
||||
regex?: string | object;
|
||||
rtl?: boolean;
|
||||
infinite?: boolean;
|
||||
aria?: object;
|
||||
clearOnBlur?: boolean;
|
||||
locale?: string;
|
||||
fallbackLocale?: string;
|
||||
searchFilter?: Function;
|
||||
allowAbsent?: boolean;
|
||||
appendToBody?: boolean;
|
||||
closeOnScroll?: boolean;
|
||||
breakTags?: boolean;
|
||||
appendTo?: string;
|
||||
}
|
||||
|
||||
declare class Multiselect implements ReturnType<typeof defineComponent> {
|
||||
modelValue: MultiselectProps['modelValue'];
|
||||
value: MultiselectProps['value'];
|
||||
mode: MultiselectProps['mode'];
|
||||
options: MultiselectProps['options'];
|
||||
searchable: MultiselectProps['searchable'];
|
||||
valueProp: MultiselectProps['valueProp'];
|
||||
trackBy: MultiselectProps['trackBy'];
|
||||
label: MultiselectProps['label'];
|
||||
placeholder: MultiselectProps['placeholder'];
|
||||
multipleLabel: MultiselectProps['multipleLabel'];
|
||||
disabled: MultiselectProps['disabled'];
|
||||
max: MultiselectProps['max'];
|
||||
limit: MultiselectProps['limit'];
|
||||
loading: MultiselectProps['loading'];
|
||||
id: MultiselectProps['id'];
|
||||
caret: MultiselectProps['caret'];
|
||||
maxHeight: MultiselectProps['maxHeight'];
|
||||
noOptionsText: MultiselectProps['noOptionsText'];
|
||||
noResultsText: MultiselectProps['noResultsText'];
|
||||
canDeselect: MultiselectProps['canDeselect'];
|
||||
canClear: MultiselectProps['canClear'];
|
||||
clearOnSearch: MultiselectProps['clearOnSearch'];
|
||||
clearOnSelect: MultiselectProps['clearOnSelect'];
|
||||
delay: MultiselectProps['delay'];
|
||||
filterResults: MultiselectProps['filterResults'];
|
||||
minChars: MultiselectProps['minChars'];
|
||||
resolveOnLoad: MultiselectProps['resolveOnLoad'];
|
||||
appendNewTag: MultiselectProps['appendNewTag'];
|
||||
appendNewOption: MultiselectProps['appendNewOption'];
|
||||
createTag: MultiselectProps['createTag'];
|
||||
createOption: MultiselectProps['createOption'];
|
||||
addTagOn: MultiselectProps['addTagOn'];
|
||||
addOptionOn: MultiselectProps['addOptionOn'];
|
||||
hideSelected: MultiselectProps['hideSelected'];
|
||||
showOptions: MultiselectProps['showOptions'];
|
||||
object: MultiselectProps['object'];
|
||||
required: MultiselectProps['required'];
|
||||
openDirection: MultiselectProps['openDirection'];
|
||||
nativeSupport: MultiselectProps['nativeSupport'];
|
||||
classes: MultiselectProps['classes'];
|
||||
strict: MultiselectProps['strict'];
|
||||
closeOnSelect: MultiselectProps['closeOnSelect'];
|
||||
closeOnDeselect: MultiselectProps['closeOnDeselect'];
|
||||
autocomplete: MultiselectProps['autocomplete'];
|
||||
groups: MultiselectProps['groups'];
|
||||
groupLabel: MultiselectProps['groupLabel'];
|
||||
groupOptions: MultiselectProps['groupOptions'];
|
||||
groupHideEmpty: MultiselectProps['groupHideEmpty'];
|
||||
groupSelect: MultiselectProps['groupSelect'];
|
||||
inputType: MultiselectProps['inputType'];
|
||||
attrs: MultiselectProps['attrs'];
|
||||
onCreate: MultiselectProps['onCreate'];
|
||||
searchStart: MultiselectProps['searchStart'];
|
||||
reverse: MultiselectProps['reverse'];
|
||||
regex: MultiselectProps['regex'];
|
||||
rtl: MultiselectProps['rtl'];
|
||||
infinite: MultiselectProps['infinite'];
|
||||
aria: MultiselectProps['aria'];
|
||||
clearOnBlur: MultiselectProps['clearOnBlur'];
|
||||
locale: MultiselectProps['locale'];
|
||||
fallbackLocale: MultiselectProps['fallbackLocale'];
|
||||
searchFilter: MultiselectProps['searchFilter'];
|
||||
allowAbsent: MultiselectProps['allowAbsent'];
|
||||
appendToBody: MultiselectProps['appendToBody'];
|
||||
closeOnScroll: MultiselectProps['closeOnScroll'];
|
||||
breakTags: MultiselectProps['breakTags'];
|
||||
appendTo: MultiselectProps['appendTo'];
|
||||
|
||||
$props: MultiselectProps;
|
||||
|
||||
$emit(eventName: 'change', value: any, instance: this): this | void;
|
||||
$emit(eventName: 'select', value: any, option: any, instance:this): this | void;
|
||||
$emit(eventName: 'deselect', value: any, option: any, instance:this): this | void;
|
||||
$emit(eventName: 'search-change', query: string, instance: this): this | void;
|
||||
$emit(eventName: 'tag', option: any, instance: this): this | void;
|
||||
$emit(eventName: 'option', option: any, instance: this): this | void;
|
||||
$emit(eventName: 'create', option: any, instance: this): this | void;
|
||||
$emit(eventName: 'paste', e: Event, instance: this): this | void;
|
||||
$emit(eventName: 'keydown', e: Event, instance: this): this | void;
|
||||
$emit(eventName: 'keyup', e: Event, instance: this): this | void;
|
||||
$emit(eventName: 'open', instance: this): this | void;
|
||||
$emit(eventName: 'close', instance: this): this | void;
|
||||
$emit(eventName: 'clear', instance: this): this | void;
|
||||
$emit(eventName: 'max', instance: this): this | void;
|
||||
|
||||
$slots: {
|
||||
placeholder: VNode[];
|
||||
afterlist: (props: { options: any[] }) => VNode[];
|
||||
beforelist: (props: { options: any[] }) => VNode[];
|
||||
multiplelabel: (props: { values: any[] | object }) => VNode[];
|
||||
singlelabel: (props: { value: any }) => VNode[];
|
||||
option: (props: { option: any, isSelected: (option: any) => boolean, isPointed: (option: any) => boolean, search: null | string }) => VNode[];
|
||||
grouplabel: (props: { group: any, isSelected: (option: any) => boolean, isPointed: (option: any) => boolean }) => VNode[];
|
||||
tag: (props: { option: any, handleTagRemove: (option: any, e: Event) => void, disabled: boolean, }) => VNode[];
|
||||
infinite: VNode[];
|
||||
nooptions: VNode[];
|
||||
noresults: VNode[];
|
||||
caret: (props: { handleCaretClick: () => void, isOpen: boolean, }) => VNode[];
|
||||
clear: (props: { clear: () => void }) => VNode[];
|
||||
spinner: VNode[];
|
||||
};
|
||||
|
||||
activate: (shouldOpen?: boolean) => void;
|
||||
ariaActiveDescendant: string | undefined;
|
||||
ariaAssist: string;
|
||||
ariaControls: string;
|
||||
ariaGroupId: (option : any) => string;
|
||||
ariaGroupLabel: (label: any) => string;
|
||||
ariaLabel: string;
|
||||
ariaMultiselectable: boolean;
|
||||
ariaOptionId: (option: any) => string;
|
||||
ariaOptionLabel: (label: any) => string;
|
||||
ariaPlaceholder: any;
|
||||
ariaTagLabel: (label: any) => string;
|
||||
arias: object;
|
||||
backwardPointer: any;
|
||||
blur: () => void;
|
||||
busy: boolean;
|
||||
canPointGroups: boolean;
|
||||
classList: ClassList;
|
||||
clear: () => void;
|
||||
clearPointer: () => void;
|
||||
clearSearch: () => void;
|
||||
close: () => void;
|
||||
deactivate: () => void;
|
||||
deselect: (option: any) => void;
|
||||
disabledProp?: string;
|
||||
extendedGroups: Array<any>
|
||||
extendedOptions: Array<any>
|
||||
externalValue: any;
|
||||
filteredGroups: Array<any>
|
||||
filteredOptions: any;
|
||||
focus: () => void;
|
||||
forwardPointer: () => void;
|
||||
getOption: (val: any) => any
|
||||
handleCaretClick: () => void;
|
||||
handleFocusIn: (e: any) => void;
|
||||
handleFocusOut: () => void;
|
||||
handleGroupClick: (group: any) => void;
|
||||
handleKeydown: (e: Event) => void;
|
||||
handleKeypress: (e: Event) => void;
|
||||
handleKeyup: (e: Event) => void;
|
||||
handleMousedown: (e: Event) => void;
|
||||
handleOptionClic: (option: any) => void;
|
||||
handlePaste: (e: Event) => void;
|
||||
handleSearchInput: (e: Event) => void;
|
||||
handleTagRemove: (option: any, e: Event) => void;
|
||||
hasMore: boolean;
|
||||
hasSelected: boolean;
|
||||
infiniteLoader: any;
|
||||
input: HTMLInputElement;
|
||||
internalValue: any;
|
||||
isActive: boolean;
|
||||
isDisabled: boolean;
|
||||
isMax: () => boolean;
|
||||
isOpen: boolean;
|
||||
isPointed: (option: any) => boolean | undefined;
|
||||
isSelected: (option: any) => boolean;
|
||||
localize: (target: any) => any;
|
||||
mouseClicked: boolean;
|
||||
multipleLabelText: string;
|
||||
multiselect: any;
|
||||
offset: number;
|
||||
open: () => void;
|
||||
plainValue: any;
|
||||
pointer: any;
|
||||
placement: string;
|
||||
popper: object;
|
||||
preparePointer: () => void;
|
||||
refreshLabels: () => void;
|
||||
refreshOptions: (callback: any) => void;
|
||||
remove: (option: any) => void;
|
||||
resolveOptions: (callback: any) => void;
|
||||
resolving: boolean;
|
||||
search: any;
|
||||
select: (option: any) => void;
|
||||
selectAll: () => void;
|
||||
selectPointer: () => void;
|
||||
setPointer: (option: any) => void;
|
||||
setPointerFirst: () => void;
|
||||
showDropdown: boolean;
|
||||
tabindex: number;
|
||||
tags: any;
|
||||
textValue: any;
|
||||
update: (val: any, triggerInput?: boolean) => void;
|
||||
updatePopper: () => void;
|
||||
}
|
||||
|
||||
export default Multiselect;
|
||||
691
client/node_modules/@vueform/multiselect/src/Multiselect.vue
generated
vendored
Normal file
691
client/node_modules/@vueform/multiselect/src/Multiselect.vue
generated
vendored
Normal file
@@ -0,0 +1,691 @@
|
||||
<template>
|
||||
<div
|
||||
ref="multiselect"
|
||||
:class="classList.container"
|
||||
:id="searchable ? undefined : id"
|
||||
:dir="rtl ? 'rtl' : undefined"
|
||||
@focusin="handleFocusIn"
|
||||
@focusout="handleFocusOut"
|
||||
@keyup="handleKeyup"
|
||||
@keydown="handleKeydown"
|
||||
>
|
||||
<div
|
||||
:class="classList.wrapper"
|
||||
@mousedown="handleMousedown"
|
||||
ref="wrapper"
|
||||
|
||||
:tabindex="tabindex"
|
||||
:aria-controls="!searchable ? ariaControls : undefined"
|
||||
:aria-placeholder="!searchable ? ariaPlaceholder : undefined"
|
||||
:aria-expanded="!searchable ? isOpen : undefined"
|
||||
:aria-activedescendant="!searchable ? ariaActiveDescendant : undefined"
|
||||
:aria-multiselectable="!searchable ? ariaMultiselectable : undefined"
|
||||
:role="!searchable ? 'combobox' : undefined"
|
||||
v-bind="!searchable ? arias : {}"
|
||||
>
|
||||
<!-- Search -->
|
||||
<template v-if="mode !== 'tags' && searchable && !disabled">
|
||||
<input
|
||||
:type="inputType"
|
||||
:modelValue="search"
|
||||
:value="search"
|
||||
:class="classList.search"
|
||||
:autocomplete="autocomplete"
|
||||
:id="searchable ? id : undefined"
|
||||
@input="handleSearchInput"
|
||||
@keypress="handleKeypress"
|
||||
@paste.stop="handlePaste"
|
||||
ref="input"
|
||||
|
||||
:aria-controls="ariaControls"
|
||||
:aria-placeholder="ariaPlaceholder"
|
||||
:aria-expanded="isOpen"
|
||||
:aria-activedescendant="ariaActiveDescendant"
|
||||
:aria-multiselectable="ariaMultiselectable"
|
||||
role="combobox"
|
||||
|
||||
v-bind="{
|
||||
...attrs,
|
||||
...arias,
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- Tags (with search) -->
|
||||
<template v-if="mode == 'tags'">
|
||||
<div :class="classList.tags" data-tags>
|
||||
<slot
|
||||
v-for="(option, i, key) in iv"
|
||||
name="tag"
|
||||
:option="option"
|
||||
:handleTagRemove="handleTagRemove"
|
||||
:disabled="disabled"
|
||||
>
|
||||
<span
|
||||
:class="[
|
||||
classList.tag,
|
||||
option.disabled ? classList.tagDisabled : null,
|
||||
]"
|
||||
tabindex="-1"
|
||||
@keyup.enter="handleTagRemove(option, $event)"
|
||||
:key="key"
|
||||
|
||||
:aria-label="ariaTagLabel(localize(option[label]))"
|
||||
>
|
||||
<span :class="classList.tagWrapper">{{ localize(option[label]) }}</span>
|
||||
<span
|
||||
v-if="!disabled && !option.disabled"
|
||||
:class="classList.tagRemove"
|
||||
@click.stop="handleTagRemove(option, $event)"
|
||||
>
|
||||
<span :class="classList.tagRemoveIcon"></span>
|
||||
</span>
|
||||
</span>
|
||||
</slot>
|
||||
|
||||
<div :class="classList.tagsSearchWrapper" ref="tags">
|
||||
<!-- Used for measuring search width -->
|
||||
<span :class="classList.tagsSearchCopy">{{ search }}</span>
|
||||
|
||||
<!-- Actual search input -->
|
||||
<input
|
||||
v-if="searchable && !disabled"
|
||||
:type="inputType"
|
||||
:modelValue="search"
|
||||
:value="search"
|
||||
:class="classList.tagsSearch"
|
||||
:id="searchable ? id : undefined"
|
||||
:autocomplete="autocomplete"
|
||||
@input="handleSearchInput"
|
||||
@keypress="handleKeypress"
|
||||
@paste.stop="handlePaste"
|
||||
ref="input"
|
||||
|
||||
:aria-controls="ariaControls"
|
||||
:aria-placeholder="ariaPlaceholder"
|
||||
:aria-expanded="isOpen"
|
||||
:aria-activedescendant="ariaActiveDescendant"
|
||||
:aria-multiselectable="ariaMultiselectable"
|
||||
role="combobox"
|
||||
|
||||
v-bind="{
|
||||
...attrs,
|
||||
...arias,
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Single label -->
|
||||
<template v-if="mode == 'single' && hasSelected && !search && iv">
|
||||
<slot name="singlelabel" :value="iv">
|
||||
<div :class="classList.singleLabel">
|
||||
<span :class="classList.singleLabelText">{{ localize(iv[label]) }}</span>
|
||||
</div>
|
||||
</slot>
|
||||
</template>
|
||||
|
||||
<!-- Multiple label -->
|
||||
<template v-if="mode == 'multiple' && hasSelected && !search">
|
||||
<slot name="multiplelabel" :values="iv">
|
||||
<div :class="classList.multipleLabel" v-html="multipleLabelText"></div>
|
||||
</slot>
|
||||
</template>
|
||||
|
||||
<!-- Placeholder -->
|
||||
<template v-if="placeholder && !hasSelected && !search">
|
||||
<slot name="placeholder">
|
||||
<div :class="classList.placeholder" aria-hidden="true">
|
||||
{{ placeholder }}
|
||||
</div>
|
||||
</slot>
|
||||
</template>
|
||||
|
||||
<!-- Spinner -->
|
||||
<slot v-if="loading || resolving" name="spinner">
|
||||
<span :class="classList.spinner" aria-hidden="true"></span>
|
||||
</slot>
|
||||
|
||||
<!-- Clear -->
|
||||
<slot v-if="hasSelected && !disabled && canClear && !busy" name="clear" :clear="clear">
|
||||
<span
|
||||
aria-hidden="true"
|
||||
tabindex="0"
|
||||
role="button"
|
||||
data-clear
|
||||
aria-roledescription="❎"
|
||||
:class="classList.clear"
|
||||
@click="clear"
|
||||
@keyup.enter="clear"
|
||||
><span :class="classList.clearIcon"></span></span>
|
||||
</slot>
|
||||
|
||||
<!-- Caret -->
|
||||
<slot v-if="caret && showOptions" name="caret" :handle-caret-click="handleCaretClick" :is-open="isOpen">
|
||||
<span :class="classList.caret" @click="handleCaretClick" aria-hidden="true"></span>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<!-- Options -->
|
||||
<Teleport :to="appendTo || 'body'" :disabled="!appendToBody && !appendTo">
|
||||
<div
|
||||
:id="id ? `${id}-dropdown` : undefined"
|
||||
:class="classList.dropdown"
|
||||
tabindex="-1"
|
||||
ref="dropdown"
|
||||
@focusin="handleFocusIn"
|
||||
@focusout="handleFocusOut"
|
||||
>
|
||||
<slot name="beforelist" :options="fo"></slot>
|
||||
|
||||
<ul :class="classList.options" :id="ariaControls" role="listbox">
|
||||
<template v-if="groups">
|
||||
<li
|
||||
v-for="(group, i, key) in fg"
|
||||
:class="classList.group"
|
||||
:key="key"
|
||||
|
||||
:id="ariaGroupId(group)"
|
||||
:aria-label="ariaGroupLabel(localize(group[groupLabel]))"
|
||||
:aria-selected="isSelected(group)"
|
||||
role="option"
|
||||
>
|
||||
<div
|
||||
v-if="!group.__CREATE__"
|
||||
:class="classList.groupLabel(group)"
|
||||
:data-pointed="isPointed(group)"
|
||||
@mouseenter="setPointer(group, i)"
|
||||
@click="handleGroupClick(group)"
|
||||
>
|
||||
<slot name="grouplabel" :group="group" :is-selected="isSelected" :is-pointed="isPointed">
|
||||
<span v-html="localize(group[groupLabel])"></span>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<ul
|
||||
:class="classList.groupOptions"
|
||||
|
||||
:aria-label="ariaGroupLabel(localize(group[groupLabel]))"
|
||||
role="group"
|
||||
>
|
||||
<li
|
||||
v-for="(option, i, key) in group.__VISIBLE__"
|
||||
:class="classList.option(option, group)"
|
||||
:data-pointed="isPointed(option)"
|
||||
:data-selected="isSelected(option) || undefined"
|
||||
:key="key"
|
||||
@mouseenter="setPointer(option)"
|
||||
@click="handleOptionClick(option)"
|
||||
|
||||
:id="ariaOptionId(option)"
|
||||
:aria-selected="isSelected(option)"
|
||||
:aria-label="ariaOptionLabel(localize(option[label]))"
|
||||
role="option"
|
||||
>
|
||||
<slot name="option" :option="option" :is-selected="isSelected" :is-pointed="isPointed" :search="search">
|
||||
<span>{{ localize(option[label]) }}</span>
|
||||
</slot>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</template>
|
||||
<template v-else>
|
||||
<li
|
||||
v-for="(option, i, key) in fo"
|
||||
:class="classList.option(option)"
|
||||
:data-pointed="isPointed(option)"
|
||||
:data-selected="isSelected(option) || undefined"
|
||||
:key="key"
|
||||
@mouseenter="setPointer(option)"
|
||||
@click="handleOptionClick(option)"
|
||||
|
||||
:id="ariaOptionId(option)"
|
||||
:aria-selected="isSelected(option)"
|
||||
:aria-label="ariaOptionLabel(localize(option[label]))"
|
||||
role="option"
|
||||
>
|
||||
<slot name="option" :option="option" :isSelected="isSelected" :is-pointed="isPointed" :search="search">
|
||||
<span>{{ localize(option[label]) }}</span>
|
||||
</slot>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
|
||||
<slot v-if="noOptions" name="nooptions">
|
||||
<div :class="classList.noOptions" v-html="localize(noOptionsText)"></div>
|
||||
</slot>
|
||||
|
||||
<slot v-if="noResults" name="noresults">
|
||||
<div :class="classList.noResults" v-html="localize(noResultsText)"></div>
|
||||
</slot>
|
||||
|
||||
<div v-if="infinite && hasMore" :class="classList.inifinite" ref="infiniteLoader">
|
||||
<slot name="infinite">
|
||||
<span :class="classList.inifiniteSpinner"></span>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<slot name="afterlist" :options="fo"></slot>
|
||||
</div>
|
||||
</Teleport>
|
||||
|
||||
<!-- Hacky input element to show HTML5 required warning -->
|
||||
<input v-if="required" :class="classList.fakeInput" tabindex="-1" :value="textValue" required/>
|
||||
|
||||
<!-- Native input support -->
|
||||
<template v-if="nativeSupport">
|
||||
<input v-if="mode == 'single'" type="hidden" :name="name" :value="plainValue !== undefined ? plainValue : ''" />
|
||||
<template v-else>
|
||||
<input v-for="(v, i) in plainValue" type="hidden" :name="`${name}[]`" :value="v" :key="i" />
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<!-- Screen reader assistive text -->
|
||||
<div v-if="searchable && hasSelected" :class="classList.assist" :id="ariaAssist" aria-hidden="true">
|
||||
{{ ariaLabel }}
|
||||
</div>
|
||||
|
||||
<!-- Create height for empty input -->
|
||||
<div :class="classList.spacer"></div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* istanbul ignore file */
|
||||
|
||||
import useData from './composables/useData'
|
||||
import useValue from './composables/useValue'
|
||||
import useSearch from './composables/useSearch'
|
||||
import usePointer from './composables/usePointer'
|
||||
import useOptions from './composables/useOptions'
|
||||
import usePointerAction from './composables/usePointerAction'
|
||||
import useDropdown from './composables/useDropdown'
|
||||
import useMultiselect from './composables/useMultiselect'
|
||||
import useKeyboard from './composables/useKeyboard'
|
||||
import useClasses from './composables/useClasses'
|
||||
import useScroll from './composables/useScroll'
|
||||
import useA11y from './composables/useA11y'
|
||||
import useI18n from './composables/useI18n'
|
||||
import useRefs from './composables/useRefs'
|
||||
|
||||
import resolveDeps from './utils/resolveDeps'
|
||||
|
||||
export default {
|
||||
name: 'Multiselect',
|
||||
emits: [
|
||||
'paste', 'open', 'close', 'select', 'deselect',
|
||||
'input', 'search-change', 'tag', 'option', 'update:modelValue',
|
||||
'change', 'clear', 'keydown', 'keyup', 'max', 'create',
|
||||
],
|
||||
props: {
|
||||
value: {
|
||||
required: false,
|
||||
},
|
||||
modelValue: {
|
||||
required: false,
|
||||
},
|
||||
options: {
|
||||
type: [Array, Object, Function],
|
||||
required: false,
|
||||
default: () => ([])
|
||||
},
|
||||
id: {
|
||||
type: [String, Number],
|
||||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
name: {
|
||||
type: [String, Number],
|
||||
required: false,
|
||||
default: 'multiselect',
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'label',
|
||||
},
|
||||
trackBy: {
|
||||
type: [String, Array],
|
||||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
valueProp: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'value',
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'single', // single|multiple|tags
|
||||
},
|
||||
searchable: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: -1,
|
||||
},
|
||||
hideSelected: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
createTag: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
createOption: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
appendNewTag: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
appendNewOption: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
addTagOn: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
addOptionOn: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
caret: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
noOptionsText: {
|
||||
type: [String, Object],
|
||||
required: false,
|
||||
default: 'The list is empty',
|
||||
},
|
||||
noResultsText: {
|
||||
type: [String, Object],
|
||||
required: false,
|
||||
default: 'No results found',
|
||||
},
|
||||
multipleLabel: {
|
||||
type: Function,
|
||||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
object: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
delay: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: -1,
|
||||
},
|
||||
minChars: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0,
|
||||
},
|
||||
resolveOnLoad: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
filterResults: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
clearOnSearch: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
clearOnSelect: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
canDeselect: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
canClear: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
max: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: -1,
|
||||
},
|
||||
showOptions: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
required: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
openDirection: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'bottom',
|
||||
},
|
||||
nativeSupport: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
classes: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({})
|
||||
},
|
||||
strict: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
closeOnSelect: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
closeOnDeselect: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
autocomplete: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
groups: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
groupLabel: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'label',
|
||||
},
|
||||
groupOptions: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'options',
|
||||
},
|
||||
groupHideEmpty: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
groupSelect: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
inputType: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'text',
|
||||
},
|
||||
attrs: {
|
||||
required: false,
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
onCreate: {
|
||||
required: false,
|
||||
type: Function,
|
||||
default: undefined,
|
||||
},
|
||||
disabledProp: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'disabled',
|
||||
},
|
||||
searchStart: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
reverse: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
regex: {
|
||||
type: [Object, String, RegExp],
|
||||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
rtl: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
infinite: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
aria: {
|
||||
required: false,
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
clearOnBlur: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
locale: {
|
||||
required: false,
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
fallbackLocale: {
|
||||
required: false,
|
||||
type: String,
|
||||
default: 'en',
|
||||
},
|
||||
searchFilter: {
|
||||
required: false,
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
allowAbsent: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
appendToBody: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
closeOnScroll: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
breakTags: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
appendTo: {
|
||||
required: false,
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
setup(props, context)
|
||||
{
|
||||
return resolveDeps(props, context, [
|
||||
useRefs,
|
||||
useI18n,
|
||||
useValue,
|
||||
usePointer,
|
||||
useDropdown,
|
||||
useSearch,
|
||||
useData,
|
||||
useMultiselect,
|
||||
useOptions,
|
||||
useScroll,
|
||||
usePointerAction,
|
||||
useKeyboard,
|
||||
useClasses,
|
||||
useA11y,
|
||||
])
|
||||
},
|
||||
beforeMount() {
|
||||
if ((this.$root.constructor && this.$root.constructor.version && this.$root.constructor.version.match(/^2\./)) || this.vueVersionMs === 2) {
|
||||
if (!this.$options.components.Teleport) {
|
||||
this.$options.components.Teleport = {
|
||||
render() {
|
||||
return this.$slots.default ? this.$slots.default[0] : null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
127
client/node_modules/@vueform/multiselect/src/composables/useA11y.js
generated
vendored
Normal file
127
client/node_modules/@vueform/multiselect/src/composables/useA11y.js
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
import { toRefs, onMounted, ref, computed } from 'vue'
|
||||
import toRef from './../utils/toRef'
|
||||
|
||||
export default function useA11y (props, context, dep)
|
||||
{
|
||||
const {
|
||||
placeholder, id, valueProp, label: labelProp, mode, groupLabel, aria, searchable ,
|
||||
} = toRefs(props)
|
||||
|
||||
// ============ DEPENDENCIES ============
|
||||
|
||||
const pointer = dep.pointer
|
||||
const iv = dep.iv
|
||||
const hasSelected = dep.hasSelected
|
||||
const multipleLabelText = dep.multipleLabelText
|
||||
|
||||
// ================ DATA ================
|
||||
|
||||
const label = ref(null)
|
||||
|
||||
// ============== COMPUTED ==============
|
||||
|
||||
const ariaAssist = toRef(() => (
|
||||
`${id.value ? id.value + '-' : ''}assist`
|
||||
))
|
||||
|
||||
const ariaControls = toRef(() => (
|
||||
`${id.value ? id.value + '-' : ''}multiselect-options`
|
||||
))
|
||||
|
||||
const ariaActiveDescendant = toRef(() => {
|
||||
if (pointer.value) {
|
||||
let texts = id.value
|
||||
? `${id.value}-`
|
||||
: '';
|
||||
|
||||
texts += `${pointer.value.group ? 'multiselect-group' : 'multiselect-option'}-`
|
||||
|
||||
texts += pointer.value.group ? pointer.value.index : pointer.value[valueProp.value]
|
||||
|
||||
return texts
|
||||
}
|
||||
})
|
||||
|
||||
const ariaPlaceholder = toRef(() => {
|
||||
return placeholder.value
|
||||
})
|
||||
|
||||
const ariaMultiselectable = toRef(() => {
|
||||
return mode.value !== 'single'
|
||||
})
|
||||
|
||||
const ariaLabel = computed(() => {
|
||||
if (mode.value === 'single' && hasSelected.value) {
|
||||
return iv.value[labelProp.value]
|
||||
}
|
||||
|
||||
if (mode.value === 'multiple' && hasSelected.value) {
|
||||
return multipleLabelText.value
|
||||
}
|
||||
|
||||
if (mode.value === 'tags' && hasSelected.value) {
|
||||
return iv.value.map(v => v[labelProp.value]).join(', ')
|
||||
}
|
||||
|
||||
return ''
|
||||
})
|
||||
|
||||
const arias = computed(() => {
|
||||
let arias = { ...aria.value }
|
||||
|
||||
// Need to add manually because focusing
|
||||
// the input won't read the selected value
|
||||
if (searchable.value) {
|
||||
arias['aria-labelledby'] = arias['aria-labelledby']
|
||||
? `${ariaAssist.value} ${arias['aria-labelledby']}`
|
||||
: ariaAssist.value
|
||||
|
||||
if (ariaLabel.value && arias['aria-label']) {
|
||||
arias['aria-label'] = `${ariaLabel.value}, ${arias['aria-label']}`
|
||||
}
|
||||
}
|
||||
|
||||
return arias
|
||||
})
|
||||
|
||||
// =============== METHODS ==============
|
||||
|
||||
const ariaOptionId = (option) => (
|
||||
`${id.value ? id.value + '-' : ''}multiselect-option-${option[valueProp.value]}`
|
||||
)
|
||||
|
||||
const ariaGroupId = (option) => (
|
||||
`${id.value ? id.value + '-' : ''}multiselect-group-${option.index}`
|
||||
)
|
||||
|
||||
const ariaOptionLabel = (label) => `${label}`
|
||||
|
||||
const ariaGroupLabel = (label) => `${label}`
|
||||
|
||||
const ariaTagLabel = (label) => `${label} ❎`
|
||||
|
||||
// =============== HOOKS ================
|
||||
|
||||
onMounted(() => {
|
||||
/* istanbul ignore next */
|
||||
if (id.value && document && document.querySelector) {
|
||||
let forTag = document.querySelector(`[for="${id.value}"]`)
|
||||
label.value = forTag ? forTag.innerText : null
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
arias,
|
||||
ariaLabel,
|
||||
ariaAssist,
|
||||
ariaControls,
|
||||
ariaPlaceholder,
|
||||
ariaMultiselectable,
|
||||
ariaActiveDescendant,
|
||||
ariaOptionId,
|
||||
ariaOptionLabel,
|
||||
ariaGroupId,
|
||||
ariaGroupLabel,
|
||||
ariaTagLabel,
|
||||
}
|
||||
}
|
||||
165
client/node_modules/@vueform/multiselect/src/composables/useClasses.js
generated
vendored
Normal file
165
client/node_modules/@vueform/multiselect/src/composables/useClasses.js
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
import { computed, toRefs } from 'vue'
|
||||
import toRef from './../utils/toRef'
|
||||
|
||||
export default function useClasses (props, context, dependencies)
|
||||
{const {
|
||||
classes: classes_, disabled, showOptions, breakTags
|
||||
} = toRefs(props)
|
||||
|
||||
// ============ DEPENDENCIES ============
|
||||
|
||||
const isOpen = dependencies.isOpen
|
||||
const isPointed = dependencies.isPointed
|
||||
const isSelected = dependencies.isSelected
|
||||
const isDisabled = dependencies.isDisabled
|
||||
const isActive = dependencies.isActive
|
||||
const canPointGroups = dependencies.canPointGroups
|
||||
const resolving = dependencies.resolving
|
||||
const fo = dependencies.fo
|
||||
const placement = dependencies.placement
|
||||
|
||||
// ============== COMPUTED ==============
|
||||
|
||||
const classes = toRef(() => ({
|
||||
container: 'multiselect',
|
||||
containerDisabled: 'is-disabled',
|
||||
containerOpen: 'is-open',
|
||||
containerOpenTop: 'is-open-top',
|
||||
containerActive: 'is-active',
|
||||
wrapper: 'multiselect-wrapper',
|
||||
singleLabel: 'multiselect-single-label',
|
||||
singleLabelText: 'multiselect-single-label-text',
|
||||
multipleLabel: 'multiselect-multiple-label',
|
||||
search: 'multiselect-search',
|
||||
tags: 'multiselect-tags',
|
||||
tag: 'multiselect-tag',
|
||||
tagWrapper: 'multiselect-tag-wrapper',
|
||||
tagWrapperBreak: 'multiselect-tag-wrapper-break',
|
||||
tagDisabled: 'is-disabled',
|
||||
tagRemove: 'multiselect-tag-remove',
|
||||
tagRemoveIcon: 'multiselect-tag-remove-icon',
|
||||
tagsSearchWrapper: 'multiselect-tags-search-wrapper',
|
||||
tagsSearch: 'multiselect-tags-search',
|
||||
tagsSearchCopy: 'multiselect-tags-search-copy',
|
||||
placeholder: 'multiselect-placeholder',
|
||||
caret: 'multiselect-caret',
|
||||
caretOpen: 'is-open',
|
||||
clear: 'multiselect-clear',
|
||||
clearIcon: 'multiselect-clear-icon',
|
||||
spinner: 'multiselect-spinner',
|
||||
inifinite: 'multiselect-inifite',
|
||||
inifiniteSpinner: 'multiselect-inifite-spinner',
|
||||
dropdown: 'multiselect-dropdown',
|
||||
dropdownTop: 'is-top',
|
||||
dropdownHidden: 'is-hidden',
|
||||
options: 'multiselect-options',
|
||||
optionsTop: 'is-top',
|
||||
group: 'multiselect-group',
|
||||
groupLabel: 'multiselect-group-label',
|
||||
groupLabelPointable: 'is-pointable',
|
||||
groupLabelPointed: 'is-pointed',
|
||||
groupLabelSelected: 'is-selected',
|
||||
groupLabelDisabled: 'is-disabled',
|
||||
groupLabelSelectedPointed: 'is-selected is-pointed',
|
||||
groupLabelSelectedDisabled: 'is-selected is-disabled',
|
||||
groupOptions: 'multiselect-group-options',
|
||||
option: 'multiselect-option',
|
||||
optionPointed: 'is-pointed',
|
||||
optionSelected: 'is-selected',
|
||||
optionDisabled: 'is-disabled',
|
||||
optionSelectedPointed: 'is-selected is-pointed',
|
||||
optionSelectedDisabled: 'is-selected is-disabled',
|
||||
noOptions: 'multiselect-no-options',
|
||||
noResults: 'multiselect-no-results',
|
||||
fakeInput: 'multiselect-fake-input',
|
||||
assist: 'multiselect-assistive-text',
|
||||
spacer: 'multiselect-spacer',
|
||||
...classes_.value,
|
||||
}))
|
||||
|
||||
const showDropdown = toRef(() => {
|
||||
return !!(isOpen.value && showOptions.value && (!resolving.value || (resolving.value && fo.value.length)))
|
||||
})
|
||||
|
||||
const classList = computed(() => {
|
||||
const c = classes.value
|
||||
|
||||
return {
|
||||
container: [c.container]
|
||||
.concat(disabled.value ? c.containerDisabled : [])
|
||||
.concat(showDropdown.value && placement.value === 'top' ? c.containerOpenTop : [])
|
||||
.concat(showDropdown.value && placement.value !== 'top' ? c.containerOpen : [])
|
||||
.concat(isActive.value ? c.containerActive : []),
|
||||
wrapper: c.wrapper,
|
||||
spacer: c.spacer,
|
||||
singleLabel: c.singleLabel,
|
||||
singleLabelText: c.singleLabelText,
|
||||
multipleLabel: c.multipleLabel,
|
||||
search: c.search,
|
||||
tags: c.tags,
|
||||
tag: [c.tag]
|
||||
.concat(disabled.value ? c.tagDisabled : []),
|
||||
tagWrapper: [c.tagWrapper, breakTags.value ? c.tagWrapperBreak : null],
|
||||
tagDisabled: c.tagDisabled,
|
||||
tagRemove: c.tagRemove,
|
||||
tagRemoveIcon: c.tagRemoveIcon,
|
||||
tagsSearchWrapper: c.tagsSearchWrapper,
|
||||
tagsSearch: c.tagsSearch,
|
||||
tagsSearchCopy: c.tagsSearchCopy,
|
||||
placeholder: c.placeholder,
|
||||
caret: [c.caret]
|
||||
.concat(isOpen.value ? c.caretOpen : []),
|
||||
clear: c.clear,
|
||||
clearIcon: c.clearIcon,
|
||||
spinner: c.spinner,
|
||||
inifinite: c.inifinite,
|
||||
inifiniteSpinner: c.inifiniteSpinner,
|
||||
dropdown: [c.dropdown]
|
||||
.concat(placement.value === 'top' ? c.dropdownTop : [])
|
||||
.concat(!isOpen.value || !showOptions.value || !showDropdown.value ? c.dropdownHidden : []),
|
||||
options: [c.options]
|
||||
.concat(placement.value === 'top' ? c.optionsTop : []),
|
||||
group: c.group,
|
||||
groupLabel: (g) => {
|
||||
let groupLabel = [c.groupLabel]
|
||||
|
||||
if (isPointed(g)) {
|
||||
groupLabel.push(isSelected(g) ? c.groupLabelSelectedPointed : c.groupLabelPointed)
|
||||
} else if (isSelected(g) && canPointGroups.value) {
|
||||
groupLabel.push(isDisabled(g) ? c.groupLabelSelectedDisabled : c.groupLabelSelected)
|
||||
} else if (isDisabled(g)) {
|
||||
groupLabel.push(c.groupLabelDisabled)
|
||||
}
|
||||
|
||||
if (canPointGroups.value) {
|
||||
groupLabel.push(c.groupLabelPointable)
|
||||
}
|
||||
|
||||
return groupLabel
|
||||
},
|
||||
groupOptions: c.groupOptions,
|
||||
option: (o, g) => {
|
||||
let option = [c.option]
|
||||
|
||||
if (isPointed(o)) {
|
||||
option.push(isSelected(o) ? c.optionSelectedPointed : c.optionPointed)
|
||||
} else if (isSelected(o)) {
|
||||
option.push(isDisabled(o) ? c.optionSelectedDisabled : c.optionSelected)
|
||||
} else if (isDisabled(o) || (g && isDisabled(g))) {
|
||||
option.push(c.optionDisabled)
|
||||
}
|
||||
|
||||
return option
|
||||
},
|
||||
noOptions: c.noOptions,
|
||||
noResults: c.noResults,
|
||||
assist: c.assist,
|
||||
fakeInput: c.fakeInput,
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
classList,
|
||||
showDropdown,
|
||||
}
|
||||
}
|
||||
62
client/node_modules/@vueform/multiselect/src/composables/useData.js
generated
vendored
Normal file
62
client/node_modules/@vueform/multiselect/src/composables/useData.js
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
import { toRefs, getCurrentInstance } from 'vue'
|
||||
import isNullish from './../utils/isNullish'
|
||||
|
||||
export default function useData (props, context, dep)
|
||||
{
|
||||
const { object, valueProp, mode } = toRefs(props)
|
||||
|
||||
const $this = getCurrentInstance().proxy
|
||||
|
||||
// ============ DEPENDENCIES ============
|
||||
|
||||
const iv = dep.iv
|
||||
|
||||
// =============== METHODS ==============
|
||||
|
||||
const update = (val, triggerInput = true) => {
|
||||
// Setting object(s) as internal value
|
||||
iv.value = makeInternal(val)
|
||||
|
||||
// Setting object(s) or plain value as external
|
||||
// value based on `option` setting
|
||||
const externalVal = makeExternal(val)
|
||||
|
||||
context.emit('change', externalVal, $this)
|
||||
|
||||
if (triggerInput) {
|
||||
context.emit('input', externalVal)
|
||||
context.emit('update:modelValue', externalVal)
|
||||
}
|
||||
}
|
||||
|
||||
// no export
|
||||
const makeExternal = (val) => {
|
||||
// If external value should be object
|
||||
// no transformation is required
|
||||
if (object.value) {
|
||||
return val
|
||||
}
|
||||
|
||||
// No need to transform if empty value
|
||||
if (isNullish(val)) {
|
||||
return val
|
||||
}
|
||||
|
||||
// If external should be plain transform
|
||||
// value object to plain values
|
||||
return !Array.isArray(val) ? val[valueProp.value] : val.map(v => v[valueProp.value])
|
||||
}
|
||||
|
||||
// no export
|
||||
const makeInternal = (val) => {
|
||||
if (isNullish(val)) {
|
||||
return mode.value === 'single' ? {} : []
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
return {
|
||||
update,
|
||||
}
|
||||
}
|
||||
158
client/node_modules/@vueform/multiselect/src/composables/useDropdown.js
generated
vendored
Normal file
158
client/node_modules/@vueform/multiselect/src/composables/useDropdown.js
generated
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
import { ref, toRefs, getCurrentInstance, onMounted, onBeforeUnmount, nextTick } from 'vue'
|
||||
import { createPopper } from '@popperjs/core/lib/popper-lite'
|
||||
import preventOverflow from '@popperjs/core/lib/modifiers/preventOverflow'
|
||||
import flip from '@popperjs/core/lib/modifiers/flip'
|
||||
import toRef from './../utils/toRef'
|
||||
|
||||
export default function useDropdown (props, context, dep)
|
||||
{
|
||||
const { disabled, appendTo, appendToBody, openDirection } = toRefs(props)
|
||||
|
||||
const $this = getCurrentInstance().proxy
|
||||
|
||||
// ============ DEPENDENCIES ============
|
||||
|
||||
const multiselect = dep.multiselect
|
||||
const dropdown = dep.dropdown
|
||||
|
||||
// ================ DATA ================
|
||||
|
||||
const isOpen = ref(false)
|
||||
const popper = ref(null)
|
||||
const forcedPlacement = ref(null)
|
||||
|
||||
// ============== COMPUTED ==============
|
||||
|
||||
const appended = toRef(() => {
|
||||
return appendTo.value || appendToBody.value
|
||||
})
|
||||
|
||||
const placement = toRef(() => {
|
||||
return (openDirection.value === 'top' && forcedPlacement.value === 'bottom') ||
|
||||
(openDirection.value === 'bottom' && forcedPlacement.value !== 'top')
|
||||
? 'bottom'
|
||||
: 'top'
|
||||
})
|
||||
|
||||
// =============== METHODS ==============
|
||||
|
||||
const open = () => {
|
||||
if (isOpen.value || disabled.value) {
|
||||
return
|
||||
}
|
||||
|
||||
isOpen.value = true
|
||||
context.emit('open', $this)
|
||||
|
||||
|
||||
if (appended.value) {
|
||||
nextTick(() => {
|
||||
updatePopper()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
if (!isOpen.value) {
|
||||
return
|
||||
}
|
||||
|
||||
isOpen.value = false
|
||||
context.emit('close', $this)
|
||||
}
|
||||
|
||||
const updatePopper = () => {
|
||||
if (!popper.value) {
|
||||
return
|
||||
}
|
||||
|
||||
let borderTopWidth = parseInt(window.getComputedStyle(dropdown.value).borderTopWidth.replace('px', ''))
|
||||
let borderBottomWidth = parseInt(window.getComputedStyle(dropdown.value).borderBottomWidth.replace('px', ''))
|
||||
|
||||
popper.value.setOptions((options) => ({
|
||||
...options,
|
||||
modifiers: [
|
||||
...options.modifiers,
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [0, (placement.value === 'top' ? borderTopWidth : borderBottomWidth) * -1],
|
||||
},
|
||||
},
|
||||
]
|
||||
}))
|
||||
|
||||
popper.value.update()
|
||||
}
|
||||
|
||||
/* istanbul ignore next: UI feature */
|
||||
const hasFixedParent = (element) => {
|
||||
while (element && element !== document.body) {
|
||||
const style = getComputedStyle(element)
|
||||
|
||||
if (style.position === 'fixed') {
|
||||
return true
|
||||
}
|
||||
|
||||
element = element.parentElement
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!appended.value) {
|
||||
return
|
||||
}
|
||||
|
||||
/* istanbul ignore next: popper mock */
|
||||
popper.value = createPopper(multiselect.value, dropdown.value, {
|
||||
strategy: hasFixedParent(multiselect.value) ? /* istanbul ignore next: UI feature */ 'fixed' : undefined,
|
||||
placement: openDirection.value,
|
||||
modifiers: [
|
||||
preventOverflow,
|
||||
flip,
|
||||
{
|
||||
name: 'sameWidth',
|
||||
enabled: true,
|
||||
phase: 'beforeWrite',
|
||||
requires: ['computeStyles'],
|
||||
fn: ({ state }) => {
|
||||
state.styles.popper.width = `${state.rects.reference.width}px`
|
||||
},
|
||||
effect: ({ state }) => {
|
||||
state.elements.popper.style.width = `${
|
||||
state.elements.reference.offsetWidth
|
||||
}px`
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'toggleClass',
|
||||
enabled: true,
|
||||
phase: 'write',
|
||||
fn({ state }) {
|
||||
forcedPlacement.value = state.placement
|
||||
},
|
||||
},
|
||||
]
|
||||
})
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (!appended.value || !popper.value) {
|
||||
return
|
||||
}
|
||||
|
||||
popper.value.destroy()
|
||||
popper.value = null
|
||||
})
|
||||
|
||||
return {
|
||||
popper,
|
||||
isOpen,
|
||||
open,
|
||||
close,
|
||||
placement,
|
||||
updatePopper,
|
||||
}
|
||||
}
|
||||
34
client/node_modules/@vueform/multiselect/src/composables/useI18n.js
generated
vendored
Normal file
34
client/node_modules/@vueform/multiselect/src/composables/useI18n.js
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
import { toRefs } from 'vue'
|
||||
|
||||
export default function useI18n (props, context, dep)
|
||||
{
|
||||
const {
|
||||
locale, fallbackLocale,
|
||||
} = toRefs(props)
|
||||
|
||||
// =============== METHODS ==============
|
||||
|
||||
const localize = (target) => {
|
||||
if (!target || typeof target !== 'object') {
|
||||
return target
|
||||
}
|
||||
|
||||
if (target && target[locale.value]) {
|
||||
return target[locale.value]
|
||||
} else if (target && locale.value && target[locale.value.toUpperCase()]) {
|
||||
return target[locale.value.toUpperCase()]
|
||||
} else if (target && target[fallbackLocale.value]) {
|
||||
return target[fallbackLocale.value]
|
||||
} else if (target && fallbackLocale.value && target[fallbackLocale.value.toUpperCase()]) {
|
||||
return target[fallbackLocale.value.toUpperCase()]
|
||||
} else if (target && Object.keys(target)[0]) {
|
||||
return target[Object.keys(target)[0]]
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
localize,
|
||||
}
|
||||
}
|
||||
247
client/node_modules/@vueform/multiselect/src/composables/useKeyboard.js
generated
vendored
Normal file
247
client/node_modules/@vueform/multiselect/src/composables/useKeyboard.js
generated
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
import { toRefs, getCurrentInstance } from 'vue'
|
||||
import toRef from './../utils/toRef'
|
||||
|
||||
export default function useKeyboard (props, context, dep)
|
||||
{
|
||||
const {
|
||||
mode, addTagOn, openDirection, searchable,
|
||||
showOptions, valueProp, groups: groupped,
|
||||
addOptionOn: addOptionOn_, createTag, createOption: createOption_,
|
||||
reverse,
|
||||
} = toRefs(props)
|
||||
|
||||
const $this = getCurrentInstance().proxy
|
||||
|
||||
// ============ DEPENDENCIES ============
|
||||
|
||||
const iv = dep.iv
|
||||
const update = dep.update
|
||||
const deselect = dep.deselect
|
||||
const search = dep.search
|
||||
const setPointer = dep.setPointer
|
||||
const selectPointer = dep.selectPointer
|
||||
const backwardPointer = dep.backwardPointer
|
||||
const forwardPointer = dep.forwardPointer
|
||||
const multiselect = dep.multiselect
|
||||
const wrapper = dep.wrapper
|
||||
const tags = dep.tags
|
||||
const isOpen = dep.isOpen
|
||||
const open = dep.open
|
||||
const blur = dep.blur
|
||||
const fo = dep.fo
|
||||
|
||||
// ============== COMPUTED ==============
|
||||
|
||||
// no export
|
||||
const createOption = toRef(() => {
|
||||
return createTag.value || createOption_.value || false
|
||||
})
|
||||
|
||||
// no export
|
||||
const addOptionOn = toRef(() => {
|
||||
if (addTagOn.value !== undefined) {
|
||||
return addTagOn.value
|
||||
}
|
||||
else if (addOptionOn_.value !== undefined) {
|
||||
return addOptionOn_.value
|
||||
}
|
||||
|
||||
return ['enter']
|
||||
})
|
||||
|
||||
// =============== METHODS ==============
|
||||
|
||||
// no export
|
||||
const preparePointer = () => {
|
||||
// When options are hidden and creating tags is allowed
|
||||
// no pointer will be set (because options are hidden).
|
||||
// In such case we need to set the pointer manually to the
|
||||
// first option, which equals to the option created from
|
||||
// the search value.
|
||||
if (mode.value === 'tags' && !showOptions.value && createOption.value && searchable.value && !groupped.value) {
|
||||
setPointer(fo.value[fo.value.map(o => o[valueProp.value]).indexOf(search.value)])
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeydown = (e) => {
|
||||
context.emit('keydown', e, $this)
|
||||
|
||||
let tagList
|
||||
let activeIndex
|
||||
|
||||
if (['ArrowLeft', 'ArrowRight', 'Enter'].indexOf(e.key) !== -1 && mode.value === 'tags') {
|
||||
tagList = [...(multiselect.value.querySelectorAll(`[data-tags] > *`))].filter(e => e !== tags.value)
|
||||
activeIndex = tagList.findIndex(e => e === document.activeElement)
|
||||
}
|
||||
|
||||
switch (e.key) {
|
||||
case 'Backspace':
|
||||
if (mode.value === 'single') {
|
||||
return
|
||||
}
|
||||
|
||||
if (searchable.value && [null, ''].indexOf(search.value) === -1) {
|
||||
return
|
||||
}
|
||||
|
||||
if (iv.value.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
let deselectables = iv.value.filter(v=>!v.disabled && v.remove !== false)
|
||||
|
||||
if (deselectables.length) {
|
||||
deselect(deselectables[deselectables.length - 1])
|
||||
}
|
||||
break
|
||||
|
||||
case 'Enter':
|
||||
e.preventDefault()
|
||||
|
||||
if (e.keyCode === 229) {
|
||||
// ignore IME confirmation
|
||||
return
|
||||
}
|
||||
|
||||
if (activeIndex !== -1 && activeIndex !== undefined) {
|
||||
update([...iv.value].filter((v, k) => k !== activeIndex))
|
||||
|
||||
if (activeIndex === tagList.length - 1) {
|
||||
if (tagList.length - 1) {
|
||||
tagList[tagList.length - 2].focus()
|
||||
} else if (searchable.value) {
|
||||
tags.value.querySelector('input').focus()
|
||||
} else {
|
||||
wrapper.value.focus()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (addOptionOn.value.indexOf('enter') === -1 && createOption.value) {
|
||||
return
|
||||
}
|
||||
|
||||
preparePointer()
|
||||
selectPointer()
|
||||
break
|
||||
|
||||
case ' ':
|
||||
if (!createOption.value && !searchable.value) {
|
||||
e.preventDefault()
|
||||
|
||||
preparePointer()
|
||||
selectPointer()
|
||||
return
|
||||
}
|
||||
|
||||
if (!createOption.value) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (addOptionOn.value.indexOf('space') === -1 && createOption.value) {
|
||||
return
|
||||
}
|
||||
|
||||
e.preventDefault()
|
||||
|
||||
preparePointer()
|
||||
selectPointer()
|
||||
break
|
||||
|
||||
case 'Tab':
|
||||
case ';':
|
||||
case ',':
|
||||
if (addOptionOn.value.indexOf(e.key.toLowerCase()) === -1 || !createOption.value) {
|
||||
return
|
||||
}
|
||||
|
||||
preparePointer()
|
||||
selectPointer()
|
||||
e.preventDefault()
|
||||
break
|
||||
|
||||
case 'Escape':
|
||||
blur()
|
||||
break
|
||||
|
||||
case 'ArrowUp':
|
||||
e.preventDefault()
|
||||
|
||||
if (!showOptions.value) {
|
||||
return
|
||||
}
|
||||
|
||||
/* istanbul ignore else */
|
||||
if (!isOpen.value) {
|
||||
open()
|
||||
}
|
||||
|
||||
backwardPointer()
|
||||
break
|
||||
|
||||
case 'ArrowDown':
|
||||
e.preventDefault()
|
||||
|
||||
if (!showOptions.value) {
|
||||
return
|
||||
}
|
||||
|
||||
/* istanbul ignore else */
|
||||
if (!isOpen.value) {
|
||||
open()
|
||||
}
|
||||
|
||||
forwardPointer()
|
||||
break
|
||||
|
||||
case 'ArrowLeft':
|
||||
if (
|
||||
(searchable.value && tags.value && tags.value.querySelector('input').selectionStart)
|
||||
|| e.shiftKey || mode.value !== 'tags' || !iv.value || !iv.value.length
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
e.preventDefault()
|
||||
|
||||
if (activeIndex === -1) {
|
||||
tagList[tagList.length-1].focus()
|
||||
}
|
||||
else if (activeIndex > 0) {
|
||||
tagList[activeIndex-1].focus()
|
||||
}
|
||||
break
|
||||
|
||||
case 'ArrowRight':
|
||||
if (activeIndex === -1 || e.shiftKey || mode.value !== 'tags' || !iv.value || !iv.value.length) {
|
||||
return
|
||||
}
|
||||
|
||||
e.preventDefault()
|
||||
|
||||
/* istanbul ignore else */
|
||||
if (tagList.length > activeIndex + 1) {
|
||||
tagList[activeIndex+1].focus()
|
||||
}
|
||||
else if (searchable.value) {
|
||||
tags.value.querySelector('input').focus()
|
||||
}
|
||||
else if (!searchable.value) {
|
||||
wrapper.value.focus()
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyup = (e) => {
|
||||
context.emit('keyup', e, $this)
|
||||
}
|
||||
|
||||
return {
|
||||
handleKeydown,
|
||||
handleKeyup,
|
||||
preparePointer,
|
||||
}
|
||||
}
|
||||
121
client/node_modules/@vueform/multiselect/src/composables/useMultiselect.js
generated
vendored
Normal file
121
client/node_modules/@vueform/multiselect/src/composables/useMultiselect.js
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
import { ref, toRefs } from 'vue'
|
||||
import toRef from './../utils/toRef'
|
||||
|
||||
export default function useMultiselect (props, context, dep)
|
||||
{
|
||||
const { searchable, disabled, clearOnBlur } = toRefs(props)
|
||||
|
||||
// ============ DEPENDENCIES ============
|
||||
|
||||
const input = dep.input
|
||||
const open = dep.open
|
||||
const close = dep.close
|
||||
const clearSearch = dep.clearSearch
|
||||
const isOpen = dep.isOpen
|
||||
const wrapper = dep.wrapper
|
||||
const tags = dep.tags
|
||||
|
||||
// ================ DATA ================
|
||||
|
||||
const isActive = ref(false)
|
||||
|
||||
const mouseClicked = ref(false)
|
||||
|
||||
// ============== COMPUTED ==============
|
||||
|
||||
const tabindex = toRef(() => {
|
||||
return searchable.value || disabled.value ? -1 : 0
|
||||
})
|
||||
|
||||
// =============== METHODS ==============
|
||||
|
||||
const blur = () => {
|
||||
if (searchable.value) {
|
||||
input.value.blur()
|
||||
}
|
||||
|
||||
wrapper.value.blur()
|
||||
}
|
||||
|
||||
const focus = () => {
|
||||
if (searchable.value && !disabled.value) {
|
||||
input.value.focus()
|
||||
}
|
||||
}
|
||||
|
||||
const activate = (shouldOpen = true) => {
|
||||
if (disabled.value) {
|
||||
return
|
||||
}
|
||||
|
||||
isActive.value = true
|
||||
|
||||
if (shouldOpen) {
|
||||
open()
|
||||
}
|
||||
}
|
||||
|
||||
const deactivate = () => {
|
||||
isActive.value = false
|
||||
|
||||
setTimeout(() => {
|
||||
if (!isActive.value) {
|
||||
close()
|
||||
|
||||
if (clearOnBlur.value) {
|
||||
clearSearch()
|
||||
}
|
||||
}
|
||||
}, 1)
|
||||
}
|
||||
|
||||
const handleFocusIn = (e) => {
|
||||
if ((e.target.closest('[data-tags]') && e.target.nodeName !== 'INPUT') || e.target.closest('[data-clear]')) {
|
||||
return
|
||||
}
|
||||
|
||||
activate(mouseClicked.value)
|
||||
}
|
||||
|
||||
const handleFocusOut = () => {
|
||||
deactivate()
|
||||
}
|
||||
|
||||
const handleCaretClick = () => {
|
||||
deactivate()
|
||||
blur()
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
const handleMousedown = (e) => {
|
||||
mouseClicked.value = true
|
||||
|
||||
if (isOpen.value && (e.target.isEqualNode(wrapper.value) || e.target.isEqualNode(tags.value))) {
|
||||
setTimeout(() => {
|
||||
deactivate()
|
||||
}, 0)
|
||||
} else if (!isOpen.value
|
||||
&& (document.activeElement.isEqualNode(wrapper.value)
|
||||
|| document.activeElement.isEqualNode(input.value))) {
|
||||
activate()
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
mouseClicked.value = false
|
||||
}, 0)
|
||||
}
|
||||
|
||||
return {
|
||||
tabindex,
|
||||
isActive,
|
||||
mouseClicked,
|
||||
blur,
|
||||
focus,
|
||||
activate,
|
||||
deactivate,
|
||||
handleFocusIn,
|
||||
handleFocusOut,
|
||||
handleCaretClick,
|
||||
handleMousedown,
|
||||
}
|
||||
}
|
||||
888
client/node_modules/@vueform/multiselect/src/composables/useOptions.js
generated
vendored
Normal file
888
client/node_modules/@vueform/multiselect/src/composables/useOptions.js
generated
vendored
Normal file
@@ -0,0 +1,888 @@
|
||||
import { ref, toRefs, computed, watch, getCurrentInstance } from 'vue'
|
||||
import normalize from './../utils/normalize'
|
||||
import isObject from './../utils/isObject'
|
||||
import isNullish from './../utils/isNullish'
|
||||
import arraysEqual from './../utils/arraysEqual'
|
||||
import objectsEqual from './../utils/objectsEqual'
|
||||
import toRef from './../utils/toRef'
|
||||
|
||||
export default function useOptions (props, context, dep)
|
||||
{
|
||||
const {
|
||||
options, mode, trackBy: trackBy_, limit, hideSelected, createTag, createOption: createOption_, label,
|
||||
appendNewTag, appendNewOption: appendNewOption_, multipleLabel, object, loading, delay, resolveOnLoad,
|
||||
minChars, filterResults, clearOnSearch, clearOnSelect, valueProp, allowAbsent, groupLabel,
|
||||
canDeselect, max, strict, closeOnSelect, closeOnDeselect, groups: groupped, reverse, infinite,
|
||||
groupOptions, groupHideEmpty, groupSelect, onCreate, disabledProp, searchStart, searchFilter,
|
||||
} = toRefs(props)
|
||||
|
||||
const $this = getCurrentInstance().proxy
|
||||
|
||||
// ============ DEPENDENCIES ============
|
||||
|
||||
const iv = dep.iv
|
||||
const ev = dep.ev
|
||||
const search = dep.search
|
||||
const clearSearch = dep.clearSearch
|
||||
const update = dep.update
|
||||
const pointer = dep.pointer
|
||||
const setPointer = dep.setPointer
|
||||
const clearPointer = dep.clearPointer
|
||||
const focus = dep.focus
|
||||
const deactivate = dep.deactivate
|
||||
const close = dep.close
|
||||
const localize = dep.localize
|
||||
|
||||
// ================ DATA ================
|
||||
|
||||
// no export
|
||||
// appendedOptions
|
||||
const ap = ref([])
|
||||
|
||||
// no export
|
||||
// resolvedOptions
|
||||
const ro = ref([])
|
||||
|
||||
const resolving = ref(false)
|
||||
|
||||
// no export
|
||||
const searchWatcher = ref(null)
|
||||
|
||||
const offset = ref(infinite.value && limit.value === -1 ? 10 : limit.value)
|
||||
|
||||
// ============== COMPUTED ==============
|
||||
|
||||
const resolvedOptions = computed({
|
||||
get: () => ro.value,
|
||||
set: (v) => ro.value = v
|
||||
})
|
||||
|
||||
// no export
|
||||
const createOption = toRef(() => {
|
||||
return createTag.value || createOption_.value || false
|
||||
})
|
||||
|
||||
// no export
|
||||
const appendNewOption = toRef(() => {
|
||||
if (appendNewTag.value !== undefined) {
|
||||
return appendNewTag.value
|
||||
} else if (appendNewOption_.value !== undefined) {
|
||||
return appendNewOption_.value
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
// no export
|
||||
// extendedOptions
|
||||
const eo = computed(() => {
|
||||
if (groupped.value) {
|
||||
let groups = eg.value || /* istanbul ignore next */ []
|
||||
|
||||
let eo = []
|
||||
|
||||
groups.forEach((group) => {
|
||||
optionsToArray(group[groupOptions.value]).forEach((option) => {
|
||||
eo.push(Object.assign({}, option, group[disabledProp.value] ? { [disabledProp.value]: true } : {}))
|
||||
})
|
||||
})
|
||||
|
||||
return eo
|
||||
} else {
|
||||
let eo = optionsToArray(ro.value || /* istanbul ignore next */ [])
|
||||
|
||||
if (ap.value.length) {
|
||||
eo = eo.concat(ap.value)
|
||||
}
|
||||
|
||||
return eo
|
||||
}
|
||||
})
|
||||
|
||||
// preFilteredOptions
|
||||
const pfo = computed(() => {
|
||||
let options = eo.value
|
||||
|
||||
if (reverse.value) {
|
||||
options = options.reverse()
|
||||
}
|
||||
|
||||
if (createdOption.value.length) {
|
||||
options = createdOption.value.concat(options)
|
||||
}
|
||||
|
||||
return filterOptions(options)
|
||||
})
|
||||
|
||||
// filteredOptions
|
||||
const fo = computed(() => {
|
||||
let options = pfo.value
|
||||
|
||||
if (offset.value > 0) {
|
||||
options = options.slice(0, offset.value)
|
||||
}
|
||||
|
||||
return options
|
||||
})
|
||||
|
||||
// no export
|
||||
// extendedGroups
|
||||
const eg = computed(() => {
|
||||
if (!groupped.value) {
|
||||
return []
|
||||
}
|
||||
|
||||
let eg = []
|
||||
let groups = ro.value || /* istanbul ignore next */ []
|
||||
|
||||
if (ap.value.length) {
|
||||
eg.push({
|
||||
[groupLabel.value]: ' ',
|
||||
[groupOptions.value]: [...ap.value],
|
||||
__CREATE__: true
|
||||
})
|
||||
}
|
||||
|
||||
return eg.concat(groups)
|
||||
})
|
||||
|
||||
// preFilteredGroups
|
||||
const pfg = computed(() => {
|
||||
let groups = [...eg.value].map(g => ({...g}))
|
||||
|
||||
if (createdOption.value.length) {
|
||||
if (groups[0] && groups[0].__CREATE__) {
|
||||
groups[0][groupOptions.value] = [...createdOption.value, ...groups[0][groupOptions.value]]
|
||||
} else {
|
||||
groups = [{
|
||||
[groupLabel.value]: ' ',
|
||||
[groupOptions.value]: [...createdOption.value],
|
||||
__CREATE__: true
|
||||
}].concat(groups)
|
||||
}
|
||||
}
|
||||
|
||||
return groups
|
||||
})
|
||||
|
||||
// filteredGroups
|
||||
const fg = computed(() => {
|
||||
if (!groupped.value) {
|
||||
return []
|
||||
}
|
||||
|
||||
let options = pfg.value
|
||||
|
||||
return filterGroups((options || /* istanbul ignore next */ []).map((group, index) => {
|
||||
const arrayOptions = optionsToArray(group[groupOptions.value])
|
||||
|
||||
return {
|
||||
...group,
|
||||
index,
|
||||
group: true,
|
||||
[groupOptions.value]: filterOptions(arrayOptions, false).map(o => Object.assign({}, o, group[disabledProp.value] ? { [disabledProp.value]: true } : {})),
|
||||
__VISIBLE__: filterOptions(arrayOptions).map(o => Object.assign({}, o, group[disabledProp.value] ? { [disabledProp.value]: true } : {})),
|
||||
}
|
||||
// Difference between __VISIBLE__ and {groupOptions}: visible does not contain selected options when hideSelected=true
|
||||
}))
|
||||
})
|
||||
|
||||
const hasSelected = computed(() => {
|
||||
switch (mode.value) {
|
||||
case 'single':
|
||||
return !isNullish(iv.value[valueProp.value])
|
||||
|
||||
case 'multiple':
|
||||
case 'tags':
|
||||
return !isNullish(iv.value) && iv.value.length > 0
|
||||
}
|
||||
})
|
||||
|
||||
const multipleLabelText = computed(() => {
|
||||
return multipleLabel.value !== undefined
|
||||
? multipleLabel.value(iv.value, $this)
|
||||
: (iv.value && iv.value.length > 1 ? `${iv.value.length} options selected` : `1 option selected`)
|
||||
})
|
||||
|
||||
const noOptions = toRef(() => {
|
||||
return !eo.value.length && !resolving.value && !createdOption.value.length
|
||||
})
|
||||
|
||||
|
||||
const noResults = toRef(() => {
|
||||
return eo.value.length > 0 && fo.value.length == 0 && ((search.value && groupped.value) || !groupped.value)
|
||||
})
|
||||
|
||||
// no export
|
||||
const createdOption = computed(() => {
|
||||
if (createOption.value === false || !search.value) {
|
||||
return []
|
||||
}
|
||||
|
||||
if (getOptionByTrackBy(search.value) !== -1) {
|
||||
return []
|
||||
}
|
||||
|
||||
return [{
|
||||
[valueProp.value]: search.value,
|
||||
[trackBy.value[0]]: search.value,
|
||||
[label.value]: search.value,
|
||||
__CREATE__: true,
|
||||
}]
|
||||
})
|
||||
|
||||
const trackBy = computed(() => {
|
||||
return trackBy_.value ? (Array.isArray(trackBy_.value) ? trackBy_.value : [trackBy_.value]) : [label.value]
|
||||
})
|
||||
|
||||
// no export
|
||||
const nullValue = toRef(() => {
|
||||
switch (mode.value) {
|
||||
case 'single':
|
||||
return null
|
||||
|
||||
case 'multiple':
|
||||
case 'tags':
|
||||
return []
|
||||
}
|
||||
})
|
||||
|
||||
const busy = toRef(() => {
|
||||
return loading.value || resolving.value
|
||||
})
|
||||
|
||||
// =============== METHODS ==============
|
||||
|
||||
/**
|
||||
* @param {array|object|string|number} option
|
||||
*/
|
||||
const select = (option) => {
|
||||
if (typeof option !== 'object') {
|
||||
option = getOption(option)
|
||||
}
|
||||
|
||||
switch (mode.value) {
|
||||
case 'single':
|
||||
update(option)
|
||||
break
|
||||
|
||||
case 'multiple':
|
||||
case 'tags':
|
||||
update((iv.value).concat(option))
|
||||
break
|
||||
}
|
||||
|
||||
context.emit('select', finalValue(option), option, $this)
|
||||
}
|
||||
|
||||
const deselect = (option) => {
|
||||
if (typeof option !== 'object') {
|
||||
option = getOption(option)
|
||||
}
|
||||
|
||||
switch (mode.value) {
|
||||
case 'single':
|
||||
clear()
|
||||
break
|
||||
|
||||
case 'tags':
|
||||
case 'multiple':
|
||||
update(Array.isArray(option)
|
||||
? iv.value.filter(v => option.map(o => o[valueProp.value]).indexOf(v[valueProp.value]) === -1)
|
||||
: iv.value.filter(v => v[valueProp.value] != option[valueProp.value]))
|
||||
break
|
||||
}
|
||||
|
||||
context.emit('deselect', finalValue(option), option, $this)
|
||||
}
|
||||
|
||||
// no export
|
||||
const finalValue = (option) => {
|
||||
return object.value ? option : option[valueProp.value]
|
||||
}
|
||||
|
||||
const remove = (option) => {
|
||||
deselect(option)
|
||||
}
|
||||
|
||||
const handleTagRemove = (option, e) => {
|
||||
if (e.button !== 0) {
|
||||
e.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
remove(option)
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
update(nullValue.value)
|
||||
context.emit('clear', $this)
|
||||
}
|
||||
|
||||
const isSelected = (option) => {
|
||||
if (option.group !== undefined) {
|
||||
return mode.value === 'single' ? false : areAllSelected(option[groupOptions.value]) && option[groupOptions.value].length
|
||||
}
|
||||
|
||||
switch (mode.value) {
|
||||
case 'single':
|
||||
return !isNullish(iv.value) && (
|
||||
iv.value[valueProp.value] == option[valueProp.value] ||
|
||||
(typeof iv.value[valueProp.value] === 'object' && typeof option[valueProp.value] === 'object' && objectsEqual(iv.value[valueProp.value], option[valueProp.value]))
|
||||
)
|
||||
|
||||
case 'tags':
|
||||
case 'multiple':
|
||||
return !isNullish(iv.value) && iv.value.map(o => o[valueProp.value]).indexOf(option[valueProp.value]) !== -1
|
||||
}
|
||||
}
|
||||
|
||||
const isDisabled = (option) => {
|
||||
return option[disabledProp.value] === true
|
||||
}
|
||||
|
||||
const isMax = () => {
|
||||
if (max === undefined || max.value === -1 || (!hasSelected.value && max.value > 0)) {
|
||||
return false
|
||||
}
|
||||
|
||||
return iv.value.length >= max.value
|
||||
}
|
||||
|
||||
const handleOptionClick = (option) => {
|
||||
if (isDisabled(option)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (onCreate.value && !isSelected(option) && option.__CREATE__) {
|
||||
option = { ...option }
|
||||
delete option.__CREATE__
|
||||
|
||||
option = onCreate.value(option, $this)
|
||||
|
||||
if (option instanceof Promise) {
|
||||
resolving.value = true
|
||||
option.then((result) => {
|
||||
resolving.value = false
|
||||
handleOptionSelect(result)
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
handleOptionSelect(option)
|
||||
}
|
||||
|
||||
const handleOptionSelect = (option) => {
|
||||
if (option.__CREATE__) {
|
||||
option = { ...option }
|
||||
delete option.__CREATE__
|
||||
}
|
||||
|
||||
switch (mode.value) {
|
||||
case 'single':
|
||||
if (option && isSelected(option)) {
|
||||
if (canDeselect.value) {
|
||||
deselect(option)
|
||||
}
|
||||
|
||||
if (closeOnDeselect.value) {
|
||||
clearPointer()
|
||||
close()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (option) {
|
||||
handleOptionAppend(option)
|
||||
}
|
||||
|
||||
/* istanbul ignore else */
|
||||
if (clearOnSelect.value) {
|
||||
clearSearch()
|
||||
}
|
||||
|
||||
if (closeOnSelect.value) {
|
||||
clearPointer()
|
||||
close()
|
||||
}
|
||||
|
||||
if (option) {
|
||||
select(option)
|
||||
}
|
||||
break
|
||||
|
||||
case 'multiple':
|
||||
if (option && isSelected(option)) {
|
||||
deselect(option)
|
||||
|
||||
if (closeOnDeselect.value) {
|
||||
clearPointer()
|
||||
close()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (isMax()) {
|
||||
context.emit('max', $this)
|
||||
return
|
||||
}
|
||||
|
||||
if (option) {
|
||||
handleOptionAppend(option)
|
||||
select(option)
|
||||
}
|
||||
|
||||
if (clearOnSelect.value) {
|
||||
clearSearch()
|
||||
}
|
||||
|
||||
if (hideSelected.value) {
|
||||
clearPointer()
|
||||
}
|
||||
|
||||
if (closeOnSelect.value) {
|
||||
close()
|
||||
}
|
||||
break
|
||||
|
||||
case 'tags':
|
||||
if (option && isSelected(option)) {
|
||||
deselect(option)
|
||||
|
||||
if (closeOnDeselect.value) {
|
||||
clearPointer()
|
||||
close()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (isMax()) {
|
||||
context.emit('max', $this)
|
||||
return
|
||||
}
|
||||
|
||||
if (option) {
|
||||
handleOptionAppend(option)
|
||||
}
|
||||
|
||||
if (clearOnSelect.value) {
|
||||
clearSearch()
|
||||
}
|
||||
|
||||
if (option) {
|
||||
select(option)
|
||||
}
|
||||
|
||||
if (hideSelected.value) {
|
||||
clearPointer()
|
||||
}
|
||||
|
||||
if (closeOnSelect.value) {
|
||||
close()
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if (!closeOnSelect.value) {
|
||||
focus()
|
||||
}
|
||||
}
|
||||
|
||||
const handleGroupClick = (group) => {
|
||||
if (isDisabled(group) || mode.value === 'single' || !groupSelect.value) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (mode.value) {
|
||||
case 'multiple':
|
||||
case 'tags':
|
||||
if (areAllEnabledSelected(group[groupOptions.value])) {
|
||||
deselect(group[groupOptions.value])
|
||||
} else {
|
||||
select(group[groupOptions.value]
|
||||
.filter(o => iv.value.map(v => v[valueProp.value]).indexOf(o[valueProp.value]) === -1)
|
||||
.filter(o => !o[disabledProp.value])
|
||||
.filter((o, k) => iv.value.length + 1 + k <= max.value || max.value === -1)
|
||||
)
|
||||
}
|
||||
|
||||
if (hideSelected.value && pointer.value) {
|
||||
// Refresh pointer because pointer.__VISIBLE__ are not reactive #354
|
||||
setPointer(fg.value.filter(g => !g[disabledProp.value])[pointer.value.index])
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if (closeOnSelect.value) {
|
||||
deactivate()
|
||||
}
|
||||
}
|
||||
|
||||
const handleOptionAppend = (option) => {
|
||||
if (getOption(option[valueProp.value]) === undefined && createOption.value) {
|
||||
context.emit('tag', option[valueProp.value], $this)
|
||||
context.emit('option', option[valueProp.value], $this)
|
||||
context.emit('create', option[valueProp.value], $this)
|
||||
|
||||
if (appendNewOption.value) {
|
||||
appendOption(option)
|
||||
}
|
||||
|
||||
clearSearch()
|
||||
}
|
||||
}
|
||||
|
||||
const selectAll = () => {
|
||||
if (mode.value === 'single') {
|
||||
return
|
||||
}
|
||||
|
||||
select(fo.value.filter(o => !o.disabled && !isSelected(o)))
|
||||
}
|
||||
|
||||
// no export
|
||||
const areAllEnabledSelected = (options) => {
|
||||
return options.find(o => !isSelected(o) && !o[disabledProp.value]) === undefined
|
||||
}
|
||||
|
||||
// no export
|
||||
const areAllSelected = (options) => {
|
||||
return options.find(o => !isSelected(o)) === undefined
|
||||
}
|
||||
|
||||
const getOption = (val) => {
|
||||
return eo.value[eo.value.map(o => String(o[valueProp.value])).indexOf(String(val))]
|
||||
}
|
||||
|
||||
// no export
|
||||
const getOptionByTrackBy = (val) => {
|
||||
return eo.value.findIndex((o) => {
|
||||
return trackBy.value.some((track) => {
|
||||
return (parseInt(o[track]) == o[track] ? parseInt(o[track]) : o[track]) === (parseInt(val) == val ? parseInt(val) : val)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// no export
|
||||
const shouldHideOption = (option) => {
|
||||
return ['tags', 'multiple'].indexOf(mode.value) !== -1 && hideSelected.value && isSelected(option)
|
||||
}
|
||||
|
||||
// no export
|
||||
const appendOption = (option) => {
|
||||
ap.value.push(option)
|
||||
}
|
||||
|
||||
// no export
|
||||
const filterGroups = (groups) => {
|
||||
// If the search has value we need to filter among
|
||||
// the ones that are visible to the user to avoid
|
||||
// displaying groups which technically have options
|
||||
// based on search but that option is already selected.
|
||||
return groupHideEmpty.value
|
||||
? groups.filter(g => search.value
|
||||
? g.__VISIBLE__.length
|
||||
: g[groupOptions.value].length
|
||||
)
|
||||
: groups.filter(g => search.value ? g.__VISIBLE__.length : true)
|
||||
}
|
||||
|
||||
// no export
|
||||
const filterOptions = (options, excludeHideSelected = true) => {
|
||||
let fo = options
|
||||
|
||||
if (search.value && filterResults.value) {
|
||||
let filter = searchFilter.value
|
||||
|
||||
if (!filter) {
|
||||
filter = (option, query, $this) => {
|
||||
return trackBy.value.some(track => {
|
||||
let target = normalize(localize(option[track]), strict.value);
|
||||
|
||||
return searchStart.value
|
||||
? target.startsWith(normalize(query, strict.value))
|
||||
: target.indexOf(normalize(query, strict.value)) !== -1;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fo = fo.filter((o) => {
|
||||
return filter(o, search.value, $this)
|
||||
})
|
||||
}
|
||||
|
||||
if (hideSelected.value && excludeHideSelected) {
|
||||
fo = fo.filter((option) => !shouldHideOption(option))
|
||||
}
|
||||
|
||||
return fo
|
||||
}
|
||||
|
||||
// no export
|
||||
const optionsToArray = (options) => {
|
||||
let uo = options
|
||||
|
||||
// Transforming an object to an array of objects
|
||||
if (isObject(uo)) {
|
||||
uo = Object.keys(uo).map((key) => {
|
||||
let val = uo[key]
|
||||
|
||||
return { [valueProp.value]: key, [trackBy.value[0]]: val, [label.value]: val}
|
||||
})
|
||||
}
|
||||
|
||||
// Transforming an plain arrays to an array of objects
|
||||
/* istanbul ignore else */
|
||||
if (uo && Array.isArray(uo)) {
|
||||
uo = uo.map((val) => {
|
||||
return typeof val === 'object' ? val : { [valueProp.value]: val, [trackBy.value[0]]: val, [label.value]: val}
|
||||
})
|
||||
} else {
|
||||
uo = []
|
||||
}
|
||||
|
||||
return uo
|
||||
}
|
||||
|
||||
// no export
|
||||
const initInternalValue = () => {
|
||||
if (!isNullish(ev.value)) {
|
||||
iv.value = makeInternal(ev.value)
|
||||
}
|
||||
}
|
||||
|
||||
const resolveOptions = (callback) => {
|
||||
resolving.value = true
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
options.value(search.value, $this).then((response) => {
|
||||
ro.value = response || []
|
||||
|
||||
if (typeof callback == 'function') {
|
||||
callback(response)
|
||||
}
|
||||
|
||||
resolving.value = false
|
||||
}).catch((e) => {
|
||||
console.error(e)
|
||||
|
||||
ro.value = []
|
||||
|
||||
resolving.value = false
|
||||
}).finally(() => {
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// no export
|
||||
const refreshLabels = () => {
|
||||
if (!hasSelected.value) {
|
||||
return
|
||||
}
|
||||
|
||||
if (mode.value === 'single') {
|
||||
let option = getOption(iv.value[valueProp.value])
|
||||
|
||||
/* istanbul ignore else */
|
||||
if (option !== undefined) {
|
||||
let newLabel = option[label.value]
|
||||
|
||||
iv.value[label.value] = newLabel
|
||||
|
||||
if (object.value) {
|
||||
ev.value[label.value] = newLabel
|
||||
}
|
||||
}
|
||||
} else {
|
||||
iv.value.forEach((val, i) => {
|
||||
let option = getOption(iv.value[i][valueProp.value])
|
||||
|
||||
/* istanbul ignore else */
|
||||
if (option !== undefined) {
|
||||
let newLabel = option[label.value]
|
||||
|
||||
iv.value[i][label.value] = newLabel
|
||||
|
||||
if (object.value) {
|
||||
ev.value[i][label.value] = newLabel
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const refreshOptions = (callback) => {
|
||||
resolveOptions(callback)
|
||||
}
|
||||
|
||||
// no export
|
||||
const makeInternal = (val) => {
|
||||
if (isNullish(val)) {
|
||||
return mode.value === 'single' ? {} : []
|
||||
}
|
||||
|
||||
if (object.value) {
|
||||
return val
|
||||
}
|
||||
|
||||
// If external should be plain transform value object to plain values
|
||||
return mode.value === 'single' ? getOption(val) || (allowAbsent.value ? {
|
||||
[label.value]: val,
|
||||
[valueProp.value]: val,
|
||||
[trackBy.value[0]]: val,
|
||||
} : {}) : val.filter(v => !!getOption(v) || allowAbsent.value).map(v => getOption(v) || {
|
||||
[label.value]: v,
|
||||
[valueProp.value]: v,
|
||||
[trackBy.value[0]]: v,
|
||||
})
|
||||
}
|
||||
|
||||
// no export
|
||||
const initSearchWatcher = () => {
|
||||
searchWatcher.value = watch(search, (query) => {
|
||||
if (query.length < minChars.value || (!query && minChars.value !== 0)) {
|
||||
return
|
||||
}
|
||||
|
||||
resolving.value = true
|
||||
|
||||
if (clearOnSearch.value) {
|
||||
ro.value = []
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (query != search.value) {
|
||||
return
|
||||
}
|
||||
|
||||
options.value(search.value, $this).then((response) => {
|
||||
if (query == search.value || !search.value) {
|
||||
ro.value = response
|
||||
pointer.value = fo.value.filter(o => o[disabledProp.value] !== true)[0] || null
|
||||
resolving.value = false
|
||||
}
|
||||
}).catch( /* istanbul ignore next */ (e) => {
|
||||
console.error(e)
|
||||
})
|
||||
}, delay.value)
|
||||
|
||||
}, { flush: 'sync' })
|
||||
}
|
||||
|
||||
// ================ HOOKS ===============
|
||||
|
||||
if (mode.value !== 'single' && !isNullish(ev.value) && !Array.isArray(ev.value)) {
|
||||
throw new Error(`v-model must be an array when using "${mode.value}" mode`)
|
||||
}
|
||||
|
||||
if (options && typeof options.value == 'function') {
|
||||
if (resolveOnLoad.value) {
|
||||
resolveOptions(initInternalValue)
|
||||
} else if (object.value == true) {
|
||||
initInternalValue()
|
||||
}
|
||||
}
|
||||
else {
|
||||
ro.value = options.value
|
||||
|
||||
initInternalValue()
|
||||
}
|
||||
|
||||
// ============== WATCHERS ==============
|
||||
|
||||
if (delay.value > -1) {
|
||||
initSearchWatcher()
|
||||
}
|
||||
|
||||
watch(delay, (value, old) => {
|
||||
/* istanbul ignore else */
|
||||
if (searchWatcher.value) {
|
||||
searchWatcher.value()
|
||||
}
|
||||
|
||||
if (value >= 0) {
|
||||
initSearchWatcher()
|
||||
}
|
||||
})
|
||||
|
||||
watch(ev, (newValue) => {
|
||||
if (isNullish(newValue)) {
|
||||
update(makeInternal(newValue), false)
|
||||
return
|
||||
}
|
||||
|
||||
switch (mode.value) {
|
||||
case 'single':
|
||||
if (object.value ? newValue[valueProp.value] != iv.value[valueProp.value] : newValue != iv.value[valueProp.value]) {
|
||||
update(makeInternal(newValue), false)
|
||||
}
|
||||
break
|
||||
|
||||
case 'multiple':
|
||||
case 'tags':
|
||||
if (!arraysEqual(object.value ? newValue.map(o => o[valueProp.value]) : newValue, iv.value.map(o => o[valueProp.value]))) {
|
||||
update(makeInternal(newValue), false)
|
||||
}
|
||||
break
|
||||
}
|
||||
}, { deep: true })
|
||||
|
||||
watch(options, (n, o) => {
|
||||
if (typeof props.options === 'function') {
|
||||
if (resolveOnLoad.value && (!o || (n && n.toString() !== o.toString()))) {
|
||||
resolveOptions()
|
||||
}
|
||||
} else {
|
||||
ro.value = props.options
|
||||
|
||||
if (!Object.keys(iv.value).length) {
|
||||
initInternalValue()
|
||||
}
|
||||
|
||||
refreshLabels()
|
||||
}
|
||||
})
|
||||
|
||||
watch(label, refreshLabels)
|
||||
|
||||
watch(limit, (n,o) => {
|
||||
offset.value = infinite.value && n === -1 ? 10 : n
|
||||
})
|
||||
|
||||
return {
|
||||
resolvedOptions,
|
||||
pfo,
|
||||
fo,
|
||||
filteredOptions: fo,
|
||||
hasSelected,
|
||||
multipleLabelText,
|
||||
eo,
|
||||
extendedOptions: eo,
|
||||
eg,
|
||||
extendedGroups: eg,
|
||||
fg,
|
||||
filteredGroups: fg,
|
||||
noOptions,
|
||||
noResults,
|
||||
resolving,
|
||||
busy,
|
||||
offset,
|
||||
select,
|
||||
deselect,
|
||||
remove,
|
||||
selectAll,
|
||||
clear,
|
||||
isSelected,
|
||||
isDisabled,
|
||||
isMax,
|
||||
getOption,
|
||||
handleOptionClick,
|
||||
handleGroupClick,
|
||||
handleTagRemove,
|
||||
refreshOptions,
|
||||
resolveOptions,
|
||||
refreshLabels,
|
||||
}
|
||||
}
|
||||
34
client/node_modules/@vueform/multiselect/src/composables/usePointer.js
generated
vendored
Normal file
34
client/node_modules/@vueform/multiselect/src/composables/usePointer.js
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
import { ref, toRefs } from 'vue'
|
||||
|
||||
export default function usePointer (props, context, dep)
|
||||
{
|
||||
const { groupSelect, mode, groups, disabledProp } = toRefs(props)
|
||||
|
||||
// ================ DATA ================
|
||||
|
||||
const pointer = ref(null)
|
||||
|
||||
// =============== METHODS ==============
|
||||
|
||||
const setPointer = (option) => {
|
||||
if (option === undefined || (option !== null && option[disabledProp.value])) {
|
||||
return
|
||||
}
|
||||
|
||||
if (groups.value && option && option.group && (mode.value === 'single' || !groupSelect.value)) {
|
||||
return
|
||||
}
|
||||
|
||||
pointer.value = option
|
||||
}
|
||||
|
||||
const clearPointer = () => {
|
||||
setPointer(null)
|
||||
}
|
||||
|
||||
return {
|
||||
pointer,
|
||||
setPointer,
|
||||
clearPointer,
|
||||
}
|
||||
}
|
||||
274
client/node_modules/@vueform/multiselect/src/composables/usePointerAction.js
generated
vendored
Normal file
274
client/node_modules/@vueform/multiselect/src/composables/usePointerAction.js
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
import { toRefs, watch, nextTick, computed } from 'vue'
|
||||
import toRef from './../utils/toRef'
|
||||
|
||||
export default function usePointer (props, context, dep)
|
||||
{
|
||||
const {
|
||||
valueProp, showOptions, searchable, groupLabel,
|
||||
groups: groupped, mode, groupSelect, disabledProp,
|
||||
groupOptions,
|
||||
} = toRefs(props)
|
||||
|
||||
// ============ DEPENDENCIES ============
|
||||
|
||||
const fo = dep.fo
|
||||
const fg = dep.fg
|
||||
const handleOptionClick = dep.handleOptionClick
|
||||
const handleGroupClick = dep.handleGroupClick
|
||||
const search = dep.search
|
||||
const pointer = dep.pointer
|
||||
const setPointer = dep.setPointer
|
||||
const clearPointer = dep.clearPointer
|
||||
const multiselect = dep.multiselect
|
||||
const isOpen = dep.isOpen
|
||||
|
||||
// ============== COMPUTED ==============
|
||||
|
||||
// no export
|
||||
const options = computed(() => {
|
||||
return fo.value.filter(o => !o[disabledProp.value])
|
||||
})
|
||||
|
||||
const groups = computed(() => {
|
||||
return fg.value.filter(g => !g[disabledProp.value])
|
||||
})
|
||||
|
||||
const canPointGroups = toRef(() => {
|
||||
return mode.value !== 'single' && groupSelect.value
|
||||
})
|
||||
|
||||
const isPointerGroup = toRef(() => {
|
||||
return pointer.value && pointer.value.group
|
||||
})
|
||||
|
||||
const currentGroup = computed(() => {
|
||||
return getParentGroup(pointer.value)
|
||||
})
|
||||
|
||||
const prevGroup = computed(() => {
|
||||
const group = isPointerGroup.value ? pointer.value : /* istanbul ignore next */ getParentGroup(pointer.value)
|
||||
const groupIndex = groups.value.map(g => g[groupLabel.value]).indexOf(group[groupLabel.value])
|
||||
let prevGroup = groups.value[groupIndex - 1]
|
||||
|
||||
if (prevGroup === undefined) {
|
||||
prevGroup = lastGroup.value
|
||||
}
|
||||
|
||||
return prevGroup
|
||||
})
|
||||
|
||||
const nextGroup = computed(() => {
|
||||
let nextIndex = groups.value.map(g => g.label).indexOf(isPointerGroup.value
|
||||
? pointer.value[groupLabel.value]
|
||||
: getParentGroup(pointer.value)[groupLabel.value]) + 1
|
||||
|
||||
if (groups.value.length <= nextIndex) {
|
||||
nextIndex = 0
|
||||
}
|
||||
|
||||
return groups.value[nextIndex]
|
||||
})
|
||||
|
||||
const lastGroup = computed(() => {
|
||||
return [...groups.value].slice(-1)[0]
|
||||
})
|
||||
|
||||
const currentGroupFirstEnabledOption = computed(() => {
|
||||
return pointer.value.__VISIBLE__.filter(o => !o[disabledProp.value])[0]
|
||||
})
|
||||
|
||||
const currentGroupPrevEnabledOption = computed(() => {
|
||||
const options = currentGroup.value.__VISIBLE__.filter(o => !o[disabledProp.value])
|
||||
return options[options.map(o => o[valueProp.value]).indexOf(pointer.value[valueProp.value]) - 1]
|
||||
})
|
||||
|
||||
const currentGroupNextEnabledOption = computed(() => {
|
||||
const options = getParentGroup(pointer.value).__VISIBLE__.filter(o => !o[disabledProp.value])
|
||||
return options[options.map(o => o[valueProp.value]).indexOf(pointer.value[valueProp.value]) + 1]
|
||||
})
|
||||
|
||||
const prevGroupLastEnabledOption = computed(() => {
|
||||
return [...prevGroup.value.__VISIBLE__.filter(o => !o[disabledProp.value])].slice(-1)[0]
|
||||
})
|
||||
|
||||
const lastGroupLastEnabledOption = computed(() => {
|
||||
return [...lastGroup.value.__VISIBLE__.filter(o => !o[disabledProp.value])].slice(-1)[0]
|
||||
})
|
||||
|
||||
// =============== METHODS ==============
|
||||
|
||||
const isPointed = (option) => {
|
||||
return (!!pointer.value && (
|
||||
(!option.group && pointer.value[valueProp.value] === option[valueProp.value]) ||
|
||||
(option.group !== undefined && pointer.value[groupLabel.value] === option[groupLabel.value])
|
||||
)) ? true : undefined
|
||||
}
|
||||
|
||||
const setPointerFirst = () => {
|
||||
setPointer(options.value[0] || null)
|
||||
}
|
||||
|
||||
const selectPointer = () => {
|
||||
if (!pointer.value || pointer.value[disabledProp.value] === true) {
|
||||
return
|
||||
}
|
||||
|
||||
if (isPointerGroup.value) {
|
||||
handleGroupClick(pointer.value)
|
||||
} else {
|
||||
handleOptionClick(pointer.value)
|
||||
}
|
||||
}
|
||||
|
||||
const forwardPointer = () => {
|
||||
if (pointer.value === null) {
|
||||
setPointer((groupped.value && canPointGroups.value ? (!groups.value[0].__CREATE__ ? groups.value[0] : options.value[0]) : options.value[0]) || null)
|
||||
}
|
||||
else if (groupped.value && canPointGroups.value) {
|
||||
let nextPointer = isPointerGroup.value ? currentGroupFirstEnabledOption.value : currentGroupNextEnabledOption.value
|
||||
|
||||
if (nextPointer === undefined) {
|
||||
nextPointer = nextGroup.value
|
||||
|
||||
if (nextPointer.__CREATE__) {
|
||||
nextPointer = nextPointer[groupOptions.value][0]
|
||||
}
|
||||
}
|
||||
|
||||
setPointer(nextPointer || /* istanbul ignore next */ null)
|
||||
} else {
|
||||
let next = options.value.map(o => o[valueProp.value]).indexOf(pointer.value[valueProp.value]) + 1
|
||||
|
||||
if (options.value.length <= next) {
|
||||
next = 0
|
||||
}
|
||||
|
||||
setPointer(options.value[next] || null)
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
adjustWrapperScrollToPointer()
|
||||
})
|
||||
}
|
||||
|
||||
const backwardPointer = () => {
|
||||
if (pointer.value === null) {
|
||||
let prevPointer = options.value[options.value.length - 1]
|
||||
|
||||
if (groupped.value && canPointGroups.value) {
|
||||
prevPointer = lastGroupLastEnabledOption.value
|
||||
|
||||
if (prevPointer === undefined) {
|
||||
prevPointer = lastGroup.value
|
||||
}
|
||||
}
|
||||
|
||||
setPointer(prevPointer || null)
|
||||
}
|
||||
else if (groupped.value && canPointGroups.value) {
|
||||
let prevPointer = isPointerGroup.value ? prevGroupLastEnabledOption.value : currentGroupPrevEnabledOption.value
|
||||
|
||||
if (prevPointer === undefined) {
|
||||
prevPointer = isPointerGroup.value ? prevGroup.value : currentGroup.value
|
||||
|
||||
if (prevPointer.__CREATE__) {
|
||||
prevPointer = prevGroupLastEnabledOption.value
|
||||
|
||||
if (prevPointer === undefined) {
|
||||
prevPointer = prevGroup.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setPointer(prevPointer || /* istanbul ignore next */ null)
|
||||
} else {
|
||||
let prevIndex = options.value.map(o => o[valueProp.value]).indexOf(pointer.value[valueProp.value]) - 1
|
||||
|
||||
if (prevIndex < 0) {
|
||||
prevIndex = options.value.length - 1
|
||||
}
|
||||
|
||||
setPointer(options.value[prevIndex] || null)
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
adjustWrapperScrollToPointer()
|
||||
})
|
||||
}
|
||||
|
||||
const getParentGroup = (option) => {
|
||||
return groups.value.find((group) => {
|
||||
return group.__VISIBLE__.map(o => o[valueProp.value]).indexOf(option[valueProp.value]) !== -1
|
||||
})
|
||||
}
|
||||
|
||||
// no export
|
||||
/* istanbul ignore next */
|
||||
const adjustWrapperScrollToPointer = () => {
|
||||
let pointedOption = multiselect.value.querySelector(`[data-pointed]`)
|
||||
|
||||
if (!pointedOption) {
|
||||
return
|
||||
}
|
||||
|
||||
let wrapper = pointedOption.parentElement.parentElement
|
||||
|
||||
if (groupped.value) {
|
||||
wrapper = isPointerGroup.value
|
||||
? pointedOption.parentElement.parentElement.parentElement
|
||||
: pointedOption.parentElement.parentElement.parentElement.parentElement
|
||||
}
|
||||
|
||||
if (pointedOption.offsetTop + pointedOption.offsetHeight > wrapper.clientHeight + wrapper.scrollTop) {
|
||||
wrapper.scrollTop = pointedOption.offsetTop + pointedOption.offsetHeight - wrapper.clientHeight
|
||||
}
|
||||
|
||||
if (pointedOption.offsetTop < wrapper.scrollTop) {
|
||||
wrapper.scrollTop = pointedOption.offsetTop
|
||||
}
|
||||
}
|
||||
|
||||
// ============== WATCHERS ==============
|
||||
|
||||
watch(search, (val) => {
|
||||
if (searchable.value) {
|
||||
if (val.length && showOptions.value) {
|
||||
setPointerFirst()
|
||||
} else {
|
||||
clearPointer()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
watch(isOpen, (val) => {
|
||||
if (val && multiselect && multiselect.value) {
|
||||
let firstSelected = multiselect.value.querySelectorAll(`[data-selected]`)[0]
|
||||
|
||||
if (!firstSelected) {
|
||||
return
|
||||
}
|
||||
|
||||
let wrapper = firstSelected.parentElement.parentElement
|
||||
|
||||
nextTick(() => {
|
||||
// Removed because of #406
|
||||
/* istanbul ignore next */
|
||||
// if (wrapper.scrollTop > 0) {
|
||||
// return
|
||||
// }
|
||||
|
||||
wrapper.scrollTop = firstSelected.offsetTop
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
pointer,
|
||||
canPointGroups,
|
||||
isPointed,
|
||||
setPointerFirst,
|
||||
selectPointer,
|
||||
forwardPointer,
|
||||
backwardPointer,
|
||||
}
|
||||
}
|
||||
24
client/node_modules/@vueform/multiselect/src/composables/useRefs.js
generated
vendored
Normal file
24
client/node_modules/@vueform/multiselect/src/composables/useRefs.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
import { shallowRef } from 'vue'
|
||||
|
||||
export default function useRefs (props, context, dep)
|
||||
{
|
||||
// ================ DATA ================
|
||||
|
||||
const multiselect = shallowRef(null)
|
||||
|
||||
const wrapper = shallowRef(null)
|
||||
|
||||
const tags = shallowRef(null)
|
||||
|
||||
const input = shallowRef(null)
|
||||
|
||||
const dropdown = shallowRef(null)
|
||||
|
||||
return {
|
||||
multiselect,
|
||||
wrapper,
|
||||
tags,
|
||||
input,
|
||||
dropdown,
|
||||
}
|
||||
}
|
||||
100
client/node_modules/@vueform/multiselect/src/composables/useScroll.js
generated
vendored
Normal file
100
client/node_modules/@vueform/multiselect/src/composables/useScroll.js
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
import { toRefs, watch, nextTick, onMounted, ref, shallowRef, computed } from 'vue'
|
||||
import toRef from '../utils/toRef'
|
||||
|
||||
export default function useScroll (props, context, dep)
|
||||
{
|
||||
const {
|
||||
limit, infinite,
|
||||
} = toRefs(props)
|
||||
|
||||
// ============ DEPENDENCIES ============
|
||||
|
||||
const isOpen = dep.isOpen
|
||||
const offset = dep.offset
|
||||
const search = dep.search
|
||||
const pfo = dep.pfo
|
||||
const eo = dep.eo
|
||||
|
||||
// ================ DATA ================
|
||||
|
||||
// no export
|
||||
const observer = ref(null)
|
||||
|
||||
const infiniteLoader = shallowRef(null)
|
||||
|
||||
// ============== COMPUTED ==============
|
||||
|
||||
const hasMore = toRef(() => {
|
||||
return offset.value < pfo.value.length
|
||||
})
|
||||
|
||||
// =============== METHODS ==============
|
||||
|
||||
// no export
|
||||
/* istanbul ignore next */
|
||||
const handleIntersectionObserver = (entries) => {
|
||||
const { isIntersecting, target } = entries[0]
|
||||
|
||||
if (isIntersecting) {
|
||||
const parent = target.offsetParent
|
||||
const scrollTop = parent.scrollTop
|
||||
|
||||
offset.value += limit.value == -1 ? 10 : limit.value
|
||||
|
||||
nextTick(() => {
|
||||
parent.scrollTop = scrollTop
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const observe = () => {
|
||||
/* istanbul ignore else */
|
||||
if (isOpen.value && offset.value < pfo.value.length) {
|
||||
observer.value.observe(infiniteLoader.value)
|
||||
} else if (!isOpen.value && observer.value) {
|
||||
observer.value.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
// ============== WATCHERS ==============
|
||||
|
||||
watch(isOpen, () => {
|
||||
if (!infinite.value) {
|
||||
return
|
||||
}
|
||||
|
||||
observe()
|
||||
})
|
||||
|
||||
watch(search, () => {
|
||||
if (!infinite.value) {
|
||||
return
|
||||
}
|
||||
|
||||
offset.value = limit.value
|
||||
|
||||
observe()
|
||||
}, { flush: 'post' })
|
||||
|
||||
watch(eo, () => {
|
||||
if (!infinite.value) {
|
||||
return
|
||||
}
|
||||
|
||||
observe()
|
||||
}, { immediate: false, flush: 'post' })
|
||||
|
||||
// ================ HOOKS ===============
|
||||
|
||||
onMounted(() => {
|
||||
/* istanbul ignore else */
|
||||
if (window && window.IntersectionObserver) {
|
||||
observer.value = new IntersectionObserver(handleIntersectionObserver)
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
hasMore,
|
||||
infiniteLoader,
|
||||
}
|
||||
}
|
||||
78
client/node_modules/@vueform/multiselect/src/composables/useSearch.js
generated
vendored
Normal file
78
client/node_modules/@vueform/multiselect/src/composables/useSearch.js
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
import { ref, getCurrentInstance, watch, toRefs } from 'vue'
|
||||
|
||||
export default function useSearch (props, context, dep)
|
||||
{
|
||||
const { regex } = toRefs(props)
|
||||
|
||||
const $this = getCurrentInstance().proxy
|
||||
|
||||
// ============ DEPENDENCIES ============
|
||||
|
||||
const isOpen = dep.isOpen
|
||||
const open = dep.open
|
||||
|
||||
// ================ DATA ================
|
||||
|
||||
const search = ref(null)
|
||||
|
||||
// =============== METHODS ==============
|
||||
|
||||
const clearSearch = () => {
|
||||
search.value = ''
|
||||
}
|
||||
|
||||
const handleSearchInput = (e) => {
|
||||
search.value = e.target.value
|
||||
}
|
||||
|
||||
const handleKeypress = (e) => {
|
||||
if (regex.value) {
|
||||
let regexp = regex.value
|
||||
|
||||
if (typeof regexp === 'string') {
|
||||
regexp = new RegExp(regexp)
|
||||
}
|
||||
|
||||
if (!e.key.match(regexp)) {
|
||||
e.preventDefault()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handlePaste = (e) => {
|
||||
if (regex.value) {
|
||||
let clipboardData = e.clipboardData || /* istanbul ignore next */ window.clipboardData
|
||||
let pastedData = clipboardData.getData('Text')
|
||||
|
||||
let regexp = regex.value
|
||||
|
||||
if (typeof regexp === 'string') {
|
||||
regexp = new RegExp(regexp)
|
||||
}
|
||||
|
||||
if (!pastedData.split('').every(c => !!c.match(regexp))) {
|
||||
e.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
context.emit('paste', e, $this)
|
||||
}
|
||||
|
||||
// ============== WATCHERS ==============
|
||||
|
||||
watch(search, (val) => {
|
||||
if (!isOpen.value && val) {
|
||||
open()
|
||||
}
|
||||
|
||||
context.emit('search-change', val, $this)
|
||||
})
|
||||
|
||||
return {
|
||||
search,
|
||||
clearSearch,
|
||||
handleSearchInput,
|
||||
handleKeypress,
|
||||
handlePaste,
|
||||
}
|
||||
}
|
||||
37
client/node_modules/@vueform/multiselect/src/composables/useValue.js
generated
vendored
Normal file
37
client/node_modules/@vueform/multiselect/src/composables/useValue.js
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
import { computed, toRefs, ref } from 'vue'
|
||||
import toRef from '../utils/toRef'
|
||||
|
||||
export default function useValue (props, context)
|
||||
{
|
||||
const { value, modelValue, mode, valueProp } = toRefs(props)
|
||||
|
||||
// ================ DATA ================
|
||||
|
||||
// internalValue
|
||||
const iv = ref(mode.value !== 'single' ? [] : {})
|
||||
|
||||
// ============== COMPUTED ==============
|
||||
|
||||
/* istanbul ignore next */
|
||||
// externalValue
|
||||
const ev = toRef(() => {
|
||||
return modelValue.value !== undefined ? modelValue.value : value.value
|
||||
})
|
||||
|
||||
const plainValue = computed(() => {
|
||||
return mode.value === 'single' ? iv.value[valueProp.value] : iv.value.map(v=>v[valueProp.value])
|
||||
})
|
||||
|
||||
const textValue = toRef(() => {
|
||||
return mode.value !== 'single' ? iv.value.map(v=>v[valueProp.value]).join(',') : iv.value[valueProp.value]
|
||||
})
|
||||
|
||||
return {
|
||||
iv,
|
||||
internalValue: iv,
|
||||
ev,
|
||||
externalValue: ev,
|
||||
textValue,
|
||||
plainValue,
|
||||
}
|
||||
}
|
||||
1
client/node_modules/@vueform/multiselect/src/index.d.ts
generated
vendored
Normal file
1
client/node_modules/@vueform/multiselect/src/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './Multiselect';
|
||||
11
client/node_modules/@vueform/multiselect/src/utils/arraysEqual.js
generated
vendored
Normal file
11
client/node_modules/@vueform/multiselect/src/utils/arraysEqual.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
export default function arraysEqual (array1, array2) {
|
||||
if (array1.length !== array2.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const array2Sorted = array2.slice().sort()
|
||||
|
||||
return array1.slice().sort().every(function(value, index) {
|
||||
return value === array2Sorted[index];
|
||||
})
|
||||
}
|
||||
3
client/node_modules/@vueform/multiselect/src/utils/isNullish.js
generated
vendored
Normal file
3
client/node_modules/@vueform/multiselect/src/utils/isNullish.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function isNullish (val) {
|
||||
return val === null || val === undefined
|
||||
}
|
||||
3
client/node_modules/@vueform/multiselect/src/utils/isObject.js
generated
vendored
Normal file
3
client/node_modules/@vueform/multiselect/src/utils/isObject.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function isObject (variable) {
|
||||
return Object.prototype.toString.call(variable) === '[object Object]'
|
||||
}
|
||||
11
client/node_modules/@vueform/multiselect/src/utils/normalize.js
generated
vendored
Normal file
11
client/node_modules/@vueform/multiselect/src/utils/normalize.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
export default function normalize (str, strict = true) {
|
||||
return strict
|
||||
? String(str).toLowerCase().trim()
|
||||
: String(str).toLowerCase()
|
||||
.normalize('NFD')
|
||||
.trim()
|
||||
.replace(/æ/g, 'ae')
|
||||
.replace(/œ/g, 'oe')
|
||||
.replace(/ø/g, 'o')
|
||||
.replace(/\p{Diacritic}/gu, '')
|
||||
}
|
||||
38
client/node_modules/@vueform/multiselect/src/utils/objectsEqual.js
generated
vendored
Normal file
38
client/node_modules/@vueform/multiselect/src/utils/objectsEqual.js
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/* istanbul ignore next */
|
||||
const objectsEqual = (obj1, obj2) => {
|
||||
// If both are strictly equal, return true
|
||||
if (obj1 === obj2) {
|
||||
return true
|
||||
}
|
||||
|
||||
// If either is not an object or is null, return false (handles primitive types and null)
|
||||
if (typeof obj1 !== 'object' || obj1 === null || typeof obj2 !== 'object' || obj2 === null) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Get the keys of both objects
|
||||
const keys1 = Object.keys(obj1)
|
||||
const keys2 = Object.keys(obj2)
|
||||
|
||||
// If they have a different number of keys, they're not equal
|
||||
if (keys1.length !== keys2.length) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Compare each key-value pair recursively
|
||||
for (let key of keys1) {
|
||||
// Check if both objects have the same key
|
||||
if (!keys2.includes(key)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Recursively compare the values
|
||||
if (!objectsEqual(obj1[key], obj2[key])) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export default objectsEqual
|
||||
10
client/node_modules/@vueform/multiselect/src/utils/resolveDeps.js
generated
vendored
Normal file
10
client/node_modules/@vueform/multiselect/src/utils/resolveDeps.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
export default function (props, context, features, deps = {}) {
|
||||
features.forEach((composable) => {
|
||||
deps = {
|
||||
...deps,
|
||||
...composable(props, context, deps)
|
||||
}
|
||||
})
|
||||
|
||||
return deps
|
||||
}
|
||||
7
client/node_modules/@vueform/multiselect/src/utils/toRef.js
generated
vendored
Normal file
7
client/node_modules/@vueform/multiselect/src/utils/toRef.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import { customRef } from 'vue'
|
||||
|
||||
// Polyfill for Vue <3.3 for getters only
|
||||
// https://vuejs.org/api/reactivity-utilities.html#toref
|
||||
export default function toRef (get) {
|
||||
return customRef(() => ({ get, set: /* istanbul ignore next */ () => { } }))
|
||||
}
|
||||
Reference in New Issue
Block a user