1 import {Component, ViewChild, Input, Output, OnInit, EventEmitter} from '@angular/core';
2 import {IdlService, IdlObject} from '@eg/core/idl.service';
3 import {PcrudService} from '@eg/core/pcrud.service';
4 import {DialogComponent} from '@eg/share/dialog/dialog.component';
5 import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
6 import {MarcEditorDialogComponent} from './editor-dialog.component';
7 import {ComboboxComponent, ComboboxEntry} from '@eg/share/combobox/combobox.component';
10 * 007 Physical Characteristics Dialog
12 * Note the dialog does not many direct changes to the bib field.
13 * It simply emits the new value on close, or null of the
18 selector: 'eg-phys-char-dialog',
19 templateUrl: './phys-char-dialog.component.html'
22 export class PhysCharDialogComponent
23 extends DialogComponent implements OnInit {
26 @Input() fieldData = '';
30 selectorLabel: string = null;
31 selectorValue: string;
32 selectorOptions: ComboboxEntry[] = [];
34 typeMap: ComboboxEntry[] = [];
36 sfMap: {[ptypeKey: string]: any[]} = {};
37 valueMap: {[ptypeKey: string]: ComboboxEntry[]} = {};
41 // step is the 1-based position in the list of data slots for the
42 // currently selected type. step==0 means we are currently selecting
46 // size and offset of the slot we're currently editing; this is
47 // maintained as a convenience for the highlighting of the currently
53 private modal: NgbModal,
54 private idl: IdlService,
55 private pcrud: PcrudService) {
60 this.onOpen$.subscribe(_ => {
61 this.initialValue = this.fieldData;
66 // Chop the field data value into 3 parts, before, middle, and
67 // after, where 'middle' is the part we're currently editing.
68 splitFieldData(): string[] {
69 const data = this.fieldData;
71 data.substring(0, this.slotOffset),
72 data.substring(this.slotOffset, this.slotOffset + this.slotSize),
73 data.substring(this.slotOffset + this.slotSize)
77 setValuesForStep(): Promise<any> {
80 if (this.step === 0) {
81 promise = this.getPhysCharTypeMap();
83 promise = this.currentSubfield().then(
84 subfield => this.getPhysCharValueMap(subfield.id()));
87 return promise.then(list => {
88 this.selectorOptions = list;
89 this.setSelectedOptionFromField();
90 this.setLabelForStep();
95 if (this.step === 0) {
96 this.selectorLabel = null; // fall back to template value
98 this.currentSubfield().then(sf => this.selectorLabel = sf.label());
102 getStepSlot(): Promise<any[]> {
103 if (this.step === 0) { return Promise.resolve([0, 1]); }
104 return this.currentSubfield()
105 .then(sf => [sf.start_pos(), sf.length()]);
108 setSelectedOptionFromField() {
109 this.getStepSlot().then(slot => {
110 this.slotOffset = slot[0];
111 this.slotSize = slot[1];
113 String.prototype.substr.apply(this.fieldData, slot) || ' ';
117 isLastStep(): boolean {
118 // This one is called w/ every digest, so avoid async
119 // calls. Wait until we have loaded the current ptype
120 // subfields to determine if this is the last step.
123 this.sfMap[this.currentPtype] &&
124 this.sfMap[this.currentPtype].length === this.step
130 if (this.step === 0) {
131 this.currentPtype = this.selectorValue;
132 this.fieldData = this.selectorValue; // total reset
135 this.getStepSlot().then(slot => {
137 let value = this.fieldData;
138 const offset = slot[0];
139 const size = slot[1];
140 while (value.length < (offset + size)) { value += ' '; }
142 // Apply the value to the field in the required slot,
143 // then delete all data after "here", since those values
144 // no longer make sense.
145 const before = value.substr(0, offset);
146 this.fieldData = before + this.selectorValue.padEnd(size, ' ');
147 this.slotOffset = offset;
148 this.slotSize = size;
155 this.setValuesForStep();
160 this.setValuesForStep();
163 currentSubfield(): Promise<any> {
164 return this.getPhysCharSubfieldMap(this.currentPtype)
165 .then(sfList => sfList[this.step - 1]);
168 reset(clear?: boolean) {
172 this.fieldData = clear ? ' ' : this.initialValue;
173 this.currentPtype = this.fieldData.substr(0, 1);
174 this.setValuesForStep();
177 getPhysCharTypeMap(): Promise<ComboboxEntry[]> {
178 if (this.typeMap.length) {
179 return Promise.resolve(this.typeMap);
182 return this.pcrud.retrieveAll(
183 'cmpctm', {order_by: {cmpctm: 'label'}}, {atomic: true})
184 .toPromise().then(maps => {
185 return this.typeMap = maps.map(
186 map => ({id: map.ptype_key(), label: map.label()}));
190 getPhysCharSubfieldMap(ptypeKey: string): Promise<IdlObject[]> {
192 if (this.sfMap[ptypeKey]) {
193 return Promise.resolve(this.sfMap[ptypeKey]);
196 return this.pcrud.search('cmpcsm',
197 {ptype_key : ptypeKey},
198 {order_by : {cmpcsm : ['start_pos']}},
200 ).toPromise().then(maps => this.sfMap[ptypeKey] = maps);
203 getPhysCharValueMap(ptypeSubfield: string): Promise<ComboboxEntry[]> {
205 if (this.valueMap[ptypeSubfield]) {
206 return Promise.resolve(this.valueMap[ptypeSubfield]);
209 return this.pcrud.search('cmpcvm',
210 {ptype_subfield : ptypeSubfield},
211 {order_by : {cmpcsm : ['value']}},
213 ).toPromise().then(maps =>
214 this.valueMap[ptypeSubfield] = maps.map(
215 map => ({id: map.value(), label: map.label()}))