@qikdev/vue-ui 0.0.2 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/content/browser.vue +23 -7
- package/src/filter/FilterBuilder.vue +3 -6
- package/src/form/field.vue +10 -0
- package/src/form/inputs/content-select.vue +2 -2
- package/src/form/inputs/textfield.vue +24 -4
- package/src/form/inputs/type-select.vue +247 -0
- package/src/layout/flex-column.vue +4 -0
- package/src/layout/flex-row.vue +4 -0
- package/src/modal/ContentModal.vue +0 -1
- package/src/ui/button.vue +2 -1
package/package.json
CHANGED
package/src/content/browser.vue
CHANGED
|
@@ -7,17 +7,23 @@
|
|
|
7
7
|
<flex-cell flex>
|
|
8
8
|
<native-table :total="totalItems" :selectAll="selectAll" :deselectAll="deselectAllFunction" :actions="false" :selection="manager.items" @click:row="rowClicked" @select:row:toggle="rowToggled" @select:multiple="selectMultiple" @deselect:multiple="deselectMultiple" :rows="items" :columns="columns" />
|
|
9
9
|
</flex-cell>
|
|
10
|
-
<flex-column style="max-width: 600px;">
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
<flex-column class="filter-column" style="max-width: 600px;" v-if="showFilters">
|
|
11
|
+
<flex-body>
|
|
12
|
+
<search v-model="search" :loading="searching" :debounce="500" placeholder="Keyword Search" />
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
<p></p>
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
14
19
|
<filter-builder :definition="definition" v-model="filter" />
|
|
20
|
+
</flex-body>
|
|
15
21
|
</flex-column>
|
|
16
22
|
</flex-row>
|
|
17
23
|
</flex-column>
|
|
18
24
|
<flex-footer>
|
|
19
25
|
<div class="footer">
|
|
20
|
-
<flex-row center>
|
|
26
|
+
<flex-row center gap >
|
|
21
27
|
<flex-cell shrink class="text">
|
|
22
28
|
<native-select v-model="perPage" :field="perPageField">
|
|
23
29
|
Showing {{displayStartIndex}} to {{endIndex}} of {{totalItems}} total
|
|
@@ -25,8 +31,8 @@
|
|
|
25
31
|
</flex-cell>
|
|
26
32
|
<flex-cell>
|
|
27
33
|
</flex-cell>
|
|
28
|
-
<flex-cell shrink>
|
|
29
|
-
<flex-row center>
|
|
34
|
+
<flex-cell shrink v-if="totalPages > 1">
|
|
35
|
+
<flex-row gap center>
|
|
30
36
|
<flex-cell shrink class="text">
|
|
31
37
|
<native-select v-model="currentPage" :field="pageField">
|
|
32
38
|
Page {{currentPage}} of {{totalPages}}
|
|
@@ -56,6 +62,7 @@ import NativeTable from '../table/Table.vue';
|
|
|
56
62
|
|
|
57
63
|
import FilterBuilder from '../filter/FilterBuilder.vue';
|
|
58
64
|
import Selection from '../services/selection.js';
|
|
65
|
+
import Search from '../form/inputs/search.vue';
|
|
59
66
|
|
|
60
67
|
|
|
61
68
|
// import FilterRule from '../filter/FilterRule.vue';
|
|
@@ -69,6 +76,9 @@ export default {
|
|
|
69
76
|
type: String,
|
|
70
77
|
required: true,
|
|
71
78
|
},
|
|
79
|
+
showFilters:{
|
|
80
|
+
type:Boolean,
|
|
81
|
+
},
|
|
72
82
|
search: {
|
|
73
83
|
type: String,
|
|
74
84
|
},
|
|
@@ -101,6 +111,7 @@ export default {
|
|
|
101
111
|
NativeSelect,
|
|
102
112
|
NativeTable,
|
|
103
113
|
FilterBuilder,
|
|
114
|
+
Search,
|
|
104
115
|
// FilterRule,
|
|
105
116
|
},
|
|
106
117
|
async created() {
|
|
@@ -464,6 +475,11 @@ export default {
|
|
|
464
475
|
}
|
|
465
476
|
}
|
|
466
477
|
|
|
478
|
+
.filter-column {
|
|
479
|
+
padding:1em;
|
|
480
|
+
background: rgba(#000, 0.1);
|
|
481
|
+
}
|
|
482
|
+
|
|
467
483
|
|
|
468
484
|
.footer {
|
|
469
485
|
padding: 1em;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<flex-column class="filter-builder">
|
|
3
3
|
<flex-body>
|
|
4
4
|
<div class="filters">
|
|
5
|
-
<div class="top">
|
|
5
|
+
<div class="top" v-if="model.filters.length">
|
|
6
6
|
<div class="summary">
|
|
7
7
|
Match <native-select v-model="model.operator" :field="operatorField">
|
|
8
8
|
{{summary}}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
</div>
|
|
11
11
|
</div>
|
|
12
12
|
<filter-rule :enableRemove="model.filters.length > 1" :key="`rule-${index}`" @remove="removeRule(index)" :definition="definition" v-model="model.filters[index]" :index="index" v-for="(rule, index) in model.filters" />
|
|
13
|
-
<ux-button @click="addRule()">Add Rule</ux-button>
|
|
13
|
+
<ux-button @click="addRule()">Add Filter Rule</ux-button>
|
|
14
14
|
</div>
|
|
15
15
|
</flex-body>
|
|
16
16
|
</flex-column>
|
|
@@ -119,12 +119,9 @@ export default {
|
|
|
119
119
|
</script>
|
|
120
120
|
<style lang="scss" scoped>
|
|
121
121
|
.filter-builder {
|
|
122
|
-
|
|
122
|
+
|
|
123
123
|
|
|
124
124
|
|
|
125
|
-
.filters {
|
|
126
|
-
padding:0.7em;
|
|
127
|
-
}
|
|
128
125
|
|
|
129
126
|
.summary {
|
|
130
127
|
font-size: 0.8em;
|
package/src/form/field.vue
CHANGED
|
@@ -35,6 +35,10 @@
|
|
|
35
35
|
<template v-if="widget == 'content-select'">
|
|
36
36
|
<content-select @touched="touch" :field="actualField" v-model="fieldModel" />
|
|
37
37
|
</template>
|
|
38
|
+
|
|
39
|
+
<template v-if="widget == 'type-select'">
|
|
40
|
+
<type-select @touched="touch" :field="actualField" v-model="fieldModel" />
|
|
41
|
+
</template>
|
|
38
42
|
<template v-if="widget == 'richtext'">
|
|
39
43
|
<text-area @touched="touch" :field="actualField" v-model="fieldModel" />
|
|
40
44
|
</template>
|
|
@@ -70,6 +74,7 @@
|
|
|
70
74
|
import PhoneNumberInput from './inputs/phone-number-input.vue';
|
|
71
75
|
import TimezoneSelect from './inputs/timezone.vue';
|
|
72
76
|
import ContentSelect from './inputs/content-select.vue';
|
|
77
|
+
import TypeSelect from './inputs/type-select.vue';
|
|
73
78
|
import CurrencyField from './inputs/currency.vue';
|
|
74
79
|
import TextField from './inputs/textfield.vue';
|
|
75
80
|
import TextArea from './inputs/textarea.vue';
|
|
@@ -137,6 +142,7 @@ export default {
|
|
|
137
142
|
BooleanSwitch: Switch,
|
|
138
143
|
FieldGroup,
|
|
139
144
|
ContentSelect,
|
|
145
|
+
TypeSelect,
|
|
140
146
|
TimezoneSelect,
|
|
141
147
|
PhoneNumberInput,
|
|
142
148
|
Upload,
|
|
@@ -529,6 +535,10 @@ export default {
|
|
|
529
535
|
case 'upload':
|
|
530
536
|
case 'options':
|
|
531
537
|
case 'button':
|
|
538
|
+
case 'type-select':
|
|
539
|
+
break;
|
|
540
|
+
case 'password':
|
|
541
|
+
return 'textfield';
|
|
532
542
|
break;
|
|
533
543
|
case 'phone':
|
|
534
544
|
case 'phonenumber':
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<div class="items" v-if="model && model.length">
|
|
6
6
|
<item :key="item._id" :item="item" v-for="(item, index) in model">
|
|
7
7
|
<template #actions>
|
|
8
|
-
<ux-button icon @click="remove(item)">
|
|
8
|
+
<ux-button icon @click.stop.prevent="remove(item)">
|
|
9
9
|
<ux-icon icon="fa-times" />
|
|
10
10
|
</ux-button>
|
|
11
11
|
</template>
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<div class="items">
|
|
17
17
|
<item :item="model">
|
|
18
18
|
<template #actions>
|
|
19
|
-
<ux-button icon @click="clear">
|
|
19
|
+
<ux-button icon @click.stop.prevent="clear">
|
|
20
20
|
<ux-icon icon="fa-times" />
|
|
21
21
|
</ux-button>
|
|
22
22
|
</template>
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
<flex-cell>
|
|
7
7
|
<div class="ux-text-wrap">
|
|
8
8
|
<span class="ux-text-prefix" v-if="prefix">{{prefix}}</span>
|
|
9
|
-
<input v-if="lazy" class="ux-field-focus ux-text-input-multiple" :placeholder="actualPlaceholder" @focus="touch" ref="input" @keydown.enter.stop.prevent="add()" v-model.lazy="model[index]" />
|
|
10
|
-
<input v-if="!lazy" class="ux-field-focus ux-text-input-multiple" :placeholder="actualPlaceholder" @focus="touch" ref="input" @keydown.enter.stop.prevent="add()" v-model="model[index]" />
|
|
9
|
+
<input :type="inputType" v-if="lazy" class="ux-field-focus ux-text-input-multiple" :placeholder="actualPlaceholder" @focus="touch" ref="input" @keydown.enter.stop.prevent="add()" v-model.lazy="model[index]" />
|
|
10
|
+
<input :type="inputType" v-if="!lazy" class="ux-field-focus ux-text-input-multiple" :placeholder="actualPlaceholder" @focus="touch" ref="input" @keydown.enter.stop.prevent="add()" v-model="model[index]" />
|
|
11
11
|
<span class="ux-text-suffix" v-if="suffix">{{suffix}}</span>
|
|
12
12
|
</div>
|
|
13
13
|
</flex-cell>
|
|
@@ -22,11 +22,12 @@
|
|
|
22
22
|
<template v-else>
|
|
23
23
|
<div class="ux-text-wrap">
|
|
24
24
|
<span class="ux-text-prefix" v-if="prefix">{{prefix}}</span>
|
|
25
|
-
<input v-if="lazy" ref="input" class="ux-field-focus ux-text-input-single" :placeholder="actualPlaceholder" @focus="touch" v-model.lazy="model" />
|
|
26
|
-
<input v-if="!lazy" ref="input" class="ux-field-focus ux-text-input-single" :placeholder="actualPlaceholder" @focus="touch" v-model="model" />
|
|
25
|
+
<input :type="inputType" v-if="lazy" ref="input" class="ux-field-focus ux-text-input-single" :placeholder="actualPlaceholder" @focus="touch" v-model.lazy="model" />
|
|
26
|
+
<input :type="inputType" v-if="!lazy" ref="input" class="ux-field-focus ux-text-input-single" :placeholder="actualPlaceholder" @focus="touch" v-model="model" />
|
|
27
27
|
<span class="ux-text-suffix" v-if="suffix">{{suffix}}</span>
|
|
28
28
|
</div>
|
|
29
29
|
</template>
|
|
30
|
+
|
|
30
31
|
</template>
|
|
31
32
|
<script>
|
|
32
33
|
import InputMixin from './input-mixin';
|
|
@@ -42,6 +43,25 @@ export default {
|
|
|
42
43
|
},
|
|
43
44
|
mixins: [InputMixin],
|
|
44
45
|
computed: {
|
|
46
|
+
inputType() {
|
|
47
|
+
switch(this.field.widget) {
|
|
48
|
+
case 'password':
|
|
49
|
+
case 'email':
|
|
50
|
+
return this.field.widget;
|
|
51
|
+
break;
|
|
52
|
+
default:
|
|
53
|
+
|
|
54
|
+
switch(this.field.type) {
|
|
55
|
+
case 'email':
|
|
56
|
+
return 'email';
|
|
57
|
+
break;
|
|
58
|
+
default:
|
|
59
|
+
return 'text';
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
},
|
|
45
65
|
lazy() {
|
|
46
66
|
switch (this.type) {
|
|
47
67
|
case 'integer':
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="native-select" :class="classes">
|
|
3
|
+
<label class="ux-field-title" v-if="showLabel">{{label}} <span class="ux-required-marker" v-if="required">*</span></label>
|
|
4
|
+
<div class="ux-field-description" v-if="showDescription">{{description}}</div>
|
|
5
|
+
<div class="ui-select-button" v-if="singleValue">
|
|
6
|
+
<slot>
|
|
7
|
+
<ux-button tag="div">
|
|
8
|
+
{{summary}}
|
|
9
|
+
</ux-button>
|
|
10
|
+
</slot>
|
|
11
|
+
</div>
|
|
12
|
+
<select @focus="touch" :multiple="multiValue" v-model="model">
|
|
13
|
+
<option value="" v-if="singleValue && !minimum">None</option>
|
|
14
|
+
<option :value="option.value" v-for="option in selectableOptions">{{option.title}}</option>
|
|
15
|
+
</select>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
<script>
|
|
19
|
+
import InputMixin from './input-mixin';
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
function isUndefined(entry) {
|
|
24
|
+
return entry === undefined || typeof entry === 'undefined' || entry === null || String(entry) === 'null' || String(entry) === 'undefined';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//////////////////////////
|
|
28
|
+
|
|
29
|
+
export default {
|
|
30
|
+
props: {
|
|
31
|
+
title: {
|
|
32
|
+
type: String,
|
|
33
|
+
},
|
|
34
|
+
modelValue: {
|
|
35
|
+
// type: [Object, Array],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
mixins: [InputMixin],
|
|
39
|
+
async created() {
|
|
40
|
+
this.model = this.model;
|
|
41
|
+
|
|
42
|
+
var glossary = await this.$qik.content.glossary();
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
var typeList = glossary;
|
|
46
|
+
|
|
47
|
+
if (this.field.basicTypes === false) {
|
|
48
|
+
typeList = typeList.filter(function(definition) {
|
|
49
|
+
return !!definition.definesType
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (this.field.definedTypes === false) {
|
|
54
|
+
typeList = typeList.filter(function(definition) {
|
|
55
|
+
return !definition.definesType
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
////////////////////////////
|
|
60
|
+
|
|
61
|
+
typeList = typeList.map(function(definition) {
|
|
62
|
+
return {
|
|
63
|
+
title: definition.title,
|
|
64
|
+
value: definition.key,
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
.sort((a, b) => a.title > b.title ? 1 : -1);
|
|
68
|
+
|
|
69
|
+
////////////////////////////
|
|
70
|
+
|
|
71
|
+
this.types = typeList;
|
|
72
|
+
},
|
|
73
|
+
data() {
|
|
74
|
+
return {
|
|
75
|
+
types: [],
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
methods: {
|
|
79
|
+
cleanOutput(val) {
|
|
80
|
+
var self = this;
|
|
81
|
+
|
|
82
|
+
if (isUndefined(val)) {
|
|
83
|
+
if (self.multiValue) {
|
|
84
|
+
val = [];
|
|
85
|
+
} else {
|
|
86
|
+
val = undefined;
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
if (self.multiValue) {
|
|
90
|
+
val = (val || []).filter(Boolean).map(function(i) {
|
|
91
|
+
return self.getValue(i);
|
|
92
|
+
})
|
|
93
|
+
} else {
|
|
94
|
+
val = self.getValue(val);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return val;
|
|
99
|
+
},
|
|
100
|
+
cleanInput(val) {
|
|
101
|
+
|
|
102
|
+
var self = this;
|
|
103
|
+
|
|
104
|
+
if (self.multiValue) {
|
|
105
|
+
if (!val) {
|
|
106
|
+
val = [];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (!Array.isArray(val)) {
|
|
110
|
+
val = [val];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/////////////////////////////////
|
|
114
|
+
|
|
115
|
+
if (self.maximum) {
|
|
116
|
+
if (val.length > self.maximum) {
|
|
117
|
+
val.length = self.maximum;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
val = val.filter(Boolean).map(function(v) {
|
|
123
|
+
var valueKey = self.getValue(v);
|
|
124
|
+
return self.returnObject ? self.optionLookup[valueKey] : valueKey;
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
} else {
|
|
128
|
+
var valueKey = self.getValue(val);
|
|
129
|
+
val = self.returnObject ? self.optionLookup[valueKey] : valueKey;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return val;
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
computed: {
|
|
136
|
+
returnObject() {
|
|
137
|
+
return false;
|
|
138
|
+
},
|
|
139
|
+
classes() {
|
|
140
|
+
var array = []
|
|
141
|
+
|
|
142
|
+
if (this.multiValue) {
|
|
143
|
+
array.push('multiple');
|
|
144
|
+
} else {
|
|
145
|
+
array.push('single');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return array;
|
|
149
|
+
},
|
|
150
|
+
// model: {
|
|
151
|
+
// get() {
|
|
152
|
+
// let val = this.cleanOutput(this.value);
|
|
153
|
+
// return val;
|
|
154
|
+
// },
|
|
155
|
+
// set(val) {
|
|
156
|
+
// val = this.cleanInput(val);
|
|
157
|
+
// // // var val = this.cleanOutput(newValue);
|
|
158
|
+
// // // var existing = this.cleanOutput(this.value);
|
|
159
|
+
|
|
160
|
+
// // if (newValue != existing) {
|
|
161
|
+
// // newValue = this.cleanInput(val);
|
|
162
|
+
// // this.value = newValue;
|
|
163
|
+
// // this.dispatch();
|
|
164
|
+
// // }
|
|
165
|
+
|
|
166
|
+
// this.value = val;
|
|
167
|
+
// this.dispatch();
|
|
168
|
+
|
|
169
|
+
// }
|
|
170
|
+
// },
|
|
171
|
+
optionLookup() {
|
|
172
|
+
var self = this;
|
|
173
|
+
return self.types.reduce(function(set, option) {
|
|
174
|
+
const key = self.getValue(option);
|
|
175
|
+
set[key] = option;
|
|
176
|
+
return set;
|
|
177
|
+
}, {})
|
|
178
|
+
},
|
|
179
|
+
summary() {
|
|
180
|
+
return this.model ? this.getLabel(this.optionLookup[this.model]) : this.title || 'Click to select';
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
selectableOptions() {
|
|
184
|
+
|
|
185
|
+
return this.types;
|
|
186
|
+
// return this.options
|
|
187
|
+
// .sort(function(option) {
|
|
188
|
+
// return option.title;
|
|
189
|
+
// });
|
|
190
|
+
// if(this.type == 'reference') {
|
|
191
|
+
|
|
192
|
+
// } else {
|
|
193
|
+
|
|
194
|
+
// }
|
|
195
|
+
|
|
196
|
+
},
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
</script>
|
|
200
|
+
<style lang="scss" scoped>
|
|
201
|
+
.native-select {
|
|
202
|
+
|
|
203
|
+
cursor: pointer;
|
|
204
|
+
|
|
205
|
+
&.multiple {
|
|
206
|
+
select {
|
|
207
|
+
width: 100%;
|
|
208
|
+
font-size: 1em;
|
|
209
|
+
border: 1px solid rgba(#000, 0.1);
|
|
210
|
+
appearance: none;
|
|
211
|
+
|
|
212
|
+
&:focus {
|
|
213
|
+
border: 1px solid $primary;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
&.single {
|
|
219
|
+
position: relative;
|
|
220
|
+
|
|
221
|
+
.ui-select-button {
|
|
222
|
+
position: relative;
|
|
223
|
+
width: 100%;
|
|
224
|
+
|
|
225
|
+
&>.ux-btn {
|
|
226
|
+
display: block;
|
|
227
|
+
text-align: left;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
select {
|
|
232
|
+
cursor: pointer;
|
|
233
|
+
opacity: 0;
|
|
234
|
+
appearance: none;
|
|
235
|
+
width: 100%;
|
|
236
|
+
height: 100%;
|
|
237
|
+
position: absolute;
|
|
238
|
+
top: 0;
|
|
239
|
+
left: 0;
|
|
240
|
+
bottom: 0;
|
|
241
|
+
right: 0;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
}
|
|
247
|
+
</style>
|
package/src/layout/flex-row.vue
CHANGED