1 import {EventEmitter} from '@angular/core';
3 /* Wrapper class for our external MARC21.Record JS library. */
7 // MARC breaker delimiter
10 export interface MarcSubfield // code, value, position
11 extends Array<string|number> { 0: string; 1: string; 2: number; }
13 // Only contains the attributes/methods we need so far.
14 export interface MarcField {
20 subfields?: MarcSubfield[];
22 // For authority validation
26 // Fields are immutable when it comes to controlfield vs.
27 // data field. Stamp the value when stamping field IDs.
29 indicator?: (ind: number) => any;
31 // Pass-through to marcrecord.js
32 isControlfield(): boolean;
34 deleteExactSubfields(...subfield: MarcSubfield[]): number;
37 export class MarcRecord {
39 id: number; // Database ID when known.
41 record: any; // MARC21.Record object
44 // Let clients know some fixed field shuffling may have occured.
45 // Emits the fixed field code.
46 fixedFieldChange: EventEmitter<string>;
48 get leader(): string {
49 return this.record.leader;
52 set leader(l: string) {
53 this.record.leader = l;
56 get fields(): MarcField[] {
57 return this.record.fields;
60 set fields(f: MarcField[]) {
61 this.record.fields = f;
64 constructor(xml?: string) {
65 this.record = new MARC21.Record({marcxml: xml, delimiter: DELIMITER});
66 this.breakerText = this.record.toBreaker();
67 this.fixedFieldChange = new EventEmitter<string>();
71 return this.record.toXmlString();
75 return this.record.toBreaker();
78 recordType(): string {
79 return this.record.recordType();
82 absorbBreakerChanges() {
83 this.record = new MARC21.Record(
84 {marcbreaker: this.breakerText, delimiter: DELIMITER});
85 // Replacing the underlying record means regenerating the field metadata
89 extractFixedField(fieldCode: string): string {
90 return this.record.extractFixedField(fieldCode);
93 setFixedField(fieldCode: string, fieldValue: string): string {
94 const response = this.record.setFixedField(fieldCode, fieldValue);
95 this.fixedFieldChange.emit(fieldCode);
99 // Give each field an identifier so it may be referenced later.
101 this.fields.forEach(f => this.stampFieldId(f));
104 // Stamp field IDs the the initial isCtrlField state.
105 stampFieldId(field: MarcField) {
106 if (!field.fieldId) {
107 field.fieldId = Math.floor(Math.random() * 10000000);
110 if (field.isCtrlField === undefined) {
111 field.isCtrlField = field.isControlfield();
115 field(spec: string, wantArray?: boolean): MarcField | MarcField[] {
116 return this.record.field(spec, wantArray);
119 appendFields(...newFields: MarcField[]) {
120 this.record.appendFields.apply(this.record, newFields);
121 this.stampFieldIds();
124 insertFieldsBefore(field: MarcField, ...newFields: MarcField[]) {
125 this.record.insertFieldsBefore.apply(
126 this.record, [field].concat(newFields));
127 this.stampFieldIds();
130 insertFieldsAfter(field: MarcField, ...newFields: MarcField[]) {
131 this.record.insertFieldsAfter.apply(
132 this.record, [field].concat(newFields));
133 this.stampFieldIds();
136 insertOrderedFields(...newFields: MarcField[]) {
137 this.record.insertOrderedFields.apply(this.record, newFields);
138 this.stampFieldIds();
141 generate008(): MarcField {
142 return this.record.generate008();
146 deleteFields(...fields: MarcField[]) {
147 this.record.deleteFields.apply(this.record, fields);
150 getField(id: number): MarcField {
151 return this.fields.filter(f => f.fieldId === id)[0];
154 getPreviousField(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];
162 getNextField(id: number): MarcField {
163 for (let idx = 0; idx < this.fields.length; idx++) {
164 if (this.fields[idx].fieldId === id) {
165 return this.fields[idx + 1];
170 // Turn an field-ish object into a proper MARC.Field
171 newField(props: any): MarcField {
172 const field = new MARC21.Field(props);
173 this.stampFieldId(field);
177 cloneField(field: any): MarcField {
178 const props: any = {tag: field.tag};
180 if (field.isControlfield()) {
181 props.data = field.data;
184 props.ind1 = field.ind1;
185 props.ind2 = field.ind2;
186 props.subfields = this.cloneSubfields(field.subfields);
189 return this.newField(props);
192 cloneSubfields(subfields: MarcSubfield[]): MarcSubfield[] {
194 subfields.forEach(sf => root.push([].concat(sf)));
198 // Returns a list of values for the tag + subfield combo
199 subfield(tag: string, subfield: string): string {
200 return this.record.subfield(tag, subfield);