Added Endless paging support to template list renderer
[ajatus.git] / js / renderers / list_tpl.js
blobc6e75b9f8f382bcfdaae394bacc21afad808a42e
1 /*
2  * This file is part of
3  *
4  * Ajatus - Distributed CRM
5  * @requires jQuery v1.2.1
6  * 
7  * Copyright (c) 2007 Jerry Jalava <jerry.jalava@gmail.com>
8  * Copyright (c) 2007 Nemein Oy <http://nemein.com>
9  * Website: http://ajatus.info
10  * Licensed under the GPL license
11  * http://www.gnu.org/licenses/gpl.html
12  * 
13  */
15 (function($){
16     $.ajatus = $.ajatus || {};
17     $.ajatus.renderer = $.ajatus.renderer || {};
18     
19     $.ajatus.renderer.list_tpl = function(target, content_type, options) {
20         var default_options = {
21             className: 'list_holder',
22             id: 'list_holder',
23             title: null,
24             plural_title: true,
25             title_suffix: null,
26             show_count_on_title: true,
27             append: false,
28             headers: false,
29             schema: false,
30             actions: null,
31             show_actions: true,
32             item_id_suffix: '',
33             main_template: null,
34             pool: {
35                 enabled: false,
36                 settings: {
37                     type: 'scroll',
38                     render_item_after_load: false,
39                     tick_limit: 20,
40                     use_db: false
41                 }
42             },
43         };
44         
45         this.options = $.extend({}, default_options, options);
46         if (   typeof options['pool'] != 'undefined'
47             && typeof options['pool']['settings'] != 'undefined')
48         {
49             this.options.pool.settings = $.extend(default_options.pool.settings, options['pool']['settings']);
50         }
51                 
52         this.target = target;
53         this.headers = this.options.headers || content_type.list_headers;
54         this.schema_fields = this.options.schema || (content_type.list_schema || content_type.schema);
56         this.options.actions = [
57             {
58                 name: 'view',
59                 title: $.ajatus.i10n.get('View'),
60                 icon: 'view.png'
61             },
62             {
63                 name: 'edit',
64                 title: $.ajatus.i10n.get('Edit'),
65                 icon: 'edit.png'
66             },
67             {
68                 name: 'archive',
69                 title: $.ajatus.i10n.get('Archive'),
70                 icon: 'archive.png',
71                 click_action: '$.ajatus.document.actions.execute("archive", doc);'
72             },
73             {
74                 name: 'delete',
75                 title: $.ajatus.i10n.get('Delete'),
76                 icon: 'trash.png',
77                 click_action: '$.ajatus.document.actions.execute("delete", doc);'
78             }          
79         ];
81         this.holder = $('<div class="'+options.className+'" id="'+options.id+'" />');
83         title_str = this.options.title || content_type.title;
84         if (this.options.plural_title) {
85             title_str = $.ajatus.i10n.plural($.ajatus.i10n.get(title_str));
86         } else {
87             title_str = $.ajatus.i10n.get(title_str);
88         }
89         if (this.options.title_suffix != null) {
90             title_str += ' ' + this.options.title_suffix;
91         }
93         this.tpl_data = {
94             title: title_str,
95             total_items: null,
96             headers: [],
97             items: [],
98             show_count: true,
99             toString: function() {
100                 var str = this.title;
101                 if (this.show_count) {
102                     var cnt = this.items.length;
103                     if (this.total_items != null) {
104                         cnt = this.total_items;
105                     }
106                     str += ' ('+cnt+')';
107                 }
108                                 return str;
109                         }
110         };
111         this.tpl_data.show_count = this.options.show_count_on_title;
113         this.items = [];
114         this.processed_items = [];
115         
116         if (this.options.main_template == null) {
117             this.options.main_template = '{#template MAIN}' +
118                     '<h2>{$T}</h2>' +
119                         '<table class="listing">' +
120                             '<thead><tr>' +
121                                         '{#foreach $T.headers as header}' +
122                                                 '{#include HCOLUMN root=$T.header}' +
123                                         '{#/for}' +
124                             '</tr></thead>' +
125                             '<tbody>' +
126                                         '{#foreach $T.items as item}' +
127                                             '<tr class="{#cycle values=[\'odd\',\'even\']}">' +
128                                                     '{#include ICOLUMNS root=$T.item}' +
129                                                 '</tr>' +
130                                         '{#/for}' +
131                             '</tbody>' +
132                         '</table>' + 
133                 '{#/template MAIN}';
134         }
135         this.header_column_tpl = $.createTemplate('<th class="{$T.className}">{$T.content}</th>');
136         this.item_columns_tpl = '';
137         this.item_actions_tpl = $.createTemplate('<a href="{$T.url}" title="{$T.title}" {#if $T.onclick} onclick="{$T.onclick}" {#/if}><img src="{$T.icon}" class="{$T.className}" alt="{$T.title}"/></a>');
138         
139         this.pool = null;
140         if (this.options.pool.enabled) {
141             this.pool = new $.ajatus.renderer(this.options.pool.settings, this);
142         }
143         
144         this.attach(this.options.append);
145     };
146     $.extend($.ajatus.renderer.list_tpl.prototype, {
147         attach: function(append) {                    
148             if (append) {
149                 this.holder.appendTo(this.target);
150             } else {
151                 this.target.html(this.holder);
152             }
153         },
154         render: function() {
155             this._collect_headers();
156             this._collect_items();
157             
158             this._render();
159         },
160         render_item: function(doc, idx) {//from_db
161             // if (   typeof from_db != 'undefined'
162             //     && from_db)
163             // {
164             //     this.items.push(doc);
165             // }
166             return this._render_item(doc, idx);
167             
168             //Render Row
169         },
170         add_item: function(doc) {
171             if (this.options.pool.enabled) {
172                 this.pool.add_item(doc);
173             } else {
174                 this.items.push(doc);                
175             }
176         },
177         add_total_count: function(count) {
178             if (typeof count != 'undefined') {
179                 this.tpl_data.total_items = count;
181                 if (this.options.pool.enabled) {
182                     this.pool.items_added(count);
183                 }
184             }
185         },
186         enable_sorting: function() {
187             $('table', this.holder).tablesorter();
188         },
189         _collect_headers: function() {
190             var _self = this;
191             $.each(this.headers, function(i,h){
192                 var schema = _self.schema_fields[h];
193                 if (! schema) {
194                     schema = {
195                         label: h
196                     };
197                 }
199                 var className = h;
200                 if (i == 0) {
201                     className = 'first_column ' + className;
202                 }
203                 
204                 _self.tpl_data.headers.push({
205                     className: className,
206                     content: $.ajatus.i10n.get(schema.label)
207                 });
208             });
209             
210             if (this.options.show_actions) {
211                 this.tpl_data.headers.push({
212                     className: 'actions',
213                     content: $.ajatus.i10n.get('Actions')
214                 });                
215             }
216         },
217         _collect_items: function() {
218             var _self = this;
219             
220             for (var i=0; i<this.items.length; i++) {
221                 var doc = this.items[i];
222                 
223                 var row_data = {};
224                 
225                 $.each(this.headers, function(i, h){
226                     var className = h;
227                     if (i == 0) {
228                         className = 'first_column ' + className;
229                     }
230                     
231                     var data = $.extend({
232                         val: null,
233                         widget: {
234                             name: 'text',
235                             config: {}
236                         }
237                     }, doc.value[h]);
239                     if (   h == '_type'
240                         || h == '_id'
241                         || h == '_rev')
242                     {
243                         data.val = doc[h] || doc.value[h];
244                     }
246                     if (data.val === null) {
247                         var full_doc = new $.ajatus.document.loader(doc._id, doc._rev);
248                         data = $.extend({
249                             val: '',
250                             widget: {
251                                 name: 'text',
252                                 config: {}
253                             }
254                         }, full_doc.value[h]);
255                     }
257                     var widget = new $.ajatus.widget(data.widget.name, data.widget.config);
258                     data.val = widget.value_on_view(data.val, 'list');
260                     if (h == '_type') {
261                         var type = data.val;
262                         var normalized_type = type.toString().replace('_', ' ');
264                         var img_title = $.ajatus.i10n.get(normalized_type);
265                         data.val = '<img src="' + $.ajatus.preferences.client.theme_icons_url + type + '.png' + '" title="'+img_title+'" alt="'+img_title+'"/>';
266                     }
268                     row_data[h] = {
269                         column_className: className,
270                         content: data.val
271                     };
272                     
273                     if (_self.options.show_actions) {
274                         row_data['actions'] = {
275                             items: _self._get_actions_for_item(doc)
276                         }
277                     }
278                     
279                     _self.processed_items.push(doc._id);
280                 });
281                 
282                 
283                 this.tpl_data.items.push(row_data);
284             }
285         },
286         _get_actions_for_item: function(doc, actions) {
287             if (typeof actions == 'undefined') {
288                 var actions = this.options.actions;
289             }
290             var content_type = $.ajatus.preferences.client.content_types[doc.value._type];
292             var actions_length = actions.length-1;
293             
294             var action_items = [];
295             
296             $.each(actions, function(i,action){
297                 var action_data = {
298                     url: '#' + action.name + '.' + content_type.name + '.' + (doc._id || doc.id),
299                     title: action.title,
300                     icon: $.ajatus.preferences.client.theme_icons_url + action.icon,
301                     className: action.name + '_link',     
302                 };
303                 
304                 if (typeof action['click_action'] != 'undefined') {
305                     action_data['onclick'] = function(e){eval(action.click_action);}
306                 }
307                 
308                 action_items.push(action_data);
309             });
310             
311             return action_items;
312         },
313         _create_items_tpl: function() {
314             var item_columns_tpl = '';
315             $.each(this.headers, function(i,h){
316                 item_columns_tpl += '<td class="{$T.'+h+'.column_className}">{$T.'+h+'.content}</td>';
317             });
318             
319             if (this.options.show_actions) {
320                 item_columns_tpl += '<td class="actions">' +
321                     '{#foreach $T.actions.items as aitem}' +
322                                             '{#include IACTIONS root=$T.aitem}' +
323                                 '{#/for}' +
324                 '</td>';
325                 
326                 this.item_columns_tpl = $.createTemplate(item_columns_tpl, {
327                     'IACTIONS': this.item_actions_tpl
328                 });  
329             } else {
330                 this.item_columns_tpl = $.createTemplate(item_columns_tpl);  
331             }
332         },
333         _render: function() {
334             this._create_items_tpl();
335             
336             $(this.holder).setTemplate(this.options.main_template, {
337                 'HCOLUMN': this.header_column_tpl,
338                 'ICOLUMNS': this.item_columns_tpl
339             });
340             $(this.holder).processTemplate(this.tpl_data);
341         },
342         _render_item: function(doc, idx) {            
343             if ($.inArray(doc._id, this.processed_items) != -1) {
344                 return true;
345             }
346             
347             var tpl_data = this._get_item_tpl_data(doc);            
348             var tbody = $('tbody', this.holder);
349             
350             var row_class = "even";
351             if (idx != 'undefined') {
352                 if (idx % 2 == 0)
353                 {
354                     row_class = 'odd';
355                 }                
356             }
357             
358             var item_columns = '';
359             $.each(this.headers, function(i,h){
360                 item_columns += '<td class="{$T.'+h+'.column_className}">{$T.'+h+'.content}</td>';
361             });
362             item_columns += '<td class="actions">' +
363                 '{#foreach $T.actions.items as aitem}' +
364                                     '{#include IACTIONS root=$T.aitem}' +
365                                 '{#/for}' +
366             '</td>';
367             
368             var item_row = '<tr class="'+row_class+'">' + item_columns + '</tr>';
369             
370             item_row_tpl = $.createTemplate(item_row, {
371                 'IACTIONS': this.item_actions_tpl
372             });
373             
374             $(tbody).setTemplate(item_row_tpl);
375             $(tbody).processTemplate(tpl_data, {}, true);
376             
377             this.processed_items.push(doc._id);
378             
379             return true;
380         },
381         _get_item_tpl_data: function(doc) {
382             var _self = this;                
383             var row_data = {};
384             
385             $.each(this.headers, function(i, h){
386                 var className = h;
387                 if (i == 0) {
388                     className = 'first_column ' + className;
389                 }
390                 
391                 var data = $.extend({
392                     val: null,
393                     widget: {
394                         name: 'text',
395                         config: {}
396                     }
397                 }, doc.value[h]);
399                 if (   h == '_type'
400                     || h == '_id'
401                     || h == '_rev')
402                 {
403                     data.val = doc[h] || doc.value[h];
404                 }
406                 if (data.val === null) {
407                     var full_doc = new $.ajatus.document.loader(doc._id, doc._rev);
408                     data = $.extend({
409                         val: '',
410                         widget: {
411                             name: 'text',
412                             config: {}
413                         }
414                     }, full_doc.value[h]);
415                 }
417                 var widget = new $.ajatus.widget(data.widget.name, data.widget.config);
418                 data.val = widget.value_on_view(data.val, 'list');
420                 if (h == '_type') {
421                     var type = data.val;
422                     var normalized_type = type.toString().replace('_', ' ');
424                     var img_title = $.ajatus.i10n.get(normalized_type);
425                     data.val = '<img src="' + $.ajatus.preferences.client.theme_icons_url + type + '.png' + '" title="'+img_title+'" alt="'+img_title+'"/>';
426                 }
428                 row_data[h] = {
429                     column_className: className,
430                     content: data.val
431                 };
432                 
433                 if (_self.options.show_actions) {
434                     row_data['actions'] = {
435                         items: _self._get_actions_for_item(doc)
436                     }
437                 }
438             });
439             
440             return row_data;
441         }
442     });
444 })(jQuery);