LP#1656036 Webstaff dynamic page titles
authorBill Erickson <berickxx@gmail.com>
Thu, 12 Oct 2017 15:27:27 +0000 (11:27 -0400)
committerKathy Lussier <klussier@masslnc.org>
Fri, 20 Oct 2017 14:55:29 +0000 (10:55 -0400)
Support page/tab titles applied by page controllers.  Each title is
composed of 2 optional components, a dynamic component and a context
component.

The dynamic component may be interpolated with real-time data (e.g. a
patron's name) and the context is generally a page or tab-level value
(e.g. Checkout).

For example:  "Smith, Jane - Checkout"

Apply a title within a controller like so:

egCore.strings.setPageTitle(
    egCore.strings.MY_DYNAMIC_TEMPLATE,
    egCore.strings.MY_CONTEXT_STRING,
    {foo : 'foo', bar : 'bar'}
);

If no values are set, the default template-level title is applied.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Jason Boyer <jboyer@library.in.gov>
Signed-off-by: Kathy Lussier <klussier@masslnc.org>
Conflicts:
Open-ILS/src/templates/staff/base_js.tt2
Open-ILS/web/js/ui/default/staff/circ/patron/app.js

Open-ILS/src/templates/staff/base.tt2
Open-ILS/src/templates/staff/base_js.tt2
Open-ILS/src/templates/staff/cat/catalog/index.tt2
Open-ILS/src/templates/staff/circ/patron/index.tt2
Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
Open-ILS/web/js/ui/default/staff/circ/patron/app.js
Open-ILS/web/js/ui/default/staff/services/strings.js

index f279759..7ce42ae 100644 (file)
@@ -10,7 +10,9 @@
         display: none !important;
     }       
     </style>
-    <title>[% l('Evergreen Staff [_1]', ctx.page_title) %]</title>
+    <!-- The page title changes with $rootScope.pageTitle, 
+        defaulting to the static template page title. -->
+    <title ng-cloak>{{pageTitle || "[% ctx.page_title %]"}}</title>
     <base href="/eg/staff/">
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
index 324e452..7973500 100644 (file)
@@ -187,6 +187,8 @@ UpUp.start({
     s.CONFIRM_CLEAR_PENDING_BODY = "[% l('Are you certain you want to clear these pending offline transactions? This action is irreversible. Transactions cannot be recovered after clearing!') %]";
     s.LOCATION_NAME_OU_QUALIFIED = "[% l('{{location_name}} ({{owning_lib_shortname}})') %]";
     s.CONFIRM_IN_HOUSE_NUM_USES_COUNT_TITLE = "[% l('Are you sure you want to record {{num_uses}} uses for this?') %]";
+    s.PAGE_TITLE_DEFAULT = "[% l('Evergreen Staff Client') %]";
+    s.PAGE_TITLE_DYNAMIC_AND_CONTEXT = "[% l('[_1] - [_2]', '{{dynamic}}', '{{context}}') %]";
   }]);
 </script>
 
index a50822e..bb7d232 100644 (file)
@@ -60,6 +60,8 @@
 
     s.SERIALS_ISSUANCE_FAIL_SAVE = "[% l('Failed to save issuance') %]";
     s.SERIALS_ISSUANCE_SUCCESS_SAVE = "[% l('Issuance saved') %]";
+    s.PAGE_TITLE_CATALOG_CONTEXT = "[% l('Catalog') %]";
+    s.PAGE_TITLE_BIB_DETAIL = "[% l('Bib [_1]', '{{record_id}}') %]";
 
   }])
 </script>
index 5cb8a29..94849f2 100644 (file)
@@ -66,6 +66,16 @@ angular.module('egCoreMod').run(['egStrings', function(s) {
   s.OPT_IN_DIALOG = "[% l('Does patron [_1], [_2] from [_3] ([_4]) consent to having their personal information shared with your library?', '{{family_name}}', '{{first_given_name}}', '{{org_name}}', '{{org_shortname}}') %]";
   s.BUCKET_ADD_SUCCESS = "[% l('Successfully added [_1] users to bucket [_2].', '{{count}}', '{{name}}') %]";
   s.BUCKET_ADD_FAIL = "[% l('Failed to add [_1] users to bucket [_2].', '{{count}}', '{{name}}') %]";
+  s.PAGE_TITLE_PATRON_SEARCH = "[% l('Patron Search') %]";
+  s.PAGE_TITLE_PATRON_NAME = "[% l('[_1], [_2] [_3]', '{{lname}}','{{fname}}','{{mname}}') %]";
+  s.PAGE_TITLE_PATRON_CHECKOUT = "[% l('Checkout') %]";
+  s.PAGE_TITLE_PATRON_MESSAGES = "[% l('Messages') %]";
+  /* TODO: The "Other" page title could be smarter.. */
+  s.PAGE_TITLE_PATRON_OTHER = "[% l('Other') %]";
+  s.PAGE_TITLE_PATRON_BILLS = "[% l('Bills') %]";
+  s.PAGE_TITLE_PATRON_HOLDS = "[% l('Holds') %]";
+  s.PAGE_TITLE_PATRON_ITEMS_OUT = "[% l('Items Out') %]";
+  s.PAGE_TITLE_PATRON_EDIT = "[% l('Edit') %]";
 }]);
 </script>
 
