LP#1746824: Provide CSV download titlecasing user/miker/lp1746824-egGrid_CSS_cell_styling-signoff
authorMike Rylander <mrylander@gmail.com>
Wed, 25 Apr 2018 18:57:56 +0000 (14:57 -0400)
committerMike Rylander <mrylander@gmail.com>
Wed, 25 Apr 2018 19:01:11 +0000 (15:01 -0400)
The CSV download available from the grid cannot apply CSS to column content.
To address that, we add a titlecase filter and make use of it during CSV
creation.

Signed-off-by: Mike Rylander <mrylander@gmail.com>
Open-ILS/src/templates/staff/cat/item/t_list.tt2
Open-ILS/web/js/ui/default/staff/services/grid.js
Open-ILS/web/js/ui/default/staff/services/ui.js

index eb584c9..5dc4ecd 100644 (file)
@@ -69,7 +69,7 @@
   <eg-grid-field label="[% l('Location') %]"       path="location.name" visible></eg-grid-field>
   <eg-grid-field label="[% l('Copy Status') %]"    path="status.name" visible></eg-grid-field>
   <eg-grid-field label="[% l('Title') %]"       
-    path="call_number.record.simple_record.title" visible>
+    path="call_number.record.simple_record.title" titlecase visible>
     <a target="_blank" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item['call_number.record.id']}}">
       {{item['call_number.record.simple_record.title']}} <span ng-show="item['call_number.record.id']" class="glyphicon glyphicon-new-window"/>
     </a>
@@ -78,7 +78,7 @@
 
   <eg-grid-field label="[% l('Acquisition Cost') %]"     path="cost" hidden></eg-grid-field>
   <eg-grid-field label="[% l('Age-Based Hold Protection') %]"  path="age_protect" hidden></eg-grid-field>
-  <eg-grid-field label="[% l('Author') %]"               path="call_number.record.simple_record.author"  hidden></eg-grid-field>
+  <eg-grid-field label="[% l('Author') %]" titlecase     path="call_number.record.simple_record.author"  hidden></eg-grid-field>
   <eg-grid-field label="[% l('Checkin Date') %]"         path="_circ_summary.last_checkin_time" datatype="timestamp" hidden></eg-grid-field>
   <eg-grid-field label="[% l('Checkin Scan Date') %]"    path="_circ_summary.last_checkin_scan_time" datatype="timestamp" hidden></eg-grid-field>
   <eg-grid-field label="[% l('Checkin Workstation') %]"  path="_circ_summary.last_checkin_workstation" hidden></eg-grid-field>
index eb23385..090ab37 100644 (file)
@@ -952,10 +952,11 @@ angular.module('egGridMod',
 
             // prepares a string for inclusion within a CSV document
             // by escaping commas and quotes and removing newlines.
-            grid.csvDatum = function(str) {
+            grid.csvDatum = function(str,col) {
                 str = ''+str;
                 if (!str) return '';
                 str = str.replace(/\n/g, '');
+                if (col && col.titlecase) str = $filter('titlecase')(str);
                 if (str.match(/\,/) || str.match(/"/)) {                                     
                     str = str.replace(/"/g, '""');
                     str = '"' + str + '"';                                           
@@ -1151,7 +1152,7 @@ angular.module('egGridMod',
                     // items
                     angular.forEach(items, function(item) {
                         angular.forEach(columns, function(col) {
-                            csvStr += grid.csvDatum(item[col.name]);
+                            csvStr += grid.csvDatum(item[col.name],col);
                             csvStr += ',';
                         });
                         csvStr = csvStr.replace(/,$/,'\n');
@@ -1279,6 +1280,7 @@ angular.module('egGridMod',
             // boolean fields are presented as value-less attributes
             angular.forEach(
                 [
+                    'titlecase', 
                     'visible', 
                     'hidden', 
                     'sortable', 
@@ -1557,6 +1559,7 @@ angular.module('egGridMod',
                 linkpath : colSpec.linkpath,
                 template : colSpec.template,
                 visible  : colSpec.visible,
+                titlecase: colSpec.titlecase,
                 hidden   : colSpec.hidden,
                 datatype : colSpec.datatype,
                 sortable : colSpec.sortable,
@@ -2103,6 +2106,8 @@ angular.module('egGridMod',
  * 1. Passes dates through the angular date filter
  * 2. Translates bools to Booleans so the browser can display translated 
  *    value.  (Though we could manually translate instead..)
+ * 3. Formats currency
+ * 4. Could (but doesn't yet) apply titlecasing when requested
  * Others likely to follow...
  */
 .filter('egGridValueFilter', ['$filter','egCore', function($filter,egCore) {
@@ -2152,6 +2157,8 @@ angular.module('egGridMod',
             case 'money':
                 return $filter('currency')(value);
             default:
+                // Alternative to CSS titlecasing...
+                // if (column.titlecase) value = $filter('titlecase')(value);
                 return value;
         }
     };
index 47632ed..d6d6f7c 100644 (file)
@@ -137,6 +137,35 @@ function($timeout , $parse) {
     };
 })
 
+// 'titlecase' filter
+// Lowercases input, then upercases the first character of each word, excepting
+// those that match the smallWords regex.
+// https://gist.github.com/jeffjohnson9046/9789876 (original)
+// Modified by mrylander@gmail.com
+.filter('titlecase', function() {
+    return function (input) {
+        if (input === undefined) return null;
+
+        var smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|vs?\.?|via)$/i;
+
+        input = input.toLowerCase();
+        return input.replace(/[A-Za-z0-9\u00C0-\u00FF]+[^\s-]*/g, function(match, index, title) {
+            if (index > 0 && index + match.length !== title.length &&
+                match.search(smallWords) > -1 && title.charAt(index - 2) !== ":" &&
+                (title.charAt(index + match.length) !== '-' || title.charAt(index - 1) === '-') &&
+                title.charAt(index - 1).search(/[^\s-]/) < 0) {
+                return match.toLowerCase();
+            }
+
+            if (match.substr(1).search(/[A-Z]|\../) > -1) {
+                return match;
+            }
+
+            return match.charAt(0).toUpperCase() + match.substr(1);
+        });
+    }
+})
+
 // 'reverse' filter 
 // <div ng-repeat="item in items | reverse">{{item.name}}</div>
 // http://stackoverflow.com/questions/15266671/angular-ng-repeat-in-reverse