UNPKG

10.9 kBJavaScriptView Raw
1
2import { Ajax } from './bunny.ajax';
3import { Template } from './bunny.template';
4import { Pagination } from './Pagination';
5import { BunnyURL } from './url';
6import { ready, addEventOnce, makeAccessible, parseTemplate} from './utils/DOM';
7import { pushCallbackToElement, callElementCallbacks, initObjectExtensions } from './utils/core';
8
9export const DataTableConfig = {
10 tagName: 'datatable',
11 attrUrl: 'url',
12 attrTemplate: 'template',
13
14 tagNamePagination: 'pagination',
15 tagNameStats: 'stats',
16
17 classNameAsc: 'arrow-down',
18 classNameDesc: 'arrow-up',
19
20 perPage: 15,
21 paginationLimit: 7,
22
23 ajaxHeaders: []
24};
25
26export const DataTableUI = {
27
28 Config: DataTableConfig,
29 Template: Template,
30
31 getSearchInput(datatable, name) {
32 return datatable.querySelector('[name="' + name + '"]') || false;
33 },
34
35 getColumn(datatable, name) {
36 return this.getTable(datatable).querySelector('[pid="' + name + '"]') || false;
37 },
38
39 getAllSearchInputs(datatable) {
40 return datatable.querySelectorAll('input, select');
41 },
42
43 getTable(datatable) {
44 return datatable.getElementsByTagName('table')[0];
45 },
46
47 getOrderCells(datatable) {
48 return datatable.querySelectorAll('th[pid]');
49 },
50
51 getPagination(datatable) {
52 return datatable.getElementsByTagName(this.Config.tagNamePagination)[0];
53 },
54
55 getStats(datatable) {
56 return datatable.getElementsByTagName(this.Config.tagNameStats)[0];
57 },
58
59 removeRows(datatable) {
60 const table = this.getTable(datatable);
61 const rowCount = table.rows.length;
62 for (let i = rowCount - 1; i > 0; i--) {
63 table.deleteRow(i);
64 }
65 },
66
67 insertRows(datatable, rowsData, templateId) {
68 const tpl = document.getElementById(templateId);
69 if (tpl.tagName === 'TEMPLATE') {
70 this.getTable(datatable).appendChild(parseTemplate(templateId, rowsData));
71 } else {
72 this.Template.insertAll(templateId, rowsData, this.getTable(datatable));
73 }
74 },
75
76 clearAllColumnsOrder(thCell) {
77 const thCells = thCell.parentNode.querySelectorAll('th');
78 [].forEach.call(thCells, cell => {
79 cell.classList.remove(this.Config.classNameAsc);
80 cell.classList.remove(this.Config.classNameDesc);
81 });
82 },
83
84 setColumnAsc(thCell) {
85 this.clearAllColumnsOrder(thCell);
86 thCell.classList.add(this.Config.classNameAsc);
87 },
88
89 setColumnDesc(thCell) {
90 this.clearAllColumnsOrder(thCell);
91 thCell.classList.add(this.Config.classNameDesc);
92 },
93
94 isColumnAsc(thCell) {
95 return thCell.classList.contains(this.Config.classNameAsc);
96 },
97
98 isColumnDesc(thCell) {
99 return thCell.classList.contains(this.Config.classNameDesc);
100 },
101
102};
103
104export const DataTable = {
105
106 Config: DataTableConfig,
107 UI: DataTableUI,
108
109 Ajax: Ajax,
110 Pagination: Pagination,
111
112 init(datatable) {
113 if (datatable.__bunny_datatable === undefined) {
114 datatable.__bunny_datatable = {};
115 } else {
116 return false;
117 }
118
119 let page = BunnyURL.getParam('page');
120 if (page === undefined) {
121 page = 1;
122 }
123
124 this.addEvents(datatable);
125
126 initObjectExtensions(this, datatable);
127
128 const orderData = this.getOrderDataFromURL(datatable);
129 if (orderData['order_by'] !== undefined) {
130 const thCell = this.UI.getColumn(datatable, orderData['order_by']);
131 if (orderData['order_rule'] === 'asc') {
132 this.UI.setColumnAsc(thCell);
133 } else {
134 this.UI.setColumnDesc(thCell);
135 }
136 }
137
138 this.setARIA(datatable);
139
140 this.changePage(datatable, page, this.getSearchAndOrderDataFromURL(datatable));
141
142 return true;
143 },
144
145 initAll() {
146 ready( () => {
147 [].forEach.call(document.getElementsByTagName(this.Config.tagName), datatable => {
148 this.init(datatable);
149 })
150 });
151 },
152
153 isInitiated(datatable) {
154 return datatable.__bunny_datatable !== undefined;
155 },
156
157
158
159 getTemplateId(datatable) {
160 return datatable.getAttribute(this.Config.attrTemplate);
161 },
162
163 getAjaxUrl(datatable) {
164 return datatable.getAttribute(this.Config.attrUrl);
165 },
166
167 getAjaxHeaders() {
168 let headers = {};
169 DataTableConfig.ajaxHeaders.forEach(header => {
170 const parts = header.split(': ');
171 headers[parts[0]] = parts[1];
172 });
173 return headers;
174 },
175
176 addAjaxHeader(header) {
177 this.Config.ajaxHeaders.push(header);
178 },
179
180 getSearchData(datatable) {
181 const searchInputs = this.UI.getAllSearchInputs(datatable);
182 const data = {};
183 [].forEach.call(searchInputs, searchInput => {
184 if (searchInput && searchInput.value.length > 0) {
185 data[searchInput.name] = searchInput.value;
186 }
187 });
188 return data;
189 },
190
191 getSearchDataFromURL(datatable, url = window.location.href) {
192 const urlParams = BunnyURL.getParams(url);
193 let data = {};
194 for (let k in urlParams) {
195 if (k !== 'page') {
196 const input = this.UI.getSearchInput(datatable, k);
197 if (input) {
198 input.value = urlParams[k];
199 data[k] = urlParams[k];
200 }
201 }
202 }
203 return data;
204 },
205
206
207 getOrderData(datatable) {
208 const data = {};
209 const thCells = this.UI.getOrderCells(datatable);
210 for (let k = 0; k < thCells.length; k++) {
211 const thCell = thCells[k];
212 if (this.UI.isColumnAsc(thCell)) {
213 data['order_by'] = thCell.getAttribute('pid');
214 data['order_rule'] = 'asc';
215 break;
216 } else if (this.UI.isColumnDesc(thCell)) {
217 data['order_by'] = thCell.getAttribute('pid');
218 data['order_rule'] = 'desc';
219 break;
220 }
221 }
222 return data;
223 },
224
225 getOrderDataFromURL(datatable, url = window.location.href) {
226 const urlParam = BunnyURL.getParam('order_by', url);
227 let data = {};
228 if (urlParam) {
229 data['order_by'] = urlParam;
230 data['order_rule'] = BunnyURL.getParam('order_rule', url);
231 }
232 return data;
233 },
234
235
236 getSearchAndOrderData(datatable) {
237 return Object.assign(this.getSearchData(datatable), this.getOrderData(datatable));
238 },
239
240 getSearchAndOrderDataFromURL(datatable) {
241 return Object.assign(this.getSearchDataFromURL(datatable), this.getOrderDataFromURL(datatable));
242 },
243
244
245 getDataUrl(datatable, page, urlParams = {}) {
246 let url = this.Pagination.addPageParamToUrl(this.getAjaxUrl(datatable), page);
247 url = BunnyURL.setParams(urlParams, url);
248 return url;
249 },
250
251
252
253 addEvents(datatable) {
254 const searchInputs = this.UI.getAllSearchInputs(datatable);
255 [].forEach.call(searchInputs, searchInput => {
256 const eventName = searchInput.tagName === 'INPUT' ? 'input' : 'change';
257 addEventOnce(searchInput, eventName, () => {
258 this.update(datatable, this.getDataUrl(datatable, 1, this.getSearchAndOrderData(datatable)));
259 });
260 });
261
262 const thCells = this.UI.getOrderCells(datatable);
263 [].forEach.call(thCells, thCell => {
264 thCell.addEventListener('click', () => {
265 if (this.UI.isColumnAsc(thCell)) {
266 this.UI.setColumnDesc(thCell);
267 this.update(datatable, this.getDataUrl(datatable, this.getPage(), this.getSearchAndOrderData(datatable)));
268 } else if (this.UI.isColumnDesc(thCell)) {
269 this.UI.clearAllColumnsOrder(thCell);
270 this.update(datatable, this.getDataUrl(datatable, this.getPage(), this.getSearchData(datatable)));
271 } else {
272 this.UI.setColumnAsc(thCell);
273 this.update(datatable, this.getDataUrl(datatable, this.getPage(), this.getSearchAndOrderData(datatable)));
274 }
275 });
276 });
277 },
278
279 setARIA(datatable) {
280 const thCells = this.UI.getOrderCells(datatable);
281 [].forEach.call(thCells, thCell => {
282 makeAccessible(thCell);
283 });
284 },
285
286 attachPaginationEventHandlers(datatable) {
287 const pg = this.UI.getPagination(datatable);
288 this.Pagination.onItemClick(pg, (page, url) => {
289 this.changePage(datatable, page);
290 });
291 },
292
293 callHandlers(datatable, data) {
294 callElementCallbacks(datatable, 'datatable_redraw', (cb) => {
295 cb(data);
296 })
297 },
298
299 callBeforeHandlers(datatable, data) {
300 callElementCallbacks(datatable, 'datatable_before_redraw', (cb) => {
301 cb(data);
302 })
303 },
304
305 onBeforeRedraw(datatable, callback) {
306 pushCallbackToElement(datatable, 'datatable_before_redraw', callback);
307 },
308
309 onRedraw(datatable, callback) {
310 pushCallbackToElement(datatable, 'datatable_redraw', callback);
311 },
312
313
314
315 fetchData(datatable, url) {
316 return new Promise(callback => {
317 this.Ajax.get(url, data => {
318 data = JSON.parse(data);
319 callback(data);
320 }, {}, this.getAjaxHeaders());
321 });
322 },
323
324 changePage(datatable, page, data = null) {
325 if (data === null) {
326 data = this.getSearchAndOrderData(datatable);
327 }
328 this.update(datatable, this.getDataUrl(datatable, page, data));
329 },
330
331 getPage() {
332 const page = BunnyURL.getParam('page');
333 if (page) {
334 return page;
335 }
336 return 1;
337 },
338
339 /*search(datatable, param, text) {
340 this.update(datatable, this.getDataUrl(datatable, 1, {[param]: text}));
341 },*/
342
343 updateURL(datatable, url) {
344 let newURL = window.location.href;
345
346 const page = BunnyURL.getParam('page', url);
347 if (page > 1) {
348 newURL = BunnyURL.setParam('page', page);
349 } else if (BunnyURL.hasParam('page', newURL)) {
350 newURL = BunnyURL.removeParam('page', newURL);
351 }
352
353 const orderBy = BunnyURL.getParam('order_by', url);
354 if (orderBy) {
355 newURL = BunnyURL.setParam('order_by', orderBy, newURL);
356 newURL = BunnyURL.setParam('order_rule', BunnyURL.getParam('order_rule', url), newURL);
357 }
358
359 const searchInputs = this.UI.getAllSearchInputs(datatable);
360 [].forEach.call(searchInputs, searchInput => {
361 const searchParam = searchInput.name;
362 const search = BunnyURL.getParam(searchParam, url);
363 if (search && search !== '') {
364 newURL = BunnyURL.setParam(searchParam, search, newURL);
365 } else if (BunnyURL.hasParam(searchParam, newURL)) {
366 newURL = BunnyURL.removeParam(searchParam, newURL);
367 }
368 });
369
370 if (newURL !== window.location.href) {
371 window.history.replaceState('', '', newURL);
372 }
373 },
374
375 update(datatable, url) {
376 this.callBeforeHandlers(datatable);
377 this.UI.getTable(datatable).classList.remove('in');
378 this.fetchData(datatable, url).then(data => {
379 const pg = this.UI.getPagination(datatable);
380 const Pagination = this.Pagination;
381 Pagination.initOrUpdate(pg, data, this.getSearchAndOrderData(datatable));
382 this.attachPaginationEventHandlers(datatable);
383 const stats = this.UI.getStats(datatable);
384 if (stats !== undefined) {
385 stats.textContent = Pagination.getStats(pg);
386 }
387 this.UI.removeRows(datatable);
388 this.UI.insertRows(datatable, data.data, this.getTemplateId(datatable));
389 this.UI.getTable(datatable).classList.add('in');
390 this.updateURL(datatable, url);
391 this.callHandlers(datatable, data);
392 });
393 }
394
395};
396
397DataTable.initAll();