# Wrap a url to open in a new tab in staff client.
MACRO opac_wrap(url) BLOCK;
- IF ctx.is_staff;
+ IF ctx.is_staff AND NOT ctx.is_browser_staff;
# void(0) to return false and not go to new page in current tab.
"javascript:xulG.new_tab(xulG.urls.XUL_OPAC_WRAPPER, {}, {'opac_url' : 'oils://remote" _ url _ "'});void(0);";
ELSE;
--- /dev/null
+[%
+ WRAPPER "staff/base.tt2";
+ ctx.page_title = l("Record Buckets");
+ ctx.page_app = "egCatalogApp";
+%]
+
+[% BLOCK APP_JS %]
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/eframe.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/cat/catalog/app.js"></script>
+[% END %]
+
+<div ng-view></div>
+
+[% END %]
+
<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/grid.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/ui.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/user.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/lframe.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/eframe.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/services/billing.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/services/circ.js"></script>
[% INCLUDE 'staff/circ/share/circ_strings.tt2' %]
%]
[% BLOCK APP_JS %]
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/lframe.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/eframe.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/patron/register.js"></script>
<link rel="stylesheet" href="[% ctx.base_path %]/staff/css/circ.css" />
[% END %]
<!-- insert the patron registration UI -->
-<eg-legacy-frame url="patron_edit_url" handlers="funcs"></eg-legacy-frame>
+<eg-embed-frame url="patron_edit_url" handlers="funcs"></eg-embed-frame>
white-space:nowrap;
}
-.eg-legacy-frame {
+/* embedded UI iframe */
+.eg-embed-frame {
width: 100%;
border: none;
margin: 0px;
</a>
<ul class="dropdown-menu">
<li>
+ <a href="./cat/catalog/index" target="_self">
+ <span class="glyphicon glyphicon-search"></span>
+ [% l('Search the Catalog') %]
+ </a>
+ </li>
+ <li>
<a href="./cat/bucket/record/view" target="_self">
<span class="glyphicon glyphicon-list-alt"></span>
[% l('Record Buckets') %]
/* staff client integration functions */
+
+// Browser staff client runs the TPAC within an iframe, whose onload
+// is not called until after the page onload is called. window.onload
+// actions are wrapped in timeouts (below) to ensure the wrapping page
+// has a chance to insert the necessary xulG, etc. functions into the
+// window.
+
function debug(msg){dump(msg+'\n')}
var eventCache={};
function attachEvt(scope, name, action) {
}
window.onload = function() {
// record details page events
- var rec = location.href.match(/\/opac\/record\/(\d+)/);
- if(rec && rec[1]) {
- runEvt('rdetail', 'recordRetrieved', rec[1]);
- runEvt('rdetail', 'MFHDDrawn');
- }
- if(location.href.match(/place_hold/)) {
- // patron barcode may come from XUL or a CGI param
- var patron_barcode = xulG.patron_barcode ||
- document.getElementById('hold_usr_input').value;
- if(patron_barcode) {
- staff_hold_usr_barcode_changed(patron_barcode);
- } else {
- staff_hold_usr_barcode_changed(true);
+
+ setTimeout(function() {
+ var rec = location.href.match(/\/opac\/record\/(\d+)/);
+ if(rec && rec[1]) {
+ runEvt('rdetail', 'recordRetrieved', rec[1]);
+ runEvt('rdetail', 'MFHDDrawn');
}
- }
+ if(location.href.match(/place_hold/)) {
+ // patron barcode may come from XUL or a CGI param
+ var patron_barcode = xulG.patron_barcode ||
+ document.getElementById('hold_usr_input').value;
+ if(patron_barcode) {
+ staff_hold_usr_barcode_changed(patron_barcode);
+ } else {
+ staff_hold_usr_barcode_changed(true);
+ }
+ }
+ });
}
function rdetail_next_prev_actions(index, count, prev, next, start, end, results) {
ol = window.onload;
window.onload = function() {
if(ol) ol();
- runEvt('rdetail', 'nextPrevDrawn', Number(index), Number(count));
+ setTimeout(function() {
+ runEvt('rdetail', 'nextPrevDrawn', Number(index), Number(count));
+ });
};
}
--- /dev/null
+/**
+ * TPAC Frame App
+ */
+
+angular.module('egCatalogApp', ['ui.bootstrap','ngRoute','egCoreMod'])
+
+.config(function($routeProvider, $locationProvider, $compileProvider) {
+ $locationProvider.html5Mode(true);
+ $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|blob):/); // grid export
+
+ var resolver = {delay :
+ ['egStartup', function(egStartup) {return egStartup.go()}]}
+
+ $routeProvider.when('/cat/catalog/index', {
+ template: '<eg-embed-frame url="catalog_url" handlers="handlers"></eg-embed-frame>',
+ controller: 'CatalogCtrl',
+ resolve : resolver
+ });
+
+ $routeProvider.otherwise({redirectTo : '/cat/catalog/index'});
+})
+
+
+/**
+ * */
+.controller('CatalogCtrl',
+ ['$scope','$routeParams','$location','egCore',
+function($scope , $routeParams , $location , egCore) {
+
+ // TODO: is start path configurable in the xul client?
+ var url = $location.absUrl().replace(/\/staff.*/, '/opac/advanced');
+
+ // pass the reg URL into the scope, thus into the
+ $scope.catalog_url = url;
+
+ $scope.handlers = {};
+}])
+
['egStartup', function(egStartup) {return egStartup.go()}]}
$routeProvider.when('/circ/patron/register', {
- template: '<eg-legacy-frame url="reg_url"></eg-legacy-frame>',
+ template: '<eg-embed-frame url="reg_url"></eg-embed-frame>',
controller: 'PatronRegCtrl',
resolve : resolver
});
$routeProvider.when('/circ/patron/register/stage/:stage_username', {
- template: '<eg-legacy-frame url="reg_url"></eg-legacy-frame>',
+ template: '<eg-embed-frame url="reg_url"></eg-embed-frame>',
controller: 'PatronRegCtrl',
resolve : resolver
});
$routeProvider.when('/circ/patron/register/edit/:edit_id', {
- template: '<eg-legacy-frame url="reg_url"></eg-legacy-frame>',
+ template: '<eg-embed-frame url="reg_url"></eg-embed-frame>',
controller: 'PatronRegCtrl',
resolve : resolver
});
$routeProvider.when('/circ/patron/register/clone/:clone_id', {
- template: '<eg-legacy-frame url="reg_url"></eg-legacy-frame>',
+ template: '<eg-embed-frame url="reg_url"></eg-embed-frame>',
controller: 'PatronRegCtrl',
resolve : resolver
});
/**
* */
.controller('PatronRegCtrl',
- ['$scope','$routeParams','$location','$filter','egCore',
-function($scope , $routeParams , $location , $filter , egCore) {
+ ['$scope','$routeParams','$location','egCore',
+function($scope , $routeParams , $location , egCore) {
var url = $location.absUrl().replace(/\/staff.*/, '/actor/user/register');
--- /dev/null
+angular.module('egCoreMod')
+
+/*
+ * Iframe container for (mostly legacy) embedded interfaces
+ */
+.directive('egEmbedFrame', function() {
+ return {
+ restrict : 'AE',
+ replace : true,
+ scope : {
+ // URL to load in the embed iframe
+ url : '=',
+
+ // optional hash of functions which augment or override
+ // the stock xulG functions defined below.
+ handlers : '='
+ },
+
+ template : '<iframe src="{{url}}" onload="egEmbedFrameLoader(this)" '
+ + 'class="eg-embed-frame" style="height:{{height}}px"></iframe>',
+
+ controller :
+ ['$scope','$window','$location','egCore',
+ function($scope , $window , $location , egCore) {
+
+ // Set the iframe height to just under the window height.
+ // leave room for the navbar, padding, margins, etc.
+ $scope.height = $window.outerHeight - 250;
+
+ // browser client doesn't use cookies, so we don't load the
+ // (at the time of writing, quite limited) angular.cookies
+ // module. We could load something, but this seems to work
+ // well enough for setting the auth cookie (at least, until
+ // it doesn't).
+ //
+ // note: document.cookie is smart enough to leave unreferenced
+ // cookies alone, so contrary to how this might look, it's not
+ // deleting other cookies (anoncache, etc.)
+
+ // delete any existing ses cookie
+ $window.document.cookie = "ses=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT";
+ // push our authtoken in
+ $window.document.cookie = 'ses=' + egCore.auth.token() + '; path=/; secure'
+
+ // $location has functions for modifying paths and search,
+ // but they all assume you are staying within the angular
+ // app, which we are not. Build the URLs by hand.
+ function open_tab(path) {
+ var url = 'https://' + $window.location.hostname +
+ egCore.env.basePath + path;
+ console.debug('egEmbedFrame opening tab ' + url);
+ $window.open(url, '_blank').focus();
+ }
+
+ // define our own xulG functions to be inserted into the
+ // iframe. NOTE: window-level functions are bad. Though
+ // there is probably a way, I was unable to correctly wire
+ // up the iframe onload handler within the controller or link
+ // funcs. In any event, the code below is meant as a stop-gap
+ // for porting dojo, etc. apps to angular apps and should
+ // eventually go away.
+ // NOTE: catalog integration is not a stop-gap
+ $window.egEmbedFrameLoader = function(iframe) {
+
+ console.debug('egEmbedFrameLoader()...');
+
+ // tell the iframe'd window its inside the staff client
+ iframe.contentWindow.IAMXUL = true;
+
+ // also tell it it's inside the browser client, which
+ // may be needed in a few special cases.
+ iframe.contentWindow.IAMBROWSER /* hear me roar */ = true;
+
+ // XUL has a dump() function which is occasinally called
+ // from embedded browsers.
+ iframe.contentWindow.dump = function(msg) {
+ console.debug('egEmbedFrame:dump(): ' + msg);
+ }
+
+ // define a few commonly used stock xulG handlers.
+
+ iframe.contentWindow.xulG = {
+ // patron search
+ spawn_search : function(search) {
+ open_tab('/circ/patron/search?search='
+ + encodeURIComponent(js2JSON(search)));
+ },
+
+ // edit an existing user
+ spawn_editor : function(info) {
+ if (info.usr) {
+ open_tab('/circ/patron/register/edit/' + info.usr);
+
+ } else if (info.clone) {
+ // FIXME: The save-and-clone operation in the
+ // patron editor results in this action.
+ // For some reason, this specific function results
+ // in a new browser window opening instead of a
+ // browser tab. Possibly this is caused by the
+ // fact that the action occurs as a result of a
+ // button click instead of an href. *shrug*.
+ // It's obnoxious.
+ open_tab('/circ/patron/register/clone/' + info.clone);
+ }
+ },
+
+ // open a user account
+ new_patron_tab : function(tab_info, usr_info) {
+ open_tab('/circ/patron/' + usr_info.id + '/checkout');
+ }
+ }
+
+ if ($scope.handlers) {
+ angular.forEach($scope.handlers, function(val, key) {
+ iframe.contentWindow.xulG[key] = val;
+ });
+ }
+ }
+ }]
+ }
+})
+
+
+++ /dev/null
-angular.module('egCoreMod')
-
-/*
- * Iframe container for legacy embedded interfaces
- */
-.directive('egLegacyFrame', function() {
- return {
- restrict : 'AE',
- replace : true,
- scope : {
- // URL to load in the legacy iframe
- url : '=',
-
- // optional hash of functions which augment or override
- // the stock xulG functions defined below.
- handlers : '='
- },
-
- template : '<iframe src="{{url}}" onload="egLegacyFrameLoader(this)" '
- + 'class="eg-legacy-frame" style="height:{{height}}px"></iframe>',
-
- controller :
- ['$scope','$window','$location','egCore',
- function($scope , $window , $location , egCore) {
-
- // Set the iframe height to just under the window height.
- // leave room for the navbar, padding, margins, etc.
- $scope.height = $window.outerHeight - 250;
-
- // $location has functions for modifying paths and search,
- // but they all assume you are staying within the angular
- // app, which we are not. Build the URLs by hand.
- function open_tab(path) {
- var url = 'https://' + $window.location.hostname +
- egCore.env.basePath + path;
- console.debug('egLegacyFrame opening tab ' + url);
- $window.open(url, '_blank').focus();
- }
-
- // define our own xulG functions to be inserted into the
- // iframe. NOTE: window-level functions are bad. Though
- // there is probably a way, I was unable to correctly wire
- // upda the iframe onload handler within the
- // way. In any event, the code below is meant as a stop-gap
- // for porting dojo, etc. apps to angular apps and should
- // eventually go away.
- $window.egLegacyFrameLoader = function(iframe) {
-
- // tell the iframe'd window its inside the staff client
- iframe.contentWindow.IAMXUL = true;
-
- // also tell it it's inside the browser client, which
- // may be needed in a few special cases.
- iframe.contentWindow.IAMBROWSER = true;
-
- // define a few commonly used stock xulG handlers.
-
- iframe.contentWindow.xulG = {
- // patron search
- spawn_search : function(search) {
- open_tab('/circ/patron/search?search='
- + encodeURIComponent(js2JSON(search)));
- },
-
- // edit an existing user
- spawn_editor : function(info) {
- if (info.usr) {
- open_tab('/circ/patron/register/edit/' + info.usr);
-
- } else if (info.clone) {
- // FIXME: The save-and-clone operation in the
- // patron editor results in this action.
- // For some reason, this specific function results
- // in a new browser window opening instead of a
- // browser tab. Possibly this is caused by the
- // fact that the action occurs as a result of a
- // button click instead of an href. *shrug*.
- // It's obnoxious.
- open_tab('/circ/patron/register/clone/' + info.clone);
- }
- },
-
- // open a user account
- new_patron_tab : function(tab_info, usr_info) {
- open_tab('/circ/patron/' + usr_info.id + '/checkout');
- }
- }
-
- if ($scope.handlers) {
- angular.forEach($scope.handlers, function(val, key) {
- iframe.contentWindow.xulG[key] = val;
- });
- }
- }
- }]
- }
-})
-
-