You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
258 lines
8.3 KiB
258 lines
8.3 KiB
<tiny-field-select>
|
|
<div class="{ getSelectClasses(['field-select']) }">
|
|
|
|
<select name="{ props.name }" multiple style="display: none;">
|
|
<option value="{ selected[ state.keys.value ] }" selected each={ selected in state.selected }></option>
|
|
</select>
|
|
|
|
<div class="field-select__options">
|
|
<div class="{ getFilterClasses(['field-select__options-filter']) }" if={ props.searchable !== undefined }>
|
|
<input type="text" class="field-text m-top-0" placeholder={ props.placeholderFilter } onkeyup={ (event) => { handleOnKeyUp(event) }} disabled={ props.disabled !== undefined } />
|
|
<button type="button" class="field-select__options-filter-reset" onclick={ (event) => { handleResetSearchable(event) } }>
|
|
⮾
|
|
</button>
|
|
</div>
|
|
<div class="panel">
|
|
<div class="bar justify-content-end">
|
|
<div class="bar__end">
|
|
{ state.selected.length } / { state.options.length } 🗇
|
|
</div>
|
|
</div>
|
|
<div class="field-select__options-panel">
|
|
<ul class="field-select__options-list">
|
|
<li class="{ getItemClasses(['field-select__options-item'], option) }" each={ option in state.options } onclick={ (event) => { handleToggle(event, option) } }>
|
|
<span class="field-select__options-item-check">
|
|
☑
|
|
</span>
|
|
<span class="field-select__options-item-uncheck">
|
|
☐
|
|
</span>
|
|
{ option[ state.keys.label ] }
|
|
</li>
|
|
<li class="field-select__item field-select__item--empty center color-danger" if={ state.options.length === 0 }>
|
|
∅
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
|
|
export default {
|
|
|
|
state: {
|
|
keys: {
|
|
label: 'label',
|
|
value: 'value'
|
|
}
|
|
},
|
|
|
|
/**
|
|
*
|
|
*
|
|
*/
|
|
onBeforeMount(props, state) {
|
|
|
|
// init state
|
|
this.state = {
|
|
...state,
|
|
selected: [],
|
|
hasUpdated: false,
|
|
options: [],
|
|
query: ''
|
|
}
|
|
|
|
if (this.props.label) {
|
|
this.state.keys.label = props.label
|
|
}
|
|
|
|
if (this.props.value) {
|
|
this.state.keys.value = props.value
|
|
}
|
|
|
|
if (this.props.options) {
|
|
this.state.options = props.options
|
|
}
|
|
},
|
|
|
|
/**
|
|
*
|
|
*
|
|
*/
|
|
onMounted() {
|
|
|
|
// if store update, add data to options
|
|
if (this.props.store) {
|
|
this.props.store.on('update.options', (data) => {
|
|
|
|
if (this.state.selected.length > 0) {
|
|
for (let i = 0; i < this.state.selected.length; i++) {
|
|
|
|
let found = false
|
|
|
|
for (let j = 0; j < data.length; j++) {
|
|
if (data[j][ this.state.keys.value ] == this.state.selected[i][ this.state.keys.value ]) {
|
|
found = true
|
|
}
|
|
}
|
|
|
|
if (found === false) {
|
|
data.unshift(this.state.selected[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
this.state.options = data
|
|
this.update()
|
|
})
|
|
|
|
this.props.store.queryOptions()
|
|
|
|
if (this.props.querySelected) {
|
|
this.props.store.on('update.selected', (data) => {
|
|
this.state.selected = data
|
|
this.update()
|
|
})
|
|
|
|
this.props.store.querySelected(this.props.querySelected)
|
|
}
|
|
}
|
|
|
|
// getting closet form-element and add reset
|
|
this.root.closest('form').addEventListener('reset', () => {
|
|
this.reset()
|
|
})
|
|
},
|
|
|
|
/**
|
|
*
|
|
*
|
|
*/
|
|
onBeforeUpdate() {
|
|
|
|
// props has changed after reset
|
|
if (this.props.selected && this.props.selected.length > 0 && !this.state.hasUpdated) {
|
|
this.state.selected = this.props.selected
|
|
this.state.hasUpdated = true
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
* reset searchable
|
|
*
|
|
*/
|
|
handleResetSearchable(event) {
|
|
event.target.previousElementSibling.value = ''
|
|
this.state.query = ''
|
|
this.props.store.queryOptions(this.state.query)
|
|
},
|
|
|
|
/**
|
|
* if pressed has ended, call query
|
|
*
|
|
*/
|
|
handleOnKeyUp(event) {
|
|
this.state.query = event.target.value.trim()
|
|
this.props.store.queryOptions(this.state.query)
|
|
},
|
|
|
|
/**
|
|
* toggle selected, if not found add to selected
|
|
*
|
|
*/
|
|
handleToggle(event, option) {
|
|
|
|
if (this.props.disabled !== undefined) {
|
|
event.preventDefault()
|
|
return false
|
|
}
|
|
|
|
const index = this.searchSelected(option)
|
|
|
|
if (index !== false) {
|
|
this.state.selected.splice(index, 1)
|
|
} else {
|
|
if ((this.props.multiple === undefined && this.state.selected.length > 0)) {
|
|
this.state.selected = []
|
|
}
|
|
|
|
this.state.selected.push(option)
|
|
}
|
|
|
|
this.update()
|
|
},
|
|
|
|
/**
|
|
* if item is in selected add css class
|
|
*
|
|
*/
|
|
getSelectClasses(classes) {
|
|
if (this.props.disabled !== undefined) {
|
|
classes.push('field-select--disabled')
|
|
}
|
|
|
|
return classes.join(' ')
|
|
},
|
|
|
|
/**
|
|
* if item is in selected add css class
|
|
*
|
|
*/
|
|
getItemClasses(classes, option) {
|
|
const index = this.searchSelected(option)
|
|
|
|
if (index !== false) {
|
|
classes.push('field-select__options-item--selected')
|
|
}
|
|
|
|
return classes.join(' ')
|
|
},
|
|
|
|
/**
|
|
* if query is not empty show button for reset filter
|
|
*
|
|
*/
|
|
getFilterClasses(classes) {
|
|
if (this.state.query.length > 0) {
|
|
classes.push('field-select__options-filter--active')
|
|
}
|
|
|
|
return classes.join(' ')
|
|
},
|
|
|
|
/**
|
|
* search all selected for value return index or false
|
|
*
|
|
* @param options object
|
|
*/
|
|
searchSelected(option) {
|
|
let index = false
|
|
|
|
for (let i = 0; i < this.state.selected.length; i++) {
|
|
if (this.state.selected[i] && this.state.selected[i][ this.state.keys.value ] == option[ this.state.keys.value ]) {
|
|
index = i
|
|
break;
|
|
}
|
|
}
|
|
|
|
return index
|
|
},
|
|
|
|
/**
|
|
* reset component
|
|
*
|
|
*/
|
|
reset() {
|
|
this.state.selected = []
|
|
this.state.hasUpdated = false
|
|
|
|
this.update()
|
|
},
|
|
}
|
|
</script>
|
|
</tiny-field-select>
|