Initiated ListBox component
parent
e601e88db2
commit
d696aeda88
|
@ -9,6 +9,7 @@
|
||||||
<div :class="{'submenuhide': activeMenuIndex !== 0, 'submenushow': activeMenuIndex === 0}">
|
<div :class="{'submenuhide': activeMenuIndex !== 0, 'submenushow': activeMenuIndex === 0}">
|
||||||
<div>
|
<div>
|
||||||
<router-link to="/inputtext">● InputText</router-link>
|
<router-link to="/inputtext">● InputText</router-link>
|
||||||
|
<router-link to="/listbox">● ListBox</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
@import '../../components/common/Common.css';
|
@import '../../components/common/Common.css';
|
||||||
@import '../../components/inputtext/InputText.css';
|
@import '../../components/inputtext/InputText.css';
|
||||||
|
@import '../../components/listbox/ListBox.css';
|
||||||
@import '../../components/button/Button.css';
|
@import '../../components/button/Button.css';
|
|
@ -0,0 +1,68 @@
|
||||||
|
.p-listbox {
|
||||||
|
padding: .25em;
|
||||||
|
width: 10em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-listbox .p-listbox-list-wrapper {
|
||||||
|
overflow:auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-listbox .p-listbox-list {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-listbox .p-listbox-item {
|
||||||
|
padding: .25em;
|
||||||
|
border: 0 none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: normal;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-listbox .p-listbox-item > span {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-listbox .p-listbox-item:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-listbox.p-disabled .p-listbox-item {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-listbox-header {
|
||||||
|
margin-bottom: 0.3em;
|
||||||
|
padding: .125em .2em;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-listbox-header .p-checkbox {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-listbox-header .p-listbox-filter-container {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-listbox-header.p-listbox-header-w-checkbox .p-listbox-filter-container {
|
||||||
|
width: calc(100% - 2em);
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-listbox-header .p-listbox-filter-container .p-listbox-filter-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: .25em;
|
||||||
|
left: .25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-listbox-header .p-inputtext {
|
||||||
|
padding: .125em .125em .125em 1.25em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
|
@ -0,0 +1,150 @@
|
||||||
|
<template>
|
||||||
|
<div class="p-listbox p-inputtext p-component">
|
||||||
|
<div class="p-listbox-list-wrapper">
|
||||||
|
<ul class="p-listbox-list">
|
||||||
|
<li v-for="option of options" tabindex="0" :class="['p-listbox-item', {'p-highlight': isSelected(option)}]"
|
||||||
|
:key="getOptionLabel(option)" @click="onOptionClick($event, option)" @touchend="onOptionTouchEnd()">
|
||||||
|
{{getOptionLabel(option)}}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ObjectUtils from '../utils/ObjectUtils';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
value: null,
|
||||||
|
options: Array,
|
||||||
|
disabled: Boolean,
|
||||||
|
dataKey: null,
|
||||||
|
multiple: Boolean,
|
||||||
|
metaKeySelection: Boolean,
|
||||||
|
filter: Boolean,
|
||||||
|
optionLabel: null,
|
||||||
|
optionValue: null
|
||||||
|
},
|
||||||
|
optionTouched: false,
|
||||||
|
methods: {
|
||||||
|
getOptionLabel(option) {
|
||||||
|
return ObjectUtils.resolveFieldData(option, this.optionLabel);
|
||||||
|
},
|
||||||
|
getOptionValue(option) {
|
||||||
|
return this.optionValue ? ObjectUtils.resolveFieldData(option, this.optionValue) : option;
|
||||||
|
},
|
||||||
|
onOptionClick(event, option) {
|
||||||
|
if (this.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.multiple)
|
||||||
|
this.onOptionClickMultiple(event, option);
|
||||||
|
else
|
||||||
|
this.onOptionClickSingle(event, option);
|
||||||
|
|
||||||
|
this.optionTouched = false;
|
||||||
|
},
|
||||||
|
onOptionTouchEnd() {
|
||||||
|
if (this.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.optionTouched = true;
|
||||||
|
},
|
||||||
|
onOptionClickSingle(event, option) {
|
||||||
|
let selected = this.isSelected(option);
|
||||||
|
let valueChanged = false;
|
||||||
|
let value = null;
|
||||||
|
let metaSelection = this.optionTouched ? false : this.metaKeySelection;
|
||||||
|
|
||||||
|
if (metaSelection) {
|
||||||
|
let metaKey = (event.metaKey || event.ctrlKey);
|
||||||
|
|
||||||
|
if (selected) {
|
||||||
|
if (metaKey) {
|
||||||
|
value = null;
|
||||||
|
valueChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
value = this.getOptionValue(option);
|
||||||
|
valueChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
value = selected ? null : this.getOptionValue(option);
|
||||||
|
valueChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueChanged) {
|
||||||
|
this.updateModel(event, value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onOptionClickMultiple(event, option) {
|
||||||
|
let selected = this.isSelected(option);
|
||||||
|
let valueChanged = false;
|
||||||
|
let value = null;
|
||||||
|
let metaSelection = this.optionTouched ? false : this.metaKeySelection;
|
||||||
|
|
||||||
|
if (metaSelection) {
|
||||||
|
let metaKey = (event.metaKey || event.ctrlKey);
|
||||||
|
|
||||||
|
if (selected) {
|
||||||
|
if(metaKey)
|
||||||
|
value = this.removeOption(option);
|
||||||
|
else
|
||||||
|
value = [this.getOptionValue(option)];
|
||||||
|
|
||||||
|
valueChanged = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
value = (metaKey) ? this.value || [] : [];
|
||||||
|
value = [...value, this.getOptionValue(option)];
|
||||||
|
valueChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (selected)
|
||||||
|
value = this.removeOption(option);
|
||||||
|
else
|
||||||
|
value = [...this.value || [], this.getOptionValue(option)];
|
||||||
|
|
||||||
|
valueChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(valueChanged) {
|
||||||
|
this.updateModel(event, value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isSelected(option) {
|
||||||
|
let selected = false;
|
||||||
|
let optionValue = this.getOptionValue(option);
|
||||||
|
|
||||||
|
if (this.multiple) {
|
||||||
|
if (this.value) {
|
||||||
|
for (let val of this.value) {
|
||||||
|
if (ObjectUtils.equals(val, optionValue, this.dataKey)) {
|
||||||
|
selected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
selected = ObjectUtils.equals(this.value, optionValue, this.dataKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return selected;
|
||||||
|
},
|
||||||
|
removeOption(option) {
|
||||||
|
return this.value.filter(val => !ObjectUtils.equals(val, this.getOptionValue(option), this.dataKey));
|
||||||
|
},
|
||||||
|
updateModel(event, value) {
|
||||||
|
this.$emit('input', value);
|
||||||
|
this.$emit('change', {originalEvent: event, value: value});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,201 @@
|
||||||
|
export default class ObjectUtils {
|
||||||
|
|
||||||
|
static equals(obj1, obj2, field) {
|
||||||
|
if(field)
|
||||||
|
return (this.resolveFieldData(obj1, field) === this.resolveFieldData(obj2, field));
|
||||||
|
else
|
||||||
|
return this.equalsByValue(obj1, obj2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static equalsByValue(obj1, obj2) {
|
||||||
|
if (obj1 === null && obj2 === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj1 === null || obj2 === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj1 === obj2) {
|
||||||
|
delete obj1._$visited;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof obj1 === 'object' && typeof obj2 === 'object') {
|
||||||
|
obj1._$visited = true;
|
||||||
|
for (var p in obj1) {
|
||||||
|
if (p === "_$visited") continue;
|
||||||
|
if (obj1.hasOwnProperty(p) !== obj2.hasOwnProperty(p)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (typeof (obj1[p])) {
|
||||||
|
case 'object':
|
||||||
|
if ((obj1[p] && obj1[p]._$visited) || !this.equals(obj1[p], obj2[p])) return false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'function':
|
||||||
|
if (typeof (obj2[p]) === 'undefined' || (p !== 'compare' && obj1[p].toString() !== obj2[p].toString())) return false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (obj1[p] !== obj2[p]) return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var pp in obj2) {
|
||||||
|
if (typeof (obj1[pp]) === 'undefined') return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete obj1._$visited;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static resolveFieldData(data, field) {
|
||||||
|
if(data && field) {
|
||||||
|
if(field.indexOf('.') === -1) {
|
||||||
|
return data[field];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let fields = field.split('.');
|
||||||
|
let value = data;
|
||||||
|
for(var i = 0, len = fields.length; i < len; ++i) {
|
||||||
|
value = value[fields[i]];
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static filter(value, fields, filterValue) {
|
||||||
|
var filteredItems=[];
|
||||||
|
|
||||||
|
if(value) {
|
||||||
|
for(let item of value) {
|
||||||
|
for(let field of fields) {
|
||||||
|
if(String(this.resolveFieldData(item, field)).toLowerCase().indexOf(filterValue.toLowerCase()) > -1) {
|
||||||
|
filteredItems.push(item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filteredItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
static reorderArray(value, from, to) {
|
||||||
|
let target;
|
||||||
|
if(value && (from !== to)) {
|
||||||
|
if(to >= value.length) {
|
||||||
|
target = to - value.length;
|
||||||
|
while((target--) + 1) {
|
||||||
|
value.push(undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value.splice(to, 0, value.splice(from, 1)[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static findIndexInList(value, list) {
|
||||||
|
let index = -1;
|
||||||
|
|
||||||
|
if(list) {
|
||||||
|
for(let i = 0; i < list.length; i++) {
|
||||||
|
if(list[i] === value) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static filterConstraints = {
|
||||||
|
|
||||||
|
startsWith(value, filter) {
|
||||||
|
if(filter === undefined || filter === null || filter.trim() === '') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value === undefined || value === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let filterValue = filter.toLowerCase();
|
||||||
|
return value.toString().toLowerCase().slice(0, filterValue.length) === filterValue;
|
||||||
|
},
|
||||||
|
|
||||||
|
contains(value, filter) {
|
||||||
|
if(filter === undefined || filter === null || (typeof filter === 'string' && filter.trim() === '')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value === undefined || value === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.toString().toLowerCase().indexOf(filter.toLowerCase()) !== -1;
|
||||||
|
},
|
||||||
|
|
||||||
|
endsWith(value, filter) {
|
||||||
|
if(filter === undefined || filter === null || filter.trim() === '') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value === undefined || value === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let filterValue = filter.toString().toLowerCase();
|
||||||
|
return value.toString().toLowerCase().indexOf(filterValue, value.toString().length - filterValue.length) !== -1;
|
||||||
|
},
|
||||||
|
|
||||||
|
equals(value, filter) {
|
||||||
|
if(filter === undefined || filter === null || (typeof filter === 'string' && filter.trim() === '')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value === undefined || value === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.toString().toLowerCase() === filter.toString().toLowerCase();
|
||||||
|
},
|
||||||
|
|
||||||
|
notEquals(value, filter) {
|
||||||
|
if(filter === undefined || filter === null || (typeof filter === 'string' && filter.trim() === '')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value === undefined || value === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.toString().toLowerCase() !== filter.toString().toLowerCase();
|
||||||
|
},
|
||||||
|
|
||||||
|
in(value, filter) {
|
||||||
|
if(filter === undefined || filter === null || filter.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value === undefined || value === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let i = 0; i < filter.length; i++) {
|
||||||
|
if(filter[i] === value)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ import Vue from 'vue';
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
import router from './router';
|
import router from './router';
|
||||||
import InputText from './components/inputtext/InputText';
|
import InputText from './components/inputtext/InputText';
|
||||||
|
import ListBox from './components/listbox/ListBox';
|
||||||
import Button from './components/button/Button';
|
import Button from './components/button/Button';
|
||||||
|
|
||||||
import './assets/styles/primevue.css';
|
import './assets/styles/primevue.css';
|
||||||
|
@ -12,6 +13,7 @@ Vue.config.productionTip = false;
|
||||||
|
|
||||||
Vue.component('p-inputtext', InputText);
|
Vue.component('p-inputtext', InputText);
|
||||||
Vue.component('p-button', Button);
|
Vue.component('p-button', Button);
|
||||||
|
Vue.component('p-listBox', ListBox);
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
router,
|
router,
|
||||||
|
|
|
@ -21,6 +21,11 @@ export default new Router({
|
||||||
name: 'inputtext',
|
name: 'inputtext',
|
||||||
component: () => import('./views/inputtext/InputTextDemo.vue')
|
component: () => import('./views/inputtext/InputTextDemo.vue')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/listbox',
|
||||||
|
name: 'listbox',
|
||||||
|
component: () => import('./views/listbox/ListBoxDemo.vue')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/button',
|
path: '/button',
|
||||||
name: 'button',
|
name: 'button',
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="content-section introduction">
|
||||||
|
<div class="feature-intro">
|
||||||
|
<h1>ListBox</h1>
|
||||||
|
<p>ListBox is used to select one or more values from a list of items.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content-section implementation">
|
||||||
|
<h3 class="first">Single</h3>
|
||||||
|
<p-listBox v-model="selectedCity" :options="cities" optionLabel="name" />{{selectedCity}}
|
||||||
|
|
||||||
|
<h3>Multiple</h3>
|
||||||
|
<p-listBox :multiple="true" v-model="selectedCities" :options="cities" optionLabel="name" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selectedCity: null,
|
||||||
|
selectedCities: null,
|
||||||
|
cities: [
|
||||||
|
{name: 'New York', code: 'NY'},
|
||||||
|
{name: 'Rome', code: 'RM'},
|
||||||
|
{name: 'London', code: 'LDN'},
|
||||||
|
{name: 'Istanbul', code: 'IST'},
|
||||||
|
{name: 'Paris', code: 'PRS'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
Loading…
Reference in New Issue