1 /* ---------------------------------------------------------------------------
2 # Copyright (C) 2008 Georgia Public Library Service
3 # Bill Erickson <erickson@esilibrary.com>
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.
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 dojo.require("dojo.parser");
16 dojo.require("dojo.io.iframe");
17 dojo.require("dijit.ProgressBar");
18 dojo.require("dijit.form.Button");
19 dojo.require("dijit.form.FilteringSelect");
20 dojo.require("dijit.layout.ContentPane");
21 dojo.require("dijit.layout.TabContainer");
22 dojo.require("dojo.cookie");
23 dojo.require("dojox.grid.Grid");
24 dojo.require("dojo.data.ItemFileReadStore");
25 dojo.require('dojo.date.locale');
26 dojo.require('dojo.date.stamp');
27 dojo.require("fieldmapper.Fieldmapper");
28 dojo.require("fieldmapper.dojoData");
29 dojo.require('openils.CGI');
30 dojo.require('openils.User');
31 dojo.require('openils.Event');
34 'vl-generic-progress',
35 'vl-generic-progress-with-total',
40 'vl-queue-select-div',
41 'vl-marc-upload-status-div'
45 var VANDELAY_URL = '/vandelay';
47 var authAttrDefs = [];
48 var queuedRecords = [];
49 var queuedRecordsMap = {};
50 var bibAttrsFetched = false;
51 var authAttrsFetched = false;
52 var attrDefMap = {}; // maps attr def code names to attr def ids
54 var currentQueueId = null;
56 var currentMatchedRecords; // set of loaded matched bib records
57 var currentOverlayRecordsMap; // map of import record to overlay record
58 var currentImportRecId; // when analyzing matches, this is the current import record
61 var selectableGridRecords;
62 var cgi = new openils.CGI();
68 authtoken = dojo.cookie('ses') || cgi.param('ses');
69 var initNeeded = 4; // how many async responses do we need before we're init'd
70 var initCount = 0; // how many async reponses we've received
72 function checkInitDone() {
74 if(initCount == initNeeded)
78 // Fetch the bib and authority attribute definitions
79 fieldmapper.standardRequest(
80 ['open-ils.permacrud', 'open-ils.permacrud.search.vqbrad'],
82 params: [authtoken, {id:{'!=':null}}],
83 onresponse: function(r) {
84 var def = r.recv().content();
85 if(e = openils.Event.parse(def[0]))
87 bibAttrDefs.push(def);
89 oncomplete: function() {
90 bibAttrDefs = bibAttrDefs.sort(
92 if(a.id() > b.id()) return 1;
93 if(a.id() < b.id()) return -1;
102 fieldmapper.standardRequest(
103 ['open-ils.permacrud', 'open-ils.permacrud.search.vqarad'],
105 params: [authtoken, {id:{'!=':null}}],
106 onresponse: function(r) {
107 var def = r.recv().content();
108 if(e = openils.Event.parse(def[0]))
110 authAttrDefs.push(def);
112 oncomplete: function() {
113 authAttrDefs = authAttrDefs.sort(
115 if(a.id() > b.id()) return 1;
116 if(a.id() < b.id()) return -1;
125 fieldmapper.standardRequest(
126 ['open-ils.vandelay', 'open-ils.vandelay.bib_queue.owner.retrieve.atomic'],
129 oncomplete: function(r) {
130 var list = r.recv().content();
131 if(e = openils.Event.parse(list[0]))
133 userBibQueues = list;
139 fieldmapper.standardRequest(
140 ['open-ils.vandelay', 'open-ils.vandelay.authority_queue.owner.retrieve.atomic'],
143 oncomplete: function(r) {
144 var list = r.recv().content();
145 if(e = openils.Event.parse(list[0]))
147 userAuthQueues = list;
154 function displayGlobalDiv(id) {
155 for(var i = 0; i < globalDivs.length; i++) {
157 dojo.style(dojo.byId(globalDivs[i]), 'display', 'none');
159 alert('please define ' + globalDivs[i]);
162 dojo.style(dojo.byId(id),'display','block');
165 function runStartupCommands() {
166 currentQueueId = cgi.param('qid');
167 currentType = cgi.param('qtype');
169 return retrievenueuedRecords(currentType, currentQueueId, handleRetrieveRecords);
174 * asynchronously upload a file of MARC records
176 function uploadMARC(onload){
177 dojo.byId('vl-ses-input').value = authtoken;
178 displayGlobalDiv('vl-marc-upload-status-div');
179 dojo.io.iframe.send({
183 form: dojo.byId('vl-marc-upload-form'),
184 handle: function(data,ioArgs){
185 var content = data.documentElement.textContent;
192 * Creates a new vandelay queue
194 function createQueue(queueName, type, onload) {
195 fieldmapper.standardRequest(
196 ['open-ils.vandelay', 'open-ils.vandelay.'+type+'_queue.create'],
198 params: [authtoken, queueName, null, type],
199 oncomplete : function(r) {
200 var queue = r.recv().content();
201 if(e = openils.Event.parse(queue))
210 * Tells vendelay to pull a batch of records from the cache and explode them
211 * out into the vandelay tables
213 function processSpool(key, queueId, type, onload) {
214 fieldmapper.standardRequest(
215 ['open-ils.vandelay', 'open-ils.vandelay.'+type+'.process_spool'],
217 params: [authtoken, key, queueId],
218 oncomplete : function(r) {
219 var resp = r.recv().content();
220 if(e = openils.Event.parse(resp))
228 function retrieveQueuedRecords(type, queueId, onload) {
229 displayGlobalDiv('vl-generic-progress');
231 queuedRecordsMap = {};
232 currentOverlayRecordsMap = {};
233 selectableGridRecords = {};
234 resetVlQueueGridLayout();
236 fieldmapper.standardRequest(
237 ['open-ils.vandelay', 'open-ils.vandelay.'+type+'_queue.records.retrieve.atomic'],
239 params: [authtoken, queueId, {clear_marc:1}],
240 /* intermittent bug in streaming, multipart requests prevents use of onreponse for now...
241 onresponse: function(r) {
242 var rec = r.recv().content();
243 if(e = openils.Event.parse(rec))
245 queuedRecords.push(rec);
246 queuedRecordsMap[rec.id()] = rec;
249 oncomplete: function(r){
250 var recs = r.recv().content();
251 if(e = openils.Event.parse(recs[0]))
253 for(var i = 0; i < recs.length; i++) {
255 queuedRecords.push(rec);
256 queuedRecordsMap[rec.id()] = rec;
264 function vlLoadMatchUI(recId, attrCode) {
265 displayGlobalDiv('vl-generic-progress');
266 var matches = getRecMatchesFromAttrCode(queuedRecordsMap[recId], attrCode);
268 currentImportRecId = recId;
269 for(var i = 0; i < matches.length; i++)
270 records.push(matches[i].eg_record());
271 fieldmapper.standardRequest(
272 ['open-ils.search', 'open-ils.search.biblio.record_entry.slim.retrieve'],
275 oncomplete: function(r) {
276 var recs = r.recv().content();
277 if(e = openils.Event.parse(recs))
279 displayGlobalDiv('vl-match-div');
280 resetVlMatchGridLayout();
281 currentMatchedRecords = recs;
282 vlMatchGrid.setStructure(vlMatchGridLayout);
283 var dataStore = bre.toStoreData(recs, null, {virtualFields:['field_type']});
284 for(var i = 0; i < dataStore.items.length; i++) {
285 var item = dataStore.items[i];
286 for(var j = 0; j < matches.length; j++) {
287 var match = matches[j];
288 if(match.eg_record() == item.id)
289 item.field_type = match.field_type();
292 var store = new dojo.data.ItemFileReadStore({data:dataStore});
293 var model = new dojox.grid.data.DojoData(
294 null, store, {rowsPerPage: 100, clientSort: true, query:{id:'*'}});
295 vlMatchGrid.setModel(model);
296 vlMatchGrid.update();
303 function vlLoadMARCHtml(recId) {
304 displayGlobalDiv('vl-generic-progress');
305 fieldmapper.standardRequest(
306 ['open-ils.search', 'open-ils.search.biblio.record.html'],
309 oncomplete: function(r) {
310 displayGlobalDiv('vl-match-html-div');
311 var html = r.recv().content();
312 dojo.byId('vl-match-record-html').innerHTML = html;
320 * Given a record, an attribute definition code, and a matching record attribute,
321 * this will determine if there are any import matches and build the UI to
322 * represent those matches. If no matches exist, simply returns the attribute value
324 function buildAttrColumnUI(rec, attrCode, attr) {
325 var matches = getRecMatchesFromAttrCode(rec, attrCode);
326 if(matches.length > 0) { // found some matches
327 return '<div class="match_div">' +
328 '<a href="javascript:void(0);" onclick="vlLoadMatchUI('+
329 rec.id()+',\''+attrCode+'\');">'+
330 attr.attr_value() + ' ('+matches.length+')</a></div>';
333 return attr.attr_value();
336 function getRecMatchesFromAttrCode(rec, attrCode) {
338 var attr = getRecAttrFromCode(rec, attrCode);
339 for(var j = 0; j < rec.matches().length; j++) {
340 var match = rec.matches()[j];
341 if(match.matched_attr() == attr.id())
347 function getRecAttrFromCode(rec, attrCode) {
348 var defId = attrDefMap[attrCode];
349 var attrs = rec.attributes();
350 for(var i = 0; i < attrs.length; i++) {
352 if(attr.field() == defId)
358 function getAttrValue(rowIdx) {
359 var data = this.grid.model.getRow(rowIdx);
361 var attrCode = this.field.split('.')[1];
362 console.log(attrCode + " : " + data.id + ' : ' + queuedRecordsMap[data.id] + " : count = " + queuedRecords.length);
363 var rec = queuedRecordsMap[data.id];
364 var attr = getRecAttrFromCode(rec, attrCode);
366 return buildAttrColumnUI(rec, attrCode, attr);
370 function vlGetDateTimeField(rowIdx) {
371 data = this.grid.model.getRow(rowIdx);
373 if(!data[this.field]) return '';
374 var date = dojo.date.stamp.fromISOString(data[this.field]);
375 return dojo.date.locale.format(date, {selector:'date'});
378 function vlGetCreator(rowIdx) {
379 data = this.grid.model.getRow(rowIdx);
381 var id = data.creator;
383 return userCache[id].usrname();
384 var user = fieldmapper.standardRequest(['open-ils.actor', 'open-ils.actor.user.retrieve'], [authtoken, id]);
385 if(e = openils.Event.parse(user))
387 userCache[id] = user;
388 return user.usrname();
391 function vlGetViewMARC(rowIdx) {
392 data = this.grid.model.getRow(rowIdx);
394 return this.value.replace('RECID', data.id);
397 function vlGetOverlayTargetSelector(rowIdx) {
398 data = this.grid.model.getRow(rowIdx);
400 var value = this.value.replace('ID', data.id);
401 var overlay = currentOverlayRecordsMap[currentImportRecId];
402 if(overlay && overlay == data.id)
403 value = value.replace('/>', 'checked="checked"/>');
409 * see if the user has enabled overlays for the current match set and,
410 * if so, map the current import record to the overlay target.
412 function vlHandleOverlayTargetSelected() {
413 if(vlOverlayTargetEnable.checked) {
414 for(var i = 0; i < currentMatchedRecords.length; i++) {
415 var matchRecId = currentMatchedRecords[i].id();
416 if(dojo.byId('vl-overlay-target-'+matchRecId).checked) {
417 console.log("found overlay target " + matchRecId);
418 currentOverlayRecordsMap[currentImportRecId] = matchRecId;
419 dojo.byId('vl-record-list-selected-' + currentImportRecId).checked = true;
420 dojo.byId('vl-record-list-selected-' + currentImportRecId).parentNode.className = 'overlay_selected';
425 delete currentOverlayRecordsMap[currentImportRecId];
426 dojo.byId('vl-record-list-selected-' + currentImportRecId).checked = false;
430 function buildRecordGrid(type) {
431 displayGlobalDiv('vl-queue-div');
433 currentOverlayRecordsMap = {};
435 if(queuedRecords.length == 0) {
436 dojo.style(dojo.byId('vl-queue-no-records'), 'display', 'block');
437 dojo.style(dojo.byId('vl-queue-div-grid'), 'display', 'none');
440 dojo.style(dojo.byId('vl-queue-no-records'), 'display', 'none');
441 dojo.style(dojo.byId('vl-queue-div-grid'), 'display', 'block');
444 var defs = (type == 'bib') ? bibAttrDefs : authAttrDefs;
445 for(var i = 0; i < defs.length; i++) {
447 attrDefMap[def.code()] = def.id();
449 name:def.description(),
450 field:'attr.' + def.code(),
453 //if(def.code().match(/title/i)) col.width = 'auto'; // this is hack.
454 vlQueueGridLayout[0].cells[0].push(col);
459 storeData = vqbr.toStoreData(queuedRecords);
461 storeData = vqar.toStoreData(queuedRecords);
463 var store = new dojo.data.ItemFileReadStore({data:storeData});
464 var model = new dojox.grid.data.DojoData(
465 null, store, {rowsPerPage: 100, clientSort: true, query:{id:'*'}});
467 vlQueueGrid.setModel(model);
468 vlQueueGrid.setStructure(vlQueueGridLayout);
469 vlQueueGrid.update();
474 alert(vlQueueGridLayout.picker);
475 vlQueueGridLayout.oils = {};
476 vlQueueGridLayout[0].cells[0].pop();
477 vlQueueGridLayout[0].cells[0].pop();
478 vlQueueGridLayout[0].cells[0].pop();
479 vlQueueGridLayout[0].cells[0].pop();
480 vlQueueGridLayout[0].cells[0].pop();
481 vlQueueGrid.setStructure(vlQueueGridLayout);
482 vlQueueGrid.update();
486 function vlQueueGridDrawSelectBox(rowIdx) {
487 var data = this.grid.model.getRow(rowIdx);
489 var domId = 'vl-record-list-selected-' +data.id;
490 selectableGridRecords[domId] = data.id;
491 return "<div><input type='checkbox' id='"+domId+"'/></div>";
494 function vlSelectAllGridRecords() {
495 for(var id in selectableGridRecords)
496 dojo.byId(id).checked = true;
498 function vlSelectNoGridRecords() {
499 for(var id in selectableGridRecords)
500 dojo.byId(id).checked = false;
503 var handleRetrieveRecords = function() {
504 buildRecordGrid(currentType);
507 function vlImportSelectedRecords() {
508 displayGlobalDiv('vl-generic-progress-with-total');
511 for(var id in selectableGridRecords) {
512 if(dojo.byId(id).checked) {
513 var recId = selectableGridRecords[id];
514 var rec = queuedRecordsMap[recId];
515 if(!rec.import_time())
520 fieldmapper.standardRequest(
521 ['open-ils.vandelay', 'open-ils.vandelay.'+currentType+'_record.list.import'],
523 params: [authtoken, records, {overlay_map:currentOverlayRecordsMap}],
524 onresponse: function(r) {
525 var resp = r.recv().content();
526 if(e = openils.Event.parse(resp))
528 vlControlledProgressBar.update({maximum:resp.total, progress:resp.progress});
530 oncomplete: function() {
531 return retrieveQueuedRecords(currentType, currentQueueId, handleRetrieveRecords);
539 * Create queue, upload MARC, process spool, load the newly created queue
541 function batchUpload() {
542 var queueName = dijit.byId('vl-queue-name').getValue();
543 currentType = dijit.byId('vl-record-type').getValue();
545 var handleProcessSpool = function() {
546 console.log('records uploaded and spooled');
547 retrieveQueuedRecords(currentType, currentQueueId, handleRetrieveRecords);
550 var handleUploadMARC = function(key) {
551 console.log('marc uploaded');
552 dojo.style(dojo.byId('vl-upload-status-processing'), 'display', 'block');
553 processSpool(key, currentQueueId, currentType, handleProcessSpool);
556 var handleCreateQueue = function(queue) {
557 console.log('queue created ' + queue.name());
558 currentQueueId = queue.id();
559 uploadMARC(handleUploadMARC);
562 if(vlUploadQueueSelector.getValue() && !queueName) {
563 currentQueueId = vlUploadQueueSelector.getValue();
564 console.log('adding records to existing queue ' + currentQueueId);
565 uploadMARC(handleUploadMARC);
567 createQueue(queueName, currentType, handleCreateQueue);
572 function vlFleshQueueSelect(selector, type) {
573 var data = (type == 'bib') ? vbq.toStoreData(userBibQueues) : vaq.toStoreData(userAuthQueues);
574 selector.store = new dojo.data.ItemFileReadStore({data:data});
575 selector.setValue(null);
576 selector.setDisplayedValue('');
578 selector.setValue(data[0].id());
581 function vlShowUploadForm() {
582 displayGlobalDiv('vl-marc-upload-div');
583 vlFleshQueueSelect(vlUploadQueueSelector, vlUploadRecordType.getValue());
586 function vlShowQueueSelect() {
587 displayGlobalDiv('vl-queue-select-div');
588 vlFleshQueueSelect(vlQueueSelectQueueList, vlQueueSelectType.getValue());
591 function vlFetchQueueFromForm() {
592 currentType = vlQueueSelectType.getValue();
593 currentQueueId = vlQueueSelectQueueList.getValue();
594 retrieveQueuedRecords(currentType, currentQueueId, handleRetrieveRecords);
597 dojo.addOnLoad(vlInit);