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);
$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);
+ }
}
'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(
--- /dev/null
+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;
</div>
</div>
<div class="col-md-7">
+ <button class="btn btn-default pull-left" ng-click="reset_to_default()">[% l('Reset to Default') %]</button>
<button class="btn btn-default pull-left" ng-click="save_locally()">[% l('Save Locally') %]</button>
<div class="btn-group pull-right">
<span class="btn btn-default btn-file">
[% INCLUDE 'staff/cat/bucket/copy/t_grid_menu.tt2' %]
- <eg-grid-action label="[% l('Request Selected Copies') %]"
+ <eg-grid-action label="[% l('Remove Selected Copies from Bucket') %]" group="[% l('Bucket') %]"
+ handler="detachCopies"></eg-grid-action>
+ <eg-grid-action label="[% l('Request Selected Copies') %]" group="[% l('Items') %]"
handler="requestItems"></eg-grid-action>
- <eg-grid-action label="[% l('Edit Selected Copies') %]"
+ <eg-grid-action label="[% l('Edit Selected Copies') %]" group="[% l('Items') %]"
handler="spawnHoldingsEdit"></eg-grid-action>
- <eg-grid-action label="[% l('Remove Selected Copies from Bucket') %]"
- handler="detachCopies"></eg-grid-action>
- <eg-grid-action label="[% l('Transfer Selected Copies to Marked Volume') %]"
+ <eg-grid-action handler="print_labels" group="[% l('Show') %]"
+ label="[% l('Print Labels') %]"></eg-grid-action>
+ <eg-grid-action label="[% l('Transfer Selected Copies to Marked Volume') %]" group="[% l('Items') %]"
handler="transferCopies"></eg-grid-action>
- <eg-grid-action label="[% l('Delete Selected Copies from Catalog') %]"
+ <eg-grid-action label="[% l('Delete Selected Copies from Catalog') %]" group="[% l('Items') %]"
handler="deleteCopiesFromCatalog"></eg-grid-action>
<eg-grid-action label="[% l('Apply Tags') %]"
handler="applyTags"></eg-grid-action>
label="[% l('Triggered Events') %]"></eg-grid-action>
<eg-grid-action handler="selectedHoldingsItemStatusHolds" group="[% l('Show') %]"
label="[% l('Item Holds') %]"></eg-grid-action>
+ <eg-grid-action handler="selectedHoldingsPrintLabels" group="[% l('Show') %]"
+ label="[% l('Print Labels') %]"></eg-grid-action>
<eg-grid-action handler="selectedHoldingsDamaged" group="[% l('Mark') %]"
label="[% l('Item as Damaged') %]"></eg-grid-action>
label="[% l('Item Holds') %]"></eg-grid-action>
<eg-grid-action handler="showBibHolds" group="[% l('Show') %]"
label="[% l('Record Holds') %]"></eg-grid-action>
+ <eg-grid-action handler="print_labels" group="[% l('Show') %]"
+ label="[% l('Print Labels') %]"></eg-grid-action>
<eg-grid-action handler="selectedHoldingsDamaged" group="[% l('Mark') %]"
label="[% l('Item as Damaged') %]"></eg-grid-action>
--- /dev/null
+[%
+ WRAPPER "staff/base.tt2";
+ ctx.page_title = l("Print Item Labels");
+ ctx.page_app = "egPrintLabels";
+%]
+
+[% BLOCK APP_JS %]
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/grid.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/ui.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/file.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/eframe.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/cat/printlabels/app.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/cat/services/record.js"></script>
+<script>
+angular.module('egCoreMod').run(['egStrings', function(s) {
+ s.KEY_EXPIRED = "[% l('Key expired, please close this window; it no longer remembers which items you are printing labels for.') %]";
+ s.PRINT_LABEL_TEMPLATE_SUCCESS_SAVE = "[% l('Saved print label template(s)') %]";
+ s.PRINT_LABEL_TEMPLATE_SUCCESS_DELETE = "[% l('Deleted print label template') %]";
+}]);
+</script>
+[% END %]
+
+<style>
+</style>
+
+<div ng-view></div>
+
+[% END %]
+
+
--- /dev/null
+<style>
+ /* TODO: move me */
+ .print-template-text {
+ height: 36em;
+ width: 100%;
+ }
+ .cn-template-text {
+ height: 12em;
+ width: 100%;
+ }
+</style>
+
+<h2>[% l('Print Item Labels') %]</h2>
+
+<div class="row bg-info">
+ <div class="col-md-6">
+ <div class="row">
+ <div class="col-md-1">
+ <span class="h4">[% l('Template') %]</span>
+ </div>
+ <div class="col-md-5">
+ <eg-basic-combo-box list="template_name_list" selected="template_name"></eg-basic-combo-box>
+ </div>
+ <div class="col-md-1">
+ <button class="btn btn-default" ng-click="applyTemplate(template_name)">[% l('Apply') %]</button>
+ </div>
+ <div class="col-md-1">
+ <span class="h4">[% l('Printer') %]</span>
+ </div>
+ <div class="col-md-4">
+ <select class="form-control" ng-model="print.template_context">
+ <option value="default">[% l('Default') %]</option>
+ <option value="receipt">[% l('Receipt') %]</option>
+ <option value="label">[% l('Label') %]</option>
+ <option value="mail">[% l('Mail') %]</option>
+ <option value="offline">[% l('Offline') %]</option>
+ </select>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-2">
+ <div class="btn-group">
+ <button class="btn btn-default" ng-click="saveTemplate(template_name)">[% l('Save') %]</button>
+ <button class="btn btn-default" ng-click="deleteTemplate(template_name)">[% l('Delete') %]</button>
+ </div>
+ </div>
+ <div class="col-md-3">
+ <div class="btn-group">
+ <span class="btn btn-default btn-file">
+ [% l('Import') %]
+ <input type="file" eg-file-reader container="imported_templates.data">
+ </span>
+ <label class="btn btn-default"
+ eg-json-exporter container="templates"
+ default-file-name="'[% l('exported_label_templates.json') %]'">
+ [% l('Export') %]
+ </label>
+ <label class="btn btn-default" ng-click="reset_to_default()">[% l('Default') %]</button>
+ </div>
+ </div>
+ <div class="col-md-1 pull-right">
+ <button class="btn btn-default" ng-click="print_labels()">[% l('Print') %]</button>
+ </div>
+</div>
+
+<hr/>
+
+<div class="row">
+ <div class="col-md-5">
+ <ul class="nav nav-tabs">
+ <li ng-class="{active : current_tab == 'cn_template'}">
+ <a ng-click="set_tab('cn_template')">
+ [% l('Call Number Template') %]
+ </a>
+ </li>
+ <li ng-class="{active : current_tab == 'call_numbers'}">
+ <a ng-click="set_tab('call_numbers')">
+ [% l('Call Numbers') %]
+ </a>
+ </li>
+ <li ng-class="{active : current_tab == 'settings'}">
+ <a ng-click="set_tab('settings')">
+ [% l('Settings') %]
+ </a>
+ </li>
+ <li ng-class="{active : current_tab == 'template'}">
+ <a ng-click="set_tab('template')">
+ [% l('Label Template') %]
+ </a>
+ </li>
+ </ul>
+ <div class="tab-content">
+ <div class="tab-pane active">
+ <div ng-show="current_tab == 'cn_template'">
+ <h4>
+ [% l('Call Number Preview') %]
+ </h4>
+ <div eg-print-template-output ng-show="true"
+ content="print.cn_template_content"
+ context="{ copy : preview_scope.copies[0], get_cn_and_location_prefix : preview_scope.get_cn_and_location_prefix, get_cn_and_location_suffix : preview_scope.get_cn_and_location_suffix, settings : preview_scope.settings }"></div>
+ <h4>
+ [% l('Call Number Template') %]
+ </h4>
+ <div><span>[% l('Changes here will wipe out manual changes in the Call Numbers tab.') %]<br/></span></div>
+ <textarea ng-model="print.cn_template_content" class="print-template-text">
+ </textarea>
+ <div ng-repeat="copy in preview_scope.copies">
+ <div id="cn_for_copy_{{copy.id}}" eg-print-template-output ng-show="false"
+ content="print.cn_template_content"
+ context="{ copy : copy, get_cn_and_location_prefix : preview_scope.get_cn_and_location_prefix, get_cn_and_location_suffix : preview_scope.get_cn_and_location_suffix, settings : preview_scope.settings }"></div>
+ </div>
+ </div>
+ <div ng-show="current_tab == 'call_numbers'">
+ <h4>
+ [% l('Formatted Call Numbers') %]
+ </h4>
+ <div><span>[% l('Manual adjustments may be made here. These do not get saved with templates.') %]<br/></span></div>
+ <div ng-repeat="cn in rendered_call_number_set">
+ <textarea ng-model="cn.value" class="cn-template-text">
+ </textarea>
+ </div>
+ </div>
+ <div ng-show="current_tab == 'settings'">
+ <div><span>[% l('These settings do get saved with templates and will override corresponding Library Settings.') %]<br/></span></div>
+ <div ng-repeat="s in org_unit_settings">
+ <div class="row" style="margin-top: 5mm; border-top: solid thin black">
+ <div class="col-md-6" style="font-weight: bold">{{s.label}}</div>
+ <div class="col-md-6"><input type="text" ng-model="preview_scope.settings[s.name]"></input></div>
+ </div>
+
+ <div class="row">
+ <div>{{s.description}}</div>
+ </div>
+ </div>
+
+ </div>
+ <div ng-show="current_tab == 'template'">
+ <div ng-if="print.load_failed" class="alert alert-danger">
+ [% l(
+ "Unable to load template '[_1]'. The web server returned an error.",
+ '{{print.template_name}}')
+ %]
+ </div>
+ <div>
+ <textarea ng-model="print.template_content" class="print-template-text">
+ </textarea>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-7">
+ <h3>
+ [% l('Label Preview') %]
+ </h3>
+ <div eg-print-template-output
+ content="print.template_content"
+ context="preview_scope"></div>
+ </div> <!-- col -->
+</div>
+
</div>
</div>
<div class="col-md-2">
- <button class="btn btn-default pull-right" ng-click="clearWorking()" type="button">Clear</button>
+ <button class="btn btn-default pull-right" ng-click="clearWorking()" type="button">[% l('Clear') %]</button>
</div>
</div>
<div class="row pad-vert">
<div class="col-xs-12">
<label>
- <input type="checkbox" ng-change="saveDefaults()" ng-model="defaults.print_spine_labels"/>
- [% l('Print Spine Labels') %]
+ <input type="checkbox" ng-change="saveDefaults()" ng-model="defaults.print_item_labels"/>
+ [% l('Print Item Labels on Save & Exit') %]
</label>
</div>
</div>
--- /dev/null
+<!--
+Template for printing item labels (spine, pocket, etc.).
+
+Like receipt slip templates, this template uses AngularJS
+which fuses HTML and code together. The code portion is
+mostly used to bind data for the item labels being printed
+to various HTML elements, but you can also use code to
+perform conditional logic, transform the data, etc.
+
+-->
+<!--
+
+The <style> section is for holding most of our CSS, which
+is a language for controlling the appearance of HTML markup.
+
+The {{ and }} markers are similar to HTML's < and > characters,
+but are for separating AngularJS variables and code from the
+HTML itself.
+
+-->
+<style>
+ /* The .spine here defines a CSS "class", which in this case, is used by our
+ left label */
+ .spine {
+
+ /* this pulls from the "Item Print Label Font Family" setting, but will
+ default to 'monospace' */
+ font-family: {{settings['webstaff.cat.label.font.family'] || 'monospace'}};
+
+ /* this pulls from the "Item Print Label Font Size" setting, but will
+ default to 'normal' */
+ font-size: {{settings['webstaff.cat.label.font.size'] || '10'}};
+
+ /* this pulls from the "Item Print Label Font Weight" setting, but will
+ default to 'normal' */
+ font-weight: {{settings['webstaff.cat.label.font.weight'] || 'normal'}};
+
+ /* this pulls from the "Item Print Label - Height for Left Label"
+ setting, but will default to '1.25in' */
+ height: {{settings['webstaff.cat.label.left_label.height'] || '1.25in'}};
+ min-height: {{settings['webstaff.cat.label.left_label.height'] || '1.25in'}};
+ max-height: {{settings['webstaff.cat.label.left_label.height'] || '1.25in'}};
+
+ /* this pulls from the "Item Print Label - Width for Left Label"
+ setting, but will default to '1in' */
+ width: {{settings['webstaff.cat.label.left_label.width'] || '1in'}};
+ min-width: {{settings['webstaff.cat.label.left_label.width'] || '1in'}};
+ max-width: {{settings['webstaff.cat.label.left_label.width'] || '1in'}};
+
+ /* this pulls from the "Item Print Label - Left Margin for Left Label"
+ setting, but will default to '0in' */
+ margin-left: {{settings['webstaff.cat.label.left_label.left_margin'] || '0in'}};
+ }
+
+ /* This CSS class is used by our right label */
+ .pocket {
+
+ /* this pulls from the "Item Print Label Font Family" setting, but will
+ default to 'monospace' */
+ font-family: {{settings['webstaff.cat.label.font.family'] || 'monospace'}};
+
+ /* this pulls from the "Item Print Label Font Size" setting, but will
+ default to 'normal' */
+ font-size: {{settings['webstaff.cat.label.font.size'] || '10'}};
+
+ /* this pulls from the "Item Print Label Font Weight" setting, but will
+ default to 'normal' */
+ font-weight: {{settings['webstaff.cat.label.font.weight'] || 'normal'}};
+
+ /* this pulls from the "Item Print Label - Height for Left Label"
+ setting, but will default to '1.25in' */
+ height: {{settings['webstaff.cat.label.right_label.height'] || '1.25in'}};
+ min-height: {{settings['webstaff.cat.label.right_label.height'] || '1.25in'}};
+ max-height: {{settings['webstaff.cat.label.right_label.height'] || '1.25in'}};
+
+ /* this pulls from the "Item Print Label - Width for Left Label"
+ setting, but will default to '2.625in' */
+ width: {{settings['webstaff.cat.label.right_label.width'] || '2.625in'}};
+ min-width: {{settings['webstaff.cat.label.right_label.width'] || '2.625in'}};
+ max-width: {{settings['webstaff.cat.label.right_label.width'] || '2.625in'}};
+
+ /* this pulls from the "Item Print Label - Left Margin for Left Label"
+ setting, but will default to '0in' */
+ margin-left: {{settings['webstaff.cat.label.right_label.left_margin'] || '0in'}};
+
+ }
+
+ /* This is to help mitigate artifacts in the Preview pane which don't
+ actually print */
+ .labels ::-webkit-scrollbar {
+ display: none;
+ }
+
+ /* This pulls from the "Item Print Label - Inline CSS" setting */
+ {{settings['webstaff.cat.label.inline_css']||''}}
+
+</style>
+
+<!-- Here we are implementing our combined label as 2-column HTML <table>, with
+ each table containing a <pre> tag for preserving whitespace and linefeeds.
+
+ The ng-repeat attribute is from AngularJS, and in this case is looping
+ through a list of all the items that were selected when the Print Label
+ interface was invoked. Each iteration puts item data into the variable
+ "copy", which may be referenced in the HTML by escaping it with {{ and }}
+
+ The following are available, and you may treat these similar to the
+ "macros" in earlier versions of Evergreen:
+
+ copy['active_date']
+ copy['age_protect']
+ copy['alert_message']
+ copy['barcode']
+ copy['call_number.copies']
+ copy['call_number.create_date']
+ copy['call_number.deleted']
+ copy['call_number.edit_date']
+ copy['call_number.id']
+ copy['call_number.label']
+ copy['call_number.label_class']
+ copy['call_number.label_sortkey']
+ copy['call_number.notes']
+ copy['call_number.owning_lib']
+ copy['call_number.prefix.id']
+ copy['call_number.prefix.label']
+ copy['call_number.prefix.label_sortkey']
+ copy['call_number.prefix.owning_lib']
+ copy['call_number.record.active']
+ copy['call_number.record.author_field_entries']
+ copy['call_number.record.call_numbers']
+ copy['call_number.record.create_date']
+ copy['call_number.record.creator.ws_ou']
+ copy['call_number.record.deleted']
+ copy['call_number.record.edit_date']
+ copy['call_number.record.fingerprint']
+ copy['call_number.record.fixed_fields']
+ copy['call_number.record.full_record_entries']
+ copy['call_number.record.id']
+ copy['call_number.record.identifier_field_entries']
+ copy['call_number.record.keyword_field_entries']
+ copy['call_number.record.language']
+ copy['call_number.record.last_xact_id']
+ copy['call_number.record.marc']
+ copy['call_number.record.metarecord']
+ copy['call_number.record.notes']
+ copy['call_number.record.owner']
+ copy['call_number.record.quality']
+ copy['call_number.record.series_field_entries']
+ copy['call_number.record.share_depth']
+ copy['call_number.record.simple_record.author']
+ copy['call_number.record.simple_record.fingerprint']
+ copy['call_number.record.simple_record.id']
+ copy['call_number.record.simple_record.isbn']
+ copy['call_number.record.simple_record.issn']
+ copy['call_number.record.simple_record.pubdate']
+ copy['call_number.record.simple_record.publisher']
+ copy['call_number.record.simple_record.quality']
+ copy['call_number.record.simple_record.tcn_source']
+ copy['call_number.record.simple_record.tcn_value']
+ copy['call_number.record.simple_record.title']
+ copy['call_number.record.source']
+ copy['call_number.record.subject_field_entries']
+ copy['call_number.record.tcn_source']
+ copy['call_number.record.tcn_value']
+ copy['call_number.record.title_field_entries']
+ copy['call_number.suffix.id']
+ copy['call_number.suffix.label']
+ copy['call_number.suffix.label_sortkey']
+ copy['call_number.suffix.owning_lib']
+ copy['call_number.uri_maps']
+ copy['call_number.uris']
+ copy['circ_as_type']
+ copy['circ_lib']
+ copy['circ_modifier']
+ copy['circulate']
+ copy['copy_number']
+ copy['cost']
+ copy['create_date']
+ copy['deleted']
+ copy['deposit']
+ copy['deposit_amount']
+ copy['dummy_author']
+ copy['dummy_isbn']
+ copy['dummy_title']
+ copy['edit_date']
+ copy['fine_level']
+ copy['floating']
+ copy['holdable']
+ copy['id']
+ copy['loan_duration']
+ copy['location.checkin_alert']
+ copy['location.circulate']
+ copy['location.copies']
+ copy['location.deleted']
+ copy['location.holdable']
+ copy['location.hold_verify']
+ copy['location.id']
+ copy['location.label_prefix']
+ copy['location.label_suffix']
+ copy['location.name']
+ copy['location.opac_visible']
+ copy['location.orders']
+ copy['location.owning_lib']
+ copy['mint_condition']
+ copy['opac_visible']
+ copy['price']
+ copy['ref']
+ copy['status_changed_time']
+ copy['status.copy_active']
+ copy['status.holdable']
+ copy['status.id']
+ copy['status.is_available']
+ copy['status.name']
+ copy['status.opac_visible']
+ copy['status.restrict_copy_delete']
+
+ There are also two functions available. The following pulls manually
+ edited call numbers for a given item:
+
+ get_cn_for(copy)
+
+ And this one pulls bibliographic data for a given item:
+
+ get_bib_for(copy)
+
+ It returns a data structure similar to "copy" that has the following fields:
+
+ get_bib_for(copy)['author']
+ get_bib_for(copy)['copy_count']
+ get_bib_for(copy)['doc_id']
+ get_bib_for(copy)['doc_type']
+ get_bib_for(copy)['edition']
+ get_bib_for(copy)['isbn']
+ get_bib_for(copy)['physical_description']
+ get_bib_for(copy)['pubdate']
+ get_bib_for(copy)['publisher']
+ get_bib_for(copy)['series.0']
+ get_bib_for(copy)['synopsis']
+ get_bib_for(copy)['tcn']
+ get_bib_for(copy)['title']
+ get_bib_for(copy)['toc']
+ get_bib_for(copy)['types_of_resource.0']
+
+ Finally, there are filter functions which can be used to modify or transform
+ data being outputted. For example, consider the following:
+
+ get_bib_for(copy)['title'] | limitTo:28
+
+ This would show up to the first 28 characters for an item's title and
+ truncate the rest. Now, this:
+
+ get_bib_for(copy)['title'] | wrap:28
+
+ This would try to the wrap the item's title every 28 characters.
+
+ get_bib_for(copy)['title'] | wrap:28:multi:' '
+
+ This does the same thing but indents subsequent lines with 2 spaces each.
+
+ get_bib_for(copy)['title'] | wrap:28:once:' '
+
+ This wraps the title just once, prefixes the second line with two spaces,
+ and truncates anything after the 2nd line.
+
+-->
+
+<table class="labels" style="page-break-after: always;" ng-repeat="copy in copies"><tr valign="top"><td>
+
+<!-- Spine Label contents -->
+<pre class="spine" style="border:none" ng-show="true">
+{{get_cn_for(copy)}}
+</pre>
+
+</td><td>
+
+<!-- Pocket Label contents -->
+<pre class="pocket" style="border:none" ng-show="true">
+{{copy.barcode}}
+{{copy['call_number.label']}}
+{{get_bib_for(copy).author }}
+{{get_bib_for(copy).title | wrap:28:'once':' '}}
+</pre>
+
+</td></tr></table>
+
--- /dev/null
+<pre>
+{{
+ [
+ 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']
+}}
+</pre>
});
}
+ $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,
});
}
+ $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) {
);
}
+ $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() {
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() };
--- /dev/null
+/**
+ * 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;
+ }
+})
+
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()});
+ }
}
});
}
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();
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;
}])