From: Jason Etheridge Date: Sun, 5 Mar 2017 21:07:17 +0000 (-0500) Subject: LP#1704873 webstaff: label printing X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=69220697852976ecddc304124b4e06d6237bb189;p=evergreen%2Fpines.git LP#1704873 webstaff: label printing ...initial hook ...better stock template for labels, and a | wrap filter ...pull in some Library Settings for Print Labels ...Reset to Default button for templates for both receipt and item print labels ...toward tabs for Print Label interface ...template management for print labels ...bundle the Call Number Template in with saved templates ...manual editing of cn's for print labels ...And affixes in the stock CN template. ...Settings tab for print labels ...add Print Labels action to Copy Buckets ...and some other cosmetic tweaks to the Actions menu ...add Print Labels to Holdings View ...provide MVR's for use with Print Labels ...better than super simple record, but Display Fields will be better yet later on ...new org unit settings for print labels ...and fix to stock call number template for affixes ...and cn_wrap filter for call numbers ...handle null location affixes ...implement Print Item Labels on Save & Exit in vol/copy editor Signed-off-by: Jason Etheridge Signed-off-by: Bill Erickson --- diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat.pm index e083c3b7ac..19c0b6ad84 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat.pm @@ -1103,6 +1103,7 @@ sub fleshed_volume_update { my $retarget_holds = []; my $auto_merge_vols = $options->{auto_merge_vols}; my $create_parts = $options->{create_parts}; + my $copy_ids = []; for my $vol (@$volumes) { $logger->info("vol-update: investigating volume ".$vol->id); @@ -1148,12 +1149,17 @@ sub fleshed_volume_update { $evt = $assetcom->update_fleshed_copies( $editor, $oargs, $vol, $copies, $delete_stats, $retarget_holds, undef, $create_parts); return $evt if $evt; + push( @$copy_ids, $_->id ) for @$copies; } } $editor->finish; reset_hold_list($auth, $retarget_holds); - return scalar(@$volumes); + if ($options->{return_copy_ids}) { + return $copy_ids; + } else { + return scalar(@$volumes); + } } diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql index eef768d400..c40c86dbcc 100644 --- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql +++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql @@ -16642,6 +16642,207 @@ VALUES 'coust', 'description'), 'bool'); + +INSERT into config.org_unit_setting_type ( + name + ,grp + ,label + ,description + ,datatype +) VALUES ( ---------------------------------------- + 'webstaff.cat.label.font.family' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.font.family' + ,'Item Print Label Font Family' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.font.family' + ,'Set the preferred font family for item print labels. You can specify a list of CSS fonts, separated by commas, in order of preference; the system will use the first font it finds with a matching name. For example, "Arial, Helvetica, serif"' + ,'coust' + ,'description' + ) + ,'string' +), ( ---------------------------------------- + 'webstaff.cat.label.font.size' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.font.size' + ,'Item Print Label Font Size' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.font.size' + ,'Set the default font size for item print labels. Please include a unit of measurement that is valid CSS. For example, "12pt" or "16px" or "1em"' + ,'coust' + ,'description' + ) + ,'string' +), ( ---------------------------------------- + 'webstaff.cat.label.font.weight' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.font.weight' + ,'Item Print Label Font Weight' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.font.weight' + ,'Set the default font weight for item print labels. Please use the CSS specification for values for font-weight. For example, "normal", "bold", "bolder", or "lighter"' + ,'coust' + ,'description' + ) + ,'string' +), ( ---------------------------------------- + 'webstaff.cat.label.left_label.left_margin' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.left_label.left_margin' + ,'Item Print Label - Left Margin for Left Label' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.left_label.left_margin' + ,'Set the default left margin for the leftmost item print Label. Please include a unit of measurement that is valid CSS. For example, "1in" or "2.5cm"' + ,'coust' + ,'description' + ) + ,'string' +), ( ---------------------------------------- + 'webstaff.cat.label.right_label.left_margin' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.right_label.left_margin' + ,'Item Print Label - Left Margin for Right Label' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.right_label.left_margin' + ,'Set the default left margin for the rightmost item print label (or in other words, the desired space between the two labels). Please include a unit of measurement that is valid CSS. For example, "1in" or "2.5cm"' + ,'coust' + ,'description' + ) + ,'string' +), ( ---------------------------------------- + 'webstaff.cat.label.left_label.height' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.left_label.height' + ,'Item Print Label - Height for Left Label' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.left_label.height' + ,'Set the default height for the leftmost item print label. Please include a unit of measurement that is valid CSS. For example, "1in" or "2.5cm"' + ,'coust' + ,'description' + ) + ,'string' +), ( ---------------------------------------- + 'webstaff.cat.label.left_label.width' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.left_label.width' + ,'Item Print Label - Width for Left Label' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.left_label.width' + ,'Set the default width for the leftmost item print label. Please include a unit of measurement that is valid CSS. For example, "1in" or "2.5cm"' + ,'coust' + ,'description' + ) + ,'string' +), ( ---------------------------------------- + 'webstaff.cat.label.right_label.height' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.right_label.height' + ,'Item Print Label - Height for Right Label' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.right_label.height' + ,'Set the default height for the rightmost item print label. Please include a unit of measurement that is valid CSS. For example, "1in" or "2.5cm"' + ,'coust' + ,'description' + ) + ,'string' +), ( ---------------------------------------- + 'webstaff.cat.label.right_label.width' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.right_label.width' + ,'Item Print Label - Width for Right Label' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.right_label.width' + ,'Set the default width for the rightmost item print label. Please include a unit of measurement that is valid CSS. For example, "1in" or "2.5cm"' + ,'coust' + ,'description' + ) + ,'string' +), ( + 'webstaff.cat.label.inline_css' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.inline_css' + ,'Item Print Label - Inline CSS' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.inline_css' + ,'This setting allows you to inject arbitrary CSS into the item print label template. For example, ".printlabel { text-transform: uppercase; }"' + ,'coust' + ,'description' + ) + ,'string' +), ( + 'webstaff.cat.label.call_number_wrap_filter_height' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.call_number_wrap_filter_height' + ,'Item Print Label - Call Number Wrap Filter Height' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.call_number_wrap_filter_height' + ,'This setting is used to set the default height (in number of lines) to use for call number wrapping in the left print label.' + ,'coust' + ,'description' + ) + ,'integer' +), ( + 'webstaff.cat.label.call_number_wrap_filter_width' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.call_number_wrap_filter_width' + ,'Item Print Label - Call Number Wrap Filter Width' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.call_number_wrap_filter_width' + ,'This setting is used to set the default width (in number of characters) to use for call number wrapping in the left print label.' + ,'coust' + ,'description' + ) + ,'integer' +); + INSERT INTO config.global_flag (name, label, value, enabled) VALUES ( 'circ.holds.retarget_interval', oils_i18n_gettext( diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.webstaff_print_label_ou_settings.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.webstaff_print_label_ou_settings.sql new file mode 100644 index 0000000000..10e7ca758c --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.webstaff_print_label_ou_settings.sql @@ -0,0 +1,252 @@ +BEGIN; + +--SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); + +INSERT into config.org_unit_setting_type ( + name + ,grp + ,label + ,description + ,datatype +) VALUES ( ---------------------------------------- + 'webstaff.cat.label.font.family' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.font.family' + ,'Item Print Label Font Family' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.font.family' + ,'Set the preferred font family for item print labels. You can specify a list of CSS fonts, separated by commas, in order of preference; the system will use the first font it finds with a matching name. For example, "Arial, Helvetica, serif"' + ,'coust' + ,'description' + ) + ,'string' +), ( ---------------------------------------- + 'webstaff.cat.label.font.size' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.font.size' + ,'Item Print Label Font Size' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.font.size' + ,'Set the default font size for item print labels. Please include a unit of measurement that is valid CSS. For example, "12pt" or "16px" or "1em"' + ,'coust' + ,'description' + ) + ,'string' +), ( ---------------------------------------- + 'webstaff.cat.label.font.weight' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.font.weight' + ,'Item Print Label Font Weight' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.font.weight' + ,'Set the default font weight for item print labels. Please use the CSS specification for values for font-weight. For example, "normal", "bold", "bolder", or "lighter"' + ,'coust' + ,'description' + ) + ,'string' +), ( ---------------------------------------- + 'webstaff.cat.label.left_label.left_margin' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.left_label.left_margin' + ,'Item Print Label - Left Margin for Left Label' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.left_label.left_margin' + ,'Set the default left margin for the leftmost item print Label. Please include a unit of measurement that is valid CSS. For example, "1in" or "2.5cm"' + ,'coust' + ,'description' + ) + ,'string' +), ( ---------------------------------------- + 'webstaff.cat.label.right_label.left_margin' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.right_label.left_margin' + ,'Item Print Label - Left Margin for Right Label' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.right_label.left_margin' + ,'Set the default left margin for the rightmost item print label (or in other words, the desired space between the two labels). Please include a unit of measurement that is valid CSS. For example, "1in" or "2.5cm"' + ,'coust' + ,'description' + ) + ,'string' +), ( ---------------------------------------- + 'webstaff.cat.label.left_label.height' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.left_label.height' + ,'Item Print Label - Height for Left Label' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.left_label.height' + ,'Set the default height for the leftmost item print label. Please include a unit of measurement that is valid CSS. For example, "1in" or "2.5cm"' + ,'coust' + ,'description' + ) + ,'string' +), ( ---------------------------------------- + 'webstaff.cat.label.left_label.width' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.left_label.width' + ,'Item Print Label - Width for Left Label' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.left_label.width' + ,'Set the default width for the leftmost item print label. Please include a unit of measurement that is valid CSS. For example, "1in" or "2.5cm"' + ,'coust' + ,'description' + ) + ,'string' +), ( ---------------------------------------- + 'webstaff.cat.label.right_label.height' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.right_label.height' + ,'Item Print Label - Height for Right Label' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.right_label.height' + ,'Set the default height for the rightmost item print label. Please include a unit of measurement that is valid CSS. For example, "1in" or "2.5cm"' + ,'coust' + ,'description' + ) + ,'string' +), ( ---------------------------------------- + 'webstaff.cat.label.right_label.width' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.right_label.width' + ,'Item Print Label - Width for Right Label' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.right_label.width' + ,'Set the default width for the rightmost item print label. Please include a unit of measurement that is valid CSS. For example, "1in" or "2.5cm"' + ,'coust' + ,'description' + ) + ,'string' +), ( + 'webstaff.cat.label.inline_css' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.inline_css' + ,'Item Print Label - Inline CSS' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.inline_css' + ,'This setting allows you to inject arbitrary CSS into the item print label template. For example, ".printlabel { text-transform: uppercase; }"' + ,'coust' + ,'description' + ) + ,'string' +), ( + 'webstaff.cat.label.call_number_wrap_filter_height' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.call_number_wrap_filter_height' + ,'Item Print Label - Call Number Wrap Filter Height' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.call_number_wrap_filter_height' + ,'This setting is used to set the default height (in number of lines) to use for call number wrapping in the left print label.' + ,'coust' + ,'description' + ) + ,'integer' +), ( + 'webstaff.cat.label.call_number_wrap_filter_width' + ,'cat' + ,oils_i18n_gettext( + 'webstaff.cat.label.call_number_wrap_filter_width' + ,'Item Print Label - Call Number Wrap Filter Width' + ,'coust' + ,'label' + ) + ,oils_i18n_gettext( + 'webstaff.cat.label.call_number_wrap_filter_width' + ,'This setting is used to set the default width (in number of characters) to use for call number wrapping in the left print label.' + ,'coust' + ,'description' + ) + ,'integer' + + +); + +-- for testing, setting removal: +--DELETE FROM actor.org_unit_setting WHERE name IN ( +-- 'webstaff.cat.label.font.family' +-- ,'webstaff.cat.label.font.size' +-- ,'webstaff.cat.label.font.weight' +-- ,'webstaff.cat.label.left_label.height' +-- ,'webstaff.cat.label.left_label.width' +-- ,'webstaff.cat.label.left_label.left_margin' +-- ,'webstaff.cat.label.right_label.height' +-- ,'webstaff.cat.label.right_label.width' +-- ,'webstaff.cat.label.right_label.left_margin' +-- ,'webstaff.cat.label.inline_css' +-- ,'webstaff.cat.label.call_number_wrap_filter_height' +-- ,'webstaff.cat.label.call_number_wrap_filter_width' +--); +--DELETE FROM config.org_unit_setting_type_log WHERE field_name IN ( +-- 'webstaff.cat.label.font.family' +-- ,'webstaff.cat.label.font.size' +-- ,'webstaff.cat.label.font.weight' +-- ,'webstaff.cat.label.left_label.height' +-- ,'webstaff.cat.label.left_label.width' +-- ,'webstaff.cat.label.left_label.left_margin' +-- ,'webstaff.cat.label.right_label.height' +-- ,'webstaff.cat.label.right_label.width' +-- ,'webstaff.cat.label.right_label.left_margin' +-- ,'webstaff.cat.label.inline_css' +-- ,'webstaff.cat.label.call_number_wrap_filter_height' +-- ,'webstaff.cat.label.call_number_wrap_filter_width' +--); +--DELETE FROM config.org_unit_setting_type WHERE name IN ( +-- 'webstaff.cat.label.font.family' +-- ,'webstaff.cat.label.font.size' +-- ,'webstaff.cat.label.font.weight' +-- ,'webstaff.cat.label.left_label.height' +-- ,'webstaff.cat.label.left_label.width' +-- ,'webstaff.cat.label.left_label.left_margin' +-- ,'webstaff.cat.label.right_label.height' +-- ,'webstaff.cat.label.right_label.width' +-- ,'webstaff.cat.label.right_label.left_margin' +-- ,'webstaff.cat.label.inline_css' +-- ,'webstaff.cat.label.call_number_wrap_filter_height' +-- ,'webstaff.cat.label.call_number_wrap_filter_width' +--); + + +COMMIT; diff --git a/Open-ILS/src/templates/staff/admin/workstation/t_print_templates.tt2 b/Open-ILS/src/templates/staff/admin/workstation/t_print_templates.tt2 index b049c5684d..064bfff811 100644 --- a/Open-ILS/src/templates/staff/admin/workstation/t_print_templates.tt2 +++ b/Open-ILS/src/templates/staff/admin/workstation/t_print_templates.tt2 @@ -46,6 +46,7 @@
+
diff --git a/Open-ILS/src/templates/staff/cat/bucket/copy/t_view.tt2 b/Open-ILS/src/templates/staff/cat/bucket/copy/t_view.tt2 index c2daf27426..98308cc865 100644 --- a/Open-ILS/src/templates/staff/cat/bucket/copy/t_view.tt2 +++ b/Open-ILS/src/templates/staff/cat/bucket/copy/t_view.tt2 @@ -10,15 +10,17 @@ [% INCLUDE 'staff/cat/bucket/copy/t_grid_menu.tt2' %] - + - - - + - diff --git a/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2 b/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2 index c4ca14b5b3..b506f3f405 100644 --- a/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2 +++ b/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2 @@ -55,6 +55,8 @@ label="[% l('Triggered Events') %]"> + diff --git a/Open-ILS/src/templates/staff/cat/item/t_list.tt2 b/Open-ILS/src/templates/staff/cat/item/t_list.tt2 index a481d0df33..6afb87ade5 100644 --- a/Open-ILS/src/templates/staff/cat/item/t_list.tt2 +++ b/Open-ILS/src/templates/staff/cat/item/t_list.tt2 @@ -34,6 +34,8 @@ label="[% l('Item Holds') %]"> + diff --git a/Open-ILS/src/templates/staff/cat/printlabels/index.tt2 b/Open-ILS/src/templates/staff/cat/printlabels/index.tt2 new file mode 100644 index 0000000000..ac89fc5b00 --- /dev/null +++ b/Open-ILS/src/templates/staff/cat/printlabels/index.tt2 @@ -0,0 +1,30 @@ +[% + WRAPPER "staff/base.tt2"; + ctx.page_title = l("Print Item Labels"); + ctx.page_app = "egPrintLabels"; +%] + +[% BLOCK APP_JS %] + + + + + + + +[% END %] + + + +
+ +[% END %] + + diff --git a/Open-ILS/src/templates/staff/cat/printlabels/t_view.tt2 b/Open-ILS/src/templates/staff/cat/printlabels/t_view.tt2 new file mode 100644 index 0000000000..418d4e8490 --- /dev/null +++ b/Open-ILS/src/templates/staff/cat/printlabels/t_view.tt2 @@ -0,0 +1,161 @@ + + +

