]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/eg2/src/app/staff/share/marc-edit/marcrecord.ts
LP1852782 MARC editor authority linking support
[working/Evergreen.git] / Open-ILS / src / eg2 / src / app / staff / share / marc-edit / marcrecord.ts
1 import {EventEmitter} from '@angular/core';
2
3 /* Wrapper class for our external MARC21.Record JS library. */
4
5 declare var MARC21;
6
7 // MARC breaker delimiter
8 const DELIMITER = '$';
9
10 export interface MarcSubfield    // code, value, position
11     extends Array<string|number> { 0: string; 1: string; 2: number; }
12
13 // Only contains the attributes/methods we need so far.
14 export interface MarcField {
15     fieldId?: number;
16     data?: string;
17     tag?: string;
18     ind1?: string;
19     ind2?: string;
20     subfields?: MarcSubfield[];
21
22     // For authority validation
23     authValid: boolean;
24     authChecked: boolean;
25
26     // Fields are immutable when it comes to controlfield vs.
27     // data field.  Stamp the value when stamping field IDs.
28     isCtrlField: boolean;
29
30     // Pass-through to marcrecord.js
31     isControlfield(): boolean;
32
33     deleteExactSubfields(...subfield: MarcSubfield[]): number;
34 }
35
36 export class MarcRecord {
37
38     id: number; // Database ID when known.
39     deleted: boolean;
40     record: any; // MARC21.Record object
41     breakerText: string;
42
43     // Let clients know some fixed field shuffling may have occured.
44     // Emits the fixed field code.
45     fixedFieldChange: EventEmitter<string>;
46
47     get leader(): string {
48         return this.record.leader;
49     }
50
51     set leader(l: string) {
52         this.record.leader = l;
53     }
54
55     get fields(): MarcField[] {
56        return this.record.fields;
57     }
58
59     set fields(f: MarcField[]) {
60         this.record.fields = f;
61     }
62
63     constructor(xml: string) {
64         this.record = new MARC21.Record({marcxml: xml, delimiter: DELIMITER});
65         this.breakerText = this.record.toBreaker();
66         this.fixedFieldChange = new EventEmitter<string>();
67     }
68
69     toXml(): string {
70         return this.record.toXmlString();
71     }
72
73     toBreaker(): string {
74         return this.record.toBreaker();
75     }
76
77     recordType(): string {
78         return this.record.recordType();
79     }
80
81     absorbBreakerChanges() {
82         this.record = new MARC21.Record(
83             {marcbreaker: this.breakerText, delimiter: DELIMITER});
84     }
85
86     extractFixedField(fieldCode: string): string {
87         return this.record.extractFixedField(fieldCode);
88     }
89
90     setFixedField(fieldCode: string, fieldValue: string): string {
91         const response = this.record.setFixedField(fieldCode, fieldValue);
92         this.fixedFieldChange.emit(fieldCode);
93         return response;
94     }
95
96     // Give each field an identifier so it may be referenced later.
97     stampFieldIds() {
98         this.fields.forEach(f => this.stampFieldId(f));
99     }
100
101     // Stamp field IDs the the initial isCtrlField state.
102     stampFieldId(field: MarcField) {
103         if (!field.fieldId) {
104             field.fieldId = Math.floor(Math.random() * 10000000);
105         }
106
107         if (field.isCtrlField === undefined) {
108             field.isCtrlField = field.isControlfield();
109         }
110     }
111
112     field(spec: string, wantArray?: boolean): MarcField | MarcField[] {
113         return this.record.field(spec, wantArray);
114     }
115
116     insertFieldsBefore(field: MarcField, ...newFields: MarcField[]) {
117         this.record.insertFieldsBefore.apply(
118             this.record, [field].concat(newFields));
119         this.stampFieldIds();
120     }
121
122     insertFieldsAfter(field: MarcField, ...newFields: MarcField[]) {
123         this.record.insertFieldsAfter.apply(
124             this.record, [field].concat(newFields));
125         this.stampFieldIds();
126     }
127
128     insertOrderedFields(...newFields: MarcField[]) {
129         this.record.insertOrderedFields.apply(this.record, newFields);
130         this.stampFieldIds();
131     }
132
133     generate008(): MarcField {
134         return this.record.generate008();
135     }
136
137
138     deleteFields(...fields: MarcField[]) {
139         this.record.deleteFields.apply(this.record, fields);
140     }
141
142     getField(id: number): MarcField {
143         return this.fields.filter(f => f.fieldId === id)[0];
144     }
145
146     getPreviousField(id: number): MarcField {
147         for (let idx = 0; idx < this.fields.length; idx++) {
148             if (this.fields[idx].fieldId === id) {
149                 return this.fields[idx - 1];
150             }
151         }
152     }
153
154     getNextField(id: number): MarcField {
155         for (let idx = 0; idx < this.fields.length; idx++) {
156             if (this.fields[idx].fieldId === id) {
157                 return this.fields[idx + 1];
158             }
159         }
160     }
161
162     // Turn an field-ish object into a proper MARC.Field
163     newField(props: any): MarcField {
164         const field = new MARC21.Field(props);
165         this.stampFieldId(field);
166         return field;
167     }
168
169     cloneField(field: any): MarcField {
170         const props: any = {tag: field.tag};
171
172         if (field.isControlfield()) {
173             props.data = field.data;
174
175         } else {
176             props.ind1 = field.ind1;
177             props.ind2 = field.ind2;
178             props.subfields = this.cloneSubfields(field.subfields);
179         }
180
181         return this.newField(props);
182     }
183
184     cloneSubfields(subfields: MarcSubfield[]): MarcSubfield[] {
185         const root = [];
186         subfields.forEach(sf => root.push([].concat(sf)));
187         return root;
188     }
189 }
190