Remove UpperCase widget.
[mkws-moved-to-github.git] / src / mkws-widgets.js
1 // Factory function for widget objects.
2 function widget($, team, type, node) {
3     // Static register of attributes that do not contribute to config
4     var ignoreAttrs = {
5         id:1, 'class':1, style:1, name:1, action:1, type:1, size:1,
6         value:1, width:1, valign:1
7     };
8
9     var that = {
10         team: team,
11         type: type,
12         node: node,
13         config: mkws.objectInheritingFrom(team.config())
14     };
15
16     function log(s) {
17         team.log(s);
18     }
19     that.log = log;
20
21     that.toString = function() {
22         return '[Widget ' + team.name() + ':' + type + ']';
23     };
24
25     that.value = function() {
26         return node.value;
27     }
28
29     for (var i = 0; i < node.attributes.length; i++) {
30         var a = node.attributes[i];
31         if (a.name === 'data-mkws-config') {
32             // Treat as a JSON fragment configuring just this widget
33             log(node + ": parsing config fragment '" + a.value + "'");
34             var data;
35             try {
36                 data = $.parseJSON(a.value);
37                 for (var key in data) {
38                     log(node + ": adding config element " + key + "='" + data[key] + "'");
39                     that.config[key] = data[key];
40                 }
41             } catch (err) {
42                 alert("Can't parse " + node + " data-mkws-config as JSON: " + a.value);
43             }
44         } else if (a.name.match (/^data-mkws-/)) {
45             var name = a.name.replace(/^data-mkws-/, '')
46             that.config[name] = a.value;
47             log(node + ": set data-mkws attribute " + name + "='" + a.value + "'");
48         } else if (!ignoreAttrs[a.name]) {
49             that.config[a.name] = a.value;
50             log(node + ": set regular attribute " + a.name + "='" + a.value + "'");
51         }
52     }
53
54     var fn = mkws.promotionFunction(type);
55     if (fn) {
56         fn.call(that);
57         log("made " + type + " widget(node=" + node + ")");
58     } else {
59         log("made UNPROMOTED widget(type=" + type + ", node=" + node + ")");
60     }
61
62     return that;
63 }
64
65
66 // Utility function for use by all widgets that can invoke autosearch.
67 widget.autosearch = function(widget) {
68     widget.team.queue("ready").subscribe(function() {
69         var query = widget.config.autosearch;
70         if (query) {
71             if (query.match(/^!param!/)) {
72                 var param = query.replace(/^!param!/, '');
73                 query = mkws.getParameterByName(param);
74                 widget.log("obtained query '" + query + "' from param '" + param + "'");
75                 if (!query) {
76                     alert("This page has a MasterKey widget that needs a query specified by the '" + param + "' parameter");
77                 }
78             } else if (query.match(/^!path!/)) {
79                 var index = query.replace(/^!path!/, '');
80                 var path = window.location.pathname.split('/');
81                 query = path[path.length - index];
82                 widget.log("obtained query '" + query + "' from path-component '" + index + "'");
83                 if (!query) {
84                     alert("This page has a MasterKey widget that needs a query specified by the path-component " + index);
85                 }
86             } else if (query.match(/^!var!/)) {
87                 var name = query.replace(/^!var!/, '');
88                 query = window[name]; // It's ridiculous that this works
89                 widget.log("obtained query '" + query + "' from variable '" + name + "'");
90                 if (!query) {
91                     alert("This page has a MasterKey widget that needs a query specified by the '" + name + "' variable");
92                 }
93             }
94
95             var sortOrder = widget.config.sort;
96             var maxrecs = widget.config.maxrecs;
97             var perpage = widget.config.perpage;
98             var limit = widget.config.limit;
99             var targets = widget.config.targets;
100             var targetfilter = widget.config.targetfilter;
101             var target = widget.config.target;
102             if (target) targetfilter = 'udb=="' + target + '"';
103
104             var s = "running auto search: '" + query + "'";
105             if (sortOrder) s += " sorted by '" + sortOrder + "'";
106             if (maxrecs) s += " restricted to " + maxrecs + " records";
107             if (perpage) s += " with " + perpage + " per page";
108             if (limit) s += " limited by '" + limit + "'";
109             if (targets) s += " in targets '" + targets + "'";
110             if (targetfilter) s += " constrained by targetfilter '" + targetfilter + "'";
111             widget.log(s);
112
113             widget.team.newSearch(query, sortOrder, maxrecs, perpage, limit, targets, targetfilter);
114         }
115     });
116 };
117
118
119 // Functions follow for promoting the regular widget object into
120 // widgets of specific types. These could be moved into their own
121 // source files.
122
123
124 mkws.registerWidgetType('Targets', function() {
125     var that = this;
126     var M = mkws.M;
127
128     this.team.queue("targets").subscribe(function(data) {
129         var table ='<table><thead><tr>' +
130             '<td>' + M('Target ID') + '</td>' +
131             '<td>' + M('Hits') + '</td>' +
132             '<td>' + M('Diags') + '</td>' +
133             '<td>' + M('Records') + '</td>' +
134             '<td>' + M('State') + '</td>' +
135             '</tr></thead><tbody>';
136
137         for (var i = 0; i < data.length; i++) {
138             table += "<tr><td>" + data[i].id +
139                 "</td><td>" + data[i].hits +
140                 "</td><td>" + data[i].diagnostic +
141                 "</td><td>" + data[i].records +
142                 "</td><td>" + data[i].state + "</td></tr>";
143         }
144
145         table += '</tbody></table>';
146         var subnode = $(that.node).children('.mkwsBytarget');
147         subnode.html(table);
148     });
149 });
150
151
152 mkws.registerWidgetType('Stat', function() {
153     var that = this;
154     var M = mkws.M;
155
156     this.team.queue("stat").subscribe(function(data) {
157         if (that.node.length === 0)  alert("huh?!");
158
159         $(that.node).html('<span class="head">' + M('Status info') + '</span>' +
160             ' -- ' +
161             '<span class="clients">' + M('Active clients') + ': ' + data.activeclients + '/' + data.clients + '</span>' +
162             ' -- ' +
163             '<span class="records">' + M('Retrieved records') + ': ' + data.records + '/' + data.hits + '</span>');
164     });
165 });
166
167
168 mkws.registerWidgetType('Pager', function() {
169     var that = this;
170     var M = mkws.M;
171
172     this.team.queue("pager").subscribe(function(data) {
173         $(that.node).html(drawPager(data))
174
175         function drawPager(data) {
176             var teamName = that.team.name();
177             var s = '<div style="float: right">' + M('Displaying') + ': '
178                 + (data.start + 1) + ' ' + M('to') + ' ' + (data.start + data.num) +
179                 ' ' + M('of') + ' ' + data.merged + ' (' + M('found') + ': '
180                 + data.total + ')</div>';
181
182             //client indexes pages from 1 but pz2 from 0
183             var onsides = 6;
184             var pages = Math.ceil(that.team.totalRecordCount() / that.team.perpage());
185             var currentPage = that.team.currentPage();
186
187             var firstClkbl = (currentPage - onsides > 0)
188                 ? currentPage - onsides
189                 : 1;
190
191             var lastClkbl = firstClkbl + 2*onsides < pages
192                 ? firstClkbl + 2*onsides
193                 : pages;
194
195             var prev = '<span class="mkwsPrev">&#60;&#60; ' + M('Prev') + '</span> | ';
196             if (currentPage > 1)
197                 prev = '<a href="#" class="mkwsPrev" onclick="mkws.pagerPrev(\'' + teamName + '\');">'
198                 +'&#60;&#60; ' + M('Prev') + '</a> | ';
199
200             var middle = '';
201             for(var i = firstClkbl; i <= lastClkbl; i++) {
202                 var numLabel = i;
203                 if(i == currentPage)
204                     numLabel = '<span class="mkwsSelected">' + i + '</span>';
205
206                 middle += '<a href="#" onclick="mkws.showPage(\'' + teamName + '\', ' + i + ')"> '
207                     + numLabel + ' </a>';
208             }
209
210             var next = ' | <span class="mkwsNext">' + M('Next') + ' &#62;&#62;</span>';
211             if (pages - currentPage > 0)
212                 next = ' | <a href="#" class="mkwsNext" onclick="mkws.pagerNext(\'' + teamName + '\')">'
213                 + M('Next') + ' &#62;&#62;</a>';
214
215             var predots = '';
216             if (firstClkbl > 1)
217                 predots = '...';
218
219             var postdots = '';
220             if (lastClkbl < pages)
221                 postdots = '...';
222
223             s += '<div style="float: clear">'
224                 + prev + predots + middle + postdots + next + '</div>';
225
226             return s;
227         }
228     });
229 });
230
231
232 mkws.registerWidgetType('Results', function() {
233     // Nothing to do apart from act as an autosearch trigger
234     // Contained elements do all the real work
235     widget.autosearch(this);
236 });
237
238
239 mkws.registerWidgetType('Records', function() {
240     var that = this;
241     var team = this.team;
242
243     this.team.queue("records").subscribe(function(data) {
244         var html = [];
245         for (var i = 0; i < data.hits.length; i++) {
246             var hit = data.hits[i];
247             that.team.queue("record").publish(hit);
248             var divId = team.recordElementId(hit.recid[0]);
249             html.push('<div class="record mkwsTeam_' + team.name() + ' ' + divId + '">', renderSummary(hit), '</div>');
250             // ### At some point, we may be able to move the
251             // m_currentRecordId and m_currentRecordData members
252             // from the team object into this widget.
253             if (hit.recid == team.currentRecordId()) {
254                 if (team.currentRecordData())
255                     html.push(team.renderDetails(team.currentRecordData()));
256             }
257         }
258         $(that.node).html(html.join(''));
259
260         function renderSummary(hit) {
261             var template = team.loadTemplate(that.config.template || "Summary");
262             hit._id = team.recordElementId(hit.recid[0]);
263             hit._onclick = "mkws.showDetails('" + team.name() + "', '" + hit.recid[0] + "');return false;"
264             return template(hit);
265         }
266     });
267
268     widget.autosearch(that);
269 });
270
271
272 mkws.registerWidgetType('Navi', function() {
273     var that = this;
274     var teamName = this.team.name();
275     var M = mkws.M;
276
277     this.team.queue("navi").subscribe(function() {
278         var filters = that.team.filters();
279         var text = "";
280
281         filters.visitTargets(function(id, name) {
282             if (text) text += " | ";
283             text += M('source') + ': <a class="crossout" href="#" onclick="mkws.delimitTarget(\'' + teamName +
284                 "', '" + id + "'" + ');return false;">' + name + '</a>';
285         });
286
287         filters.visitFields(function(field, value) {
288             if (text) text += " | ";
289             text += M(field) + ': <a class="crossout" href="#" onclick="mkws.delimitQuery(\'' + teamName +
290                 "', '" + field + "', '" + value + "'" +
291                 ');return false;">' + value + '</a>';
292         });
293
294         $(that.node).html(text);
295     });
296 });
297
298
299 // It seems this and the Perpage widget doen't need to subscribe to
300 // anything, since they produce events rather than consuming them.
301 //
302 mkws.registerWidgetType('Sort', function() {
303     var that = this;
304
305     $(this.node).change(function() {
306         that.team.set_sortOrder($(that.node).val());
307         if (that.team.submitted()) {
308             that.team.reShow();
309         }
310         return false;
311     });
312 });
313
314
315 mkws.registerWidgetType('Perpage', function() {
316     var that = this;
317
318     $(this.node).change(function() {
319         that.team.set_perpage($(that.node).val());
320         if (that.team.submitted()) {
321             that.team.reShow();
322         }
323         return false;
324     });
325 });
326
327
328 mkws.registerWidgetType('Done', function() {
329     var that = this;
330
331     this.team.queue("complete").subscribe(function(n) {
332         $(that.node).html("Search complete: found " + n + " records");
333     });
334 });
335
336
337 mkws.registerWidgetType('Switch', function() {
338     var tname = this.team.name();
339     $(this.node).html('\
340 <a href="#" onclick="mkws.switchView(\'' + tname + '\', \'records\')">Records</a><span> \
341 | \
342 </span><a href="#" onclick="mkws.switchView(\'' + tname + '\', \'targets\')">Targets</a>');
343 });