1 angular.module('egSerialsAppDep')
3 .directive('egPredictionWizard', function() {
13 templateUrl: './serials/t_prediction_wizard',
15 ['$scope','$q','egSerialsCoreSvc','egCore','egGridDataProvider',
16 function($scope , $q , egSerialsCoreSvc , egCore , egGridDataProvider) {
18 $scope.tab = { active : 0 };
19 if (angular.isUndefined($scope.showShare)) {
20 $scope.showShare = true;
22 if (angular.isUndefined($scope.viewOnly)) {
23 $scope.viewOnly = false;
26 // for use by ng-value
30 // class for MARC21 serial prediction pattern
31 // TODO move elsewhere
32 function PredictionPattern(patternCode) {
34 this.use_enum = false;
35 this.use_alt_enum = false;
36 this.use_chron = false;
37 this.use_alt_chron = false;
38 this.use_calendar_changes = false;
39 this.calendar_change = [];
40 this.compress_expand = '3';
41 this.caption_evaluation = '0';
42 this.enum_levels = [];
43 this.alt_enum_levels = [];
44 this.chron_levels = [];
45 this.alt_chron_levels = [{ caption : null, display_caption: false }];
46 this.frequency_type = 'preset';
47 this.use_regularity = false;
53 'p' : 'pieces_per_issuance',
57 var enum_level_map = {
65 var alt_enum_level_map = {
69 var chron_level_map = {
75 var alt_chron_level_map = {
79 var curr_enum_level = -1;
80 var curr_alt_enum_level = -1;
81 var curr_chron_level = -1;
82 var curr_alt_chron_level = -1;
83 if (patternCode && patternCode.length > 2 && (patternCode.length % 2 == 0)) {
84 // set indicator values
85 this.compress_expand = patternCode[0];
86 this.caption_evaluation = patternCode[1];
87 for (var i = 2; i < patternCode.length; i += 2) {
88 var sf = patternCode[i];
89 var value = patternCode[i + 1];
90 if (sf in nr_sf_map) {
91 this[nr_sf_map[sf]] = value;
94 if (sf in enum_level_map) {
96 curr_enum_level = enum_level_map[sf];
97 this.enum_levels[curr_enum_level] = {
103 if (sf in alt_enum_level_map) {
104 this.use_enum = true;
105 this.use_alt_enum = true;
106 curr_enum_level = -1;
107 curr_alt_enum_level = alt_enum_level_map[sf];
108 this.alt_enum_levels[curr_alt_enum_level] = {
114 if (sf in chron_level_map) {
115 this.use_chron = true;
116 curr_chron_level = chron_level_map[sf];
118 if (value.match(/^\(.*\)$/)) {
119 chron.display_caption = false;
120 chron.caption = value.replace(/^\(/, '').replace(/\)$/, '');
122 chron.display_caption = true;
123 chron.caption = value;
125 this.chron_levels[curr_chron_level] = chron;
128 if (sf in alt_chron_level_map) {
129 this.use_alt_chron = true;
130 curr_chron_level = -1;
131 curr_alt_chron_level = alt_chron_level_map[sf];
133 if (value.match(/^\(.*\)$/)) {
134 chron.display_caption = false;
135 chron.caption = value.replace(/^\(/, '').replace(/\)$/, '');
137 chron.display_caption = true;
138 chron.caption = value;
140 this.alt_chron_levels[curr_alt_chron_level] = chron;
148 if (value == 'und' || value == 'var') {
150 } else if (!isNaN(parseInt(value))) {
151 units.value = parseInt(value);
153 continue; // escape garbage
155 if (curr_enum_level > 0) {
156 this.enum_levels[curr_enum_level].units_per_next_higher = units;
157 } else if (curr_alt_enum_level > 0) {
158 this.alt_enum_levels[curr_alt_enum_level].units_per_next_higher = units;
161 if (sf == 'v' && value == 'r') {
162 if (curr_enum_level > 0) {
163 this.enum_levels[curr_enum_level].restart = true;
164 } else if (curr_alt_enum_level > 0) {
165 this.alt_enum_levels[curr_alt_enum_level].restart = true;
169 if (curr_enum_level > -1) {
170 this.enum_levels[curr_enum_level].numbering_scheme = value;
171 } else if (curr_alt_enum_level > -1) {
172 this.alt_enum_levels[curr_alt_enum_level].numbering_scheme = value;
176 this.use_calendar_change = true;
177 value.split(',').forEach(function(chg) {
178 var calendar_change = {
184 if (chg.length == 2) {
186 calendar_change.type = 'season';
187 calendar_change.season = chg;
189 calendar_change.type = 'month';
190 calendar_change.month = chg;
192 } else if (chg.length == 4) {
193 calendar_change.type = 'date';
194 calendar_change.month = chg.substring(0, 2);
195 calendar_change.day = chg.substring(2, 4);
197 self.calendar_change.push(calendar_change);
201 this.use_regularity = true;
202 var regularity_type = value.substring(0, 1);
204 var chron_type = value.substring(1, 2);
205 value.substring(2).split(/,/).forEach(function(value) {
207 if (regularity_type == 'c') {
208 piece.combined_code = value;
209 } else if (chron_type == 'd') {
210 if (value.match(/^\d\d$/)) {
211 piece.sub_type = 'day_of_month';
212 piece.day_of_month = value;
213 } else if (value.match(/^\d\d\d\d$/)) {
214 piece.sub_type = 'specific_date';
215 piece.specific_date = value;
217 piece.sub_type = 'day_of_week';
218 piece.day_of_week = value;
220 } else if (chron_type == 'm') {
221 piece.sub_type = 'month';
223 } else if (chron_type == 's') {
224 piece.sub_type = 'season';
225 piece.season = value;
226 } else if (chron_type == 'w') {
227 if (value.match(/^\d\d\d\d$/)) {
228 piece.sub_type = 'week_in_month';
229 piece.week = value.substring(0, 2);
230 piece.month = value.substring(2, 4);
231 } else if (value.match(/^\d\d[a-z][a-z]$/)) {
232 piece.sub_type = 'week_day';
233 piece.week = value.substring(0, 2);
234 piece.day = value.substring(2, 4);
235 } else if (value.length == 6) {
236 piece.sub_type = 'week_day_in_month';
237 piece.month = value.substring(0, 2);
238 piece.week = value.substring(2, 4);
239 piece.day = value.substring(4, 6);
241 } else if (chron_type == 'y') {
242 piece.sub_type = 'year';
247 self.regularity.push({
248 regularity_type : regularity_type,
249 chron_type : chron_type,
256 if (self.frequency) {
257 if (self.frequency.match(/^\d+$/)) {
258 self.frequency_type = 'numeric';
259 self.frequency_numeric = self.frequency;
261 self.frequency_type = 'preset';
262 self.frequency_preset = self.frequency;
266 // return current pattern compiled to subfield list
267 this.compile = function() {
268 var patternCode = [];
269 patternCode.push(self.compress_expand);
270 patternCode.push(self.caption_evaluation);
271 patternCode.push('8');
272 patternCode.push(self.link);
274 for (var i = 0; i < self.enum_levels.length; i++) {
275 patternCode.push(['a', 'b', 'c', 'd', 'e', 'f'][i]);
276 patternCode.push(self.enum_levels[i].caption);
277 if (i > 0 && self.enum_levels[i].units_per_next_higher) {
278 patternCode.push('u');
279 if (self.enum_levels[i].units_per_next_higher.type == 'number') {
280 patternCode.push(self.enum_levels[i].units_per_next_higher.value.toString());
282 patternCode.push(self.enum_levels[i].units_per_next_higher.type);
285 if (i > 0 && self.enum_levels[i].restart != null) {
286 patternCode.push('v');
287 patternCode.push(self.enum_levels[i].restart ? 'r' : 'c');
291 if (self.use_enum && self.use_alt_enum) {
292 for (var i = 0; i < self.alt_enum_levels.length; i++) {
293 patternCode.push(['g','h'][i]);
294 patternCode.push(self.alt_enum_levels[i].caption);
295 if (i > 0 && self.alt_enum_levels[i].units_per_next_higher) {
296 patternCode.push('u');
297 if (self.alt_enum_levels[i].units_per_next_higher.type == 'number') {
298 patternCode.push(self.alt_enum_levels[i].units_per_next_higher.value);
300 patternCode.push(self.alt_enum_levels[i].units_per_next_higher.type);
303 if (i > 0 && self.alt_enum_levels[i].restart != null) {
304 patternCode.push('v');
305 patternCode.push(self.alt_enum_levels[i].restart ? 'r' : 'c');
309 var chron_sfs = (self.use_enum) ? ['i', 'j', 'k', 'l'] : ['a', 'b', 'c', 'd'];
310 if (self.use_chron) {
311 for (var i = 0; i < self.chron_levels.length; i++) {
312 patternCode.push(chron_sfs[i],
313 self.chron_levels[i].display_caption ?
314 self.chron_levels[i].caption :
315 '(' + self.chron_levels[i].caption + ')'
319 var alt_chron_sf = (self.use_enum) ? 'm' : 'g';
320 if (self.use_alt_chron) {
321 patternCode.push(alt_chron_sf,
322 self.alt_chron_levels[0].display_caption ?
323 self.alt_chron_levels[0].caption :
324 '(' + self.alt_chron_levels[0].caption + ')'
328 patternCode.push('w',
329 self.frequency_type == 'numeric' ?
330 self.frequency_numeric :
331 self.frequency_preset
334 if (self.use_enum && self.use_calendar_change) {
335 patternCode.push('x');
336 patternCode.push(self.calendar_change.map(function(chg) {
337 if (chg.type == 'season') {
339 } else if (chg.type == 'month') {
341 } else if (chg.type == 'date') {
342 return chg.month + chg.day;
347 if (self.use_regularity) {
348 self.regularity.forEach(function(reg) {
349 patternCode.push('y');
350 var val = reg.regularity_type + reg.chron_type;
351 val += reg.parts.map(function(part) {
352 if (reg.regularity_type == 'c') {
353 return part.combined_code;
354 } else if (reg.chron_type == 'd') {
355 return part[part.sub_type];
356 } else if (reg.chron_type == 'm') {
358 } else if (reg.chron_type == 'w') {
359 if (part.sub_type == 'week_in_month') {
360 return part.week + part.month;
361 } else if (part.sub_type == 'week_day') {
362 return part.week + part.day;
363 } else if (part.sub_type == 'week_day_in_month') {
364 return part.month + part.week + part.day;
366 } else if (reg.chron_type == 's') {
368 } else if (reg.chron_type == 'y') {
372 patternCode.push(val);
378 this.compile_stringify = function() {
379 return JSON.stringify(this.compile(), null, 2);
382 this.add_enum_level = function() {
383 if (self.enum_levels.length < 6) {
384 self.enum_levels.push({
386 units_per_next_higher : { type : 'und' },
391 this.drop_enum_level = function() {
392 if (self.enum_levels.length > 1) {
393 self.enum_levels.pop();
397 this.add_alt_enum_level = function() {
398 if (self.alt_enum_levels.length < 2) {
399 self.alt_enum_levels.push({
401 units_per_next_higher : { type : 'und' },
406 this.drop_alt_enum_level = function() {
407 if (self.alt_enum_levels.length > 1) {
408 self.alt_enum_levels.pop();
411 this.remove_calendar_change = function(idx) {
412 if (self.calendar_change.length > idx) {
413 self.calendar_change.splice(idx, 1);
416 this.add_calendar_change = function() {
417 self.calendar_change.push({
425 this.add_chron_level = function() {
426 if (self.chron_levels.length < 4) {
427 self.chron_levels.push({
429 display_caption : false
433 this.drop_chron_level = function() {
434 if (self.chron_levels.length > 1) {
435 self.chron_levels.pop();
438 this.add_regularity = function() {
439 self.regularity.push({
440 regularity_type : null,
442 parts : [{ sub_type : null }]
445 this.remove_regularity = function(idx) {
446 if (self.regularity.length > idx) {
447 self.regularity.splice(idx, 1);
449 // and add a blank entry back if need be
450 if (self.regularity.length == 0) {
451 self.add_regularity();
454 this.add_regularity_part = function(reg) {
459 this.remove_regularity_part = function(reg, idx) {
460 if (reg.parts.length > idx) {
461 reg.parts.splice(idx, 1);
463 // and add a blank entry back if need be
464 if (reg.parts.length == 0) {
465 self.add_regularity_part(reg);
469 this.display_enum_captions = function() {
470 return self.enum_levels.map(function(lvl) {
474 this.display_alt_enum_captions = function() {
475 return self.alt_enum_levels.map(function(lvl) {
479 this.display_chron_captions = function() {
480 return self.chron_levels.map(function(lvl) {
484 this.display_alt_chron_captions = function() {
485 return self.alt_chron_levels.map(function(lvl) {
491 // starting from scratch, ensure there's
492 // enough so that the input wizard can be used
493 this.use_enum = true;
494 this.use_chron = true;
496 self.add_enum_level();
497 self.add_alt_enum_level();
498 self.add_chron_level();
499 self.add_calendar_change();
500 self.add_regularity();
502 // fill in potential missing bits
503 if (!self.use_enum && self.enum_levels.length == 0) self.add_enum_level();
504 if (!self.use_alt_enum && self.alt_enum_levels.length == 0) self.add_alt_enum_level();
505 if (!self.use_chron && self.chron_levels.length == 0) self.add_chron_level();
506 if (!self.use_calendar_change) self.add_calendar_change();
507 if (!self.use_regularity) self.add_regularity();
512 if ($scope.patternCode) {
513 $scope.pattern = new PredictionPattern(JSON.parse($scope.patternCode));
515 $scope.pattern = new PredictionPattern();
524 $scope.chron_captions = [];
525 $scope.alt_chron_captions = [];
527 $scope.handle_save = function() {
528 $scope.patternCode = JSON.stringify($scope.pattern.compile());
529 if ($scope.share.pattern_name !== null) {
530 var spt = new egCore.idl.spt();
531 spt.name($scope.share.pattern_name);
532 spt.pattern_code($scope.patternCode);
533 spt.share_depth($scope.share.depth);
534 spt.owning_lib(egCore.auth.user().ws_ou());
535 egCore.pcrud.create(spt).then(function() {
536 if (angular.isFunction($scope.onSave)) {
537 $scope.onSave($scope.patternCode);
541 if (angular.isFunction($scope.onSave)) {
542 $scope.onSave($scope.patternCode);
551 .directive('egChronSelector', function() {
558 linkedSelector : '=',
560 templateUrl: './serials/t_chron_selector',
562 ['$scope','$q','egCore',
563 function($scope , $q , egCore) {
565 { value : 'year', label : egCore.strings.CHRON_LABEL_YEAR, disabled: false },
566 { value : 'season', label : egCore.strings.CHRON_LABEL_SEASON, disabled: false },
567 { value : 'month', label : egCore.strings.CHRON_LABEL_MONTH, disabled: false },
568 { value : 'week', label : egCore.strings.CHRON_LABEL_WEEK, disabled: false },
569 { value : 'day', label : egCore.strings.CHRON_LABEL_DAY, disabled: false },
570 { value : 'hour', label : egCore.strings.CHRON_LABEL_HOUR, disabled: false }
580 $scope.$watch('ngModel', function(newVal, oldVal) {
581 $scope.linkedSelector[$scope.chronLevel] = $scope.ngModel;
583 $scope.$watch('linkedSelector', function(newVal, oldVal) {
584 if ($scope.chronLevel > 0 && $scope.linkedSelector[$scope.chronLevel - 1]) {
585 var level_to_disable = levels[ $scope.linkedSelector[$scope.chronLevel - 1] ];
586 for (var i = 0; i < $scope.options.length; i++) {
587 $scope.options[i].disabled =
588 (levels[ $scope.options[i].value ] <= level_to_disable);
596 .directive('egMonthSelector', function() {
603 templateUrl: './serials/t_month_selector',
606 function($scope , $q) {
611 .directive('egSeasonSelector', function() {
618 templateUrl: './serials/t_season_selector',
621 function($scope , $q) {
626 .directive('egWeekInMonthSelector', function() {
633 templateUrl: './serials/t_week_in_month_selector',
636 function($scope , $q) {
641 .directive('egDayOfWeekSelector', function() {
648 templateUrl: './serials/t_day_of_week_selector',
651 function($scope , $q) {
656 .directive('egMonthDaySelector', function() {
664 templateUrl: './serials/t_month_day_selector',
667 function($scope , $q) {
668 if ($scope.month == null) $scope.month = '01';
669 if ($scope.day == null) $scope.day = '01';
670 $scope.dt = new Date(2012, parseInt($scope.month) - 1, parseInt($scope.day), 1);
674 datepickerMode : 'day',
676 // use a leap year, though any publisher who uses 29 February as a
677 // calendar change is simply trolling
678 // also note that when https://github.com/angular-ui/bootstrap/issues/1993
679 // is fixed, setting minDate and maxDate would make sense, as
680 // user wouldn't be able to keeping hit the left or right arrows
681 // past the end of the range
682 // minDate : new Date('2012-01-01 00:00:01'),
683 // maxDate : new Date('2012-12-31 23:59:59'),
684 formatDayTitle : 'MMMM',
686 $scope.datePickerIsOpen = false;
687 $scope.$watch('dt', function(newVal, oldVal) {
688 if (newVal != oldVal) {
689 $scope.day = ('00' + $scope.dt.getDate() ).slice(-2);
690 $scope.month = ('00' + ($scope.dt.getMonth() + 1)).slice(-2);
697 .directive('egPredictionPatternSummary', function() {
704 templateUrl: './serials/t_pattern_summary',
707 function($scope , $q) {