2 * Z39.50 search and import
5 angular.module('egCatZ3950Search',
6 ['ngRoute', 'ui.bootstrap', 'ngOrderObjectBy', 'egCoreMod', 'egUiMod', 'egGridMod', 'egZ3950Mod', 'egMarcMod'])
8 .config(function($routeProvider, $locationProvider, $compileProvider) {
9 $locationProvider.html5Mode(true);
10 $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|blob):/); // grid export
12 var resolver = {delay : function(egStartup) {return egStartup.go()}};
14 // search page shows the list view by default
15 $routeProvider.when('/cat/z3950/search', {
16 templateUrl: './cat/z3950/t_list',
17 controller: 'Z3950SearchCtrl',
21 // default page / bucket view
22 $routeProvider.otherwise({redirectTo : '/cat/z3950/search'});
26 * List view - grid stuff
28 .controller('Z3950SearchCtrl',
29 ['$scope','$q','$location','$timeout','$window','egCore','egGridDataProvider','egZ3950TargetSvc','$uibModal',
31 function($scope , $q , $location , $timeout , $window, egCore , egGridDataProvider, egZ3950TargetSvc, $uibModal,
34 // get list of targets
35 egZ3950TargetSvc.loadTargets();
36 egZ3950TargetSvc.loadActiveSearchFields();
38 $scope.field_strip_groups = [];
39 egCore.startup.go().then(function() {
40 // and list of field strip groups; need to ensure
41 // that enough of the startup has happened so that
42 // we have the user WS
43 egCore.pcrud.search('vibtg',
51 transform : 'actor.org_unit_ancestors',
57 id : egCore.auth.user().ws_ou()
62 { order_by : { vibtq : ['label'] } }
63 ).then(null, null, function(strip_group) {
64 strip_group.selected = false;
65 $scope.field_strip_groups.push(strip_group);
69 $scope.total_hits = 0;
71 var provider = egGridDataProvider.instance({});
73 provider.get = function(offset, count) {
74 var deferred = $q.defer();
76 var query = egZ3950TargetSvc.currentQuery();
77 if (!query.raw_search && Object.keys(query.search).length == 0) {
81 var method = query.raw_search ?
82 'open-ils.search.z3950.search_service' :
83 'open-ils.search.z3950.search_class';
85 if (query.raw_search) {
86 query.query = query.raw_search;
87 delete query['search'];
88 delete query['raw_search'];
89 query.service = query.service[0];
90 query.username = query.username[0];
91 query.password = query.password[0];
94 query['limit'] = count;
95 query['offset'] = offset;
97 var resultIndex = offset;
98 $scope.total_hits = 0;
99 $scope.searchInProgress = true;
106 function() { $scope.searchInProgress = false; deferred.resolve() },
109 // FIXME when the search offset is > 0, the
110 // total hits count can be wrong if one of the
111 // Z39.50 targets has fewer than $offset hits; in that
112 // case, result.count is not supplied.
113 $scope.total_hits += (result.count || 0);
114 for (var i in result.records) {
115 result.records[i].mvr['service'] = result.service;
116 result.records[i].mvr['index'] = resultIndex++;
117 result.records[i].mvr['marcxml'] = result.records[i].marcxml;
118 deferred.notify(result.records[i].mvr);
123 return deferred.promise;
126 $scope.z3950SearchGridProvider = provider;
127 $scope.gridControls = {};
129 $scope.search = function() {
130 $scope.z3950SearchGridProvider.refresh();
132 $scope.clearForm = function() {
133 egZ3950TargetSvc.clearSearchFields();
136 $scope.saveDefaultZ3950Targets = function() {
137 egZ3950TargetSvc.saveDefaultZ3950Targets();
140 var display_form = true;
141 $scope.show_search_form = function() {
144 $scope.toggle_search_form = function() {
145 display_form = !display_form;
148 $scope.raw_search_impossible = function() {
149 return egZ3950TargetSvc.rawSearchImpossible();
151 $scope.showRawSearchForm = function() {
153 templateUrl: './cat/z3950/t_raw_search',
157 ['$scope', '$uibModalInstance', function($scope, $uibModalInstance) {
158 egZ3950TargetSvc.setRawSearch('');
159 $scope.focusMe = true;
160 $scope.ok = function(args) { $uibModalInstance.close(args) }
161 $scope.cancel = function () { $uibModalInstance.dismiss() }
163 }).result.then(function (args) {
164 if (!args || !args.raw_search) return;
166 egZ3950TargetSvc.setRawSearch(args.raw_search);
167 $scope.z3950SearchGridProvider.refresh();
171 $scope.showInCatalog = function() {
172 var items = $scope.gridControls.selectedItems();
173 // relying on cant_showInCatalog to protect us
174 var url = egCore.env.basePath +
175 'cat/catalog/record/' + items[0].tcn();
176 $timeout(function() { $window.open(url, '_blank') });
178 $scope.cant_showInCatalog = function() {
179 var items = $scope.gridControls.selectedItems();
180 if (items.length != 1) return true;
181 if (items[0]['service'] == 'native-evergreen-catalog') return false;
185 $scope.local_overlay_target = egCore.hatch.getLocalItem('eg.cat.marked_overlay_record') || 0;
186 $scope.mark_as_overlay_target = function() {
187 var items = $scope.gridControls.selectedItems();
188 if ($scope.local_overlay_target == items[0].tcn()) {
189 $scope.local_overlay_target = 0;
191 $scope.local_overlay_target = items[0].tcn();
193 egCore.hatch.setLocalItem('eg.cat.marked_overlay_record',$scope.local_overlay_target);
195 $scope.cant_overlay = function() {
196 if (!$scope.local_overlay_target) return true;
197 var items = $scope.gridControls.selectedItems();
198 if (items.length != 1) return true;
200 items[0]['service'] == 'native-evergreen-catalog' &&
201 items[0].tcn() == $scope.local_overlay_target
206 $scope.selectFieldStripGroups = function() {
208 angular.forEach($scope.field_strip_groups, function(grp, idx) {
210 groups.push(grp.id());
215 $scope.import = function() {
216 var deferred = $q.defer();
217 var items = $scope.gridControls.selectedItems();
220 'open-ils.cat.biblio.record.xml.import',
223 null, // FIXME bib source
226 $scope.selectFieldStripGroups()
228 function() { deferred.resolve() },
231 egConfirmDialog.open(
232 egCore.strings.IMPORTED_RECORD_FROM_Z3950,
233 egCore.strings.IMPORTED_RECORD_FROM_Z3950_AS_ID,
234 { id : result.id() },
235 egCore.strings.GO_TO_RECORD,
236 egCore.strings.GO_BACK
237 ).result.then(function() {
238 // NOTE: $location.path('/cat/catalog/record/' + result.id()) did not work
240 $window.location.href = egCore.env.basePath + 'cat/catalog/record/' + result.id();
245 return deferred.promise;
247 $scope.need_one_selected = function() {
248 var items = $scope.gridControls.selectedItems();
249 if (items.length == 1) return false;
253 $scope.spawn_editor = function() {
254 var items = $scope.gridControls.selectedItems();
257 templateUrl: './cat/z3950/t_marc_edit',
261 ['$scope', '$uibModalInstance', function($scope, $uibModalInstance) {
262 $scope.focusMe = true;
263 $scope.record_id = recId;
264 $scope.dirty_flag = false;
265 $scope.marc_xml = items[0]['marcxml'];
266 $scope.ok = function(args) { $uibModalInstance.close(args) }
267 $scope.cancel = function () { $uibModalInstance.dismiss() }
268 $scope.save_label = egCore.strings.IMPORT_BUTTON_LABEL;
269 $scope.import_record_callback = function (record_id) {
271 $scope.save_label = egCore.strings.SAVE_BUTTON_LABEL;
274 }).result.then(function () {
276 $window.location.href = egCore.env.basePath + 'cat/catalog/record/' + recId;
281 $scope.view_marc = function() {
282 var items = $scope.gridControls.selectedItems();
284 templateUrl: './cat/z3950/t_marc_html',
288 ['$scope', '$uibModalInstance', function($scope, $uibModalInstance) {
289 $scope.focusMe = true;
290 $scope.marc_xml = items[0]['marcxml'];
291 $scope.isbn = (items[0].isbn() || '').replace(/ .*/, '');
292 $scope.ok = function(args) { $uibModalInstance.close(args) }
293 $scope.cancel = function () { $uibModalInstance.dismiss() }
295 }).result.then(function (args) {
296 if (!args || !args.name) return;
300 $scope.overlay_record = function() {
301 var items = $scope.gridControls.selectedItems();
302 var overlay_target = $scope.local_overlay_target;
304 'marc_xml' : items[0]['marcxml']
307 templateUrl: './cat/z3950/t_overlay',
311 ['$scope', '$uibModalInstance', function($scope, $uibModalInstance) {
312 $scope.focusMe = true;
313 $scope.merge_profile = null;
314 $scope.overlay_target = {
319 $scope.overlay_target.marc_xml = args.marc_xml;
320 egCore.pcrud.retrieve('bre', $scope.overlay_target.id)
321 .then(function(rec) {
322 $scope.overlay_target.orig_marc_xml = rec.marc();
323 $scope.merge_marc(); // in case a sticky value was already set
326 $scope.merge_marc = function() {
327 if (!$scope.merge_profile) return;
330 'open-ils.cat.merge.marc.per_profile',
332 $scope.merge_profile,
333 [ args.marc_xml, $scope.overlay_target.orig_marc_xml ]
334 ).then(function(merged) {
336 $scope.overlay_target.marc_xml = merged;
337 $scope.overlay_target.merged = true;
341 $scope.$watch('merge_profile', function(newVal, oldVal) {
342 if (newVal && newVal !== oldVal) {
348 args.overlay_target = $scope.overlay_target;
349 $scope.ok = function(args) { $uibModalInstance.close(args) };
350 $scope.cancel = function () { $uibModalInstance.dismiss() };
351 $scope.editOverlayRecord = function() {
353 templateUrl: './cat/z3950/t_edit_overlay_record',
357 ['$scope', '$uibModalInstance', function($scope, $uibModalInstance) {
358 $scope.focusMe = true;
359 $scope.record_id = 0;
360 $scope.dirty_flag = false;
362 $scope.ok = function(args) { $uibModalInstance.close(args) }
363 $scope.cancel = function () { $uibModalInstance.dismiss() }
365 }).result.then(function (args) {
367 if (!args || !args.name) return;
371 }).result.then(function (args) {
374 'open-ils.cat.biblio.record.marc.replace',
377 (args.overlay_target.merged ? args.overlay_target.marc_xml : args.marc_xml),
378 null, // FIXME bib source
380 $scope.selectFieldStripGroups()
383 console.debug('overlay complete');