Initial dev repository
[kcls-web.git] / js / ui / default / cat / authority / list.js
1 /*
2  * Copyright (C) 2010 Internationaal Instituut voor Sociale Geschiedenis <info@iisg.nl>
3  * Dan Scott <dan@coffeecode.net>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.  
14  *
15  */
16 dojo.require('dijit.form.Button');
17 dojo.require('dijit.form.DropDownButton');
18 dojo.require('dijit.form.FilteringSelect');
19 dojo.require('dijit.form.Form');
20 dojo.require('dijit.form.NumberSpinner');
21 dojo.require('dijit.form.TextBox');
22 dojo.require("dijit.Menu");
23 dojo.require("dijit.MenuItem");
24 dojo.require('dojox.xml.parser');
25 dojo.require('DojoSRF');
26 dojo.require("fieldmapper.Fieldmapper");
27 dojo.require('openils.CGI');
28 dojo.require('openils.PermaCrud');
29 dojo.require('openils.XUL');
30 dojo.require('openils.widget.OrgUnitFilteringSelect');
31
32 var cgi = new openils.CGI();
33
34 /*
35 // OrgUnits do not currently affect the retrieval of authority records,
36 // but this is how to display them if they become OrgUnit-aware
37 function authOUListInit() {
38     new openils.User().buildPermOrgSelector(
39         "STAFF_LOGIN", // anywhere you can log in
40         dijit.byId("authOU"),
41         null, // pre-selected org
42         null
43     );
44 }
45 dojo.addOnLoad(authOUListInit);
46 */
47 function displayAuthorities(data) { 
48
49     var idArr = [];
50     // Grab each record from the returned authority records
51     dojo.query("record", data).forEach(function(node) {
52         var auth = {};
53         auth.text = '';
54         auth.id = 0;
55
56         // Grab each authority record field from the authority record
57         dojo.query("datafield[tag^='1']", node).forEach(function(dfNode) {
58             auth.text += dojox.xml.parser.textContent(dfNode); 
59             auth.name = dojo.attr(dfNode, 'tag');
60             auth.ind1 = dojo.attr(dfNode, 'ind1');
61             auth.ind2 = dojo.attr(dfNode, 'ind2');
62         });
63
64         
65         // Grab the ID of the authority record
66         dojo.query("datafield[tag='901'] subfield[code='c']", node).forEach(function(dfNode) {
67             auth.id = dojox.xml.parser.textContent(dfNode); 
68         });
69
70         idArr.push(parseInt(auth.id));
71
72         // Create the authority record listing entry
73         dojo.place('<div class="authEntry" id="auth' + auth.id + '"><span class="text" id="authLabel' + auth.id + '">' + auth.text + '</span></div>', "authlist-div", "last");
74
75         // Add the menu of new/edit/delete/mark-for-merge options
76         var auth_menu = new dijit.Menu({});
77
78         // "Edit" menu item
79         new dijit.MenuItem({"id": "edit_" + auth.id, "onClick": function(){
80             var pcrud = new openils.PermaCrud();
81             var auth_rec = pcrud.retrieve("are", auth.id);
82             if (auth_rec) {
83                 loadMarcEditor(pcrud, auth_rec);
84             }
85         }, "label":"Edit"}).placeAt(auth_menu, "first");
86
87         // "Merge" menu item
88         new dijit.MenuItem({"id": "merge_" + auth.id, "onClick":function(){
89             auth.text = '';
90             dojo.query('#auth' + auth.id + ' span.text').forEach(function(node) {
91                 auth.text += dojox.xml.parser.textContent(node); 
92             });
93
94             // If there is a toMerge item already, this is a target record
95             var mergeRole = '<td style="border: 1px solid black; padding-left: 0.5em; padding-right: 1em;">';
96             var isTarget = dojo.query('.toMerge').length;
97             if (isTarget) {
98                 mergeRole += 'Target</td>';
99             } else {
100                 mergeRole += 'Master</td>';
101             }
102
103             dojo.place('<tr class="toMerge" id="toMerge_' + auth.id + '"><td>' + mergeRole + '</td><td  style="border: 1px solid black;" id="mergeMeta_' + auth.id + '"></td><td style="border: 1px solid black; padding-left: 1em; padding-right: 1em;" >' + auth.text + '</td></tr>', 'mergebox-tbody', 'last');
104             dojo.place('<span class="authmeta" style="font-family: monospace;">' + auth.name + ' ' + auth.ind1 + auth.ind2 + '</span>', 'mergeMeta_' + auth.id, 'last');
105             dojo.removeClass('mergebox-div', 'hidden');
106         }, "label":"Mark for Merge"}).placeAt(auth_menu, "last");
107
108         // "Delete" menu item
109         new dijit.MenuItem({
110             "id": "delete_" + auth.id,
111             "onClick":function(){
112                 auth.text = '';
113
114                 var pcrud = new openils.PermaCrud();
115                 var auth_rec = pcrud.retrieve("are", auth.id);
116
117                 // Bit of a hack to get the linked bib count until an explicit ID
118                 var linkedBibs = dojox.xml.parser.textContent(
119                     dojo.query("#authLabel" + auth.id)[0].previousSibling
120                 );
121
122                 var delDlg = dijit.byId("delDialog_" + auth.id);
123
124                 dojo.query('#auth' + auth.id + ' span.text').forEach(function(node) {
125                     auth.text += dojo.trim(dojox.xml.parser.textContent(node)); 
126                 });
127
128                 if (!delDlg) {
129                     var content = '<div>Delete the authority record: "' + auth.text + '"?</div>';
130                     if (parseInt(linkedBibs) > 0) {
131                         content = "<div id='delAuthSum_" + auth.id + "'>Number of linked bibliographic records: " + linkedBibs + "</div>";
132                     }
133                     content += "<div id='authMARC" + auth.id + "' style='width: 100%; display:none;'>";
134                     content += "<hr style='width: 100%;' />";
135                     content += marcToHTML(auth_rec.marc());
136                     content += "</div><hr style='width: 100%;' /><div>";
137                     content += "<input type='button' dojoType='dijit.form.Button' label='Cancel' onClick='cancelDelete(" + auth.id + ")'/>";
138                     content += "<input type='button' dojoType='dijit.form.Button' label='Delete' onClick='confirmDelete(" + auth.id + ")'/>";
139                     content += "<input id='viewMARC" + auth.id + "' type='button' "
140                         + "style='float:right;' dojoType='dijit.form.Button' "
141                         + "label='View MARC' onClick='viewMARC(" + auth.id + ")'/>";
142                     content += "<input id='hideMARC" + auth.id + "' type='button' "
143                         + "style='display: none; float:right;' dojoType='dijit.form.Button' "
144                         + "label='Hide MARC' onClick='hideMARC(" + auth.id + ")'/>";
145                     content += "</div>";
146                     delDlg = new dijit.Dialog({
147                         "id":"delDialog_" + auth.id,
148                         "title":"Confirm deletion of record # " + auth.id,
149                         "content": content
150                     });
151                 }
152                 delDlg.show();
153
154         }, "label":"Delete"}).placeAt(auth_menu, "last");
155
156         auth_mb = new dijit.form.DropDownButton({dropDown: auth_menu, label:"Actions", id:"menu" + auth.id});
157         auth_mb.placeAt("auth" + auth.id, "first");
158         auth_menu.startup();
159     });
160
161     showBibCount(idArr);
162 }
163
164 function viewMARC(recId) {
165     dojo.style(dojo.byId("authMARC" + recId), 'display', 'block');
166     dojo.style(dijit.byId("viewMARC" + recId).domNode, 'display', 'none');
167     dojo.style(dijit.byId("hideMARC" + recId).domNode, 'display', 'block');
168 }
169
170 function hideMARC(recId) {
171     dojo.style(dojo.byId("authMARC" + recId), 'display', 'none');
172     dojo.style(dijit.byId("hideMARC" + recId).domNode, 'display', 'none');
173     dojo.style(dijit.byId("viewMARC" + recId).domNode, 'display', 'block');
174 }
175
176 function marcToHTML(marc) {
177     var html = '<table><tbody>';
178     marc = dojox.xml.parser.parse(marc);
179     dojo.query('leader', marc).forEach(function(node) {
180         html += '<tr><td>LDR</td><td>&nbsp;</td><td>&nbsp;</td><td>' + dojox.xml.parser.textContent(node) + '</td></tr>';
181     });
182     dojo.query('controlfield', marc).forEach(function(node) {
183         html += '<tr><td>' + dojo.attr(node, "tag") + '</td><td>&nbsp;</td><td>&nbsp;</td><td>' + dojox.xml.parser.textContent(node) + '</td></tr>';
184     });
185     dojo.query('datafield', marc).forEach(function(node) {
186         var cnt = 0;
187         html += '<tr><td>' + dojo.attr(node, "tag") + '</td><td>' + dojo.attr(node, "ind1") + '</td><td>' + dojo.attr(node, "ind2") + '</td>';
188         dojo.query('subfield', node).forEach(function(sf) {
189             if (cnt == 0) {
190                 html += '<td>$' + dojo.attr(sf, "code") + ' ' + dojox.xml.parser.textContent(sf) + '</td></tr>';
191                 cnt = 1;
192             } else {
193                 html += '<tr><td colspan="3"></td><td>$' + dojo.attr(sf, "code") + ' ' + dojox.xml.parser.textContent(sf) + '</td></tr>';
194             }
195         });
196     });
197     html += '</tbody></table>';
198     return html;
199 }
200
201 function cancelDelete(recId) {
202     dijit.byId("delDialog_" + recId).hide();
203 }
204
205 function confirmDelete(recId) {
206     var pcrud = new openils.PermaCrud();
207     var auth_rec = pcrud.retrieve("are", recId);
208     if (auth_rec) {
209         pcrud.eliminate(auth_rec);
210         dijit.byId("delDialog_" + recId).attr("content", "Deleted authority record # " + recId);
211         setTimeout(function() {
212             dijit.byId("delDialog_" + recId).hide();
213         }, 3000);
214     }
215 }
216
217 function showBibCount(authIds) {
218     /* Decorate the list with # of bibs linked to each authority record */
219     var ses = new OpenSRF.ClientSession('open-ils.cat');
220     var req = ses.request('open-ils.cat.authority.records.count_linked_bibs', authIds);
221     var linkedIds = [];
222     req.oncomplete = function(r) {
223         var msg = r.recv().content();
224         dojo.forEach(msg, function(auth) {
225                 linkedIds.push(auth.authority);
226                 dojo.place('<span class="bibcount">' + auth.bibs + '</span>', 'authLabel' + auth.authority, 'before');
227             }
228         );
229
230         /* Assign counts of 0 for every non-linked authority */
231         dojo.forEach(authIds, function (id) {
232             var found = false;
233             dojo.forEach(linkedIds, function (lid) {
234                 if (id == lid) {
235                     found = true;
236                 }
237             });
238             if (!found) {
239                 dojo.place('<span class="bibcount">0</span>', 'authLabel' + id, 'before');
240             }
241         });
242     }
243     req.send();
244 }
245
246 function loadMarcEditor(pcrud, rec) {
247     /*
248        To run in Firefox directly, must set signed.applets.codebase_principal_support
249        to true in about:config
250      */
251     netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
252     win = window.open('/xul/server/cat/marcedit.xul'); // XXX version?
253
254     win.xulG = {
255         "record": {"marc": rec.marc(), "rtype": "are"},
256         "save": {
257             "label": "Save",
258             "func": function(xmlString) {
259                 rec.marc(xmlString);
260                 rec.edit_date('now');
261                 rec.ischanged(true);
262                 pcrud.update(rec);
263                 alert("Record was saved");
264                 win.close();
265             }
266         }
267     };
268 }
269
270 function authListInit() {
271     var term = cgi.param('authTerm') || '';
272     var page = cgi.param('authPage') || 0;
273     var axis = cgi.param('authAxis') || 'authority.author';
274     if (axis) {
275         dijit.byId('authAxis').attr('value', axis);
276     }
277     if (page) {
278         dijit.byId('authPage').attr('value', page);
279     }
280     if (term) {
281         dijit.byId('authTerm').attr('value', term);
282         displayRecords();
283     }
284
285     dojo.connect(dijit.byId('authAxis'), 'onKeyPress', function(evt) {
286         if (evt.keyCode == dojo.keys.ENTER) {
287             dijit.byId('authPage').attr('value', 0);
288             displayRecords();
289         }
290     }); 
291
292     dojo.connect(dijit.byId('authPage'), 'onKeyPress', function(evt) {
293         if (evt.keyCode == dojo.keys.ENTER) {
294             dijit.byId('authPage').attr('value', 0);
295             displayRecords();
296         }
297     });
298
299     dojo.connect(dijit.byId('authTerm'), 'onKeyPress', function(evt) {
300         if (evt.keyCode == dojo.keys.ENTER) {
301             dijit.byId('authPage').attr('value', 0);
302             displayRecords();
303         }
304     });
305
306     dijit.byId('authTerm').focus();
307
308 }
309 dojo.addOnLoad(authListInit);
310
311 function displayRecords(parms) {
312
313     if (parms && parms.page) {
314         if (parms.page == 'next') {
315             page = dijit.byId('authPage').attr('value');
316             dijit.byId('authPage').attr('value', page + 1);
317         } else if (parms.page == 'prev') {
318             page = dijit.byId('authPage').attr('value');
319             dijit.byId('authPage').attr('value', page - 1);
320         } else {
321             dijit.byId('authPage').attr('value', parms.page);
322         }
323     }
324
325     /* Protect against null input */
326     if (!dijit.byId('authTerm').attr('value')) {
327         return;
328     }
329
330     /* Clear out the current contents of the page */
331     var widgets = dijit.findWidgets(dojo.byId('authlist-div'));
332     dojo.forEach(widgets, function(w) { w.destroyRecursive(true); });
333
334     dojo.query("#authlist-div div").orphan();
335
336     var url = '/opac/extras/startwith/marcxml/'
337         + dijit.byId('authAxis').attr('value')
338         // + '/' + dijit.byId('authOU').attr('value')
339         + '/1' // replace with preceding line if OUs gain some meaning
340         + '/' + dijit.byId('authTerm').attr('value')
341         + '/' + dijit.byId('authPage').attr('value')
342         + '/' + '20' // 20 results per page
343     ;
344     dojo.xhrGet({"url":url, "handleAs":"xml", "content":{"format":"marcxml"}, "preventCache": true, "load":displayAuthorities });
345 }
346
347 function clearMergeRecords() {
348     var records = dojo.query('.toMerge').orphan();
349     dojo.addClass('mergebox-div', 'hidden');
350 }
351
352 function mergeRecords() {
353     var records = dojo.query('.toMerge').attr('id');
354     dojo.forEach(records, function(item, idx) {
355         records[idx] = parseInt(item.slice(item.lastIndexOf('_') + 1));
356     });
357
358     /* Take the first record in the list and use that as the master */
359     fieldmapper.standardRequest(
360         ['open-ils.cat', 'open-ils.cat.authority.records.merge'],
361         {   async: false,
362             params: [openils.User.authtoken, records.shift(), records],
363             oncomplete : function(r) {
364                 alert("Record merge is complete.");
365                 clearMergeRecords();
366                 displayRecords();
367             }
368         }
369     );
370 }