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