index 95c1dd3..90d7fd1 100644 (file)
@@ -259,6 +259,19 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
     $scope.record_id = $routeParams.record_id;
     $scope.summary_pane_record;
 
+    if ($scope.record_id) {
+        // TODO: Apply tab-specific title contexts
+        egCore.strings.setPageTitle(
+            egCore.strings.PAGE_TITLE_BIB_DETAIL,
+            egCore.strings.PAGE_TITLE_CATALOG_CONTEXT,
+            {record_id : $scope.record_id}
+        );
+    } else {
+        // Default to title = Catalog
+        egCore.strings.setPageTitle(
+            egCore.strings.PAGE_TITLE_CATALOG_CONTEXT);
+    }
+
     if ($routeParams.record_id) $scope.from_route = true;
     else $scope.from_route = false;
 
@@ -535,6 +548,13 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
             egHolds.fetch_holds(hold_ids).then($scope.hold_grid_data_provider.refresh);
             init_parts_url();
             $location.update_path('/cat/catalog/record/' + $scope.record_id);
+            // update_path() bypasses the controller for path 
+            // /cat/catalog/record/:record_id. Manually set title here too.
+            egCore.strings.setPageTitle(
+                egCore.strings.PAGE_TITLE_BIB_DETAIL,
+                egCore.strings.PAGE_TITLE_CATALOG_CONTEXT,
+                {record_id : $scope.record_id}
+            );
         } else {
             delete $scope.record_id;
             $scope.from_route = false;
index 4d4c728..748cbfc 100644 (file)
@@ -291,12 +291,27 @@ function($scope,  $q , $location , $filter , egCore , egNet , egUser , egAlertDi
         if (patron_id) {
             $scope.patron_id = patron_id;
             return patronSvc.setPrimary($scope.patron_id)
+            .then(function() {
+                // the page title context label comes from the tab.
+                egCore.strings.setPageTitle(
+                    egCore.strings.PAGE_TITLE_PATRON_NAME, 
+                    egCore.strings['PAGE_TITLE_PATRON_' + tab.toUpperCase()],
+                    {   lname : patronSvc.current.family_name(),
+                        fname : patronSvc.current.first_given_name(),
+                        mname : patronSvc.current.second_given_name()
+                    }
+                );
+            })
             .then(function() {return patronSvc.checkAlerts()})
             .then(redirectToAlertPanel)
             .then(function(){
                 $scope.ident_type_name = $scope.patron().ident_type().name()
                 $scope.hasIdentTypeName = $scope.ident_type_name.length > 0;
             });
+        } else {
+            // No patron, use the tab name as the page title.
+            egCore.strings.setPageTitle(
+                egCore.strings['PAGE_TITLE_PATRON_' + tab.toUpperCase()]);
         }
         return $q.when();
     }
index d9a801b..92d2aeb 100644 (file)
  */
 
 angular.module('egCoreMod').factory('egStrings', 
-['$interpolate', function($interpolate) { 
-    return {
+['$interpolate', '$rootScope', function($interpolate, $rootScope) { 
+    var service = {
+
         '$replace' : function(str, args) {
             if (!str) return '';
             return $interpolate(str)(args);
+        },
+
+        /**
+         * Sets the page <title> value.  
+         *
+         * The title is composed of a dynamic and static component.
+         * The dynamic component may optionally be compiled via
+         * $interpolate'ion.  
+         *
+         * The dynamic component is subject to truncation if it exceeds 
+         * titleTruncLevel length and a context value is also applied.
+         *
+         * Only components that have values applied are used.  When
+         * both have a value, they are combined into a single string
+         * separated by a - (by default).
+         */
+        titleTruncLevel : 12,
+        setPageTitle : function(dynamic, context, dynargs) {
+
+            if (!dynamic) {
+                $rootScope.pageTitle = context || service.PAGE_TITLE_DEFAULT;
+                return;
+            }
+
+            if (dynargs) dynamic = service.$replace(dynamic, dynargs);
+
+            if (!context) {
+                $rootScope.pageTitle = dynamic;
+                return;
+            }
+
+            // only truncate when it's competing with a context value
+            dynamic = dynamic.substring(0, service.titleTruncLevel);
+
+            $rootScope.pageTitle = service.$replace(
+                service.PAGE_TITLE_DYNAMIC_AND_CONTEXT, {
+                    dynamic : dynamic,
+                    context : context
+                }
+            );
         }
-    } 
+    };
+
+    return service;
 }]);