1 | 'use strict'
|
2 |
|
3 | export const TEMPLATE_EVENT_INIT = 'init';
|
4 | export const TEMPLATE_EVENT_FORMAT_DATA = 'format_data';
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | export var Template = {
|
10 |
|
11 | _loadedTemplates: [],
|
12 | _dataVarName: 'v',
|
13 | _dataAttrVarName: 'av',
|
14 |
|
15 | define: function(id, handlers = {}, events = {})
|
16 | {
|
17 | if (this._loadedTemplates[id] === undefined) {
|
18 | var e = document.getElementById(id);
|
19 | if (e === null) {
|
20 | console.error('Template with id="'+id+'" doesn\'t exists');
|
21 | return false;
|
22 | }
|
23 | var f = document.createDocumentFragment();
|
24 | var sub = null;
|
25 | if (e.tagName === 'TABLE') {
|
26 | sub = e.querySelector('tbody')
|
27 | } else {
|
28 | sub = e;
|
29 | }
|
30 | while (sub.firstChild) {
|
31 | f.appendChild(sub.firstChild);
|
32 | }
|
33 | this._loadedTemplates[id] = {
|
34 | templateFragment: f,
|
35 | handlers: handlers,
|
36 | events: events,
|
37 | isTable: (e.tagName === 'TABLE')
|
38 | };
|
39 | } else {
|
40 | console.error('Template with id="'+id+'" already defined!');
|
41 | return false;
|
42 | }
|
43 | return true;
|
44 | },
|
45 |
|
46 | isTable: function(tpl_id) {
|
47 | return this._loadedTemplates[tpl_id].isTable;
|
48 | },
|
49 |
|
50 | create: function(id, related_data) {
|
51 | var t = {};
|
52 | var attr_parts = [];
|
53 | var data_var_name = this._dataVarName;
|
54 | var attr_data_var_name = this._dataAttrVarName;
|
55 | if (this._loadedTemplates[id] === undefined) {
|
56 | console.error('Template with id="' + id + '" is not defined. Use Template.define() first.');
|
57 | return false;
|
58 | }
|
59 | t.id = id;
|
60 | t.content = this._loadedTemplates[id].templateFragment.cloneNode(true);
|
61 | t.nodes = [].slice.call(t.content.childNodes, 0);
|
62 | t.isTable = (this._loadedTemplates[id].tagName === 'TABLE');
|
63 |
|
64 | t.varElements = [];
|
65 | [].forEach.call(t.content.querySelectorAll('[' + data_var_name + ']'), function (e) {
|
66 | t.varElements[e.getAttribute(data_var_name)] = e;
|
67 | });
|
68 |
|
69 | t.attrVarElements = [];
|
70 | [].forEach.call(t.content.querySelectorAll('[' + attr_data_var_name + ']'), function (e) {
|
71 | attr_parts = e.getAttribute(attr_data_var_name).split(':');
|
72 | t.attrVarElements[attr_parts[1]] = {
|
73 | el: e,
|
74 | attr: attr_parts[0]
|
75 | };
|
76 | });
|
77 |
|
78 |
|
79 |
|
80 | |
81 |
|
82 |
|
83 |
|
84 |
|
85 | t.handlerElements = [];
|
86 | [].forEach.call(t.content.querySelectorAll('[data-handler]'), function (e) {
|
87 | t.handlerElements.push(e);
|
88 | });
|
89 |
|
90 | if (related_data !== undefined) {
|
91 | t.relatedData = related_data;
|
92 | }
|
93 | return t;
|
94 | },
|
95 |
|
96 | |
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 | parse: function(data, tpl) {
|
106 | var t = Object.create(tpl);
|
107 | if (data === undefined || data === null) {
|
108 | data = [];
|
109 | } else if (typeof data !== 'object') {
|
110 | console.error('1st argument of Template.parse() - "data" must be an array or object.');
|
111 | return false;
|
112 | }
|
113 |
|
114 | if (this._loadedTemplates[t.id].events[TEMPLATE_EVENT_FORMAT_DATA] !== undefined) {
|
115 | data = this._loadedTemplates[t.id].events[TEMPLATE_EVENT_FORMAT_DATA](data, t.relatedData);
|
116 | }
|
117 |
|
118 | t.escapedData = [];
|
119 |
|
120 | for (var d in data) {
|
121 | t.escapedData[d] = this.nl2br(this.escape(data[d]));
|
122 | if (t.varElements[d] !== undefined) {
|
123 | t.varElements[d].innerHTML = t.escapedData[d];
|
124 | }
|
125 | if (t.attrVarElements[d] !== undefined) {
|
126 | t.attrVarElements[d].el.setAttribute(t.attrVarElements[d].attr, data[d]);
|
127 | }
|
128 | |
129 |
|
130 |
|
131 | }
|
132 | return t;
|
133 | },
|
134 |
|
135 | escape: function(str) {
|
136 | return String(str).replace(/&/g, '&').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
137 | },
|
138 |
|
139 | nl2br: function(str) {
|
140 | return String(str).replace(/(\n)+/g, '<br>');
|
141 | },
|
142 |
|
143 | callHandlers: function(tpl) {
|
144 | for (var h in tpl.handlerElements) {
|
145 | var f = this._loadedTemplates[tpl.id].handlers[tpl.handlerElements[h].getAttribute('data-handler')];
|
146 | if (f === undefined) {
|
147 | console.error('Template\'s "'+tpl.id+'" handler "'+f+'" does not exists. Pass second argument to Template.define() as object where keys=handler names.');
|
148 | return false;
|
149 | }
|
150 | f(tpl.handlerElements[h], tpl.escapedData, tpl.nodes);
|
151 | }
|
152 | },
|
153 |
|
154 | append: function (tpl, parent_el) {
|
155 | if (parent_el === null || parent_el === undefined) {
|
156 | console.error('Unable to append template to parent element. Passed as 2nd argument to Template.append(). parent_el is: ' + parent_el);
|
157 | return false;
|
158 | }
|
159 | var el_to_append = null;
|
160 | if (this.isTable(tpl.id)) {
|
161 | el_to_append = parent_el.querySelector('tbody');
|
162 | } else {
|
163 | el_to_append = parent_el;
|
164 | }
|
165 | el_to_append.appendChild(tpl.content);
|
166 | this.callHandlers(tpl);
|
167 | return tpl.nodes;
|
168 | },
|
169 |
|
170 | insert: function(tpl_id, data, parent_el) {
|
171 | return this.append(this.parse(data, this.create(tpl_id)), parent_el);
|
172 | },
|
173 |
|
174 | insertAll: function(tpl_id, data_collection, parent_el) {
|
175 | var f = document.createDocumentFragment();
|
176 | var tpl_collection = [];
|
177 | for (var k=0; k<data_collection.length; k++) {
|
178 | var tpl = this.create(tpl_id);
|
179 | tpl = this.parse(data_collection[k], tpl);
|
180 | f.appendChild(tpl.content);
|
181 | tpl_collection.push(tpl);
|
182 | }
|
183 | var el_to_append = null;
|
184 | if (this.isTable(tpl_id)) {
|
185 | el_to_append = parent_el.querySelector('tbody');
|
186 | } else {
|
187 | el_to_append = parent_el;
|
188 | }
|
189 | el_to_append.appendChild(f);
|
190 | for (k=0; k<tpl_collection.length; k++) {
|
191 | this.callHandlers(tpl_collection[k]);
|
192 | }
|
193 | },
|
194 |
|
195 | insertAdjacencyList: function(tpl_id, data_adj_list, parent_el, parent_id_column, branch_container_class, order) {
|
196 |
|
197 | if (parent_id_column === undefined || parent_id_column === null) {
|
198 | parent_id_column = 'parent_id';
|
199 | }
|
200 |
|
201 | if (order === undefined || order === null || (order !== 'asc' && order !== 'desc')) {
|
202 | order = 'asc'
|
203 | }
|
204 |
|
205 |
|
206 | var data = {
|
207 | _0: {}
|
208 | };
|
209 | data['_0']._rendered = false;
|
210 | data['_0'].id = 0;
|
211 | for (var k in data_adj_list) {
|
212 |
|
213 | data['_'+data_adj_list[k].id] = data_adj_list[k];
|
214 | data['_'+data_adj_list[k].id]._rendered = false;
|
215 | }
|
216 | for (var k in data_adj_list) {
|
217 | var p = data['_'+data_adj_list[k].id][parent_id_column];
|
218 | if (data['_'+p]._children_ids === undefined) {
|
219 | data['_'+p]._children_ids = [];
|
220 | }
|
221 | data['_'+p]._children_ids.push(data_adj_list[k].id);
|
222 | }
|
223 |
|
224 |
|
225 | var f = document.createDocumentFragment();
|
226 | var tpl_collection = [];
|
227 |
|
228 | var append_node = function(node, where) {
|
229 | if (node._rendered === false) {
|
230 | node._rendered = true;
|
231 | if (node.id === 0) {
|
232 | for (var i in node._children_ids) {
|
233 | append_node(data['_'+node._children_ids[i]], where);
|
234 | }
|
235 | } else {
|
236 | var related_data = build_related_data(node);
|
237 | var tpl = Template.create(tpl_id, related_data);
|
238 | tpl = Template.parse(node, tpl);
|
239 | tpl_collection.push(tpl);
|
240 | if (node._children_ids !== undefined) {
|
241 | for (var i in node._children_ids) {
|
242 | if (tpl.content.querySelector('.'+branch_container_class) === null) {
|
243 | console.error('Element inside template with class "'+branch_container_class+'" not found. Passed in as 5th argument in Template.insertAdjacencyList() - "branch_container_class"')
|
244 | }
|
245 | append_node(data['_'+node._children_ids[i]], tpl.content.querySelector('.'+branch_container_class));
|
246 | }
|
247 | }
|
248 | where.appendChild(tpl.content);
|
249 | }
|
250 | }
|
251 | };
|
252 |
|
253 | var build_related_data = function(node) {
|
254 | if (node.parent_id > 0) {
|
255 | var related_data = {};
|
256 | related_data = data['_'+node.parent_id];
|
257 | if (data['_'+node.parent_id].parent_id > 0) {
|
258 | related_data.parent = build_related_data(data['_'+node.parent_id]);
|
259 | }
|
260 | return related_data;
|
261 | }
|
262 | return undefined;
|
263 | };
|
264 |
|
265 | append_node(data['_0'], f);
|
266 |
|
267 | parent_el.appendChild(f);
|
268 |
|
269 | for (k=0; k<tpl_collection.length; k++) {
|
270 | this.callHandlers(tpl_collection[k]);
|
271 | }
|
272 | }
|
273 | };
|
274 |
|
275 |
|
276 |
|
277 |
|
278 |
|
279 |
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 |
|
287 |
|
288 |
|
289 |
|