[% l('Print Item Labels') %]

+ +
+
+
+
+ [% l('Template') %] +
+
+ +
+
+ +
+
+ [% l('Printer') %] +
+
+ +
+
+
+
+
+ + +
+
+
+
+ + [% l('Import') %] + + + +
+
+
+ +
+
+ +
+ +
+
+ +
+
+
+

+ [% l('Call Number Preview') %] +

+
+

+ [% l('Call Number Template') %] +

+
[% l('Changes here will wipe out manual changes in the Call Numbers tab.') %]
+ +
+
+
+
+
+

+ [% l('Formatted Call Numbers') %] +

+
[% l('Manual adjustments may be made here. These do not get saved with templates.') %]
+
+ +
+
+
+
[% l('These settings do get saved with templates and will override corresponding Library Settings.') %]
+
+
+
{{s.label}}
+
+
+ +
+
{{s.description}}
+
+
+ +
+
+
+ [% l( + "Unable to load template '[_1]'. The web server returned an error.", + '{{print.template_name}}') + %] +
+
+ +
+
+
+
+
+
+

+ [% l('Label Preview') %] +

+
+
+
+ diff --git a/Open-ILS/src/templates/staff/cat/volcopy/t_attr_edit.tt2 b/Open-ILS/src/templates/staff/cat/volcopy/t_attr_edit.tt2 index fc2c5e6cee..70fac46e2b 100644 --- a/Open-ILS/src/templates/staff/cat/volcopy/t_attr_edit.tt2 +++ b/Open-ILS/src/templates/staff/cat/volcopy/t_attr_edit.tt2 @@ -41,7 +41,7 @@
- +
diff --git a/Open-ILS/src/templates/staff/cat/volcopy/t_defaults.tt2 b/Open-ILS/src/templates/staff/cat/volcopy/t_defaults.tt2 index 507205d843..8d20cf21ae 100644 --- a/Open-ILS/src/templates/staff/cat/volcopy/t_defaults.tt2 +++ b/Open-ILS/src/templates/staff/cat/volcopy/t_defaults.tt2 @@ -69,8 +69,8 @@
diff --git a/Open-ILS/src/templates/staff/share/print_templates/t_item_label.tt2 b/Open-ILS/src/templates/staff/share/print_templates/t_item_label.tt2 new file mode 100644 index 0000000000..263e1b07ee --- /dev/null +++ b/Open-ILS/src/templates/staff/share/print_templates/t_item_label.tt2 @@ -0,0 +1,285 @@ + + + + + + +
+ + +
+{{get_cn_for(copy)}}
+
+ +
+ + +
+{{copy.barcode}}
+{{copy['call_number.label']}}
+{{get_bib_for(copy).author }}
+{{get_bib_for(copy).title | wrap:28:'once':' '}}
+
+ +
+ diff --git a/Open-ILS/src/templates/staff/share/print_templates/t_item_label_cn.tt2 b/Open-ILS/src/templates/staff/share/print_templates/t_item_label_cn.tt2 new file mode 100644 index 0000000000..85d201c279 --- /dev/null +++ b/Open-ILS/src/templates/staff/share/print_templates/t_item_label_cn.tt2 @@ -0,0 +1,10 @@ +
+{{
+    [
+         get_cn_and_location_prefix(copy)
+        ,copy['call_number.label']
+        ,get_cn_and_location_suffix(copy)
+    ]
+    | cn_wrap:settings['webstaff.cat.label.call_number_wrap_filter_width']:settings['webstaff.cat.label.call_number_wrap_filter_height']:copy['call_number.label_class']
+}}
+
diff --git a/Open-ILS/web/js/ui/default/staff/admin/workstation/app.js b/Open-ILS/web/js/ui/default/staff/admin/workstation/app.js index 15c1fcbaa0..06a908d3c3 100644 --- a/Open-ILS/web/js/ui/default/staff/admin/workstation/app.js +++ b/Open-ILS/web/js/ui/default/staff/admin/workstation/app.js @@ -555,6 +555,16 @@ function($scope , $q , egCore , ngToast) { }); } + $scope.reset_to_default = function() { + egCore.print.removePrintTemplate( + $scope.print.template_name + ); + egCore.print.removePrintTemplateContext( + $scope.print.template_name + ); + $scope.template_changed(); + } + $scope.save_locally = function() { egCore.print.storePrintTemplate( $scope.print.template_name, diff --git a/Open-ILS/web/js/ui/default/staff/cat/bucket/copy/app.js b/Open-ILS/web/js/ui/default/staff/cat/bucket/copy/app.js index 7eea044ddc..d99e70e08c 100644 --- a/Open-ILS/web/js/ui/default/staff/cat/bucket/copy/app.js +++ b/Open-ILS/web/js/ui/default/staff/cat/bucket/copy/app.js @@ -485,6 +485,28 @@ function($scope, $q , $routeParams , $timeout , $window , $uibModal , bucketSvc }); } + $scope.print_labels = function() { + 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, '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!'); + } + }); + } + $scope.requestItems = function() { var copy_list = $scope.gridControls.selectedItems().map( function (i) { diff --git a/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js b/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js index e71f74f6b0..d73224aebb 100644 --- a/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js +++ b/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js @@ -1416,6 +1416,23 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e ); } + $scope.selectedHoldingsPrintLabels = 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!'); + } + }); + } + $scope.selectedHoldingsDamaged = function () { egCirc.mark_damaged(gatherSelectedHoldingsIds()).then(function() { holdingsSvcInst.fetchAgain().then(function() { diff --git a/Open-ILS/web/js/ui/default/staff/cat/item/app.js b/Open-ILS/web/js/ui/default/staff/cat/item/app.js index 002061eaee..865a842389 100644 --- a/Open-ILS/web/js/ui/default/staff/cat/item/app.js +++ b/Open-ILS/web/js/ui/default/staff/cat/item/app.js @@ -1285,6 +1285,23 @@ function($scope , $q , $routeParams , $location , $timeout , $window , egCore , itemSvc.transferItems(copyGrid.selectedItems()); } + $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!'); + } + }); + } + $scope.print_list = function() { var print_data = { copies : copyGrid.allItems() }; diff --git a/Open-ILS/web/js/ui/default/staff/cat/printlabels/app.js b/Open-ILS/web/js/ui/default/staff/cat/printlabels/app.js new file mode 100644 index 0000000000..1fd5296d68 --- /dev/null +++ b/Open-ILS/web/js/ui/default/staff/cat/printlabels/app.js @@ -0,0 +1,633 @@ +/** + * Vol/Copy Editor + */ + +angular.module('egPrintLabels', + ['ngRoute', 'ui.bootstrap', 'egCoreMod', 'egUiMod', 'egGridMod']) + +.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/printlabels/:dataKey', { + templateUrl: './cat/printlabels/t_view', + controller: 'LabelCtrl', + resolve : resolver + }); + +}) + +.factory('itemSvc', + ['egCore', +function(egCore) { + + var service = { + copies : [], // copy barcode search results + index : 0 // search grid index + }; + + service.flesh = { + flesh : 3, + flesh_fields : { + acp : ['call_number','location','status','location','floating','circ_modifier','age_protect'], + acn : ['record','prefix','suffix'], + bre : ['simple_record','creator','editor'] + }, + select : { + // avoid fleshing MARC on the bre + // note: don't add simple_record.. not sure why + bre : ['id','tcn_value','creator','editor'], + } + } + + // resolved with the last received copy + service.fetch = function(barcode, id, noListDupes) { + var promise; + + if (barcode) { + promise = egCore.pcrud.search('acp', + {barcode : barcode, deleted : 'f'}, service.flesh); + } else { + promise = egCore.pcrud.retrieve('acp', id, service.flesh); + } + + var lastRes; + return promise.then( + function() {return lastRes}, + null, // error + + // notify reads the stream of copies, one at a time. + function(copy) { + + var flatCopy; + if (noListDupes) { + // use the existing copy if possible + flatCopy = service.copies.filter( + function(c) {return c.id == copy.id()})[0]; + } + + if (!flatCopy) { + flatCopy = egCore.idl.toHash(copy, true); + flatCopy.index = service.index++; + service.copies.unshift(flatCopy); + } + + return lastRes = { + copy : copy, + index : flatCopy.index + } + } + ); + } + + return service; +}]) + +/** + * Label controller! + */ +.controller('LabelCtrl', + ['$scope','$q','$window','$routeParams','$location','$timeout','egCore','egNet','ngToast','itemSvc', +function($scope , $q , $window , $routeParams , $location , $timeout , egCore , egNet , ngToast , itemSvc ) { + + var dataKey = $routeParams.dataKey; + console.debug('dataKey: ' + dataKey); + + $scope.print = { + template_name : 'item_label', + template_output : '', + template_context : 'default' + }; + + + if (dataKey && dataKey.length > 0) { + + egNet.request( + 'open-ils.actor', + 'open-ils.actor.anon_cache.get_value', + dataKey, 'print-labels-these-copies' + ).then(function (data) { + + if (data) { + + $scope.preview_scope = { + 'copies' : [] + ,'settings' : {} + ,'get_cn_for' : function(copy) { + var key = $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) { + return manual_cn.value; + } else { + return '..'; + } + } else { + return '...'; + } + } + ,'get_bib_for' : function(copy) { + return $scope.record_details[copy['call_number.record.id']]; + } + ,'get_cn_prefix' : function(copy) { + return copy['call_number.prefix.label']; + } + ,'get_cn_suffix' : function(copy) { + return copy['call_number.suffix.label']; + } + ,'get_location_prefix' : function(copy) { + return copy['location.label_prefix']; + } + ,'get_location_suffix' : function(copy) { + return copy['location.label_suffix']; + } + ,'get_cn_and_location_prefix' : function(copy,separator) { + var acpl_prefix = copy['location.label_prefix'] || ''; + var cn_prefix = copy['call_number.prefix.label'] || ''; + var prefix = acpl_prefix + ' ' + cn_prefix; + prefix = prefix.trim(); + if (separator && prefix != '') { prefix += separator; } + return prefix; + } + ,'get_cn_and_location_suffix' : function(copy,separator) { + var acpl_suffix = copy['location.label_suffix'] || ''; + var cn_suffix = copy['call_number.suffix.label'] || ''; + var suffix = cn_suffix + ' ' + acpl_suffix; + suffix = suffix.trim(); + if (separator && suffix != '') { suffix = separator + suffix; } + return suffix; + } + }; + $scope.record_details = {}; + $scope.org_unit_settings = {}; + + var promises = []; + $scope.org_unit_setting_list = [ + 'webstaff.cat.label.font.family' + ,'webstaff.cat.label.font.size' + ,'webstaff.cat.label.font.weight' + ,'webstaff.cat.label.inline_css' + ,'webstaff.cat.label.left_label.height' + ,'webstaff.cat.label.left_label.left_margin' + ,'webstaff.cat.label.left_label.width' + ,'webstaff.cat.label.right_label.height' + ,'webstaff.cat.label.right_label.left_margin' + ,'webstaff.cat.label.right_label.width' + ,'webstaff.cat.label.call_number_wrap_filter_height' + ,'webstaff.cat.label.call_number_wrap_filter_width' + ]; + + promises.push( + egCore.pcrud.search('coust',{name:$scope.org_unit_setting_list}).then( + null + ,null + ,function(yaous) { + $scope.org_unit_settings[yaous.name()] = egCore.idl.toHash(yaous, true); + } + ) + ); + + promises.push( + egCore.org.settings($scope.org_unit_setting_list).then(function(res) { + $scope.preview_scope.settings = res; + egCore.hatch.getItem('cat.printlabels.last_settings').then(function(last_settings) { + if (last_settings) { + for (s in last_settings) { + $scope.preview_scope.settings[s] = last_settings[s]; + } + } + }); + }) + ); + + angular.forEach(data.copies, function(copy) { + promises.push( + itemSvc.fetch(null,copy).then(function(res) { + var flat_copy = egCore.idl.toHash(res.copy, true); + $scope.preview_scope.copies.push(flat_copy); + $scope.record_details[ flat_copy['call_number.record.id'] ] = 1; + }) + ) + }); + + $q.all(promises).then(function() { + + var promises2 = []; + angular.forEach($scope.record_details, function(el,k,obj) { + promises2.push( + egNet.request( + 'open-ils.search', + 'open-ils.search.biblio.record.mods_slim.retrieve.authoritative', + k + ).then(function (data) { + obj[k] = egCore.idl.toHash(data, true); + }) + ); + }); + + $q.all(promises2).then(function() { + // today, staff, current_location, etc. + egCore.print.fleshPrintScope($scope.preview_scope); + $scope.template_changed(); // load the default + $scope.rebuild_cn_set(); + }); + + }); + } else { + ngToast.danger(egCore.strings.KEY_EXPIRED); + } + + }); + + } + + $scope.fetchTemplates = function () { + egCore.hatch.getItem('cat.printlabels.templates').then(function(t) { + if (t) { + $scope.templates = t; + $scope.template_name_list = Object.keys(t); + } + }); + } + $scope.fetchTemplates(); + + $scope.applyTemplate = function (n) { + $scope.print.cn_template_content = $scope.templates[n].cn_content; + $scope.print.template_content = $scope.templates[n].content; + $scope.print.template_context = $scope.templates[n].context; + for (var s in $scope.templates[n].settings) { + $scope.preview_scope.settings[s] = $scope.templates[n].settings[s]; + } + } + + $scope.deleteTemplate = function (n) { + if (n) { + delete $scope.templates[n] + $scope.template_name_list = Object.keys($scope.templates); + $scope.template_name = ''; + egCore.hatch.setItem('cat.printlabels.templates', $scope.templates); + $scope.fetchTemplates(); + ngToast.create(egCore.strings.PRINT_LABEL_TEMPLATE_SUCCESS_DELETE); + } + } + + $scope.saveTemplate = function (n) { + if (n) { + + $scope.templates[n] = { + content : $scope.print.template_content + ,context : $scope.print.template_context + ,cn_content : $scope.print.cn_template_content + ,settings : $scope.preview_scope.settings + }; + $scope.template_name_list = Object.keys($scope.templates); + + egCore.hatch.setItem('cat.printlabels.templates', $scope.templates); + $scope.fetchTemplates(); + + $scope.dirty = false; + } else { + // save all templates, as we might do after an import + egCore.hatch.setItem('cat.printlabels.templates', $scope.templates); + $scope.fetchTemplates(); + } + ngToast.create(egCore.strings.PRINT_LABEL_TEMPLATE_SUCCESS_SAVE); + } + + $scope.templates = {}; + $scope.imported_templates = { data : '' }; + $scope.template_name = ''; + $scope.template_name_list = []; + + $scope.print_labels = function() { + $scope.save_locally(); + return egCore.print.print({ + context : $scope.print.template_context, + template : $scope.print.template_name, + scope : $scope.preview_scope, + }); + } + + $scope.template_changed = function() { + $scope.print.load_failed = false; + egCore.print.getPrintTemplate('item_label') + .then( + function(html) { + $scope.print.template_content = html; + }, + function() { + $scope.print.template_content = ''; + $scope.print.load_failed = true; + } + ); + egCore.print.getPrintTemplateContext('item_label') + .then(function(template_context) { + $scope.print.template_context = template_context; + }); + egCore.print.getPrintTemplate('item_label_cn') + .then( + function(html) { + $scope.print.cn_template_content = html; + }, + function() { + $scope.print.cn_template_content = ''; + $scope.print.load_failed = true; + } + ); + egCore.hatch.getItem('cat.printlabels.last_settings').then(function(s) { + if (s) { + $scope.preview_scope.settings = s; + } + }); + + } + + $scope.reset_to_default = function() { + egCore.print.removePrintTemplate( + 'item_label' + ); + egCore.print.removePrintTemplateContext( + 'item_label' + ); + egCore.print.removePrintTemplate( + 'item_label_cn' + ); + egCore.hatch.removeItem('cat.printlabels.last_settings'); + for (s in $scope.preview_scope.settings) { + $scope.preview_scope.settings[s] = undefined; + } + $scope.preview_scope.settings = {}; + egCore.org.settings($scope.org_unit_setting_list).then(function(res) { + $scope.preview_scope.settings = res; + }); + + $scope.template_changed(); + } + + $scope.save_locally = function() { + egCore.print.storePrintTemplate( + 'item_label', + $scope.print.template_content + ); + egCore.print.storePrintTemplateContext( + 'item_label', + $scope.print.template_context + ); + egCore.print.storePrintTemplate( + 'item_label_cn', + $scope.print.cn_template_content + ); + egCore.hatch.setItem('cat.printlabels.last_settings', $scope.preview_scope.settings); + } + + $scope.imported_print_templates = { data : '' }; + $scope.$watch('imported_templates.data', function(newVal, oldVal) { + if (newVal && newVal != oldVal) { + try { + var data = JSON.parse(newVal); + angular.forEach(data, function(el,k) { + $scope.templates[k] = { + content : el.content + ,context : el.context + ,cn_content : el.cn_content + ,settings : el.settings + }; + }); + $scope.saveTemplate(); + $scope.template_changed(); // refresh + ngToast.create(egCore.strings.PRINT_TEMPLATES_SUCCESS_IMPORT); + } catch (E) { + ngToast.warning(egCore.strings.PRINT_TEMPLATES_FAIL_IMPORT); + } + } + }); + + $scope.rendered_call_number_set = {}; + $scope.rendered_cn_key_by_copy_id = {}; + $scope.rebuild_cn_set = function() { + $timeout(function(){ + $scope.rendered_call_number_set = {}; + $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]; + 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.preview_scope.tickle = Date() + ' ' + Math.random(); + }); + } + + $scope.$watch('print.cn_template_content', function(newVal, oldVal) { + if (newVal && newVal != oldVal) { + $scope.rebuild_cn_set(); + } + }); + + $scope.$watch("preview_scope.settings['webstaff.cat.label.call_number_wrap_filter_height']", function(newVal, oldVal) { + if (newVal && newVal != oldVal) { + $scope.rebuild_cn_set(); + } + }); + + $scope.$watch("preview_scope.settings['webstaff.cat.label.call_number_wrap_filter_width']", function(newVal, oldVal) { + if (newVal && newVal != oldVal) { + $scope.rebuild_cn_set(); + } + }); + + $scope.current_tab = 'call_numbers'; + $scope.set_tab = function(tab) { + $scope.current_tab = tab; + } + +}]) + +// +.directive('egPrintTemplateOutput', ['$compile',function($compile) { + return function(scope, element, attrs) { + scope.$watch( + function(scope) { + return scope.$eval(attrs.content); + }, + function(value) { + // create an isolate scope and copy the print context + // data into the new scope. + // TODO: see also print security concerns in egHatch + var result = element.html(value); + var context = scope.$eval(attrs.context); + var print_scope = scope.$new(true); + angular.forEach(context, function(val, key) { + print_scope[key] = val; + }) + $compile(element.contents())(print_scope); + } + ); + }; +}]) + +.filter('cn_wrap', function() { + return function(input, w, h, wrap_type) { + var names; + var prefix = input[0]; + var callnum = input[1]; + var suffix = input[2]; + + 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'); + } else { + callnum = callnum.split(/\s+/).join('\t'); + } + + /* 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 ); + } + } else { + /* otherwise we're set */ + tb[j] = name; + } + } + } + j++; + } + return tb.join('\n'); + } +}) + +.filter('wrap', function() { + return function(input, w, wrap_type, indent) { + var output; + + if (!w) return input; + if (!indent) indent = ''; + + function wrap_on_space( + text, + length, + wrap_just_once, + if_cant_wrap_then_truncate, + idx + ) { + if (idx>10) { + console.log('possible infinite recursion, aborting'); + return ''; + } + if (String(text).length <= length) { + return text; + } else { + var truncated_text = String(text).substr(0,length); + var pivot_pos = truncated_text.lastIndexOf(' '); + var left_chunk = text.substr(0,pivot_pos).replace(/\s*$/,''); + var right_chunk = String(text).substr(pivot_pos+1); + + var wrapped_line; + if (left_chunk.length == 0) { + if (if_cant_wrap_then_truncate) { + wrapped_line = truncated_text; + } else { + wrapped_line = text; + } + } else { + wrapped_line = + left_chunk + '\n' + + indent + ( + wrap_just_once + ? right_chunk + : ( + right_chunk.length > length + ? wrap_on_space( + right_chunk, + length, + false, + if_cant_wrap_then_truncate, + idx+1) + : right_chunk + ) + ) + ; + } + return wrapped_line; + } + } + + switch(wrap_type) { + case 'once': + output = wrap_on_space(input,w,true,false,0); + break; + default: + output = wrap_on_space(input,w,false,false,0); + break; + } + + return output; + } +}) + diff --git a/Open-ILS/web/js/ui/default/staff/cat/volcopy/app.js b/Open-ILS/web/js/ui/default/staff/cat/volcopy/app.js index fce1e7ab7d..8399f72923 100644 --- a/Open-ILS/web/js/ui/default/staff/cat/volcopy/app.js +++ b/Open-ILS/web/js/ui/default/staff/cat/volcopy/app.js @@ -1586,11 +1586,30 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore , egNet.request( 'open-ils.cat', 'open-ils.cat.asset.volume.fleshed.batch.update.override', - egCore.auth.token(), cnList, 1, { auto_merge_vols : 1, create_parts : 1 } - ).then(function(update_count) { + egCore.auth.token(), cnList, 1, { auto_merge_vols : 1, create_parts : 1, return_copy_ids : 1 } + ).then(function(copy_ids) { if (and_exit) { $scope.dirty = false; - $timeout(function(){$window.close()}); + 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 + } + ).then(function(key) { + if (key) { + var url = egCore.env.basePath + 'cat/printlabels/' + key; + $timeout(function() { $window.open(url, '_blank') }).then( + function() { $timeout(function(){$window.close()}); } + ); + } else { + alert('Could not create anonymous cache key!'); + } + }); + } else { + $timeout(function(){$window.close()}); + } } }); } diff --git a/Open-ILS/web/js/ui/default/staff/services/print.js b/Open-ILS/web/js/ui/default/staff/services/print.js index de6e7663d6..03ea6b89f8 100644 --- a/Open-ILS/web/js/ui/default/staff/services/print.js +++ b/Open-ILS/web/js/ui/default/staff/services/print.js @@ -235,6 +235,10 @@ function($q , $window , $timeout , $http , egHatch , egAuth , egIDL , egOrg , eg return egHatch.setItem('eg.print.template.' + name, html); } + service.removePrintTemplate = function(name) { + return egHatch.removeItem('eg.print.template.' + name); + } + service.getPrintTemplateContext = function(name) { var deferred = $q.defer(); @@ -249,6 +253,9 @@ function($q , $window , $timeout , $http , egHatch , egAuth , egIDL , egOrg , eg service.storePrintTemplateContext = function(name, context) { return egHatch.setItem('eg.print.template_context.' + name, context); } + service.removePrintTemplateContext = function(name) { + return egHatch.removeItem('eg.print.template_context.' + name); + } return service; }])