UNPKG

4.92 kBJavaScriptView Raw
1import Animate from '../mixin/animate';
2import {$$, $, append, assign, css, data, each, fastdom, hasClass, includes, isEmpty, isEqual, isUndefined, matches, parseOptions, toggleClass, toNodes, trigger} from 'uikit-util';
3
4export default {
5
6 mixins: [Animate],
7
8 args: 'target',
9
10 props: {
11 target: Boolean,
12 selActive: Boolean
13 },
14
15 data: {
16 target: null,
17 selActive: false,
18 attrItem: 'uk-filter-control',
19 cls: 'uk-active',
20 animation: 250
21 },
22
23 computed: {
24
25 toggles: {
26
27 get({attrItem}, $el) {
28 return $$(`[${this.attrItem}],[data-${this.attrItem}]`, $el);
29 },
30
31 watch() {
32 this.updateState();
33 }
34
35 },
36
37 target({target}, $el) {
38 return $(target, $el);
39 },
40
41 children: {
42
43 get() {
44 return toNodes(this.target && this.target.children);
45 },
46
47 watch(list, old) {
48 if (!isEqualList(list, old)) {
49 this.updateState();
50 }
51 }
52 }
53
54 },
55
56 events: [
57
58 {
59
60 name: 'click',
61
62 delegate() {
63 return `[${this.attrItem}],[data-${this.attrItem}]`;
64 },
65
66 handler(e) {
67
68 e.preventDefault();
69 this.apply(e.current);
70
71 }
72
73 }
74
75 ],
76
77 connected() {
78
79 this.updateState();
80
81 if (this.selActive !== false) {
82 const actives = $$(this.selActive, this.$el);
83 this.toggles.forEach(el => toggleClass(el, this.cls, includes(actives, el)));
84 }
85
86 },
87
88 methods: {
89
90 apply(el) {
91 this.setState(mergeState(el, this.attrItem, this.getState()));
92 },
93
94 getState() {
95 return this.toggles
96 .filter(item => hasClass(item, this.cls))
97 .reduce((state, el) => mergeState(el, this.attrItem, state), {filter: {'': ''}, sort: []});
98 },
99
100 setState(state, animate = true) {
101
102 state = assign({filter: {'': ''}, sort: []}, state);
103
104 trigger(this.$el, 'beforeFilter', [this, state]);
105
106 const {children} = this;
107
108 this.toggles.forEach(el => toggleClass(el, this.cls, !!matchFilter(el, this.attrItem, state)));
109
110 const apply = () => {
111
112 const selector = getSelector(state);
113
114 children.forEach(el => css(el, 'display', selector && !matches(el, selector) ? 'none' : ''));
115
116 const [sort, order] = state.sort;
117
118 if (sort) {
119 const sorted = sortItems(children, sort, order);
120 if (!isEqual(sorted, children)) {
121 sorted.forEach(el => append(this.target, el));
122 }
123 }
124
125 };
126
127 if (animate) {
128 this.animate(apply).then(() => trigger(this.$el, 'afterFilter', [this]));
129 } else {
130 apply();
131 trigger(this.$el, 'afterFilter', [this]);
132 }
133
134 },
135
136 updateState() {
137 fastdom.write(() => this.setState(this.getState(), false));
138 }
139
140 }
141
142};
143
144function getFilter(el, attr) {
145 return parseOptions(data(el, attr), ['filter']);
146}
147
148function mergeState(el, attr, state) {
149
150 const filterBy = getFilter(el, attr);
151 const {filter, group, sort, order = 'asc'} = filterBy;
152
153 if (filter || isUndefined(sort)) {
154
155 if (group) {
156
157 if (filter) {
158 delete state.filter[''];
159 state.filter[group] = filter;
160 } else {
161 delete state.filter[group];
162
163 if (isEmpty(state.filter) || '' in state.filter) {
164 state.filter = {'': filter || ''};
165 }
166
167 }
168
169 } else {
170 state.filter = {'': filter || ''};
171 }
172
173 }
174
175 if (!isUndefined(sort)) {
176 state.sort = [sort, order];
177 }
178
179 return state;
180}
181
182function matchFilter(el, attr, {filter: stateFilter = {'': ''}, sort: [stateSort, stateOrder]}) {
183
184 const {filter = '', group = '', sort, order = 'asc'} = getFilter(el, attr);
185
186 return isUndefined(sort)
187 ? group in stateFilter && filter === stateFilter[group]
188 || !filter && group && !(group in stateFilter) && !stateFilter['']
189 : stateSort === sort && stateOrder === order;
190}
191
192function isEqualList(listA, listB) {
193 return listA.length === listB.length
194 && listA.every(el => ~listB.indexOf(el));
195}
196
197function getSelector({filter}) {
198 let selector = '';
199 each(filter, value => selector += value || '');
200 return selector;
201}
202
203function sortItems(nodes, sort, order) {
204 return assign([], nodes).sort((a, b) => data(a, sort).localeCompare(data(b, sort), undefined, {numeric: true}) * (order === 'asc' || -1));
205}