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

<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) } }>
&#11198;
</button>
</div>
<div class="panel">
<div class="bar justify-content-end">
<div class="bar__end">
{ state.selected.length } / { state.options.length } &#128455;
</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">
&#9745;
</span>
<span class="field-select__options-item-uncheck">
&#9744;
</span>
{ option[ state.keys.label ] }
</li>
<li class="field-select__item field-select__item--empty center color-danger" if={ state.options.length === 0 }>
&#8709;
</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>