Move that various specific-widget-type functions outside the scope of
[mkws-moved-to-github.git] / src / mkws-widgets.js
1 // Factory function for widget objects.
2 function widget($, team, type, node) {
3     var that = {
4         team: team,
5         type: type,
6         node: node
7     };
8
9     function log(s) {
10         team.log(s);
11     }
12     that.log = log;
13
14     that.toString = function() {
15         return '[Widget ' + team.name() + ':' + type + ']';
16     }
17
18     mkws.registerWidgetType('Targets', promoteTargets);
19     mkws.registerWidgetType('Stat', promoteStat);
20     mkws.registerWidgetType('Termlists', promoteTermlists);
21     mkws.registerWidgetType('Pager', promotePager);
22     mkws.registerWidgetType('Records', promoteRecords);
23     mkws.registerWidgetType('Navi', promoteNavi);
24     mkws.registerWidgetType('Sort', promoteSort);
25     mkws.registerWidgetType('Perpage', promotePerpage);
26
27     var promote = mkws.promotionFunction(type);
28     if (promote) {
29         promote.call(that);
30         log("made " + type + " widget(node=" + node + ")");
31     } else {
32         log("made UNENCAPSULATED widget(type=" + type + ", node=" + node + ")");
33     }
34
35     return that;
36 }
37
38
39     // Functions follow for promoting the regular widget object into
40     // widgets of specific types. These could be moved outside of the
41     // widget object, or even into their own source files.
42
43     function promoteTargets() {
44         var that = this;
45         var M = mkws.M;
46
47         this.team.queue("targets").subscribe(function(data) {
48             var table ='<table><thead><tr>' +
49                 '<td>' + M('Target ID') + '</td>' +
50                 '<td>' + M('Hits') + '</td>' +
51                 '<td>' + M('Diags') + '</td>' +
52                 '<td>' + M('Records') + '</td>' +
53                 '<td>' + M('State') + '</td>' +
54                 '</tr></thead><tbody>';
55
56             for (var i = 0; i < data.length; i++) {
57                 table += "<tr><td>" + data[i].id +
58                     "</td><td>" + data[i].hits +
59                     "</td><td>" + data[i].diagnostic +
60                     "</td><td>" + data[i].records +
61                     "</td><td>" + data[i].state + "</td></tr>";
62             }
63             
64             table += '</tbody></table>';
65             var subnode = $(that.node).children('.mkwsBytarget');
66             subnode.html(table);
67         });
68     }
69
70
71     function promoteStat() {
72         var that = this;
73         var M = mkws.M;
74
75         this.team.queue("stat").subscribe(function(data) {
76             if (that.node.length === 0)  alert("huh?!");
77
78             $(that.node).html('<span class="head">' + M('Status info') + '</span>' +
79                 ' -- ' +
80                 '<span class="clients">' + M('Active clients') + ': ' + data.activeclients + '/' + data.clients + '</span>' +
81                 ' -- ' +
82                 '<span class="records">' + M('Retrieved records') + ': ' + data.records + '/' + data.hits + '</span>');
83         });
84     }
85
86
87     function promoteTermlists() {
88         var that = this;
89         var M = mkws.M;
90
91         this.team.queue("termlists").subscribe(function(data) {
92             if (!that.node) {
93                 alert("termlists event when there are no termlists");
94                 return;
95             }
96
97             // no facets: this should never happen
98             if (!mkws_config.facets || mkws_config.facets.length == 0) {
99                 alert("onTerm called even though we have no facets: " + $.toJSON(data));
100                 $(that.node).hide();
101                 return;
102             }
103
104             // display if we first got results
105             $(that.node).show();
106
107             var acc = [];
108             acc.push('<div class="title">' + M('Termlists') + '</div>');
109             var facets = mkws_config.facets;
110
111             for (var i = 0; i < facets.length; i++) {
112                 if (facets[i] == "xtargets") {
113                     addSingleFacet(acc, "Sources",  data.xtargets, 16, null);
114                 } else if (facets[i] == "subject") {
115                     addSingleFacet(acc, "Subjects", data.subject,  10, "subject");
116                 } else if (facets[i] == "author") {
117                     addSingleFacet(acc, "Authors",  data.author,   10, "author");
118                 } else {
119                     alert("bad facet configuration: '" + facets[i] + "'");
120                 }
121             }
122
123             $(that.node).html(acc.join(''));
124
125             function addSingleFacet(acc, caption, data, max, pzIndex) {
126                 var teamName = that.team.name();
127                 acc.push('<div class="facet mkwsFacet' + caption + ' mkwsTeam_' + teamName + '">');
128                 acc.push('<div class="termtitle">' + M(caption) + '</div>');
129                 for (var i = 0; i < data.length && i < max; i++) {
130                     acc.push('<div class="term">');
131                     acc.push('<a href="#" ');
132                     var action = '';
133                     if (!pzIndex) {
134                         // Special case: target selection
135                         acc.push('target_id='+data[i].id+' ');
136                         if (!that.team.targetFiltered(data[i].id)) {
137                             action = 'mkws.limitTarget(\'' + teamName + '\', this.getAttribute(\'target_id\'),this.firstChild.nodeValue)';
138                         }
139                     } else {
140                         action = 'mkws.limitQuery(\'' + teamName + '\', \'' + pzIndex + '\', this.firstChild.nodeValue)';
141                     }
142                     acc.push('onclick="' + action + ';return false;">' + data[i].name + '</a>'
143                              + ' <span>' + data[i].freq + '</span>');
144                     acc.push('</div>');
145                 }
146                 acc.push('</div>');
147             }
148         });
149     }
150
151
152     function promotePager() {
153         var that = this;
154         var M = mkws.M;
155
156         this.team.queue("pager").subscribe(function(data) {
157             $(that.node).html(drawPager(data))
158
159             function drawPager(data) {
160                 var teamName = that.team.name();
161                 var s = '<div style="float: right">' + M('Displaying') + ': '
162                     + (data.start + 1) + ' ' + M('to') + ' ' + (data.start + data.num) +
163                     ' ' + M('of') + ' ' + data.merged + ' (' + M('found') + ': '
164                     + data.total + ')</div>';
165
166                 //client indexes pages from 1 but pz2 from 0
167                 var onsides = 6;
168                 var pages = Math.ceil(that.team.totalRecordCount() / that.team.perpage());
169                 var currentPage = that.team.currentPage();
170
171                 var firstClkbl = (currentPage - onsides > 0)
172                     ? currentPage - onsides
173                     : 1;
174
175                 var lastClkbl = firstClkbl + 2*onsides < pages
176                     ? firstClkbl + 2*onsides
177                     : pages;
178
179                 var prev = '<span class="mkwsPrev">&#60;&#60; ' + M('Prev') + '</span><b> | </b>';
180                 if (currentPage > 1)
181                     prev = '<a href="#" class="mkwsPrev" onclick="mkws.pagerPrev(\'' + teamName + '\');">'
182                     +'&#60;&#60; ' + M('Prev') + '</a><b> | </b>';
183
184                 var middle = '';
185                 for(var i = firstClkbl; i <= lastClkbl; i++) {
186                     var numLabel = i;
187                     if(i == currentPage)
188                         numLabel = '<b>' + i + '</b>';
189
190                     middle += '<a href="#" onclick="mkws.showPage(\'' + teamName + '\', ' + i + ')"> '
191                         + numLabel + ' </a>';
192                 }
193
194                 var next = '<b> | </b><span class="mkwsNext">' + M('Next') + ' &#62;&#62;</span>';
195                 if (pages - currentPage > 0)
196                     next = '<b> | </b><a href="#" class="mkwsNext" onclick="mkws.pagerNext(\'' + teamName + '\')">'
197                     + M('Next') + ' &#62;&#62;</a>';
198
199                 var predots = '';
200                 if (firstClkbl > 1)
201                     predots = '...';
202
203                 var postdots = '';
204                 if (lastClkbl < pages)
205                     postdots = '...';
206
207                 s += '<div style="float: clear">'
208                     + prev + predots + middle + postdots + next + '</div>';
209
210                 return s;
211             }
212         });
213     }                        
214
215
216     function promoteRecords() {
217         var that = this;
218         var team = this.team;
219
220         this.team.queue("records").subscribe(function(data) {
221             var html = [];
222             for (var i = 0; i < data.hits.length; i++) {
223                 var hit = data.hits[i];
224                 var divId = team.recordElementId(hit.recid[0]);
225                 html.push('<div class="record mkwsTeam_' + team.name() + ' ' + divId + '">', renderSummary(hit), '</div>');
226                 // ### At some point, we may be able to move the
227                 // m_currentRecordId and m_currentRecordData members
228                 // from the team object into this widget.
229                 if (hit.recid == team.currentRecordId()) {
230                     if (team.currentRecordData())
231                         html.push(team.renderDetails(team.currentRecordData()));
232                 }
233             }
234             $(that.node).html(html.join(''));
235
236             function renderSummary(hit)
237             {
238                 var template = team.loadTemplate("Summary");
239                 hit._id = team.recordElementId(hit.recid[0]);
240                 hit._onclick = "mkws.showDetails('" + team.name() + "', '" + hit.recid[0] + "');return false;"
241                 return template(hit);
242             }
243         });
244     }
245
246
247     function promoteNavi() {
248         var that = this;
249         var teamName = this.team.name();
250         var M = mkws.M;
251
252         this.team.queue("navi").subscribe(function() {
253             var filters = that.team.filters();
254             var text = "";
255
256             for (var i in filters) {
257                 if (text) {
258                     text += " | ";
259                 }
260                 var filter = filters[i];
261                 if (filter.id) {
262                     text += M('source') + ': <a class="crossout" href="#" onclick="mkws.delimitTarget(\'' + teamName +
263                         "', '" + filter.id + "'" + ');return false;">' + filter.name + '</a>';
264                 } else {
265                     text += M(filter.field) + ': <a class="crossout" href="#" onclick="mkws.delimitQuery(\'' + teamName +
266                         "', '" + filter.field + "', '" + filter.value + "'" +
267                         ');return false;">' + filter.value + '</a>';
268                 }
269             }
270
271             $(that.node).html(text);
272         });
273     }
274
275
276     function promoteSort() {
277         // It seems this and the Perpage widget doen't need to
278         // subscribe to anything, since they produce events rather
279         // than consuming them.
280         $(this.node).change(function () {
281             this.team.set_sortOrder($(node).val());
282             if (this.team.submitted()) {
283                 this.team.resetPage();
284                 this.team.reShow();
285             }
286             return false;
287         });
288     }
289
290
291     function promotePerpage() {
292         $(this.node).change(function() {
293             this.team.set_perpage($(node).val());
294             if (this.team.submitted()) {
295                 this.team.resetPage();
296                 this.team.reShow();
297             }
298             return false;
299         });
300     }