Rebase of spine label enhanced printing features with current user/abowling/spine_label_enhanced_printing
authorAdam Bowling <abowling@emeralddata.net>
Thu, 16 Jul 2020 06:20:51 +0000 (02:20 -0400)
committerAdam Bowling <abowling@emeralddata.net>
Thu, 16 Jul 2020 06:20:51 +0000 (02:20 -0400)
master.

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/catalog/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
Open-ILS/web/js/ui/default/staff/circ/services/item.js

index 47ccde6..e142d48 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">
index e7aeccd..a519ce2 100644 (file)
@@ -594,24 +594,39 @@ 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);
         })
-
+        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_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_full.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');
+                }
+            });
         });
     }
 
index 68f387e..ba33440 100644 (file)
@@ -1674,6 +1674,26 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
                 alert('Could not create anonymous cache key!');
             }
         });
+        var cp_list = gatherSelectedHoldingsIds();
+        var cp_full = [], promises = [];
+        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 create print label export.');
+        } 
     }
 
     $scope.selectedHoldingsDamaged = function () {
index 614db62..2e9ed92 100644 (file)
@@ -670,20 +670,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..a3aea06 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
@@ -523,40 +523,51 @@ function ($scope, $q, $window, $routeParams, $location, $timeout, egCore, egNet,
         });
     }
 
-    $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 +736,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 +746,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');
     }
 })
 
index 29bd7f0..366a62b 100644 (file)
@@ -2022,12 +2022,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) {
index 82bd4c8..1edd2c1 100644 (file)
@@ -421,6 +421,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);
     }
 
index 8150f18..eb05543 100644 (file)
@@ -980,20 +980,27 @@ function(egCore , egOrg , egCirc , $uibModal , $q , $timeout , $window , ngToast
     }
 
     service.print_spine_labels = function(copy_ids){
-        egCore.net.request(
-            'open-ils.actor',
-            'open-ils.actor.anon_cache.set_value',
-            null, 'print-labels-these-copies', {
-                copies : copy_ids
-            }
-        ).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.');
+        }
     }
 
     service.show_in_catalog = function(copy_list){