<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/ui.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/cat/services/copy_details.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/cat/item/app.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/cat/services/record_html.js"></script>
[% END %]
<style>
<!-- barcode input -->
<input type="text" id="item-status-barcode"
- focus-me="focusBarcode" class="form-control" ng-model="args.barcode">
+ select-me="context.selectBarcode" class="form-control" ng-model="args.barcode">
<!-- submit -->
<input class="btn btn-default"
</div><!-- row -->
</form>
+<div class="row">
+ <div class="col-md-6">
+ <div ng-show="context.itemNotFound" class="alert alert-danger">
+ [% l('Item Not Found') %]
+ </div>
+ </div>
+</div>
+
<div ng-view></div>
[% END %]
-<div class="flex-container-striped flex-container-bordered">
+<div class="flex-container-striped flex-container-bordered"
+ ng-hide="context.itemNotFound">
<div class="flex-row">
<div class="flex-cell header-label">[% l('Title:') %]</div>
<div class="flex-cell flex-2">
-<h1>summary</h1>
+<h3>[% l('MARC Record') %]</h3>
+
+<eg-record-html record-id="recordId"></eg-record-html>
-<div class="col-md-12">
+<div class="col-md-6" ng-show="!prev_circ_summary">
+ <div class="alert alert-info">
+ [% l('No Previous Circ Group') %]
+ </div>
+</div>
+<div class="col-md-6" ng-show="prev_circ_summary">
<div class="flex-row">
<div class="flex-cell flex-2 header-label-big">
[% l('Previous Circ Group') %]
</div>
- <div class="flex-cell flex-2 header-label-big">
- [% l('Most Recent Circ Group') %]
- </div>
</div>
<div class="flex-row">
'{{prev_circ_usr.card().barcode()}}') %]
</a>
</div>
+ </div>
+
+ <div class="flex-row">
+ <div class="flex-cell">[% l('Total Circs') %]</div>
+ <div class="flex-cell flex-cell-well">
+ {{prev_circ_summary.num_circs()}}
+ </div>
+ </div>
+
+ <div class="flex-row">
+ <div class="flex-cell">[% l('Checkout Date') %]</div>
+ <div class="flex-cell flex-cell-well">
+ {{prev_circ_summary.start_time() | date:'short'}}
+ </div>
+ </div>
+
+ <div class="flex-row">
+ <div class="flex-cell">[% l('Checkout Workstation') %]</div>
+ <div class="flex-cell flex-cell-well">
+ {{prev_circ_summary.checkout_workstation()}}
+ </div>
+ </div>
+
+ <div class="flex-row">
+ <div class="flex-cell">[% l('Last Renewed On') %]</div>
+ <div class="flex-cell flex-cell-well">
+ {{prev_circ_summary.last_renewal_time() | date:'short'}}
+ </div>
+ </div>
+
+ <div class="flex-row">
+ <div class="flex-cell">[% l('Renewal Workstation') %]</div>
+ <div class="flex-cell flex-cell-well">
+ {{prev_circ_summary.last_renewal_workstation()}}
+ </div>
+ </div>
+
+ <div class="flex-row">
+ <div class="flex-cell">[% l('Stop Fines Reason') %]</div>
+ <div class="flex-cell flex-cell-well">
+ {{prev_circ_summary.last_stop_fines()}}
+ </div>
+ </div>
+ <div class="flex-row">
+ <div class="flex-cell">[% l('Stop Fines Time') %]</div>
+ <div class="flex-cell flex-cell-well">
+ {{prev_circ_summary.last_stop_fines_time() | date:'short'}}
+ </div>
+ </div>
+ <div class="flex-row">
+ <div class="flex-cell">[% l('Checkin Time') %]</div>
+ <div class="flex-cell flex-cell-well">
+ {{prev_circ_summary.last_checkin_time() | date:'short'}}
+ </div>
+ </div>
+ <div class="flex-row">
+ <div class="flex-cell">[% l('Checkin Scan Time') %]</div>
+ <div class="flex-cell flex-cell-well">
+ {{prev_circ_summary.last_checkin_scan_time() | date:'short'}}
+ </div>
+ </div>
+ <div class="flex-row">
+ <div class="flex-cell">[% l('Checkin Workstation') %]</div>
+ <div class="flex-cell flex-cell-well">
+ {{prev_circ_summary.last_checkin_workstation()}}
+ </div>
+ </div>
+</div>
+
+<div class="col-md-6" ng-show="!circ">
+ <div class="alert alert-info">
+ [% l('No Recent Circ Group') %]
+ </div>
+</div>
+<div class="col-md-6" ng-show="circ">
+ <div class="flex-row">
+ <div class="flex-cell flex-2 header-label-big">
+ [% l('Most Recent Circ Group') %]
+ </div>
+ </div>
+ <div class="flex-row">
<div class="flex-cell">[% l('Patron') %]</div>
<div class="flex-cell flex-cell-well">
<a href="./circ/patron/{{circ.usr().id()}}/checkout"
<div class="flex-row">
<div class="flex-cell">[% l('Total Circs') %]</div>
<div class="flex-cell flex-cell-well">
- {{prev_circ_summary.num_circs()}}
- </div>
- <div class="flex-cell">[% l('Total Circs') %]</div>
- <div class="flex-cell flex-cell-well">
{{circ_summary.num_circs()}}
</div>
</div>
<div class="flex-row">
<div class="flex-cell">[% l('Checkout Date') %]</div>
<div class="flex-cell flex-cell-well">
- {{prev_circ_summary.start_time() | date:'short'}}
- </div>
- <div class="flex-cell">[% l('Checkout Date') %]</div>
- <div class="flex-cell flex-cell-well">
{{circ.xact_start() | date:'short'}}
</div>
</div>
<div class="flex-row">
<div class="flex-cell">[% l('Checkout Workstation') %]</div>
<div class="flex-cell flex-cell-well">
- {{prev_circ_summary.checkout_workstation()}}
- </div>
- <div class="flex-cell">[% l('Checkout Workstation') %]</div>
- <div class="flex-cell flex-cell-well">
{{circ.workstation().name()}}
</div>
</div>
<div class="flex-row">
<div class="flex-cell">[% l('Last Renewed On') %]</div>
<div class="flex-cell flex-cell-well">
- {{prev_circ_summary.last_renewal_time() | date:'short'}}
- </div>
- <div class="flex-cell">[% l('Last Renewed On') %]</div>
- <div class="flex-cell flex-cell-well">
{{circ_summary.last_renewal_time() | date:'short'}}
</div>
</div>
<div class="flex-row">
<div class="flex-cell">[% l('Renewal Workstation') %]</div>
<div class="flex-cell flex-cell-well">
- {{prev_circ_summary.last_renewal_workstation()}}
- </div>
- <div class="flex-cell">[% l('Renewal Workstation') %]</div>
- <div class="flex-cell flex-cell-well">
{{circ_summary.last_renewal_workstation()}}
</div>
</div>
<div class="flex-row">
<div class="flex-cell">[% l('Stop Fines Reason') %]</div>
<div class="flex-cell flex-cell-well">
- {{prev_circ_summary.last_stop_fines()}}
- </div>
- <div class="flex-cell">[% l('Stop Fines Reason') %]</div>
- <div class="flex-cell flex-cell-well">
{{circ.stop_fines()}}
</div>
</div>
<div class="flex-row">
<div class="flex-cell">[% l('Stop Fines Time') %]</div>
<div class="flex-cell flex-cell-well">
- {{prev_circ_summary.last_stop_fines_time() | date:'short'}}
- </div>
- <div class="flex-cell">[% l('Stop Fines Time') %]</div>
- <div class="flex-cell flex-cell-well">
{{circ.stop_fines_time() | date:'short'}}
</div>
</div>
<div class="flex-row">
<div class="flex-cell">[% l('Checkin Time') %]</div>
<div class="flex-cell flex-cell-well">
- {{prev_circ_summary.last_checkin_time() | date:'short'}}
- </div>
- <div class="flex-cell">[% l('Checkin Time') %]</div>
- <div class="flex-cell flex-cell-well">
{{circ.checkin_time() | date:'short'}}
</div>
</div>
<div class="flex-row">
<div class="flex-cell">[% l('Checkin Scan Time') %]</div>
<div class="flex-cell flex-cell-well">
- {{prev_circ_summary.last_checkin_scan_time() | date:'short'}}
- </div>
- <div class="flex-cell">[% l('Checkin Scan Time') %]</div>
- <div class="flex-cell flex-cell-well">
{{circ.checkin_scan_time() | date:'short'}}
</div>
</div>
<div class="flex-row">
<div class="flex-cell">[% l('Checkin Workstation') %]</div>
<div class="flex-cell flex-cell-well">
- {{prev_circ_summary.last_checkin_workstation()}}
- </div>
- <div class="flex-cell">[% l('Checkin Workstation') %]</div>
- <div class="flex-cell flex-cell-well">
{{circ.checkin_workstation.name()}}
</div>
</div>
features="-display,-sort,-multisort"
main-label="[% l('Item Status') %]"
items-provider="gridDataProvider"
+ on-item-retrieved="gridItemRetrieved"
persist-key="cat.items">
<eg-grid-field label="[% l('Barcode') %]" path='barcode' visible></eg-grid-field>
<div class="flex-cell">[% l('Circ Library') %]</div>
<div class="flex-cell flex-cell-well">{{copy.circ_lib().shortname()}}</div>
- <div class="flex-cell">[% l('Item Call #') %]</div>
- <div class="flex-cell flex-cell-well">{{copy.call_number().label()}}</div>
+ <div class="flex-cell">[% l('Call # Prefix') %]</div>
+ <div class="flex-cell flex-cell-well">
+ {{copy.call_number().prefix().label()}}
+ </div>
<div class="flex-cell">[% l('Status') %]</div>
<div class="flex-cell flex-cell-well">{{copy.status().name()}}</div>
<div class="flex-cell">[% l('Owning Library') %]</div>
<div class="flex-cell flex-cell-well">{{copy.circ_lib().shortname()}}</div>
- <div class="flex-cell">[% l('Renewal Type') %]</div>
- <div class="flex-cell flex-cell-well">
- <div ng-if="circ.opac_renewal() == 't'">[% l('OPAC') %]</div>
- <div ng-if="circ.desk_renewal() == 't'">[% l('Desk') %]</div>
- <div ng-if="circ.phone_renewal() == 't'">[% l('Phone') %]</div>
- </div>
+ <div class="flex-cell">[% l('Call #') %]</div>
+ <div class="flex-cell flex-cell-well">{{copy.call_number().label()}}</div>
<div class="flex-cell">[% l('Due Date') %]</div>
<div class="flex-cell flex-cell-well">{{circ.due_date() | date:'short'}}</div>
<div class="flex-cell">[% l('Copy Location') %]</div>
<div class="flex-cell flex-cell-well">{{copy.location().name()}}</div>
- <div class="flex-cell">[% l('Total Circs') %]</div>
- <div class="flex-cell flex-cell-well">{{total_circs}}</div>
+ <div class="flex-cell">[% l('Call # Suffix') %]</div>
+ <div class="flex-cell flex-cell-well">
+ {{copy.call_number().suffix().label()}}
+ </div>
<div class="flex-cell">[% l('Checkout Date') %]</div>
<div class="flex-cell flex-cell-well">{{circ.xact_start() | date:'short'}}</div>
<div class="flex-cell">[% l('Loan Duration') %]</div>
<div class="flex-cell flex-cell-well">{{circ.duration()}}</div>
- <div class="flex-cell">[% l('Total Circs - Current Year') %]</div>
- <div class="flex-cell flex-cell-well">{{total_circs_this_year}}</div>
+ <div class="flex-cell">[% l('Renewal Type') %]</div>
+ <div class="flex-cell flex-cell-well">
+ <div ng-if="circ.opac_renewal() == 't'">[% l('OPAC') %]</div>
+ <div ng-if="circ.desk_renewal() == 't'">[% l('Desk') %]</div>
+ <div ng-if="circ.phone_renewal() == 't'">[% l('Phone') %]</div>
+ </div>
<div class="flex-cell">[% l('Checkout Workstation') %]</div>
<div class="flex-cell flex-cell-well">{{circ.workstation().name()}}</div>
<div class="flex-cell">[% l('Fine Level') %]</div>
<div class="flex-cell flex-cell-well">{{circ.duration_rule().name()}}</div>
- <div class="flex-cell">[% l('Total Circs - Prev Year') %]</div>
- <div class="flex-cell flex-cell-well">{{total_circs_prev_year}}</div>
+ <div class="flex-cell">[% l('Total Circs') %]</div>
+ <div class="flex-cell flex-cell-well">{{total_circs}}</div>
<div class="flex-cell">[% l('Duration Rule') %]</div>
<div class="flex-cell flex-cell-well">{{circ.duration_rule().name()}}</div>
<div class="flex-cell">[% l('Reference') %]</div>
<div class="flex-cell flex-cell-well">{{copy.ref()}}</div>
- <div class="flex-cell">[% l('Renewal Workstation') %]</div>
- <div class="flex-cell flex-cell-well">{{circ_summary.last_renewal_workstation()}}</div>
+ <div class="flex-cell">[% l('Total Circs - Current Year') %]</div>
+ <div class="flex-cell flex-cell-well">{{total_circs_this_year}}</div>
<div class="flex-cell">[% l('Recurring Fine Rule') %]</div>
<div class="flex-cell flex-cell-well">{{circ.recurring_fine_rule().name()}}</div>
<div class="flex-cell">[% l('OPAC Visible') %]</div>
<div class="flex-cell flex-cell-well">{{copy.opac_visible()}}</div>
- <div class="flex-cell">[% l('Remaining Renewals') %]</div>
- <div class="flex-cell flex-cell-well">{{circ.renewal_remaining()}}</div>
+ <div class="flex-cell">[% l('Total Circs - Prev Year') %]</div>
+ <div class="flex-cell flex-cell-well">{{total_circs_prev_year}}</div>
<div class="flex-cell">[% l('Max Fine Rule') %]</div>
<div class="flex-cell flex-cell-well">{{circ.max_fine_rule().name()}}</div>
<div class="flex-cell">[% l('Holdable') %]</div>
<div class="flex-cell flex-cell-well">{{copy.opac_visible()}}</div>
- <!-- empty -->
- <div class="flex-cell"></div>
- <div class="flex-cell"></div>
+ <div class="flex-cell">[% l('Renewal Workstation') %]</div>
+ <div class="flex-cell flex-cell-well">{{circ_summary.last_renewal_workstation()}}</div>
<div class="flex-cell">[% l('Checkin Time') %]</div>
<div class="flex-cell flex-cell-well">
<div class="flex-cell">[% l('Circulate') %]</div>
<div class="flex-cell flex-cell-well">{{copy.circulate()}}</div>
- <!-- empty -->
- <div class="flex-cell"></div>
- <div class="flex-cell"></div>
+ <div class="flex-cell">[% l('Remaining Renewals') %]</div>
+ <div class="flex-cell flex-cell-well">{{circ.renewal_remaining()}}</div>
<div class="flex-cell">[% l('Checkin Scan Time') %]</div>
<div class="flex-cell flex-cell-well">
<ul class="nav nav-tabs">
<li ng-class="{active : tab == 'summary'}">
- <a href="./cat/item/view/{{copy.id()}}/summary">
- [% l('Quick Summary') %]
- </a>
+ <a href="./cat/item/{{copy.id()}}">[% l('Quick Summary') %]</a>
</li>
<li ng-class="{active : tab == 'circs'}">
- <a href="./cat/item/view/{{copy.id()}}/circs">
- [% l('Circulation History') %]
- </a>
+ <a href="./cat/item/{{copy.id()}}/circs">[% l('Circulation History') %]</a>
</li>
<li ng-class="{active : tab == 'holds'}">
- <a href="./cat/item/view/{{copy.id()}}/holds">
- [% l('Holds / Transit') %]
- </a>
+ <a href="./cat/item/{{copy.id()}}/holds">[% l('Holds / Transit') %]</a>
</li>
<li ng-class="{active : tab == 'cat'}">
- <a href="./cat/item/view/{{copy.id()}}/cat">
- [% l('Cataloging Info') %]
- </a>
+ <a href="./cat/item/{{copy.id()}}/cat">[% l('Cataloging Info') %]</a>
</li>
</ul>
<div class="tab-content">
/* status bar along the bottom of the page ------------------------ */
/* decrease padding to decrease overall height */
+
+/* bottom padding ensures no body content is hidden behind the status
+ * bar. When content reaches the status bar a scroll bar appears */
+body { padding-bottom: 26px; }
+
#status-bar {
min-height:1.8em !important;
}
resolve : resolver
});
- $routeProvider.when('/cat/item/view/:id/:tab', {
+ $routeProvider.when('/cat/item/:id', {
+ templateUrl: './cat/item/t_view',
+ controller: 'ViewCtrl',
+ resolve : resolver
+ });
+
+ $routeProvider.when('/cat/item/:id/:tab', {
templateUrl: './cat/item/t_view',
controller: 'ViewCtrl',
resolve : resolver
flesh : 3,
flesh_fields : {
acp : ['call_number','location','status','location'],
- acn : ['record'],
+ acn : ['record','prefix','suffix'],
bre : ['simple_record','creator','editor']
},
select : {
}
}
- service.fetch = function(barcode, id) {
+ service.fetch = function(barcode, id, noListDupes) {
var promise;
if (barcode) {
return promise.then(function(copy) {
if (!copy) return null;
- var flatCopy = egCore.idl.toHash(copy, true);
- flatCopy.index = service.index++;
- service.copies.unshift(flatCopy);
+ var flatCopy;
+ if (noListDupes) {
+ // use the existing copy if possible
+ flatCopy = service.copies.filter(
+ function(c) {return c.id == copy.id()})[0];
+ }
+
+ if (!flatCopy) {
+ flatCopy = egCore.idl.toHash(copy, true);
+ flatCopy.index = service.index++;
+ service.copies.unshift(flatCopy);
+ }
return {
copy : copy,
.controller('SearchCtrl',
['$scope','$location','egCore','egGridDataProvider','itemSvc',
function($scope , $location , egCore , egGridDataProvider , itemSvc) {
- $scope.focusBarcode = true;
+ $scope.args = {}; // search args
// sub-scopes (search / detail-view) apply their version
// of retrieval function to $scope.context.search
// and display toggling via $scope.context.toggleDisplay
- $scope.context = {};
+ $scope.context = {
+ selectBarcode : true
+ };
$scope.toggleView = function($event) {
$scope.context.toggleDisplay();
$event.preventDefault(); // avoid form submission
}
-
- $scope.args = {};
}])
/**
$scope.gridDataProvider = provider;
$scope.context.search = function(args) {
+ $scope.context.itemNotFound = false;
itemSvc.fetch(args.barcode).then(function(res) {
if (res) {
provider.increment();
provider.selectOneItem(res.index);
+ $scope.args.barcode = '';
+ } else {
+ $scope.context.itemNotFound = true;
}
+ $scope.context.selectBarcode = true;
})
}
- if (itemSvc.copy) {
- // If a copy was just displayed in the detail view, ensure it's
- // focused in the list view. However, give the grid a chance to
- // instantiate before attempting to select any items.
- $timeout(function() {
- var flatCopy = itemSvc.copies.filter(
- function(c) { return c.id == itemSvc.copy.id() })[0];
- provider.selectOneItem(flatCopy.index);
- });
- }
+ // If a copy was just displayed in the detail view, ensure it's
+ // focused in the list view.
+ var selected = false;
+ $scope.gridItemRetrieved = function(item) {
+ if (selected || !itemSvc.copy) return;
+ if (itemSvc.copy.id() == item.id) {
+ provider.selectOneItem(item.index);
+ selected = true;
+ }
+ };
$scope.context.toggleDisplay = function() {
var item = provider.getSelectedItems()[0];
if (item)
- $location.path('/cat/item/view/' + item.id + '/summary');
+ $location.path('/cat/item/' + item.id);
}
}])
* Detail view -- shows one copy
*/
.controller('ViewCtrl',
- ['$scope','$location','$routeParams','egCore','itemSvc',
-function($scope , $location , $routeParams , egCore , itemSvc) {
+ ['$scope','$q','$location','$routeParams','egCore','itemSvc',
+function($scope , $q, $location , $routeParams , egCore , itemSvc) {
var copyId = $routeParams.id;
- $scope.tab = $routeParams.tab;
+ $scope.tab = $routeParams.tab || 'summary';
$scope.context.page = 'detail';
function loadCopy(barcode) {
+ $scope.context.itemNotFound = false;
+
+ // Avoid re-fetching the same copy while jumping tabs.
+ // In addition to being quicker, this helps to avoid flickering
+ // of the top panel which is always visible in the detail view.
+ //
+ // 'barcode' represents the loading of a new item - refetch it
+ // regardless of whether it matches the current item.
+ if (!barcode && itemSvc.copy && itemSvc.copy.id() == copyId) {
+ $scope.copy = itemSvc.copy;
+ $scope.recordId = itemSvc.copy.call_number().record().id();
+ return $q.when();
+ }
+
delete $scope.copy;
delete itemSvc.copy;
- return itemSvc.fetch(barcode, copyId).then(function(res) {
- if (!res) return;
+ var deferred = $q.defer();
+ itemSvc.fetch(barcode, copyId, true).then(function(res) {
+ $scope.context.selectBarcode = true;
+
+ if (!res) {
+ copyId = null;
+ $scope.context.itemNotFound = true;
+ deferred.reject(); // avoid propagation of data fetch calls
+ return;
+ }
+
var copy = res.copy;
- copyId = copy.id();
- $scope.args.barcode = copy.barcode();
itemSvc.copy = copy;
+ if (copyId && copyId != copy.id()) {
+ // if a new barcode is scanned in the detail view,
+ // update the url to match the ID of the new copy
+ $location.path('/cat/item/' + copy.id() + '/' + $scope.tab);
+ deferred.reject(); // avoid propagation of data fetch calls
+ return;
+ }
+
+ copyId = copy.id();
+ $scope.copy = copy;
+ $scope.recordId = copy.call_number().record().id();
+ $scope.args.barcode = '';
+
// locally flesh org units
copy.circ_lib(egCore.org.get(copy.circ_lib()));
copy.call_number().owning_lib(
function(field) { copy[field](Boolean(copy[field]() == 't')) }
);
- $scope.copy = copy;
+ deferred.resolve();
});
+
+ return deferred.promise;
}
// if loadPrev load the two most recent circulations
delete $scope.circ;
delete $scope.circ_summary;
delete $scope.prev_circ_summary;
+ if (!copyId) return;
egCore.pcrud.search('circ',
{target_copy : copyId},
$scope.total_circs = 0;
$scope.total_circs_this_year = 0;
$scope.total_circs_prev_year = 0;
+ if (!copyId) return;
egCore.pcrud.search('circbyyr',
{copy : copyId}, null, {atomic : true})
function loadHolds() {
delete $scope.hold;
+ if (!copyId) return;
egCore.pcrud.search('ahr',
{ current_copy : copyId,
function loadTransits() {
delete $scope.transit;
delete $scope.hold_transit;
+ if (!copyId) return;
egCore.pcrud.search('atc',
{target_copy : copyId},
}
}
+ $scope.context.toggleDisplay = function() {
+ $location.path('/cat/item/search');
+ }
+
// handle the barcode scan box, which will replace our current copy
$scope.context.search = function(args) {
- // when searching by barcode, we have to wait for the
- // copy to arrive (to collect the copyID) before
- // fetching the remaining tab data.
loadCopy(args.barcode).then(loadTabData);
}
- $scope.context.toggleDisplay = function() {
- $location.path('/cat/item/search');
- }
-
- loadCopy();
- loadTabData();
+ loadCopy().then(loadTabData);
}])
grid.dataProvider.get(grid.offset, grid.limit)
.then(null, null, function(item) {
if (item) {
+ $scope.items.push(item)
if (grid.onItemRetrieved)
grid.onItemRetrieved(item);
- $scope.items.push(item)
}
});
}
* print media CSS to ensure this content (and not the rest
* of the page) is printed.
*/
+
+// FIXME: only apply print CSS when print commands are issued via the
+// print container, otherwise using the browser's native print page
+// option will always result in empty pages. Move the print CSS
+// out of the standalone CSS file and put it into a template file
+// for this directive.
.directive('egPrintContainer', function() {
return {
restrict : 'AE',