<option value="checkout">[% l('Checkout') %]</option>
<option value="hold_transit_slip">[% l('Hold Transit Slip') %]</option>
<option value="hold_shelf_slip">[% l('Hold Shelf Slip') %]</option>
+ <option value="holds_for_bibs">[% l('Holds for Bib Record') %]</option>
<option value="holds_for_patron">[% l('Holds for Patron') %]</option>
<option value="patron_address">[% l('Patron Address') %]</option>
<option value="patron_note">[% l('Patron Note') %]</option>
<eg-grid-field path="id" required hidden></eg-grid-field>
<eg-grid-field label="[% l('Title') %]" path="title">
- <a target="_self" href="[% ctx.base_path %]/opac/record/{{item.id}}">
+ <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.id}}">
{{item.title}}
</a>
</eg-grid-field>
<div class="row pad-vert">
<div class="col-md-9">
<div class="alert alert-info alert-less-pad strong-text-2">
- <span>[% l('Catalog') %]</span>
+ <span ng-if="record_tab == 'catalog'">[% l('Catalog') %]</span>
+ <span ng-if="record_tab == 'marc_html'">[% l('MARC HTML') %]</span>
+ <span ng-if="record_tab == 'holds'">[% l('Holds for Record') %]</span>
</div>
</div>
<div class="col-md-3">
+ <!-- actions for this record menu -->
<div class="btn-group pull-right" dropdown>
<button type="button"
class="btn btn-default dropdown-toggle" ng-disabled="!record_id">
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
- <li><a href dropdown-toggle ng-click="set_record_tab('catalog')">[% l('OPAC View') %]</a></li>
- <li><a href dropdown-toggle ng-click="set_record_tab('record_html')">[% l('MARC View') %]</a></li>
+ <li><a href dropdown-toggle ng-click="set_record_tab('catalog')">
+ [% l('OPAC View') %]</a></li>
+ <li><a href dropdown-toggle ng-click="set_record_tab('marc_html')">
+ [% l('MARC View') %]</a></li>
<li class="divider"></li>
- <li><a href dropdown-toggle ng-click="set_record_tab('holds')">[% l('View Holds') %]</a></li>
- <li class="disabled"><a href dropdown-toggle>[% l('Mark as Title Hold Transfer Destination') %]</a></li>
- <li class="disabled"><a href dropdown-toggle>[% l('Transfer All Title Holds') %]</a></li>
+ <li><a href dropdown-toggle ng-click="set_record_tab('holds')">
+ [% l('View Holds') %]</a></li>
+ <li><a href dropdown-toggle ng-click="mark_hold_transfer_dest()">
+ [% l('Mark as Title Hold Transfer Destination') %]</a></li>
+ <li><a href dropdown-toggle ng-click="transfer_holds_to_marked()">
+ [% l('Transfer All Title Holds') %]</a></li>
</ul>
</div>
</div>
<eg-embed-frame url="catalog_url" handlers="handlers" onchange="handle_page"></eg-embed-frame>
</div>
<!-- ng-if the remaining tabs so they can be instantiated on demand -->
- <div ng-if="record_tab == 'record_html'">
+ <div ng-if="record_tab == 'marc_html'">
<eg-record-html record-id="record_id"></eg-record-html>
</div>
<div ng-if="record_tab == 'holds'">
<eg-grid-field label="[% l('Pickup Library') %]" path='hold.pickup_lib.shortname'></eg-grid-field>
<eg-grid-field label="[% l('Title') %]" path='mvr.title'>
- <a href="[% ctx.base_path %]/opac/record/{{item.mvr.doc_id()}}">
+ <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.mvr.doc_id()}}">
{{item.mvr.title()}}
</a>
</eg-grid-field>
<eg-grid-field label="[% l('Title') %]"
path="call_number.record.simple_record.title" visible>
- <a href="[% ctx.base_path %]/opac/record/{{item['call_number.record.id']}}">
+ <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item['call_number.record.id']}}">
{{item['call_number.record.simple_record.title']}}
</a>
</eg-grid-field>
<div class="flex-row">
<div class="flex-cell strong-text">[% l('Title:') %]</div>
<div class="flex-cell flex-2">
- <a target="_blank"
- href="[% ctx.base_path %]/opac/record/{{record.id()}}">
+ <a target="_self"
+ href="[% ctx.base_path %]/staff/cat/catalog/record/{{record.id()}}">
{{record.simple_record().title()}}
</a>
</div>
path='circ.xact_start'></eg-grid-field>
<eg-grid-field label="[% l('Title') %]" path="title">
- <a target="_self" href="[% ctx.base_path %]/opac/record/{{record.doc_id()}}">
+ <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{record.doc_id()}}">
{{item.title}}
</a>
</eg-grid-field>
<eg-grid-field label="[% l('Call Number') %]" path='volume.label'></eg-grid-field>
<eg-grid-field label="[% l('Title') %]" path='mvr.title'>
- <a href="[% ctx.base_path %]/opac/record/{{item.mvr.doc_id()}}">
+ <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.mvr.doc_id()}}">
{{item.mvr.title()}}
</a>
</eg-grid-field>
<eg-grid-field label="[% l('Post-Clear') %]" path='post_clear'></eg-grid-field>
<eg-grid-field label="[% l('Title') %]" path='mvr.title'>
- <a href="[% ctx.base_path %]/opac/record/{{item.mvr.doc_id()}}">
+ <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.mvr.doc_id()}}">
{{item.mvr.title()}}
</a>
</eg-grid-field>
<eg-grid-field label="[% l('Title') %]" name="title"
path="xact.circulation.target_copy.call_number.record.simple_record.title">
- <a href="[% ctx.base_path %]/opac/record/{{item.record_id}}">{{item.title}}</a>
+ <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.record_id}}">{{item.title}}</a>
</eg-grid-field>
<!-- needed for bib link -->
<eg-grid-field label="[% l('Title') %]" name="title"
path="circulation.target_copy.call_number.record.simple_record.title">
- <a href="[% ctx.base_path %]/opac/record/{{item.record_id}}">{{item.title}}</a>
+ <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.record_id}}">{{item.title}}</a>
</eg-grid-field>
<!-- needed for bib link -->
<eg-grid-field label="[% l('Title') %]" name="title"
path='circulation.target_copy.call_number.record.simple_record.title'>
- <a href="[% ctx.base_path %]/opac/record/{{item.record_id}}">{{item.title}}</a>
+ <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.record_id}}">{{item.title}}</a>
</eg-grid-field>
<!-- fetch the record ID so we can link to it. hide it by default -->
<eg-grid-field path="circulation.target_copy.call_number.record.id"
return;
}
- if(typeof xulG != 'undefined' && xulG.get_barcode_and_settings) {
- var cur_hold_barcode = undefined;
- var barcode = isload;
- if(!barcode || barcode === true) barcode = document.getElementById('staff_barcode').value;
- var only_settings = true;
- if(!document.getElementById('hold_usr_is_requestor').checked) {
- if(!isload) {
- barcode = document.getElementById('hold_usr_input').value;
- only_settings = false;
- }
- if(barcode && barcode != '' && !document.getElementById('hold_usr_is_requestor_not').checked)
- document.getElementById('hold_usr_is_requestor_not').checked = 'checked';
- }
- if(barcode == undefined || barcode == '') {
- document.getElementById('patron_name').innerHTML = '';
- // No submitting on empty barcode, but empty barcode doesn't really count as "not found" either
- document.getElementById('place_hold_submit').disabled = true;
- document.getElementById("patron_usr_barcode_not_found").style.display = 'none';
- cur_hold_barcode = null;
- return;
+ if (!window.xulG) return;
+
+ var cur_hold_barcode = undefined;
+ var barcode = isload;
+ if(!barcode || barcode === true) barcode = document.getElementById('staff_barcode').value;
+ var only_settings = true;
+ if(!document.getElementById('hold_usr_is_requestor').checked) {
+ if(!isload) {
+ barcode = document.getElementById('hold_usr_input').value;
+ only_settings = false;
}
- if(barcode == cur_hold_barcode)
- return;
- // No submitting until we think the barcode is valid
+ if(barcode && barcode != '' && !document.getElementById('hold_usr_is_requestor_not').checked)
+ document.getElementById('hold_usr_is_requestor_not').checked = 'checked';
+ }
+ if(barcode == undefined || barcode == '') {
+ document.getElementById('patron_name').innerHTML = '';
+ // No submitting on empty barcode, but empty barcode doesn't really count as "not found" either
document.getElementById('place_hold_submit').disabled = true;
+ document.getElementById("patron_usr_barcode_not_found").style.display = 'none';
+ cur_hold_barcode = null;
+ return;
+ }
+ if(barcode == cur_hold_barcode)
+ return;
+ // No submitting until we think the barcode is valid
+ document.getElementById('place_hold_submit').disabled = true;
+
+ if (window.IAMBROWSER) {
+ // Browser client operates asynchronously
+ if (!xulG.get_barcode_and_settings_async) return;
+ xulG.get_barcode_and_settings_async(barcode, only_settings)
+ .then(
+ function(load_info) { // load succeeded
+ staff_hold_usr_barcode_changed2(
+ isload, only_settings, barcode, cur_hold_barcode, load_info);
+ },
+ function() {
+ // load failed (rejected). Call staff_hold_usr_barcode_changed2
+ // anyway, since it handles clearing the form
+ staff_hold_usr_barcode_changed2(
+ isload, only_settings, barcode, cur_hold_barcode, false);
+ }
+ )
+ } else {
+ // XUL version is synchronous
+ if (!xulG.get_barcode_and_settings) return;
var load_info = xulG.get_barcode_and_settings(window, barcode, only_settings);
- if(load_info == false || load_info == undefined) {
- document.getElementById('patron_name').innerHTML = '';
- document.getElementById("patron_usr_barcode_not_found").style.display = '';
- cur_hold_barcode = null;
- return;
- }
- cur_hold_barcode = load_info.barcode;
- if(!only_settings || (isload && isload !== true)) document.getElementById('hold_usr_input').value = load_info.barcode; // Safe at this point as we already set cur_hold_barcode
- if(load_info.settings['opac.default_pickup_location'])
- document.getElementById('pickup_lib').value = load_info.settings['opac.default_pickup_location'];
- if(!load_info.settings['opac.default_phone']) load_info.settings['opac.default_phone'] = '';
- if(!load_info.settings['opac.default_sms_notify']) load_info.settings['opac.default_sms_notify'] = '';
- if(!load_info.settings['opac.default_sms_carrier']) load_info.settings['opac.default_sms_carrier'] = '';
- if(load_info.settings['opac.hold_notify'] || load_info.settings['opac.hold_notify'] === '') {
- var email = load_info.settings['opac.hold_notify'].indexOf('email') > -1;
- var phone = load_info.settings['opac.hold_notify'].indexOf('phone') > -1;
- var sms = load_info.settings['opac.hold_notify'].indexOf('sms') > -1;
- var update_elements = document.getElementsByName('email_notify');
- for(var i in update_elements) update_elements[i].checked = (email ? 'checked' : '');
- update_elements = document.getElementsByName('phone_notify_checkbox');
- for(var i in update_elements) update_elements[i].checked = (phone ? 'checked' : '');
- update_elements = document.getElementsByName('sms_notify_checkbox');
- for(var i in update_elements) update_elements[i].checked = (sms ? 'checked' : '');
- }
- update_elements = document.getElementsByName('phone_notify');
- for(var i in update_elements) update_elements[i].value = load_info.settings['opac.default_phone'];
- update_elements = document.getElementsByName('sms_notify');
- for(var i in update_elements) update_elements[i].value = load_info.settings['opac.default_sms_notify'];
- update_elements = document.getElementsByName('sms_carrier');
- for(var i in update_elements) update_elements[i].value = load_info.settings['opac.default_sms_carrier'];
- update_elements = document.getElementsByName('email_notify');
- for(var i in update_elements) {
- update_elements[i].disabled = (load_info.user_email ? false : true);
- if(update_elements[i].disabled) update_elements[i].checked = false;
- }
- update_elements = document.getElementsByName('email_address');
- for(var i in update_elements) update_elements[i].textContent = load_info.user_email;
- if(!document.getElementById('hold_usr_is_requestor').checked && document.getElementById('hold_usr_input').value) {
- document.getElementById('patron_name').innerHTML = load_info.patron_name;
- document.getElementById("patron_usr_barcode_not_found").style.display = 'none';
- }
- // Ok, now we can allow submitting again, unless this is a "true" load, in which case we likely have a blank barcode box active
-
- // update the advanced hold options link to propagate the patron
- // barcode if clicked. This is needed when the patron barcode
- // is manually entered (i.e. the staff client does not provide one).
- var adv_link = document.getElementById('advanced_hold_link');
- if (adv_link) { // not present on MR hold pages
- var href = adv_link.getAttribute('href').replace(
- /;usr_barcode=[^;\&]+|$/,
- ';usr_barcode=' + encodeURIComponent(cur_hold_barcode));
- adv_link.setAttribute('href', href);
- }
+ staff_hold_usr_barcode_changed2(isload, only_settings, barcode, cur_hold_barcode, load_info);
+ }
+}
+
+function staff_hold_usr_barcode_changed2(
+ isload, only_settings, barcode, cur_hold_barcode, load_info) {
+
+ if(load_info == false || load_info == undefined) {
+ document.getElementById('patron_name').innerHTML = '';
+ document.getElementById("patron_usr_barcode_not_found").style.display = '';
+ cur_hold_barcode = null;
+ return;
+ }
+ cur_hold_barcode = load_info.barcode;
+ if(!only_settings || (isload && isload !== true)) document.getElementById('hold_usr_input').value = load_info.barcode; // Safe at this point as we already set cur_hold_barcode
+ if(load_info.settings['opac.default_pickup_location'])
+ document.getElementById('pickup_lib').value = load_info.settings['opac.default_pickup_location'];
+ if(!load_info.settings['opac.default_phone']) load_info.settings['opac.default_phone'] = '';
+ if(!load_info.settings['opac.default_sms_notify']) load_info.settings['opac.default_sms_notify'] = '';
+ if(!load_info.settings['opac.default_sms_carrier']) load_info.settings['opac.default_sms_carrier'] = '';
+ if(load_info.settings['opac.hold_notify'] || load_info.settings['opac.hold_notify'] === '') {
+ var email = load_info.settings['opac.hold_notify'].indexOf('email') > -1;
+ var phone = load_info.settings['opac.hold_notify'].indexOf('phone') > -1;
+ var sms = load_info.settings['opac.hold_notify'].indexOf('sms') > -1;
+ var update_elements = document.getElementsByName('email_notify');
+ for(var i in update_elements) update_elements[i].checked = (email ? 'checked' : '');
+ update_elements = document.getElementsByName('phone_notify_checkbox');
+ for(var i in update_elements) update_elements[i].checked = (phone ? 'checked' : '');
+ update_elements = document.getElementsByName('sms_notify_checkbox');
+ for(var i in update_elements) update_elements[i].checked = (sms ? 'checked' : '');
+ }
+ update_elements = document.getElementsByName('phone_notify');
+ for(var i in update_elements) update_elements[i].value = load_info.settings['opac.default_phone'];
+ update_elements = document.getElementsByName('sms_notify');
+ for(var i in update_elements) update_elements[i].value = load_info.settings['opac.default_sms_notify'];
+ update_elements = document.getElementsByName('sms_carrier');
+ for(var i in update_elements) update_elements[i].value = load_info.settings['opac.default_sms_carrier'];
+ update_elements = document.getElementsByName('email_notify');
+ for(var i in update_elements) {
+ update_elements[i].disabled = (load_info.user_email ? false : true);
+ if(update_elements[i].disabled) update_elements[i].checked = false;
+ }
+ update_elements = document.getElementsByName('email_address');
+ for(var i in update_elements) update_elements[i].textContent = load_info.user_email;
+ if(!document.getElementById('hold_usr_is_requestor').checked && document.getElementById('hold_usr_input').value) {
+ document.getElementById('patron_name').innerHTML = load_info.patron_name;
+ document.getElementById("patron_usr_barcode_not_found").style.display = 'none';
+ }
+ // Ok, now we can allow submitting again, unless this is a "true" load, in which case we likely have a blank barcode box active
- if (isload !== true)
- document.getElementById('place_hold_submit').disabled = false;
+ // update the advanced hold options link to propagate the patron
+ // barcode if clicked. This is needed when the patron barcode
+ // is manually entered (i.e. the staff client does not provide one).
+ var adv_link = document.getElementById('advanced_hold_link');
+ if (adv_link) { // not present on MR hold pages
+ var href = adv_link.getAttribute('href').replace(
+ /;usr_barcode=[^;\&]+|$/,
+ ';usr_barcode=' + encodeURIComponent(cur_hold_barcode));
+ adv_link.setAttribute('href', href);
}
+
+ if (isload !== true)
+ document.getElementById('place_hold_submit').disabled = false;
}
window.onload = function() {
// record details page events
resolve : resolver
});
+ // create some catalog page-specific mappings
+ $routeProvider.when('/cat/catalog/record/:record_id/:record_tab', {
+ templateUrl: './cat/catalog/t_catalog',
+ controller: 'CatalogCtrl',
+ resolve : resolver
+ });
+
$routeProvider.otherwise({redirectTo : '/cat/catalog/index'});
})
function($scope , $routeParams , $location , $q , egCore , egHolds,
egGridDataProvider , egHoldGridActions) {
- // TODO: is start path configurable in the xul client?
- var url = $location.absUrl().replace(/\/staff.*/, '/opac/advanced');
+ // set record ID on page load if available...
+ $scope.record_id = $routeParams.record_id;
- if ($routeParams.record_id) {
- $scope.record_id = $routeParams.record_id;
- url = url.replace(/advanced/, '/record/' + $scope.record_id);
- }
+ // also set it when the iframe changes to a new record
+ $scope.handle_page = function(url) {
- // pass the reg URL into the scope, thus into the
- $scope.catalog_url = url;
- // default to catalog view of the record page
- $scope.record_tab = 'catalog';
+ if (!url || url == 'about:blank') {
+ // nothing loaded. If we already have a record ID, leave it.
+ return;
+ }
- $scope.handle_page = function(url) {
var match = url.match(/\/+opac\/+record\/+(\d+)/);
if (match) {
$scope.record_id = match[1];
}
}
- // xulG handlers
- $scope.handlers = {};
+ // xulG catalog handlers
+ $scope.handlers = {
+ get_barcode_and_settings_async : function(barcode, only_settings) {
+ if (!barcode) return $q.reject();
+ var deferred = $q.defer();
+
+ var barcode_promise = $q.when(barcode);
+ if (!only_settings) {
+
+ // first verify / locate the barcode
+ barcode_promise = egCore.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.get_barcodes',
+ egCore.auth.token(),
+ egCore.auth.user().ws_ou(), 'actor', barcode
+ ).then(function(resp) {
+
+ if (!resp || egCore.evt.parse(resp) || !resp.length) {
+ console.error('user not found: ' + barcode);
+ deferred.reject();
+ return null;
+ }
+
+ resp = resp[0];
+ return barcode = resp.barcode;
+ });
+ }
+
+ barcode_promise.then(function(barcode) {
+ if (!barcode) return;
+
+ return egCore.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.user.fleshed.retrieve_by_barcode',
+ egCore.auth.token(), barcode);
+
+ }).then(function(user) {
+ if (!user) return null;
+
+ if (e = egCore.evt.parse(user)) {
+ console.error('user fetch failed : ' + e.toString());
+ deferred.reject();
+ return null;
+ }
+
+ // copied more or less directly from XUL menu.js
+ var settings = {};
+ for(var i = 0; i < user.settings().length; i++) {
+ settings[user.settings()[i].name()] =
+ JSON2js(user.settings()[i].value());
+ }
- // Holds bits -------------------------------
+ if(!settings['opac.default_phone'] && user.day_phone())
+ settings['opac.default_phone'] = user.day_phone();
+ if(!settings['opac.hold_notify'] && settings['opac.hold_notify'] !== '')
+ settings['opac.hold_notify'] = 'email:phone';
+
+ // Taken from patron/util.js format_name
+ // FIXME: I18n
+ var patron_name =
+ ( user.prefix() ? user.prefix() + ' ' : '') +
+ user.family_name() + ', ' +
+ user.first_given_name() + ' ' +
+ ( user.second_given_name() ? user.second_given_name() + ' ' : '' ) +
+ ( user.suffix() ? user.suffix() : '');
+
+ deferred.resolve({
+ "barcode": barcode,
+ "settings" : settings,
+ "user_email" : user.email(),
+ "patron_name" : patron_name
+ });
+ });
+
+ return deferred.promise;
+ }
+ }
+
+ // ------------------------------------------------------------------
+ // Holds
var provider = egGridDataProvider.instance({});
$scope.hold_grid_data_provider = provider;
$scope.grid_actions = egHoldGridActions;
var ids = hold_ids.slice(offset, offset + count);
return egHolds.fetch_holds(ids).then(null, null,
function(hold_data) {
- //patronSvc.holds.push(hold_data);
- console.log('returning hold ' + hold_data.mvr.title());
return hold_data;
}
);
provider.refresh();
}
- $scope.set_record_tab = function(tab) {
- $scope.record_tab = tab;
-
- if (tab == 'holds') {
- $scope.detail_hold_record_id = $scope.record_id;
-
- // refresh the holds grid
- provider.refresh();
- }
- }
-
$scope.print_holds = function() {
var holds = [];
angular.forEach($scope.hold_grid_controls.allItems(), function(item) {
});
}
+ $scope.mark_hold_transfer_dest = function() {
+ egCore.hatch.setLocalItem(
+ 'eg.circ.hold.title_transfer_target', $scope.record_id);
+ }
+
+ // UI presents this option as "all holds"
+ $scope.transfer_holds_to_marked = function() {
+ var hold_ids = $scope.hold_grid_controls.allItems().map(
+ function(hold_data) {return hold_data.hold.id()});
+ egHolds.transfer_to_marked_title(hold_ids);
+ }
+
+ // ------------------------------------------------------------------
+ // Initialize the selected tab
+
+ function init_cat_url() {
+ // Set the initial catalog URL. This only happens once.
+ // The URL is otherwise generated through user navigation.
+ if ($scope.catalog_url) return;
+
+ var url = $location.absUrl().replace(/\/staff.*/, '/opac/advanced');
+
+ // A record ID in the path indicates a request for the record-
+ // specific page.
+ if ($routeParams.record_id) {
+ url = url.replace(/advanced/, '/record/' + $scope.record_id);
+ }
+
+ $scope.catalog_url = url;
+ }
+
+ $scope.set_record_tab = function(tab) {
+ $scope.record_tab = tab;
+
+ switch(tab) {
+
+ case 'catalog':
+ init_cat_url();
+ break;
+
+ case 'holds':
+ $scope.detail_hold_record_id = $scope.record_id;
+ // refresh the holds grid
+ provider.refresh();
+ break;
+ }
+ }
+
+ var tab = $routeParams.record_tab || 'catalog';
+ $scope.set_record_tab(tab);
}])