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.FilteringSelect");
19 dojo.require("dijit.layout.ContentPane");
20 dojo.require("dijit.layout.TabContainer");
21 dojo.require("dijit.layout.LayoutContainer");
22 dojo.require('dijit.form.Button');
23 dojo.require('dijit.form.CheckBox');
24 dojo.require('dijit.Toolbar');
25 dojo.require('dijit.Tooltip');
26 dojo.require('dijit.Menu');
27 dojo.require("dijit.Dialog");
28 dojo.require("dojo.cookie");
29 dojo.require('dojox.grid.DataGrid');
30 dojo.require("dojo.data.ItemFileReadStore");
31 dojo.require('dojo.date.locale');
32 dojo.require('dojo.date.stamp');
33 dojo.require("fieldmapper.Fieldmapper");
34 dojo.require("fieldmapper.dojoData");
35 dojo.require("fieldmapper.OrgUtils");
36 dojo.require('openils.CGI');
37 dojo.require('openils.User');
38 dojo.require('openils.Event');
39 dojo.require('openils.Util');
40 dojo.require('openils.MarcXPathParser');
41 dojo.require('openils.widget.GridColumnPicker');
42 dojo.require('openils.PermaCrud');
43 dojo.require('openils.widget.OrgUnitFilteringSelect');
44 dojo.require('openils.widget.AutoGrid');
45 dojo.require('openils.widget.AutoFieldWidget');
49 'vl-generic-progress',
50 'vl-generic-progress-with-total',
55 'vl-queue-select-div',
56 'vl-marc-upload-status-div',
59 'vl-profile-editor-div'
63 var VANDELAY_URL = '/vandelay-upload';
65 var authAttrDefs = [];
66 var queuedRecords = [];
67 var queuedRecordsMap = {};
68 var bibAttrsFetched = false;
69 var authAttrsFetched = false;
70 var attrDefMap = {}; // maps attr def code names to attr def ids
72 var currentQueueId = null;
74 var currentMatchedRecords; // set of loaded matched bib records
75 var currentOverlayRecordsMap; // map of import record to overlay record
76 var currentOverlayRecordsMapGid; // map of import record to overlay record grid id
77 var currentImportRecId; // when analyzing matches, this is the current import record
78 var userBibQueues = []; // only non-complete queues
79 var userAuthQueues = []; // only non-complete queues
81 var allUserAuthQueues;
82 var selectableGridRecords;
83 var cgi = new openils.CGI();
84 var vlQueueGridColumePicker = {};
85 var vlBibSources = [];
86 var importItemDefs = [];
92 authtoken = openils.User.authtoken;
93 var initNeeded = 6; // how many async responses do we need before we're init'd
94 var initCount = 0; // how many async reponses we've received
96 openils.Util.registerEnterHandler(
97 vlQueueDisplayPage.domNode, function(){retrieveQueuedRecords();});
98 openils.Util.addCSSClass(dojo.byId('vl-menu-marc-upload'), 'toolbar_selected');
100 function checkInitDone() {
102 if(initCount == initNeeded)
103 runStartupCommands();
106 var profiles = new openils.PermaCrud().retrieveAll('vmp');
107 vlUploadMergeProfile.store = new dojo.data.ItemFileReadStore({data:fieldmapper.vmp.toStoreData(profiles)});
108 vlUploadMergeProfile.labelAttr = 'name';
109 vlUploadMergeProfile.searchAttr = 'name';
110 vlUploadMergeProfile.startup();
112 vlUploadMergeProfile2.store = new dojo.data.ItemFileReadStore({data:fieldmapper.vmp.toStoreData(profiles)});
113 vlUploadMergeProfile2.labelAttr = 'name';
114 vlUploadMergeProfile2.searchAttr = 'name';
115 vlUploadMergeProfile2.startup();
118 // Fetch the bib and authority attribute definitions
119 vlFetchBibAttrDefs(function () { checkInitDone(); });
120 vlFetchAuthAttrDefs(function () { checkInitDone(); });
122 vlRetrieveQueueList('bib', null,
124 allUserBibQueues = list;
125 for(var i = 0; i < allUserBibQueues.length; i++) {
126 if(allUserBibQueues[i].complete() == 'f')
127 userBibQueues.push(allUserBibQueues[i]);
133 vlRetrieveQueueList('auth', null,
135 allUserAuthQueues = list;
136 for(var i = 0; i < allUserAuthQueues.length; i++) {
137 if(allUserAuthQueues[i].complete() == 'f')
138 userAuthQueues.push(allUserAuthQueues[i]);
144 fieldmapper.standardRequest(
145 ['open-ils.permacrud', 'open-ils.permacrud.search.cbs.atomic'],
147 params: [authtoken, {id:{"!=":null}}, {order_by:{cbs:'id'}}],
148 oncomplete : function(r) {
149 vlBibSources = openils.Util.readResponse(r, false, true);
155 var owner = fieldmapper.aou.orgNodeTrail(fieldmapper.aou.findOrgUnit(new openils.User().user.ws_ou()));
156 new openils.PermaCrud().search('viiad',
157 {owner: owner.map(function(org) { return org.id(); })},
159 oncomplete: function(r) {
160 importItemDefs = openils.Util.readResponse(r);
170 openils.Util.addOnLoad(vlInit);
173 // fetch the bib and authority attribute definitions
175 function vlFetchBibAttrDefs(postcomplete) {
177 fieldmapper.standardRequest(
178 ['open-ils.permacrud', 'open-ils.permacrud.search.vqbrad'],
180 params: [authtoken, {id:{'!=':null}}],
181 onresponse: function(r) {
182 var def = r.recv().content();
183 if(e = openils.Event.parse(def[0]))
185 bibAttrDefs.push(def);
187 oncomplete: function() {
188 bibAttrDefs = bibAttrDefs.sort(
190 if(a.id() > b.id()) return 1;
191 if(a.id() < b.id()) return -1;
201 function vlFetchAuthAttrDefs(postcomplete) {
203 fieldmapper.standardRequest(
204 ['open-ils.permacrud', 'open-ils.permacrud.search.vqarad'],
206 params: [authtoken, {id:{'!=':null}}],
207 onresponse: function(r) {
208 var def = r.recv().content();
209 if(e = openils.Event.parse(def[0]))
211 authAttrDefs.push(def);
213 oncomplete: function() {
214 authAttrDefs = authAttrDefs.sort(
216 if(a.id() > b.id()) return 1;
217 if(a.id() < b.id()) return -1;
227 function vlRetrieveQueueList(type, filter, onload) {
228 type = (type == 'bib') ? type : 'authority';
229 fieldmapper.standardRequest(
230 ['open-ils.vandelay', 'open-ils.vandelay.'+type+'_queue.owner.retrieve.atomic'],
232 params: [authtoken, null, filter],
233 oncomplete: function(r) {
234 var list = r.recv().content();
235 if(e = openils.Event.parse(list[0]))
244 function displayGlobalDiv(id) {
245 for(var i = 0; i < globalDivs.length; i++) {
247 dojo.style(dojo.byId(globalDivs[i]), 'display', 'none');
249 alert('please define div ' + globalDivs[i]);
252 dojo.style(dojo.byId(id),'display','block');
254 openils.Util.removeCSSClass(dojo.byId('vl-menu-marc-export'), 'toolbar_selected');
255 openils.Util.removeCSSClass(dojo.byId('vl-menu-marc-upload'), 'toolbar_selected');
256 openils.Util.removeCSSClass(dojo.byId('vl-menu-queue-select'), 'toolbar_selected');
257 openils.Util.removeCSSClass(dojo.byId('vl-menu-attr-editor'), 'toolbar_selected');
258 openils.Util.removeCSSClass(dojo.byId('vl-menu-profile-editor'), 'toolbar_selected');
261 case 'vl-marc-export-div':
262 openils.Util.addCSSClass(dojo.byId('vl-menu-marc-export'), 'toolbar_selected');
264 case 'vl-marc-upload-div':
265 openils.Util.addCSSClass(dojo.byId('vl-menu-marc-upload'), 'toolbar_selected');
267 case 'vl-queue-select-div':
268 openils.Util.addCSSClass(dojo.byId('vl-menu-queue-select'), 'toolbar_selected');
270 case 'vl-attr-editor-div':
271 openils.Util.addCSSClass(dojo.byId('vl-menu-attr-editor'), 'toolbar_selected');
273 case 'vl-profile-editor-div':
274 openils.Util.addCSSClass(dojo.byId('vl-menu-profile-editor'), 'toolbar_selected');
279 function runStartupCommands() {
280 currentQueueId = cgi.param('qid');
281 currentType = cgi.param('qtype');
282 dojo.style('vl-nav-bar', 'visibility', 'visible');
284 return retrieveQueuedRecords(currentType, currentQueueId, handleRetrieveRecords);
289 * asynchronously upload a file of MARC records
291 function uploadMARC(onload){
292 dojo.byId('vl-upload-status-count').innerHTML = '0';
293 dojo.byId('vl-ses-input').value = authtoken;
294 displayGlobalDiv('vl-marc-upload-status-div');
295 dojo.io.iframe.send({
299 form: dojo.byId('vl-marc-upload-form'),
300 handle: function(data,ioArgs){
301 var content = data.documentElement.textContent;
308 * Creates a new vandelay queue
310 function createQueue(queueName, type, onload, importDefId) {
311 var name = (type=='bib') ? 'bib' : 'authority';
312 var method = 'open-ils.vandelay.'+ name +'_queue.create'
313 fieldmapper.standardRequest(
314 ['open-ils.vandelay', method],
316 params: [authtoken, queueName, null, name, importDefId],
317 oncomplete : function(r) {
318 var queue = r.recv().content();
319 if(e = openils.Event.parse(queue))
328 * Tells vandelay to pull a batch of records from the cache and explode them
329 * out into the vandelay tables
331 function processSpool(key, queueId, type, onload) {
332 fieldmapper.standardRequest(
333 ['open-ils.vandelay', 'open-ils.vandelay.'+type+'.process_spool'],
335 params: [authtoken, key, queueId],
336 onresponse : function(r) {
337 var resp = r.recv().content();
338 if(e = openils.Event.parse(resp))
340 dojo.byId('vl-upload-status-count').innerHTML = resp;
342 oncomplete : function(r) {onload();}
347 function retrieveQueuedRecords(type, queueId, onload) {
348 displayGlobalDiv('vl-generic-progress');
350 queuedRecordsMap = {};
351 currentOverlayRecordsMap = {};
352 currentOverlayRecordsMapGid = {};
353 selectableGridRecords = {};
354 //resetVlQueueGridLayout();
356 if(!type) type = currentType;
357 if(!queueId) queueId = currentQueueId;
358 if(!onload) onload = handleRetrieveRecords;
360 var method = 'open-ils.vandelay.'+type+'_queue.records.retrieve.atomic';
361 if(vlQueueGridShowMatches.checked)
362 method = method.replace('records', 'records.matches');
364 var sel = dojo.byId('vl-queue-display-limit-selector');
365 var limit = parseInt(sel.options[sel.selectedIndex].value);
366 var offset = limit * parseInt(vlQueueDisplayPage.attr('value')-1);
368 var params = [authtoken, queueId, {clear_marc: 1, offset: offset, limit: limit}];
369 if(vlQueueGridShowNonImport.checked)
370 params[2].non_imported = 1;
372 fieldmapper.standardRequest(
373 ['open-ils.vandelay', method],
377 onresponse: function(r) {
378 console.log("ONREPONSE");
379 var rec = r.recv().content();
380 if(e = openils.Event.parse(rec))
382 console.log("got record " + rec.id());
383 queuedRecords.push(rec);
384 queuedRecordsMap[rec.id()] = rec;
387 oncomplete: function(r){
388 var recs = r.recv().content();
389 if(e = openils.Event.parse(recs[0]))
391 for(var i = 0; i < recs.length; i++) {
393 queuedRecords.push(rec);
394 queuedRecordsMap[rec.id()] = rec;
402 function vlLoadMatchUI(recId) {
403 displayGlobalDiv('vl-generic-progress');
404 var matches = queuedRecordsMap[recId].matches();
406 currentImportRecId = recId;
407 for(var i = 0; i < matches.length; i++)
408 records.push(matches[i].eg_record());
410 var retrieve = ['open-ils.search', 'open-ils.search.biblio.record_entry.slim.retrieve'];
411 var params = [records];
412 if(currentType == 'auth') {
413 retrieve = ['open-ils.cat', 'open-ils.cat.authority.record.retrieve'];
414 parmas = [authtoken, records, {clear_marc:1}];
417 fieldmapper.standardRequest(
421 oncomplete: function(r) {
422 var recs = r.recv().content();
423 if(e = openils.Event.parse(recs))
427 displayGlobalDiv('vl-match-div');
428 resetVlMatchGridLayout();
429 currentMatchedRecords = recs;
430 vlMatchGrid.setStructure(vlMatchGridLayout);
432 // build the data store of records with match information
433 var dataStore = bre.toStoreData(recs, null,
434 {virtualFields:['dest_matchpoint', 'src_matchpoint', '_id']});
435 dataStore.identifier = '_id';
437 var matchSeenMap = {};
439 for(var i = 0; i < dataStore.items.length; i++) {
440 var item = dataStore.items[i];
441 item._id = i; // just need something unique
442 for(var j = 0; j < matches.length; j++) {
443 var match = matches[j];
444 if(match.eg_record() == item.id && !matchSeenMap[match.id()]) {
445 item.dest_matchpoint = match.field_type();
446 var attr = getRecAttrFromMatch(queuedRecordsMap[recId], match);
447 item.src_matchpoint = getRecAttrDefFromAttr(attr, currentType).code();
448 matchSeenMap[match.id()] = 1;
454 // now populate the grid
455 vlPopulateMatchGrid(vlMatchGrid, dataStore);
461 function vlPopulateMatchGrid(grid, data) {
462 var store = new dojo.data.ItemFileReadStore({data:data});
463 grid.setStore(store);
467 function showMe(id) {
468 dojo.style(dojo.byId(id), 'display', 'block');
470 function hideMe(id) {
471 dojo.style(dojo.byId(id), 'display', 'none');
475 function vlLoadMARCHtml(recId, inCat, oncomplete) {
476 dijit.byId('vl-marc-html-done-button').onClick = oncomplete;
477 displayGlobalDiv('vl-generic-progress');
479 var params = [recId, 1];
482 hideMe('vl-marc-html-edit-button'); // don't show marc editor button
483 dijit.byId('vl-marc-html-edit-button').onClick = function(){}
484 api = ['open-ils.search', 'open-ils.search.biblio.record.html'];
485 if(currentType == 'auth')
486 api = ['open-ils.search', 'open-ils.search.authority.to_html'];
488 showMe('vl-marc-html-edit-button'); // plug in the marc editor button
489 dijit.byId('vl-marc-html-edit-button').onClick =
490 function() {vlLoadMarcEditor(currentType, recId, oncomplete);};
491 params = [authtoken, recId];
492 api = ['open-ils.vandelay', 'open-ils.vandelay.queued_bib_record.html'];
493 if(currentType == 'auth')
494 api = ['open-ils.vandelay', 'open-ils.vandelay.queued_authority_record.html'];
497 fieldmapper.standardRequest(
501 oncomplete: function(r) {
502 displayGlobalDiv('vl-marc-html-div');
503 var html = r.recv().content();
504 dojo.byId('vl-marc-record-html').innerHTML = html;
512 function getRecMatchesFromAttrCode(rec, attrCode) {
514 var attr = getRecAttrFromCode(rec, attrCode);
515 for(var j = 0; j < rec.matches().length; j++) {
516 var match = rec.matches()[j];
517 if(match.matched_attr() == attr.id())
524 function getRecAttrFromMatch(rec, match) {
525 for(var i = 0; i < rec.attributes().length; i++) {
526 var attr = rec.attributes()[i];
527 if(attr.id() == match.matched_attr())
532 function getRecAttrDefFromAttr(attr, type) {
533 var defs = (type == 'bib') ? bibAttrDefs : authAttrDefs;
534 for(var i = 0; i < defs.length; i++) {
536 if(def.id() == attr.field())
541 function getRecAttrFromCode(rec, attrCode) {
542 var defId = attrDefMap[currentType][attrCode];
543 var attrs = rec.attributes();
544 for(var i = 0; i < attrs.length; i++) {
546 if(attr.field() == defId)
552 function vlGetViewMatches(rowIdx, item) {
554 var id = this.grid.store.getValue(item, 'id');
555 var rec = queuedRecordsMap[id];
556 if(rec.matches().length > 0)
562 function vlFormatViewMatches(id) {
563 if(id == -1) return '';
564 return '<a href="javascript:void(0);" onclick="vlLoadMatchUI(' + id + ');">' + this.name + '</a>';
567 function vlFormatViewMatchMARC(id) {
568 return '<a href="javascript:void(0);" onclick="vlLoadMARCHtml(' + id + ', false, '+
569 'function(){displayGlobalDiv(\'vl-match-div\');});">' + this.name + '</a>';
572 function getAttrValue(rowIdx, item) {
574 var attrCode = this.field.split('.')[1];
575 var rec = queuedRecordsMap[this.grid.store.getValue(item, 'id')];
576 var attr = getRecAttrFromCode(rec, attrCode);
577 return (attr) ? attr.attr_value() : '';
580 function vlGetDateTimeField(rowIdx, item) {
582 var value = this.grid.store.getValue(item, this.field);
583 if(!value) return '';
584 var date = dojo.date.stamp.fromISOString(value);
585 return dojo.date.locale.format(date, {selector:'date'});
588 function vlGetCreator(rowIdx, item) {
590 var id = this.grid.store.getValue(item, 'creator');
592 return userCache[id].usrname();
593 var user = fieldmapper.standardRequest(
594 ['open-ils.actor', 'open-ils.actor.user.retrieve'], [authtoken, id]);
595 if(e = openils.Event.parse(user))
597 userCache[id] = user;
598 return user.usrname();
601 function vlGetViewMARC(rowIdx, item) {
602 return item && this.grid.store.getValue(item, 'id');
605 function vlFormatViewMARC(id) {
606 return '<a href="javascript:void(0);" onclick="vlLoadMARCHtml(' + id + ', false, '+
607 'function(){displayGlobalDiv(\'vl-queue-div\');});">' + this.name + '</a>';
610 function vlGetOverlayTargetSelector(rowIdx, item) {
612 return this.grid.store.getValue(item, '_id') + ':' + this.grid.store.getValue(item, 'id');
615 function vlFormatOverlayTargetSelector(val) {
617 var parts = val.split(':');
620 var value = '<input type="checkbox" name="vl-overlay-target-RECID" '+
621 'onclick="vlHandleOverlayTargetSelected(ID, GRIDID);" gridid="GRIDID" match="ID"/>';
622 value = value.replace(/GRIDID/g, _id);
623 value = value.replace(/RECID/g, currentImportRecId);
624 value = value.replace(/ID/g, id);
625 if(_id == currentOverlayRecordsMapGid[currentImportRecId])
626 return value.replace('/>', 'checked="checked"/>');
632 * see if the user has enabled overlays for the current match set and,
633 * if so, map the current import record to the overlay target.
635 function vlHandleOverlayTargetSelected(recId, gridId) {
636 var noneSelected = true;
637 var checkboxes = dojo.query('[name=vl-overlay-target-'+currentImportRecId+']');
638 for(var i = 0; i < checkboxes.length; i++) {
639 var checkbox = checkboxes[i];
640 var matchRecId = checkbox.getAttribute('match');
641 var gid = checkbox.getAttribute('gridid');
642 if(checkbox.checked) {
643 if(matchRecId == recId && gid == gridId) {
644 noneSelected = false;
645 currentOverlayRecordsMap[currentImportRecId] = matchRecId;
646 currentOverlayRecordsMapGid[currentImportRecId] = gid;
647 dojo.byId('vl-record-list-selected-' + currentImportRecId).checked = true;
648 dojo.byId('vl-record-list-selected-' + currentImportRecId).parentNode.className = 'overlay_selected';
650 checkbox.checked = false;
656 delete currentOverlayRecordsMap[currentImportRecId];
657 delete currentOverlayRecordsMapGid[currentImportRecId];
658 dojo.byId('vl-record-list-selected-' + currentImportRecId).checked = false;
659 dojo.byId('vl-record-list-selected-' + currentImportRecId).parentNode.className = '';
663 var valLastQueueType = null;
664 var vlQueueGridLayout = null;
665 function buildRecordGrid(type) {
666 displayGlobalDiv('vl-queue-div');
669 openils.Util.show('vl-bib-queue-grid-wrapper');
670 openils.Util.hide('vl-auth-queue-grid-wrapper');
671 vlQueueGrid = vlBibQueueGrid;
673 openils.Util.show('vl-auth-queue-grid-wrapper');
674 openils.Util.hide('vl-bib-queue-grid-wrapper');
675 vlQueueGrid = vlAuthQueueGrid;
679 if(valLastQueueType != type) {
680 valLastQueueType = type;
681 vlQueueGridLayout = vlQueueGrid.attr('structure');
682 var defs = (type == 'bib') ? bibAttrDefs : authAttrDefs;
683 attrDefMap[type] = {};
684 for(var i = 0; i < defs.length; i++) {
686 attrDefMap[type][def.code()] = def.id();
688 name:def.description(),
689 field:'attr.' + def.code(),
691 selectableColumn:true
693 vlQueueGridLayout[0].cells[0].push(col);
697 dojo.forEach(vlQueueGridLayout[0].cells[0],
699 if(cell.field.match(/^\+/))
700 cell.nonSelectable=true;
706 storeData = vqbr.toStoreData(queuedRecords);
708 storeData = vqar.toStoreData(queuedRecords);
710 var store = new dojo.data.ItemFileReadStore({data:storeData});
711 vlQueueGrid.setStore(store);
713 if(vlQueueGridColumePicker[type]) {
714 vlQueueGrid.update();
717 vlQueueGridColumePicker[type] =
718 new openils.widget.GridColumnPicker(
719 authtoken, 'vandelay.queue.'+type, vlQueueGrid, vlQueueGridLayout);
720 vlQueueGridColumePicker[type].load();
724 function vlQueueGridPrevPage() {
725 var page = parseInt(vlQueueDisplayPage.getValue());
727 vlQueueDisplayPage.setValue(page - 1);
728 retrieveQueuedRecords(currentType, currentQueueId, handleRetrieveRecords);
731 function vlQueueGridNextPage() {
732 vlQueueDisplayPage.setValue(parseInt(vlQueueDisplayPage.getValue())+1);
733 retrieveQueuedRecords(currentType, currentQueueId, handleRetrieveRecords);
736 function vlDeleteQueue(type, queueId, onload) {
737 fieldmapper.standardRequest(
738 ['open-ils.vandelay', 'open-ils.vandelay.'+type+'_queue.delete'],
740 params: [authtoken, queueId],
741 oncomplete: function(r) {
742 var resp = r.recv().content();
743 if(e = openils.Event.parse(resp))
752 function vlQueueGridDrawSelectBox(rowIdx, item) {
753 return item && this.grid.store.getValue(item, 'id');
756 function vlQueueGridFormatSelectBox(id) {
757 var domId = 'vl-record-list-selected-' + id;
758 if (id) { selectableGridRecords[domId] = id; }
759 return "<div><input type='checkbox' id='"+domId+"'/></div>";
762 function vlSelectAllQueueGridRecords() {
763 for(var id in selectableGridRecords)
764 dojo.byId(id).checked = true;
766 function vlSelectNoQueueGridRecords() {
767 for(var id in selectableGridRecords)
768 dojo.byId(id).checked = false;
770 function vlToggleQueueGridSelect() {
771 if(dojo.byId('vl-queue-grid-row-selector').checked)
772 vlSelectAllQueueGridRecords();
774 vlSelectNoQueueGridRecords();
777 var handleRetrieveRecords = function() {
778 buildRecordGrid(currentType);
779 vlFetchQueueSummary(currentQueueId, currentType,
781 dojo.byId('vl-queue-summary-name').innerHTML = summary.queue.name();
782 dojo.byId('vl-queue-summary-total-count').innerHTML = summary.total +'';
783 dojo.byId('vl-queue-summary-import-count').innerHTML = summary.imported + '';
788 function vlFetchQueueSummary(qId, type, onload) {
789 fieldmapper.standardRequest(
790 ['open-ils.vandelay', 'open-ils.vandelay.'+type+'_queue.summary.retrieve'],
792 params: [authtoken, qId],
793 oncomplete : function(r) {
794 var summary = r.recv().content();
795 if(e = openils.Event.parse(summary))
797 return onload(summary);
803 function vlHandleQueueItemsAction(action) {
806 queueItemsImportCancelButton,
809 queueItemsImportDialog.hide();
814 queueItemsImportGoButton,
817 queueItemsImportDialog.hide();
819 // hack to set the widgets the import funcs will be looking at. Reset them below.
820 vlUploadQueueAutoImport.attr('value', vlUploadQueueAutoImport2.attr('value'));
821 vlUploadQueueAutoOverlayExact.attr('value', vlUploadQueueAutoOverlayExact2.attr('value'));
822 vlUploadQueueAutoOverlay1Match.attr('value', vlUploadQueueAutoOverlay1Match2.attr('value'));
823 vlUploadMergeProfile.attr('value', vlUploadMergeProfile2.attr('value'));
825 if(action == 'import') {
826 vlImportSelectedRecords();
827 } else if(action == 'import_all') {
828 vlImportAllRecords();
831 // reset the widgets to prevent accidental future actions
832 vlUploadQueueAutoImport.attr('value', false);
833 vlUploadQueueAutoImport2.attr('value', false);
834 vlUploadQueueAutoOverlayExact.attr('value', false);
835 vlUploadQueueAutoOverlayExact2.attr('value', false);
836 vlUploadQueueAutoOverlay1Match.attr('value', false);
837 vlUploadQueueAutoOverlay1Match2.attr('value', false);
838 vlUploadMergeProfile.attr('value', '');
839 vlUploadMergeProfile2.attr('value', '');
843 queueItemsImportDialog.show();
847 function vlImportSelectedRecords() {
848 displayGlobalDiv('vl-generic-progress-with-total');
851 for(var id in selectableGridRecords) {
852 if(dojo.byId(id).checked) {
853 var recId = selectableGridRecords[id];
854 var rec = queuedRecordsMap[recId];
855 if(!rec.import_time())
860 var options = {overlay_map : currentOverlayRecordsMap};
862 if(vlUploadQueueAutoOverlayExact.checked) {
863 options.auto_overlay_exact = true;
864 vlUploadQueueAutoOverlayExact.checked = false;
867 if(vlUploadQueueAutoOverlay1Match.checked) {
868 options.auto_overlay_1match = true;
869 vlUploadQueueAutoOverlay1Match.checked = false;
872 var profile = vlUploadMergeProfile.attr('value');
873 if(profile != null && profile != '') {
874 options.merge_profile = profile;
877 fieldmapper.standardRequest(
878 ['open-ils.vandelay', 'open-ils.vandelay.'+currentType+'_record.list.import'],
880 params: [authtoken, records, options],
881 onresponse: function(r) {
882 var resp = r.recv().content();
883 if(e = openils.Event.parse(resp))
886 return retrieveQueuedRecords(currentType, currentQueueId, handleRetrieveRecords);
888 vlControlledProgressBar.update({maximum:resp.total, progress:resp.progress});
895 function vlImportAllRecords() {
896 vlImportRecordQueue(currentType, currentQueueId, false,
897 function(){displayGlobalDiv('vl-queue-div');});
900 function vlImportRecordQueue(type, queueId, noMatchOnly, onload) {
901 displayGlobalDiv('vl-generic-progress-with-total');
902 var method = 'open-ils.vandelay.bib_queue.import';
904 method = method.replace('import', 'nomatch.import');
906 method = method.replace('bib', 'auth');
909 if(vlUploadQueueAutoOverlayExact.checked) {
910 options.auto_overlay_exact = true;
911 vlUploadQueueAutoOverlayExact.checked = false;
914 if(vlUploadQueueAutoOverlay1Match.checked) {
915 options.auto_overlay_1match = true;
916 vlUploadQueueAutoOverlay1Match.checked = false;
919 var profile = vlUploadMergeProfile.attr('value');
920 if(profile != null && profile != '') {
921 options.merge_profile = profile;
924 fieldmapper.standardRequest(
925 ['open-ils.vandelay', method],
927 params: [authtoken, queueId, options],
928 onresponse: function(r) {
929 var resp = r.recv().content();
930 if(e = openils.Event.parse(resp))
932 vlControlledProgressBar.update({maximum:resp.total, progress:resp.progress});
934 oncomplete: function() {onload();}
940 function vlImportHoldings(queueId, importProfile, onload) {
941 displayGlobalDiv('vl-generic-progress-with-total');
942 fieldmapper.standardRequest(
943 ['open-ils.vandelay', 'open-ils.vandelay.bib_record.queue.asset.import'],
945 params: [authtoken, importProfile, queueId],
946 onresponse: function(r) {
947 var resp = openils.Util.readResponse(r);
948 vlControlledProgressBar.update({maximum:resp.total, progress:resp.progress});
950 oncomplete: function() {onload();}
956 * Create queue, upload MARC, process spool, load the newly created queue
958 function batchUpload() {
959 var queueName = dijit.byId('vl-queue-name').getValue();
960 currentType = dijit.byId('vl-record-type').getValue();
962 var handleProcessSpool = function() {
963 if(vlUploadQueueAutoImport.checked || vlUploadQueueAutoOverlayExact.checked || vlUploadQueueAutoOverlay1Match.checked) {
968 vlUploadQueueAutoImport.checked,
970 if(vlUploadQueueHoldingsImport.checked) {
973 vlUploadQueueHoldingsImportProfile.attr('value'),
975 retrieveQueuedRecords(currentType, currentQueueId, handleRetrieveRecords);
979 retrieveQueuedRecords(currentType, currentQueueId, handleRetrieveRecords);
984 retrieveQueuedRecords(currentType, currentQueueId, handleRetrieveRecords);
988 var handleUploadMARC = function(key) {
989 dojo.style(dojo.byId('vl-upload-status-processing'), 'display', 'block');
990 processSpool(key, currentQueueId, currentType, handleProcessSpool);
993 var handleCreateQueue = function(queue) {
994 currentQueueId = queue.id();
995 uploadMARC(handleUploadMARC);
998 if(vlUploadQueueSelector.getValue() && !queueName) {
999 currentQueueId = vlUploadQueueSelector.getValue();
1000 uploadMARC(handleUploadMARC);
1002 createQueue(queueName, currentType, handleCreateQueue, vlUploadQueueHoldingsImportProfile.attr('value'));
1007 function vlFleshQueueSelect(selector, type) {
1008 var data = (type == 'bib') ? vbq.toStoreData(allUserBibQueues) : vaq.toStoreData(allUserAuthQueues);
1009 selector.store = new dojo.data.ItemFileReadStore({data:data});
1010 selector.setValue(null);
1011 selector.setDisplayedValue('');
1013 selector.setValue(data[0].id());
1016 function vlShowUploadForm() {
1017 displayGlobalDiv('vl-marc-upload-div');
1018 vlFleshQueueSelect(vlUploadQueueSelector, vlUploadRecordType.getValue());
1019 vlUploadSourceSelector.store =
1020 new dojo.data.ItemFileReadStore({data:cbs.toStoreData(vlBibSources, 'source')});
1021 vlUploadSourceSelector.setValue(vlBibSources[0].id());
1022 vlUploadQueueHoldingsImportProfile.store =
1023 new dojo.data.ItemFileReadStore({data:viiad.toStoreData(importItemDefs)});
1024 vlUploadQueueHoldingsImportProfile.attr('disabled', true);
1025 dojo.connect(vlUploadQueueHoldingsImport, 'onChange',
1028 vlUploadQueueHoldingsImportProfile.attr('disabled', false);
1030 vlUploadQueueHoldingsImportProfile.attr('disabled', true);
1035 function vlShowQueueSelect() {
1036 displayGlobalDiv('vl-queue-select-div');
1037 vlFleshQueueSelect(vlQueueSelectQueueList, vlQueueSelectType.getValue());
1040 function vlFetchQueueFromForm() {
1041 currentType = vlQueueSelectType.getValue();
1042 currentQueueId = vlQueueSelectQueueList.getValue();
1043 retrieveQueuedRecords(currentType, currentQueueId, handleRetrieveRecords);
1046 function vlOpenMarcEditWindow(rec, postReloadHTMLHandler) {
1048 To run in Firefox directly, must set signed.applets.codebase_principal_support
1049 to true in about:config
1051 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
1052 win = window.open('/xul/server/cat/marcedit.xul'); // XXX version?
1054 function onsave(r) {
1055 // after the record is saved, reload the HTML display
1056 var stat = r.recv().content();
1057 if(e = openils.Event.parse(stat))
1059 alert(dojo.byId('vl-marc-edit-complete-label').innerHTML);
1061 vlLoadMARCHtml(rec.id(), false, postReloadHTMLHandler);
1065 record : {marc : rec.marc()},
1067 label: dojo.byId('vl-marc-edit-save-label').innerHTML,
1068 func: function(xmlString) {
1069 var method = 'open-ils.permacrud.update.' + rec.classname;
1070 rec.marc(xmlString);
1071 fieldmapper.standardRequest(
1072 ['open-ils.permacrud', method],
1074 params: [authtoken, rec],
1083 function vlLoadMarcEditor(type, recId, postReloadHTMLHandler) {
1084 var method = 'open-ils.permacrud.search.vqbr';
1085 if(currentType != 'bib')
1086 method = method.replace(/vqbr/,'vqar');
1088 fieldmapper.standardRequest(
1089 ['open-ils.permacrud', method],
1091 params: [authtoken, {id : recId}],
1092 oncomplete: function(r) {
1093 var rec = r.recv().content();
1094 if(e = openils.Event.parse(rec))
1096 vlOpenMarcEditWindow(rec, postReloadHTMLHandler);
1104 //------------------------------------------------------------
1105 // attribute editors
1107 // attribute-editor global variables
1109 var ATTR_EDITOR_IN_UPDATE_MODE = false; // true on 'edit', false on 'create'
1110 var ATTR_EDIT_ID = null; // id of current 'edit' attribute
1111 var ATTR_EDIT_GROUP = 'bib'; // bib-attrs or auth-attrs
1113 function vlAttrEditorInit() {
1114 // set up tooltips on the edit form
1115 connectTooltip('attr-editor-tags');
1116 connectTooltip('attr-editor-subfields');
1119 function vlShowAttrEditor() {
1120 displayGlobalDiv('vl-attr-editor-div');
1121 loadAttrEditorGrid();
1122 idHide('vl-generic-progress');
1125 function setAttrEditorGroup(groupName) {
1126 // put us into 'bib'-attr or 'auth'-attr mode.
1127 if (ATTR_EDIT_GROUP != groupName) {
1128 ATTR_EDIT_GROUP = groupName;
1129 loadAttrEditorGrid();
1133 function onAttrEditorOpen() {
1134 // the "bars" have the create/update/cancel/etc. buttons.
1135 var create_bar = document.getElementById('attr-editor-create-bar');
1136 var update_bar = document.getElementById('attr-editor-update-bar');
1137 if (ATTR_EDITOR_IN_UPDATE_MODE) {
1138 update_bar.style.display='table-row';
1139 create_bar.style.display='none';
1140 // hide the dropdown-button
1141 idStyle('vl-create-attr-editor-button', 'visibility', 'hidden');
1143 dijit.byId('attr-editor-dialog').reset();
1144 create_bar.style.display='table-row';
1145 update_bar.style.display='none';
1149 function onAttrEditorClose() {
1150 // reset the form to a "create" form. (We may have borrowed it for editing.)
1151 ATTR_EDITOR_IN_UPDATE_MODE = false;
1152 // show the dropdown-button
1153 idStyle('vl-create-attr-editor-button', 'visibility', 'visible');
1156 function loadAttrEditorGrid() {
1157 var _data = (ATTR_EDIT_GROUP == 'auth') ?
1158 vqarad.toStoreData(authAttrDefs) : vqbrad.toStoreData(bibAttrDefs) ;
1160 var store = new dojo.data.ItemFileReadStore({data:_data});
1161 attrEditorGrid.setStore(store);
1162 dojo.connect(attrEditorGrid, 'onRowDblClick', onAttrEditorClick);
1163 attrEditorGrid.update();
1166 function attrGridGetTag(n, item) {
1167 // grid helper: return the tags from the row's xpath column.
1168 return item && xpathParser.parse(this.grid.store.getValue(item, 'xpath')).tags;
1171 function attrGridGetSubfield(n, item) {
1172 // grid helper: return the subfields from the row's xpath column.
1173 return item && xpathParser.parse(this.grid.store.getValue(item, 'xpath')).subfields;
1176 function onAttrEditorClick() {
1177 var row = this.getItem(this.focus.rowIndex);
1178 ATTR_EDIT_ID = this.store.getValue(row, 'id');
1179 ATTR_EDITOR_IN_UPDATE_MODE = true;
1181 // populate the popup editor.
1182 dijit.byId('attr-editor-code').attr('value', this.store.getValue(row, 'code'));
1183 dijit.byId('attr-editor-description').attr('value', this.store.getValue(row, 'description'));
1184 var parsed_xpath = xpathParser.parse(this.store.getValue(row, 'xpath'));
1185 dijit.byId('attr-editor-tags').attr('value', parsed_xpath.tags);
1186 dijit.byId('attr-editor-subfields').attr('value', parsed_xpath.subfields);
1187 dijit.byId('attr-editor-identifier').attr('value', this.store.getValue(row, 'ident'));
1188 dijit.byId('attr-editor-xpath').attr('value', this.store.getValue(row, 'xpath'));
1189 dijit.byId('attr-editor-remove').attr('value', this.store.getValue(row, 'remove'));
1191 // set up UI for editing
1192 dojo.byId('vl-create-attr-editor-button').click();
1195 function vlSaveAttrDefinition(data) {
1196 idHide('vl-attr-editor-div');
1197 idShow('vl-generic-progress');
1199 data.id = ATTR_EDIT_ID;
1201 // this ought to honour custom xpaths, but overwrite xpaths
1202 // derived from tags/subfields.
1203 if (data.xpath == '' || looksLikeDerivedXpath(data.xpath)) {
1204 var _xpath = tagAndSubFieldsToXpath(data.tag, data.subfield);
1205 data.xpath = _xpath;
1208 // build up our permacrud params. Key variables here are
1209 // "create or update" and "bib or auth".
1211 var isAuth = (ATTR_EDIT_GROUP == 'auth');
1212 var isCreate = (ATTR_EDIT_ID == null);
1213 var rad = isAuth ? new vqarad() : new vqbrad() ;
1214 var method = 'open-ils.permacrud' + (isCreate ? '.create.' : '.update.')
1215 + (isAuth ? 'vqarad' : 'vqbrad');
1216 var _data = rad.fromStoreItem(data);
1220 fieldmapper.standardRequest(
1221 ['open-ils.permacrud', method],
1223 params: [authtoken, _data ],
1224 onresponse: function(r) { },
1225 oncomplete: function(r) {
1226 attrEditorFetchAttrDefs(vlShowAttrEditor);
1227 ATTR_EDIT_ID = null;
1229 onerror: function(r) {
1230 alert('vlSaveAttrDefinition comms error: ' + r);
1236 function attrEditorFetchAttrDefs(callback) {
1237 var fn = (ATTR_EDIT_GROUP == 'auth') ? vlFetchAuthAttrDefs : vlFetchBibAttrDefs;
1238 return fn(callback);
1241 function vlAttrDelete() {
1242 idHide('vl-attr-editor-div');
1243 idShow('vl-generic-progress');
1245 var isAuth = (ATTR_EDIT_GROUP == 'auth');
1246 var method = 'open-ils.permacrud.delete.' + (isAuth ? 'vqarad' : 'vqbrad');
1247 var rad = isAuth ? new vqarad() : new vqbrad() ;
1248 fieldmapper.standardRequest(
1249 ['open-ils.permacrud', method],
1251 params: [authtoken, rad.fromHash({ id : ATTR_EDIT_ID }), ],
1252 oncomplete: function() {
1253 dijit.byId('attr-editor-dialog').onCancel(); // close the dialog
1254 attrEditorFetchAttrDefs(vlShowAttrEditor);
1255 ATTR_EDIT_ID = null;
1257 onerror: function(r) {
1258 alert('vlAttrDelete comms error: ' + r);
1264 // ------------------------------------------------------------
1265 // utilities for attribute editors
1267 // dom utilities (maybe dojo does these, and these should be replaced)
1269 function idStyle(obId, k, v) { document.getElementById(obId).style[k] = v; }
1270 function idShow(obId) { idStyle(obId, 'display', 'block'); }
1271 function idHide(obId) { idStyle(obId, 'display' , 'none'); }
1273 function connectTooltip(fieldId) {
1274 // Given an element id, look up a tooltip element in the doc (same
1275 // id with a '-tip' suffix) and associate the two. Maybe dojo has
1276 // a better way to do this?
1277 var fld = dojo.byId(fieldId);
1278 var tip = dojo.byId(fieldId + '-tip');
1279 dojo.connect(fld, 'onfocus', function(evt) {
1280 dijit.showTooltip(tip.innerHTML, fld, ['below', 'after']); });
1281 dojo.connect(fld, 'onblur', function(evt) { dijit.hideTooltip(fld); });
1286 var xpathParser = new openils.MarcXPathParser();
1288 function tagAndSubFieldsToXpath(tags, subfields) {
1289 // given tags, and subfields, build up an XPath.
1292 'tags':tags.match(/[\d]+/g),
1293 'subfields':subfields.match(/[a-zA-z]/g) };
1294 return xpathParser.compile(parts);
1296 return {'parts':null, 'tags':null, 'error':err};
1300 function looksLikeDerivedXpath(path) {
1301 // Does this path look like it was derived from tags and subfields?
1302 var parsed = xpathParser.parse(path);
1303 if (parsed.tags == null)
1305 var compiled = xpathParser.compile(parsed);
1306 return (path == compiled);
1309 // amazing xpath-util unit-tests
1310 if (!looksLikeDerivedXpath('//*[@tag="901"]/*[@code="c"]')) alert('vandelay xpath-utility error');
1311 if ( looksLikeDerivedXpath('ba-boo-ba-boo!')) alert('vandelay xpath-utility error');
1315 var profileContextOrg
1316 function vlShowProfileEditor() {
1317 displayGlobalDiv('vl-profile-editor-div');
1320 var connect = function() {
1321 dojo.connect(profileContextOrgSelector, 'onChange',
1323 profileContextOrg = this.attr('value');
1330 new openils.User().buildPermOrgSelector(
1331 '"ADMIN_MERGE_PROFILE', profileContextOrgSelector, null, connect);
1334 function buildProfileGrid() {
1336 if(profileContextOrg == null)
1337 profileContextOrg = openils.User.user.ws_ou();
1340 {order_by : {vmp : 'name'}},
1341 {owner : fieldmapper.aou.fullPath(profileContextOrg, true)}