1 import {Component, Input, Output, OnInit, EventEmitter, ViewChild} from '@angular/core';
2 import {IdlService} from '@eg/core/idl.service';
3 import {EventService} from '@eg/core/event.service';
4 import {NetService} from '@eg/core/net.service';
5 import {AuthService} from '@eg/core/auth.service';
6 import {OrgService} from '@eg/core/org.service';
7 import {PcrudService} from '@eg/core/pcrud.service';
8 import {ToastService} from '@eg/share/toast/toast.service';
9 import {StringComponent} from '@eg/share/string/string.component';
10 import {MarcRecord} from './marcrecord';
11 import {ComboboxEntry, ComboboxComponent
12 } from '@eg/share/combobox/combobox.component';
13 import {ConfirmDialogComponent} from '@eg/share/dialog/confirm.component';
15 interface MarcSavedEvent {
21 * MARC Record editor main interface.
25 selector: 'eg-marc-editor',
26 templateUrl: './editor.component.html'
29 export class MarcEditorComponent implements OnInit {
32 editorTab: 'rich' | 'flat';
33 sources: ComboboxEntry[];
35 @Input() set recordId(id: number) {
37 if (this.record && this.record.id === id) { return; }
41 @Input() set recordXml(xml: string) {
42 if (xml) { this.fromXml(xml); }
45 // Tell us which record source to select by default.
46 // Useful for new records and in-place editing from bare XML.
47 @Input() recordSource: number;
49 // If true, saving records to the database is assumed to
50 // happen externally. IOW, the record editor is just an
51 // in-place MARC modification interface.
52 @Input() inPlaceMode: boolean;
54 // In inPlaceMode, this is emitted in lieu of saving the record
55 // in th database. When inPlaceMode is false, this is emitted after
56 // the record is successfully saved.
57 @Output() recordSaved: EventEmitter<MarcSavedEvent>;
59 @ViewChild('sourceSelector', { static: true }) sourceSelector: ComboboxComponent;
60 @ViewChild('confirmDelete', { static: true }) confirmDelete: ConfirmDialogComponent;
61 @ViewChild('confirmUndelete', { static: true }) confirmUndelete: ConfirmDialogComponent;
62 @ViewChild('cannotDelete', { static: true }) cannotDelete: ConfirmDialogComponent;
63 @ViewChild('successMsg', { static: true }) successMsg: StringComponent;
64 @ViewChild('failMsg', { static: true }) failMsg: StringComponent;
67 private evt: EventService,
68 private idl: IdlService,
69 private net: NetService,
70 private auth: AuthService,
71 private org: OrgService,
72 private pcrud: PcrudService,
73 private toast: ToastService
76 this.recordSaved = new EventEmitter<MarcSavedEvent>();
80 // Default to flat for now since it's all that's supported.
81 this.editorTab = 'flat';
83 this.pcrud.retrieveAll('cbs').subscribe(
84 src => this.sources.push({id: +src.id(), label: src.source()}),
87 this.sources = this.sources.sort((a, b) =>
88 a.label.toLowerCase() < b.label.toLowerCase() ? -1 : 1
91 if (this.recordSource) {
92 this.sourceSelector.applyEntryId(this.recordSource);
98 saveRecord(): Promise<any> {
99 const xml = this.record.toXml();
101 let sourceName: string = null;
102 let sourceId: number = null;
104 if (this.sourceSelector.selected) {
105 sourceName = this.sourceSelector.selected.label;
106 sourceId = this.sourceSelector.selected.id;
109 if (this.inPlaceMode) {
110 // Let the caller have the modified XML and move on.
111 this.recordSaved.emit({marcXml: xml, bibSource: sourceId});
112 return Promise.resolve();
115 if (this.record.id) { // Editing an existing record
117 const method = 'open-ils.cat.biblio.record.xml.update';
119 return this.net.request('open-ils.cat', method,
120 this.auth.token(), this.record.id, xml, sourceName
121 ).toPromise().then(response => {
123 const evt = this.evt.parse(response);
126 this.failMsg.current().then(msg => this.toast.warning(msg));
130 this.successMsg.current().then(msg => this.toast.success(msg));
131 this.recordSaved.emit({marcXml: xml, bibSource: sourceId});
136 // TODO: create a new record
140 fromId(id: number): Promise<any> {
141 return this.pcrud.retrieve('bre', id)
142 .toPromise().then(bib => {
143 this.record = new MarcRecord(bib.marc());
145 this.record.deleted = bib.deleted() === 't';
147 this.sourceSelector.applyEntryId(+bib.source());
152 fromXml(xml: string) {
153 this.record = new MarcRecord(xml);
154 this.record.id = null;
157 deleteRecord(): Promise<any> {
159 return this.confirmDelete.open().toPromise()
161 if (!yes) { return; }
163 return this.net.request('open-ils.cat',
164 'open-ils.cat.biblio.record_entry.delete',
165 this.auth.token(), this.record.id).toPromise()
169 const evt = this.evt.parse(resp);
171 if (evt.textcode === 'RECORD_NOT_EMPTY') {
172 return this.cannotDelete.open().toPromise();
178 return this.fromId(this.record.id)
179 .then(_ => this.recordSaved.emit(
180 {marcXml: this.record.toXml()}));
185 undeleteRecord(): Promise<any> {
187 return this.confirmUndelete.open().toPromise()
189 if (!yes) { return; }
191 return this.net.request('open-ils.cat',
192 'open-ils.cat.biblio.record_entry.undelete',
193 this.auth.token(), this.record.id).toPromise()
197 const evt = this.evt.parse(resp);
198 if (evt) { console.error(evt); return alert(evt); }
200 return this.fromId(this.record.id)
201 .then(_ => this.recordSaved.emit(
202 {marcXml: this.record.toXml()}));