LP#1845556: Spine Label Enhanced Printing user/csharp/lp1845556_spine_label_enhanced_printing
authorAdam Bowling <abowling@emeralddata.net>
Wed, 2 Sep 2020 21:56:22 +0000 (17:56 -0400)
committerChris Sharp <csharp@georgialibraries.org>
Fri, 15 Jan 2021 13:14:10 +0000 (08:14 -0500)
Rebase of spine label enhanced printing features from current master.
Cleanup of some comments.

Signed-off-by: Adam Bowling <abowling@emeralddata.net>
Open-ILS/src/templates/staff/cat/printlabels/t_view.tt2
Open-ILS/web/js/ui/default/staff/cat/bucket/copy/app.js
Open-ILS/web/js/ui/default/staff/cat/item/app.js
Open-ILS/web/js/ui/default/staff/cat/printlabels/app.js
Open-ILS/web/js/ui/default/staff/cat/volcopy/app.js
Open-ILS/web/js/ui/default/staff/circ/checkin/app.js

index 47ccde6..9d7ac7a 100644 (file)
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="Windows-1252"?>
 <style>
   /* TODO: move me */
 
@@ -6,6 +5,59 @@
       page-break-before: always;
   }
 
+    div.print-label-toolbox input[type=number], div.print-label-toolbox input[type=text] {
+  border: 1px solid #999;
+  border-radius: 3px;
+  margin-right: 12px;
+  width: 56px;
+  }
+
+  div.print-label-toolbox div.eg-print-label-section {
+  border-bottom: 1px solid #DED;
+  display: block;
+  margin: 0 0 10px 0;
+  padding: 0 0 10px 0;
+  }
+
+  div.print-label-toolbox input.ng-invalid {
+  background-color: #FFFF00;
+  color: #FF0000;
+  }
+
+  div.print-label-toolbox label {
+  padding-right: 4px;
+  }
+
+  div.print-label-toolbox ul {
+  display: block;
+  list-style-type: none;
+  margin: 0;
+  padding: 0;
+  }
+
+  div.print-label-toolbox ul li {
+  display: inline-block;
+  padding: 0 0 0 6px;
+  }
+
+  div.print-label-toolbox ul li:first-child {
+  display: inline-block;
+  padding: 0 0 0 0;
+  }
+
+  table.custom-label-table td {
+  vertical-align: top;
+  }
+
+  .print-template-text {
+  height: 36em;
+  width: 100%;
+  }
+
+  .cn-template-text {
+  height: 12em;
+  width: 100%;
+  }
 </style>
 
 <div class="container-fluid" style="text-align:center">
 
 <hr/>
 
+<!-- PINES customization -->
+<div style="width:40%;border:1px dashed gray;padding:10px;text-align:center;font-weight:bold;font-style:italic;margin-bottom:15px;">
+    <a href="https://pines.georgialibraries.org/dokuwiki/doku.php?id=cat:spine-label-printing" target="_blank">
+        Instructions for setting up spine & pocket labels
+    </a>
+</div>
+
 <div class="row">
     <div class="col-md-5">
         <ul class="nav nav-tabs">
@@ -267,4 +326,4 @@ label. Use pocket label left margin to identify how much space to provide betwee
           context="preview_scope"></div>
     </div>
     <!-- col -->
-</div>
\ No newline at end of file
+</div>
index 4216128..7d16534 100644 (file)
@@ -568,27 +568,20 @@ function($scope,  $q , $routeParams , $timeout , $window , $uibModal , bucketSvc
         $scope.detachCopies(copies);
     }
 
