UNPKG

10.6 kBJavaScriptView Raw
1'use strict'
2
3export const TEMPLATE_EVENT_INIT = 'init';
4export const TEMPLATE_EVENT_FORMAT_DATA = 'format_data';
5
6/**
7 * Base object Template
8 */
9export 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 //t.attributeReplaceElements = [];
79 // value attribute
80 /*this.addAttributeReplaceElement('value', t);
81 this.addAttributeReplaceElement('datetime', t);
82 this.addAttributeReplaceElement('data-id', t);
83 this.addAttributeReplaceElement('src', t);*/
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 /*addAttributeReplaceElement: function(attribute_name, tpl) {
97 tpl.content.querySelectorAll('['+attribute_name+'^="$"]').forEach(function (e) {
98 tpl.attributeReplaceElements[e.getAttribute(attribute_name)] = {
99 attribute: attribute_name,
100 element: e
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 /*if (t.attributeReplaceElements['$'+d] !== undefined) {
129 t.attributeReplaceElements['$'+d].element.setAttribute(t.attributeReplaceElements['$'+d].attribute, t.escapedData[d]);
130 }*/
131 }
132 return t;
133 },
134
135 escape: function(str) {
136 return String(str).replace(/&amp;/g, '&').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
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 // transform adjacency list
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 // prepend _ before id because JavaScript will break an original data order
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 // end transform
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/*document.addEventListener('DOMContentLoaded', function() {
276
277 /!**
278 * Insert templates on page load if there are data-template attributes on any elements
279 *!/
280 document.querySelectorAll('[data-template]').forEach(function(e) {
281 var tpl_id = e.getAttribute('data-template');
282 var data = [];
283 if (Template._loadedTemplates[tpl_id].events[TEMPLATE_EVENT_INIT] !== undefined) {
284 data = Template._loadedTemplates[tpl_id].events[TEMPLATE_EVENT_INIT]();
285 }
286 Template.insert(tpl_id, data, e)
287 });
288
289}, false);*/