-    $scope.spawnHoldingsEdit = function() {
-        $scope.spawnEdit(true, false);
-    }
-
-    $scope.spawnCallNumberEdit = function() {
-        $scope.spawnEdit(false, true);
-    }
-
-    $scope.spawnEdit = function(hide_vols,hide_copies) {
+    $scope.spawnHoldingsEdit = function (copies) {
         var cp_list = []
         angular.forEach($scope.gridControls.selectedItems(), function (i) {
             cp_list.push(i.id);
-        });
+        })
+
         egCore.net.request(
             'open-ils.actor',
             'open-ils.actor.anon_cache.set_value',
             null, 'edit-these-copies', {
                 record_id: 0, // false-y value for record_id disables record summary
                 copies: cp_list,
-                hide_vols : hide_vols,
-                hide_copies : hide_copies
+                hide_vols : true,
+                hide_copies : false
             }
         ).then(function(key) {
             if (key) {
@@ -601,36 +594,43 @@ function($scope,  $q , $routeParams , $timeout , $window , $uibModal , bucketSvc
     }
 
     $scope.print_labels = function() {
-        var cp_list = []
+        var cp_list = [];
         angular.forEach($scope.gridControls.selectedItems(), function (i) {
             cp_list.push(i.id);
         })
-
+        console.log(cp_list);
+        //var cp_full = [], promises = [];
+        //promises.push(
+        //    egCore.pcrud.search('ccbi', { bucket: bucketSvc.currentBucket.a[2], "target_copy": { "in": cp_list } }).then(
+        //        null,
+        //        null,
+        //        function (ccbi) {
+        //            cp_full.push(egCore.idl.toHash(ccbi, true));
+        //        }
+        //    )
+        //);
         egCore.net.request(
             'open-ils.actor',
             'open-ils.actor.anon_cache.set_value',
             null, 'print-labels-these-copies', {
-                copies : cp_list
+                copies : cp_list //cp_full
             }
         ).then(function(key) {
-            if (key) {
-                var url = egCore.env.basePath + 'cat/printlabels/' + key;
-                $timeout(function() { $window.open(url, '_blank') });
-            } else {
-                alert('Could not create anonymous cache key!');
-            }
+            //$q.all(promises).then(function () {
+                if (cp_list.length > 0) {
+                    if (key) {
+                        var url = egCore.env.basePath + 'cat/printlabels/' + key;
+                        $timeout(function() { $window.open(url, '_blank') });
+                    } else {
+                        alert('Could not create anonymous cache key!');
+                    }
+                } else {
+                    alert('Could not print label export');
+                }
+            //});
         });
     }
 
-    $scope.showItems = function() {
-        var cp_list = []
-        angular.forEach($scope.gridControls.selectedItems(), function (i) {
-            cp_list.push(i.id);
-        })
-        var url = egCore.env.basePath + '/cat/item/search/' + cp_list.join();
-        $timeout(function() { $window.open(url, '_blank') });
-    }
-
     $scope.requestItems = function() {
         var copy_list = $scope.gridControls.selectedItems().map(
             function (i) {
index dbf7176..1cd8f3e 100644 (file)
@@ -712,20 +712,27 @@ function($scope , $q , $window , $location , $timeout , egCore , egNet , egGridD
     }
 
     $scope.print_labels = function() {
-        egCore.net.request(
-            'open-ils.actor',
-            'open-ils.actor.anon_cache.set_value',
-            null, 'print-labels-these-copies', {
-                copies : gatherSelectedHoldingsIds()
-            }
-        ).then(function(key) {
-            if (key) {
-                var url = egCore.env.basePath + 'cat/printlabels/' + key;
-                $timeout(function() { $window.open(url, '_blank') });
-            } else {
-                alert('Could not create anonymous cache key!');
-            }
-        });
+        var cp_list = gatherSelectedHoldingsIds();
+        !$scope.gridDataProvider.sort ? cp_list.reverse() : $scope.gridDataProvider.sort.length === 0 ? cp_list.reverse() : false;
+        var i = 1;
+        if (cp_list.length > 0) {        
+            egCore.net.request(
+                'open-ils.actor',
+                'open-ils.actor.anon_cache.set_value',
+                null, 'print-labels-these-copies', {
+                    copies : cp_list
+                }
+            ).then(function(key) {
+                if (key) {
+                    var url = egCore.env.basePath + 'cat/printlabels/' + key;
+                    $timeout(function() { $window.open(url, '_blank') });
+                } else {
+                    alert('Could not create anonymous cache key!');
+                }
+            });
+        } else {
+            alert('Could not generate print labels.');
+        }
     }
 
     $scope.print_list = function() {
index 2553689..d60660f 100644 (file)
@@ -117,13 +117,13 @@ function ($scope, $q, $window, $routeParams, $location, $timeout, egCore, egNet,
         },
         mode: {
             options: [
-                { label: "Spine Label", value: "spine-only" },
-                { label: "Pocket Label", value: "spine-pocket" }
+                { label: "Label 1 Only", value: "spine-only" },
+                { label: "Labels 1 & 2", value: "spine-pocket" }
             ],
             selected: "spine-pocket"
         },
         page: {
-            column_class: ["spine", "pocket"],
+            column_class: ["spine"],
             dimensions: {
                 columns: 2,
                 rows: 1
@@ -164,9 +164,9 @@ function ($scope, $q, $window, $routeParams, $location, $timeout, egCore, egNet,
                 $scope.preview_scope = {
                     'copies': []
                     , 'settings': {}
-                    , 'toolbox_settings': JSON.parse(JSON.stringify(toolbox_settings))
+                    , 'toolbox_settings': toolbox_settings
                     , 'get_cn_for': function (copy) {
-                        var key = $scope.rendered_cn_key_by_copy_id[copy.id];
+                        var key = copy.id; //$scope.rendered_cn_key_by_copy_id[copy.id];
                         if (key) {
                             var manual_cn = $scope.rendered_call_number_set[key];
                             if (manual_cn && manual_cn.value) {
@@ -290,9 +290,17 @@ function ($scope, $q, $window, $routeParams, $location, $timeout, egCore, egNet,
 
                     $q.all(promises2).then(function () {
                         // today, staff, current_location, etc.
+                       $scope.preview_scope.copies.sort((a, b) => (data.copies.indexOf(a.id) > data.copies.indexOf(b.id)) ? 1 : ((data.copies.indexOf(b.id) > data.copies.indexOf(a.id)) ? -1 : 0));
                         egCore.print.fleshPrintScope($scope.preview_scope);
                         $scope.template_changed(); // load the default
                         $scope.rebuild_cn_set();
+                        if ($scope.preview_scope.toolbox_settings && $scope.template_name && $scope.print.template_content) {
+                            var re = /eg\_plt/i;
+                            if (re.test($scope.print.template_content)) {
+                                $scope.applyTemplate($scope.template_name);
+                                $scope.redraw_label_table();
+                            }
+                        }
                     });
 
                 });
@@ -304,12 +312,6 @@ function ($scope, $q, $window, $routeParams, $location, $timeout, egCore, egNet,
 
     }
 
-    $scope.checkForToolboxCustomizations = function (tText, redraw) {
-        var re = /eg\_plt\_(\d+)/;
-        redraw ? $scope.redraw_label_table() : false;
-        return re.test(tText);
-    }
-
     $scope.fetchTemplates = function (set_default) {
         return egCore.hatch.getItem('cat.printlabels.templates').then(function (t) {
             if (t) {
@@ -335,7 +337,8 @@ function ($scope, $q, $window, $routeParams, $location, $timeout, egCore, egNet,
             $scope.preview_scope.settings[s] = $scope.templates[n].settings[s];
         }
         if ($scope.templates[n].toolbox_settings) {
-            $scope.preview_scope.toolbox_settings = JSON.parse(JSON.stringify($scope.templates[n].toolbox_settings));
+            $scope.preview_scope.toolbox_settings = $scope.templates[n].toolbox_settings;
+            $scope.create_print_label_table();
         }
         egCore.hatch.setItem('cat.printlabels.default_template', n);
         $scope.save_locally();
@@ -365,7 +368,7 @@ function ($scope, $q, $window, $routeParams, $location, $timeout, egCore, egNet,
                 , context: $scope.print.template_context
                 , cn_content: $scope.print.cn_template_content
                 , settings: JSON.parse(JSON.stringify($scope.preview_scope.settings))
-                , toolbox_settings: JSON.parse(JSON.stringify($scope.preview_scope.toolbox_settings))
+                , toolbox_settings: $scope.preview_scope.toolbox_settings
             };
             $scope.template_name_list = Object.keys($scope.templates);
 
@@ -400,7 +403,8 @@ function ($scope, $q, $window, $routeParams, $location, $timeout, egCore, egNet,
         .then(
             function (html) {
                 $scope.print.template_content = html;
-                $scope.checkForToolboxCustomizations(html, true);
+               $scope.redraw_label_table();
+                //$scope.checkForToolboxCustomizations(html, true);
             },
             function () {
                 $scope.print.template_content = '';
@@ -508,55 +512,82 @@ function ($scope, $q, $window, $routeParams, $location, $timeout, egCore, egNet,
             $scope.rendered_cn_key_by_copy_id = {};
             for (var i = 0; i < $scope.preview_scope.copies.length; i++) {
                 var copy = $scope.preview_scope.copies[i];
+                copy.rendered_cn = {};
                 var rendered_cn = document.getElementById('cn_for_copy_' + copy.id);
                 if (rendered_cn && rendered_cn.textContent) {
-                    var key = rendered_cn.textContent;
-                    if (typeof $scope.rendered_call_number_set[key] == 'undefined') {
-                        $scope.rendered_call_number_set[key] = {
-                            value: key
-                        };
-                    }
-                    $scope.rendered_cn_key_by_copy_id[copy.id] = key;
+                    $scope.rendered_call_number_set[copy.id] = {
+                        value : rendered_cn.textContent
+                    };
+                    copy.rendered_cn = rendered_cn; //{ value : rendered_cn.textContent };
+                   console.log(copy.rendered_cn.textContent);
                 }
             }
+            console.log("brick01");
+
+
+            //for (var i = 0; i < $scope.preview_scope.copies.length; i++) {
+            //    var copy = $scope.preview_scope.copies[i];
+            //    var rendered_cn = document.getElementById('cn_for_copy_' + copy.id);
+            //    if (rendered_cn && rendered_cn.textContent) {
+            //        var key = rendered_cn.textContent;
+            //        if (typeof $scope.rendered_call_number_set[key] == 'undefined') {
+            //            $scope.rendered_call_number_set[key] = {
+            //                value: key
+            //            };
+            //        }
+            //        $scope.rendered_cn_key_by_copy_id[copy.id] = key;
+                    //copy.rendered_cn = { value : rendered_cn.textContent };
+            //    }
+            //}
             $scope.preview_scope.tickle = Date() + ' ' + Math.random();
         });
     }
 
-    $scope.redraw_label_table = function () {
+    $scope.create_print_label_table = function () {
         if ($scope.print_label_form.$valid && $scope.print.template_content && $scope.preview_scope) {
             $scope.preview_scope.label_output_copies = labelOutputRowsFilter($scope.preview_scope.copies, $scope.preview_scope.toolbox_settings);
-            var d = new Date().getTime().toString();
             var html = $scope.print.template_content;
-            if ($scope.checkForToolboxCustomizations(html)) {
-                html = html.replace(/eg\_plt\_\d+/, "eg_plt_" + d);
-                $scope.print.template_content = html;
-            } else {
-                var table = "<table id=\"eg_plt_" + d + "_{{$index}}\" eg-print-label-table style=\"border-collapse: collapse; border: 0 solid transparent; border-spacing: 0; margin: {{$index === 0 ? toolbox_settings.page.margins.top.size : 0}} 0 0 0;\" class=\"custom-label-table{{$index % toolbox_settings.page.dimensions.rows === 0 && $index > 0 && toolbox_settings.feed_option.selected === 'sheet' ? ' page-break' : ''}}\" ng-init=\"parentIndex = $index\" ng-repeat=\"row in label_output_copies\">\n";
-                table += "<tr>\n";
-                table += "<td style=\"border: 0 solid transparent; padding: {{parentIndex % toolbox_settings.page.dimensions.rows === 0 && toolbox_settings.feed_option.selected === 'sheet' && parentIndex > 0 ? toolbox_settings.page.space_between_labels.vertical.size : parentIndex > 0 ? toolbox_settings.page.space_between_labels.vertical.size : 0}} 0 0 {{$index === 0 ? toolbox_settings.page.margins.left.size : col.styl ? col.styl : toolbox_settings.page.space_between_labels.horizontal.size}};\" ng-repeat=\"col in row.columns\">\n";
-                table += "<pre class=\"{{col.cls}}\" style=\"border: none; margin-bottom: 0; margin-top: 0; overflow: hidden;\" ng-if=\"col.cls === 'spine'\">\n";
-                table += "{{col.c ? get_cn_for(col.c) : ''}}";
-                table += "</pre>\n";
-                table += "<pre class=\"{{col.cls}}{{parentIndex % toolbox_settings.page.dimensions.rows === 0 && parentIndex > 0 && toolbox_settings.feed_option.selected === 'sheet' ? ' page-break' : ''}}\" style=\"border: none;  margin-bottom: 0; margin-top: 0; overflow: hidden;\" ng-if=\"col.cls === 'pocket'\">\n";
-                table += "{{col.c ? col.c.barcode : ''}}\n";
-                table += "{{col.c ? col.c['call_number.label'] : ''}}\n";
-                table += "{{col.c ? get_bib_for(col.c).author : ''}}\n";
-                table += "{{col.c ? (get_bib_for(col.c).title | wrap:28:'once':'  ') : ''}}\n";
-                table += "</pre>\n";
-                table += "</td>\n"
-                table += "</tr>\n";
-                table += "</table>";
-                var comments = html.match(/\<\!\-\-(?:(?!\-\-\>)(?:.|\s))*\-\-\>\s*/g);
-                html = html.replace(/\<\!\-\-(?:(?!\-\-\>)(?:.|\s))*\-\-\>\s*/g, '');
-                var style = html.match(/\<style[^\>]*\>(?:(?!\<\/style\>)(?:.|\s))*\<\/style\>\s*/gi);
-                var output = (comments ? comments.join("\n") : "") + (style ? style.join("\n") : "") + table;
-                output = output.replace(/\n+/, "\n");
-                $scope.print.template_content = output;
-            }
+            var d = new Date(); //Added to table ID with 'eg_plt_' to cause $complie on $scope.print.template_content to fire due to template content change.
+            var table = "<table id=\"eg_plt_" + d.getTime().toString() + "_{{$index}}\" eg-print-label-table style=\"border-collapse: collapse; border: 0 solid transparent; border-spacing: 0; margin: {{$index === 0 ? toolbox_settings.page.margins.top.size : 0}} 0 0 0;\" class=\"custom-label-table{{$index % toolbox_settings.page.dimensions.rows === 0 && $index > 0 && toolbox_settings.feed_option.selected === 'sheet' ? ' page-break' : ''}}\" ng-init=\"parentIndex = $index\" ng-repeat=\"row in label_output_copies\">\n";
+            table += "<tr>\n";
+            table += "<td style=\"border: 0 solid transparent; padding: {{parentIndex % toolbox_settings.page.dimensions.rows === 0 && toolbox_settings.feed_option.selected === 'sheet' && parentIndex > 0 ? toolbox_settings.page.space_between_labels.vertical.size : parentIndex > 0 ? toolbox_settings.page.space_between_labels.vertical.size : 0}} 0 0 {{$index === 0 ? toolbox_settings.page.margins.left.size : col.styl ? col.styl : toolbox_settings.page.space_between_labels.horizontal.size}};\" ng-repeat=\"col in row.columns\">\n";
+            table += "<pre class=\"{{col.cls}}\" style=\"border: none; margin-bottom: 0; margin-top: 0; overflow: hidden;\" ng-if=\"col.cls === 'spine'\">\n";
+            table += "{{col.c ? get_cn_for(col.c) : ''}}";
+            table += "</pre>\n";
+            table += "<pre class=\"{{col.cls}}{{parentIndex % toolbox_settings.page.dimensions.rows === 0 && parentIndex > 0 && toolbox_settings.feed_option.selected === 'sheet' ? ' page-break' : ''}}\" style=\"border: none;  margin-bottom: 0; margin-top: 0; overflow: hidden;\" ng-if=\"col.cls === 'pocket'\">\n";
+            table += "{{col.c ? col.c.barcode : ''}}\n";
+            table += "{{col.c ? col.c['call_number.label'] : ''}}\n";
+            table += "{{col.c ? get_bib_for(col.c).author : ''}}\n";
+            table += "{{col.c ? (get_bib_for(col.c).title | wrap:28:'once':'  ') : ''}}\n";
+            table += "</pre>\n";
+            table += "</td>\n"
+            table += "</tr>\n";
+            table += "</table>";
+            var comments = html.match(/\<\!\-\-(?:(?!\-\-\>)(?:.|\s))*\-\-\>\s*/g);
+            html = html.replace(/\<\!\-\-(?:(?!\-\-\>)(?:.|\s))*\-\-\>\s*/g, "");
+            var style = html.match(/\<style[^\>]*\>(?:(?!\<\/style\>)(?:.|\s))*\<\/style\>\s*/gi);
+            var output = (style ? style.join("\n") : "") + (comments ? comments.join("\n") : "") + table;
+            output = output.replace(/\n+/, "\n");
+            $scope.print.template_content = output;
+            $scope.save_locally();
         }
     }
 
+    $scope.redraw_label_table = function () {
+        var d = new Date(); //Added to table ID with 'eg_plt_' to cause $complie on $scope.print.template_content to fire due to template content change.
+        var table = "<table id=\"eg_plt_" + d.getTime().toString() + "\"\></table>\n";
+        $scope.print.template_content += table;
+        $scope.create_print_label_table();
+    }
+
+    $scope.$watch('preview_scope.toolbox_settings.page.dimensions.columns',
+        function (newVal, oldVal) {
+            if (newVal && newVal != oldVal && $scope.preview_scope) {
+                $scope.redraw_label_table();
+            }
+        }
+    );
+
     $scope.$watch('print.cn_template_content', function (newVal, oldVal) {
         if (newVal && newVal != oldVal) {
             $scope.rebuild_cn_set();
@@ -725,7 +756,9 @@ function ($scope, $q, $window, $routeParams, $location, $timeout, egCore, egNet,
 
 .filter('cn_wrap', function () {
     return function (input, w, h, wrap_type) {
-        var names;
+        var addedElements = 0;
+        /* Pattern matches for LC ([0]) and non-LC ([1]) CNs */
+        var patterns = [/^([A-Z]{1,3})\s*(\d{1,4}(?:\.*\d{1,3})?)\s*(\d[A-Z0-9]{0,3})?(\.*[A-Z]\d{1,3})?(\d[A-Z0-9]{0,3})?([A-Z]\d{1,3})?(.*)?/i, /^([A-Z]+)?\s*(\d+(?:\.\d+)?)\s*(.*)?$/i];
         var prefix = input[0];
         var callnum = input[1];
         var suffix = input[2];
@@ -733,78 +766,70 @@ function ($scope, $q, $window, $routeParams, $location, $timeout, egCore, egNet,
         if (!w) { w = 8; }
         if (!h) { h = 9; }
 
-        /* handle spine labels differently if using LC */
-        if (wrap_type == 'lc' || wrap_type == 3) {
-            /* Establish a pattern where every return value should be isolated on its own line 
-               on the spine label: subclass letters, subclass numbers, cutter numbers, trailing stuff (date) */
-            var patt1 = /^([A-Z]{1,3})\s*(\d+(?:\.\d+)?)\s*(\.[A-Z]\d*)\s*([A-Z]\d*)?\s*(\d\d\d\d(?:-\d\d\d\d)?)?\s*(.*)$/i;
-            var result = callnum.match(patt1);
-            if (result) {
-                callnum = result.slice(1).join('\t');
+        var cn_patt; /* <- regex from patterns to use based on wrap_type */
+        var z = 3; /* <-Text match position in patterns for variable text (7th position in LC regex pattern); default to non-LC (3rd position in non-LC regex pattern) */
+        if (wrap_type === 3 || wrap_type === 'lc') {
+            cn_patt = patterns[0];
+            z = 7;
+        } else {
+            cn_patt = patterns[1];
+        }
+
+        callnum = callnum.replace(/^\s+|\s+$/, "");
+
+
+        var result = callnum.split(/\s+/);
+        if (!result) {
+            var hasDigits = /\d/;
+            var hasSpace = /\s/;
+            if (!hasDigits.test(callnum) && hasSpace.test(callnum)) {
+                result = callnum.split(/\s+/);
             } else {
-                callnum = callnum.split(/\s+/).join('\t');
+                result = [];
+                divideOnCharLen(callnum, result, 0, 0);
             }
+        }
+        prefix ? result.splice(0, 0, prefix) : false;
+        suffix ? result.push(suffix) : false;
+
+        /* Give each line a final check and cleanup if it exceeds width of 'w' */
+        addedElements = 0;
+        for (var i = 0; i < result.length; i++) {
+            if (result[i]) {
+                var dec_test = /(\d+)\.(\d+)/;
+                if (dec_test.test(result[i])) {
+                    var dec_split = result[i].match(dec_test);
+                    result.splice(i, 1, dec_split[1], "." + dec_split[2]);
+                }
+                divideOnCharLen(result[i], result, i, addedElements);
+            }
+        }
+        var output = [];
+        for (var j = 0; j < result.length; j++) {
+            result[j] ? result[j] = result[j].replace(/^\s*(.*?)\s*$/, "$1") : false;
+            result[j] ? output.push(result[j]) : false;
+        }
+        output = output.slice(0, h); /*Limit lines to height in org unit settings (or default) */
 
-            /* If result is null, leave callnum alone. Can't parse this malformed call num */
-        } else {
-            callnum = callnum.split(/\s+/).join('\t');
-        }
-
-        if (prefix) {
-            callnum = prefix + '\t' + callnum;
-        }
-        if (suffix) {
-            callnum += '\t' + suffix;
-        }
-
-        /* At this point, the call number pieces are separated by tab characters.  This allows
-        *  some space-containing constructs like "v. 1" to appear on one line
-        */
-        callnum = callnum.replace(/\t\t/g, '\t');  /* Squeeze out empties */
-        names = callnum.split('\t');
-        var j = 0; var tb = [];
-        while (j < h) {
-
-            /* spine */
-            if (j < w) {
-
-                var name = names.shift();
-                if (name) {
-                    name = String(name);
-
-                    /* if the name is greater than the label width... */
-                    if (name.length > w) {
-                        /* then try to split it on periods */
-                        var sname = name.split(/\./);
-                        if (sname.length > 1) {
-                            /* if we can, then put the periods back in on each splitted element */
-                            if (name.match(/^\./)) sname[0] = '.' + sname[0];
-                            for (var k = 1; k < sname.length; k++) sname[k] = '.' + sname[k];
-                            /* and put all but the first one back into the names array */
-                            names = sname.slice(1).concat(names);
-                            /* if the name fragment is still greater than the label width... */
-                            if (sname[0].length > w) {
-                                /* then just truncate and throw the rest back into the names array */
-                                tb[j] = sname[0].substr(0, w);
-                                names = [sname[0].substr(w)].concat(names);
-                            } else {
-                                /* otherwise we're set */
-                                tb[j] = sname[0];
-                            }
-                        } else {
-                            /* if we can't split on periods, then just truncate and throw the rest back into the names array */
-                            tb[j] = name.substr(0, w);
-                            names = [name.substr(w)].concat(names);
-                        }
+        return output.join('\n');
+
+        function divideOnCharLen(val, arr, index, incr) {
+            var x = 1;
+            while ((val.length / x) > w) {
+                x++;
+            }
+            var charMatch = val.match(new RegExp(".{1," + Math.ceil((val.length / x)) + "}", "g"));
+            if (charMatch) {
+                for (var t = 0; t < charMatch.length; t++) {
+                    if (t === 0) {
+                        arr[index] = charMatch[t];
                     } else {
-                        /* otherwise we're set */
-                        tb[j] = name;
+                        arr.splice((index + t), 0, charMatch[t]);
+                        incr++;
                     }
                 }
             }
-            j++;
         }
-        return tb.join('\n');
     }
 })
 
@@ -933,4 +958,4 @@ function getPrintLabelOutputClass(index, settings) {
 
 function getPrintLabelStyle(index, settings) {
     return index > 0 && (index % settings.page.label.set.size === 0) ? settings.page.label.gap.size : "";
-}
\ No newline at end of file
+}
index 57848b4..5319272 100644 (file)
@@ -127,9 +127,10 @@ function(egCore , $q) {
     service.get_statcats = function(orgs) {
         return egCore.pcrud.search('asc',
             {owner : orgs},
-            { flesh : 1,
+            { flesh : 2,
               flesh_fields : {
-                asc : ['owner','entries']
+                asc : ['owner','entries'],
+                asce : ['value']
               },
               order_by : [{'class':'asc', 'field':'owner'},{'class':'asc', 'field':'name'},{'class':'asce', 'field':'value'} ]
             },
@@ -281,121 +282,109 @@ function(egCore , $q) {
 
     };
 
-    service.get_acp_templates = function() {
-        // Already downloaded for this user? Return local copy. Changing users or logging out causes another download
-        // so users always have their own templates, and any changes made on other machines appear as expected.
-        if (egCore.hatch.getSessionItem('cat.copy.templates.usr') == egCore.auth.user().id()) {
-            return egCore.hatch.getItem('cat.copy.templates').then(function(templ) {
-                return templ;
-            });
-        } else {
-            // this can be disabled for debugging to force a re-download and translation of test templates
-            egCore.hatch.setSessionItem('cat.copy.templates.usr', egCore.auth.user().id());
-            return service.load_remote_acp_templates();
-        }
-
-    };
-
-    service.save_acp_templates = function(t) {
-        egCore.hatch.setItem('cat.copy.templates', t);
-        egCore.net.request('open-ils.actor', 'open-ils.actor.patron.settings.update',
-            egCore.auth.token(), egCore.auth.user().id(), { "webstaff.cat.copy.templates": t });
-        // console.warn('Saved ' + JSON.stringify({"webstaff.cat.copy.templates": t}));
-    };
-
-    service.load_remote_acp_templates = function() {
-        // After the XUL Client is completely removed everything related
-        // to staff_client.copy_editor.templates and convert_xul_templates
-        // can be thrown away.
-        return egCore.net.request('open-ils.actor', 'open-ils.actor.patron.settings.retrieve.authoritative',
-            egCore.auth.token(), egCore.auth.user().id(),
-            ['webstaff.cat.copy.templates','staff_client.copy_editor.templates']).then(function(settings) {
-                if (settings['webstaff.cat.copy.templates']) {
-                    egCore.hatch.setItem('cat.copy.templates', settings['webstaff.cat.copy.templates']);
-                    return settings['webstaff.cat.copy.templates'];
-                } else {
-                    if (settings['staff_client.copy_editor.templates']) {
-                        var new_templ = service.convert_xul_templates(settings['staff_client.copy_editor.templates']);
-                        egCore.hatch.setItem('cat.copy.templates', new_templ);
-                        // console.warn('Saving: ' + JSON.stringify({'webstaff.cat.copy.templates' : new_templ}));
-                        egCore.net.request('open-ils.actor', 'open-ils.actor.patron.settings.update',
-                            egCore.auth.token(), egCore.auth.user().id(), {'webstaff.cat.copy.templates' : new_templ});
-                        return new_templ;
-                    }
-                }
-                return {};
-        });
-    };
-
-    service.convert_xul_templates = function(xultempl) {
-        var conv_templ = {};
-        var templ_names = Object.keys(xultempl);
-        var name;
-        var xul_t;
-        var curr_templ;
-        var stat_cats;
-        var fields;
-        var curr_field;
-        var tmp_val;
-        var i, j;
-
-        if (templ_names) {
-            for (i=0; i < templ_names.length; i++) {
-                name = templ_names[i];
-                curr_templ = {};
-                stat_cats = {};
-                xul_t  = xultempl[name];
-                fields = Object.keys(xul_t);
-
-                if (fields.length > 0) {
-                    for (j=0; j < fields.length; j++) {
-                        curr_field = xul_t[fields[j]];
-                        var field_name = curr_field["field"];
-
-                        if ( field_name == null ) { continue; }
-                        if ( curr_field["value"] == "<HACK:KLUDGE:NULL>" ) { continue; }
-
-                        // floating changed from a boolean to an integer at one point;
-                        // take this opportunity to remove the boolean from any old templates
-                        if ( curr_field["type"] === "attribute" && field_name === "floating" ) {
-                            if ( curr_field["value"].match(/[tf]/) ) { continue; }
-                        }
-
-                        if ( curr_field["type"] === "stat_cat" ) {
-                            stat_cats[field_name] = parseInt(curr_field["value"]);
-                        } else {
-                            tmp_val = curr_field['value'];
-                            if ( tmp_val.toString().match(/^[-0-9.]+$/)) {
-                                tmp_val = parseFloat(tmp_val);
-                            }
-
-                            if (field_name.match(/^batch_.*_menulist$/)) {
-                                // special handling for volume fields
-                                if (!("callnumber" in curr_templ)) curr_templ["callnumber"] = {};
-                                if (field_name === "batch_class_menulist")  curr_templ["callnumber"]["classification"] = tmp_val;
-                                if (field_name === "batch_prefix_menulist") curr_templ["callnumber"]["prefix"] = tmp_val;
-                                if (field_name === "batch_suffix_menulist") curr_templ["callnumber"]["suffix"] = tmp_val;
-                            } else {
-                                curr_templ[field_name] = tmp_val;
-                            }
-                        }
-                    }
-
-                    if ( (Object.keys(stat_cats)).length > 0 ) {
-                        curr_templ["statcats"] = stat_cats;
-                    }
-
-                    conv_templ[name] = curr_templ;
-                }
-            }
-        }
-        return conv_templ;
-    };
+   service.get_acp_templates = function() {
+       // Already downloaded for this user? Return local copy. Changing users or logging out causes another download
+       // so users always have their own templates, and any changes made on other machines appear as expected.
+       if (egCore.hatch.getSessionItem('cat.copy.templates.usr') == egCore.auth.user().id()) {
+           return egCore.hatch.getItem('cat.copy.templates').then(function(templ) {
+               return templ;
+           });
+       } else {
+          // this can be disabled for debugging to force a re-download and translation of test templates
+          egCore.hatch.setSessionItem('cat.copy.templates.usr', egCore.auth.user().id());
+          return service.load_remote_acp_templates();
+      }
+
+   };
+
+   service.save_acp_templates = function(t) {
+       egCore.hatch.setItem('cat.copy.templates', t);
+       egCore.net.request('open-ils.actor', 'open-ils.actor.patron.settings.update',
+           egCore.auth.token(), egCore.auth.user().id(), { "webstaff.cat.copy.templates": t });
+       // console.warn('Saved ' + JSON.stringify({"webstaff.cat.copy.templates": t}));
+   };
+
+   service.load_remote_acp_templates = function() {
+       // After the XUL Client is completely removed everything related to staff_client.copy_editor.templates and convert_xul_templates can be thrown away.
+       return egCore.net.request('open-ils.actor', 'open-ils.actor.patron.settings.retrieve.authoritative',
+           egCore.auth.token(), egCore.auth.user().id(),
+           ['webstaff.cat.copy.templates','staff_client.copy_editor.templates']).then(function(settings) {
+               if (settings['webstaff.cat.copy.templates']) {
+                   egCore.hatch.setItem('cat.copy.templates', settings['webstaff.cat.copy.templates']);
+                   return settings['webstaff.cat.copy.templates'];
+               } else {
+                   if (settings['staff_client.copy_editor.templates']) {
+                      var new_templ = service.convert_xul_templates(settings['staff_client.copy_editor.templates']);
+                      egCore.hatch.setItem('cat.copy.templates', new_templ);
+                      // console.warn('Saving: ' + JSON.stringify({'webstaff.cat.copy.templates' : new_templ}));
+                      egCore.net.request('open-ils.actor', 'open-ils.actor.patron.settings.update',
+                          egCore.auth.token(), egCore.auth.user().id(), {'webstaff.cat.copy.templates' : new_templ});
+                      return new_templ;
+                   }
+               }
+               return {};
+       });
+   };
+
+   service.convert_xul_templates = function(xultempl) {
+       var conv_templ = {};
+       var templ_names = Object.keys(xultempl);
+       var name;
+       var xul_t;
+       var curr_templ;
+       var stat_cats;
+       var fields;
+       var field_name;
+       var curr_field;
+       var tmp_val;
+       var i, j;
+
+       if (templ_names){
+         for (i=0; i < templ_names.length; i++) {
+           name = templ_names[i];
+           curr_templ = {};
+           stat_cats = {};
+           xul_t  = xultempl[name];
+           fields = Object.keys(xul_t);
+
+           if (fields.length > 0) {
+             for (j=0; j < fields.length; j++) {
+               field_name = fields[j];
+               curr_field = xul_t[field_name];
+
+               if ( curr_field["field"] == null ) { continue; }
+               if ( curr_field["value"] == "<HACK:KLUDGE:NULL>" ) { continue; }
+
+               // floating changed from a boolean to an integer at one point; take this opportunity to remove the boolean from any old templates
+               if ( curr_field["type"] === "attribute" && curr_field["field"] === "floating" ) {
+                 if ( curr_field["value"].match(/[tf]/) ) { continue; }
+               }
+
+               if ( curr_field["type"] === "stat_cat" ) {
+                 stat_cats[curr_field["field"]] = parseInt(curr_field["value"]);
+               }
+               else {
+                 tmp_val = curr_field['value']; // so... some of the number fields are actually strings. Groovy.
+                 if ( tmp_val.match(/^[-0-9.]+$/) && !(curr_field["field"].match(/(?:loan_duration|fine_level)/))) { tmp_val = parseFloat(tmp_val); }
+                 curr_templ[curr_field["field"]] = tmp_val;
+               }
+             }
+
+             if ( (Object.keys(stat_cats)).length > 0 ){
+               curr_templ["statcats"] = stat_cats;
+             }
+
+             conv_templ[name] = curr_templ;
+           }
+         }
+       }
+       return conv_templ;
+   };
 
     service.flesh = {   
         flesh : 3, 
         flesh_fields : {
-            acp : ['call_number','parts','stat_cat_entries', 'notes', 'tags', 'creator', 'editor'],
+            acp : ['call_number','parts','stat_cat_entries', 'notes', 'tags'],
             acn : ['label_class','prefix','suffix'],
             acptcm : ['tag']
         }
@@ -514,13 +503,12 @@ function(egCore , $q) {
     return service;
 }])
 
-.directive("egVolCopyEdit", ['egCore', function (egCore) {
+.directive("egVolCopyEdit", function () {
     return {
         restrict: 'E',
         replace: true,
         template:
-            '<div class="row" ng-class="{'+"'new-cp'"+':is_new}">'+
-                '<span ng-if="is_new" class="sr-only">' + egCore.strings.VOL_COPY_NEW_ITEM + '</span>' +
+            '<div class="row">'+
                 '<div class="col-xs-5" ng-class="{'+"'has-error'"+':barcode_has_error}">'+
                     '<input id="{{callNumber.id()}}_{{copy.id()}}"'+
                     ' eg-enter="nextBarcode(copy.id())" class="form-control"'+
@@ -540,13 +528,11 @@ function(egCore , $q) {
                 $scope.barcode_has_error = false;
                 $scope.duplicate_barcode = false;
                 $scope.empty_barcode = false;
-                $scope.is_new = false;
                 $scope.duplicate_barcode_string = window.duplicate_barcode_string;
                 $scope.empty_barcode_string = window.empty_barcode_string;
                 var duplicate_check_count = 0;
 
                 if (!$scope.copy.barcode()) $scope.copy.empty_barcode = true;
-                if ($scope.copy.isnew() || $scope.copy.id() < 0) $scope.copy.is_new = $scope.is_new = true;
 
                 $scope.selectOnFocus = function($event) {
                     if (!$scope.copy.empty_barcode)
@@ -624,29 +610,28 @@ function(egCore , $q) {
         ]
 
     }
-}])
+})
 
-.directive("egVolRow", ['egCore', function (egCore) {
+.directive("egVolRow", function () {
     return {
         restrict: 'E',
         replace: true,
         transclude: true,
         template:
-            '<div class="row" ng-class="{'+"'new-cn'"+':!callNumber.not_ephemeral}">'+
-                '<span ng-if="!callNumber.not_ephemeral" class="sr-only">' + egCore.strings.VOL_COPY_NEW_CALL_NUMBER + '</span>' +
+            '<div class="row">'+
                 '<div class="col-xs-2">'+
                     '<button aria-label="Delete" style="margin:-5px -15px; float:left;" ng-hide="callNumber.not_ephemeral" type="button" class="close" ng-click="removeCN()">&times;</button>' +
-                    '<select class="form-control" ng-model="classification" ng-change="updateClassification()" ng-options="cl.name() for cl in classification_list"></select>'+
+                    '<select class="form-control" ng-model="classification" ng-change="updateClassification()" ng-options="cl.name() for cl in classification_list"/>'+
                 '</div>'+
                 '<div class="col-xs-1">'+
-                    '<select class="form-control" ng-model="prefix" ng-change="updatePrefix()" ng-options="p.label() for p in prefix_list"></select>'+
+                    '<select class="form-control" ng-model="prefix" ng-change="updatePrefix()" ng-options="p.label() for p in prefix_list"/>'+
                 '</div>'+
                 '<div class="col-xs-2">'+
                     '<input class="form-control" type="text" ng-change="updateLabel()" ng-model="label"/>'+
                     '<div class="label label-danger" ng-if="empty_label">{{empty_label_string}}</div>'+
                 '</div>'+
                 '<div class="col-xs-1">'+
-                    '<select class="form-control" ng-model="suffix" ng-change="updateSuffix()" ng-options="s.label() for s in suffix_list"></select>'+
+                    '<select class="form-control" ng-model="suffix" ng-change="updateSuffix()" ng-options="s.label() for s in suffix_list"/>'+
                 '</div>'+
                 '<div ng-hide="onlyVols" class="col-xs-1"><input class="form-control" type="number" ng-model="copy_count" min="{{orig_copy_count}}" ng-change="changeCPCount()"></div>'+
                 '<div ng-hide="onlyVols" class="col-xs-5">'+
@@ -876,7 +861,7 @@ function(egCore , $q) {
         ]
 
     }
-}])
+})
 
 .directive("egVolEdit", function () {
     return {
@@ -1193,8 +1178,6 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
         return true;
     }
 
-    $scope.changed_fields = [];
-
     $scope.completeToWorking = function () {
         angular.forEach( $scope.completedGridControls.selectedItems(), function (c) {
             angular.forEach( $scope.completed_copies, function (w, i) {
@@ -1231,7 +1214,6 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
                                 return;
                             }
                             if (cp[field]() !== newval) {
-                                $scope.changed_fields[cp.$$hashKey+field] = true;
                                 cp[field](newval);
                                 cp.ischanged(1);
                                 $scope.dirty = true;
@@ -1243,14 +1225,6 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
         });
     }
 
-    // determine if any of the selected copies have had changed their value for this field:
-    $scope.field_changed = function (field){
-        // if objects controlling selection don't exist, assume the fields haven't changed
-        if(!$scope.workingGridControls || !$scope.workingGridControls.selectedItems){ return false; }
-        var selected = $scope.workingGridControls.selectedItems();
-        return selected.reduce((acc, cp) => acc || $scope.changed_fields[cp.$$hashKey+field], false);
-    };
-
     $scope.working = {
         MultiMap: {},
         statcats: {},
@@ -1285,7 +1259,6 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
                 angular.forEach(
                     $scope.workingGridControls.selectedItems(),
                     function (cp) {
-                        if (!angular.isArray(cp.copy_alerts())) cp.copy_alerts([]);
                         $scope.dirty = true;
                         angular.forEach(alerts, function(alrt) {
                             var a = egCore.idl.fromHash('aca', alrt);
@@ -1310,7 +1283,6 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
             angular.forEach(
                 $scope.workingGridControls.selectedItems(),
                 function (cp) {
-                    if (!angular.isArray(cp.notes())) cp.notes([]);
                     $scope.dirty = true;
                     angular.forEach(notes, function(note) {
                         var n = egCore.idl.fromHash('acpn', note);
@@ -2078,12 +2050,19 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
             ).then(function(copy_ids) {
                 if (and_exit) {
                     $scope.dirty = false;
+                    !$scope.completedGridDataProvider.sort ? copy_ids.reverse() : $scope.completedGridDataProvider.sort.length === 0 ? copy_ids.reverse() : false;
+                    var cp_full = [];
+                    var i = 1;
+                    angular.forEach(copy_ids, function (copy) {
+                        cp_full.push({ id: i, target_copy: copy });
+                        i++;
+                    });
                     if ($scope.defaults.print_item_labels) {
                         egCore.net.request(
                             'open-ils.actor',
                             'open-ils.actor.anon_cache.set_value',
                             null, 'print-labels-these-copies', {
-                                copies : copy_ids
+                                copies : cp_full
                             }
                         ).then(function(key) {
                             if (key) {
@@ -2359,7 +2338,6 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
                     if (typeof(copy_alert.note) != 'undefined' &&
                         copy_alert.note != '') {
                         angular.forEach(copy_list, function (cp) {
-                            if (!angular.isArray(cp.copy_alerts())) cp.copy_alerts([]);
                             var a = new egCore.idl.aca();
                             a.isnew(1);
                             a.create_staff(copy_alert.create_staff);
index 5c89922..4bf61db 100644 (file)
@@ -41,6 +41,7 @@ function($scope , $q , $window , $location , $timeout , egCore , checkinSvc , eg
     $scope.checkins = checkinSvc.checkins;
     var today = new Date(new Date().setHours(0,0,0,0));
     $scope.checkinArgs = {backdate : today}
+    $scope.using_hatch_printer = egCore.hatch.usePrinting();
     $scope.modifiers = {};
     $scope.fine_total = 0;
     $scope.is_capture = $location.path().match(/capture$/);
@@ -48,10 +49,6 @@ function($scope , $q , $window , $location , $timeout , egCore , checkinSvc , eg
     $scope.grid_persist_key = $scope.is_capture ? 
         'circ.checkin.capture' : 'circ.checkin.checkin';
 
-    egCore.hatch.usePrinting().then(function(useHatch) {
-        $scope.using_hatch_printer = useHatch;
-    });
-
     // TODO: add this to the setting batch lookup below
     egCore.hatch.getItem('circ.checkin.strict_barcode')
         .then(function(sb){ $scope.strict_barcode = sb });
@@ -401,7 +398,7 @@ function($scope , $q , $window , $location , $timeout , egCore , checkinSvc , eg
             recordIds.push(i.acn.record());
         });
         angular.forEach(recordIds, function (r) {
-            var url = '/eg2/staff/catalog/record/' + r + '/holds';
+            var url = egCore.env.basePath + 'cat/catalog/record/' + r + '/holds';
             $timeout(function() { $window.open(url, '_blank') });
         });
     }
@@ -442,6 +439,7 @@ function($scope , $q , $window , $location , $timeout , egCore , checkinSvc , eg
         angular.forEach(items, function(item) {
             if (item.acp) copy_ids.push(item.acp.id());
         });
+        !$scope.gridDataProvider.sort ? copy_ids.reverse() : $scope.gridDataProvider.sort.length === 0 ? copy_ids.reverse() : false;
         itemSvc.print_spine_labels(copy_ids);
     }