LPXXX Copy fields up/down
authorBill Erickson <berickxx@gmail.com>
Wed, 20 Nov 2019 21:04:55 +0000 (16:04 -0500)
committerBill Erickson <berickxx@gmail.com>
Fri, 6 Dec 2019 15:37:03 +0000 (10:37 -0500)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/staff/share/marc-edit/editable-content.component.ts
Open-ILS/src/eg2/src/app/staff/share/marc-edit/editor-context.ts
Open-ILS/src/eg2/src/app/staff/share/marc-edit/marcrecord.ts
Open-ILS/src/eg2/src/app/staff/share/marc-edit/rich-editor.component.ts

index af537d1..2b202df 100644 (file)
@@ -1,7 +1,7 @@
 import {ElementRef, Component, Input, Output, OnInit, EventEmitter, 
     AfterViewInit, Renderer2} from '@angular/core';
 import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
-import {MarcRecord} from './marcrecord';
+import {MarcRecord, MarcField} from './marcrecord';
 import {MarcEditContext} from './editor-context';
 
 /**
@@ -17,7 +17,7 @@ import {MarcEditContext} from './editor-context';
 export class EditableContentComponent implements OnInit, AfterViewInit {
 
     @Input() context: MarcEditContext;
-    @Input() field: any; // MARC.Field
+    @Input() field: MarcField;
     @Input() fieldType: 'ldr' | 'tag' | 'cfld' | 'ind' | 'sfc' | 'sfv' = null;
 
     // used when the fieldType is ambiguous. E.g. 'ind1'
@@ -27,7 +27,7 @@ export class EditableContentComponent implements OnInit, AfterViewInit {
     @Input() fieldText: string = null;
 
     // array of subfield code and subfield value
-    @Input() subfield: any; // MARC.Subfield
+    @Input() subfield: string[]; // [code, value]
 
     // space-separated list of additional CSS classes to append
     @Input() moreClasses: string;
@@ -140,10 +140,16 @@ export class EditableContentComponent implements OnInit, AfterViewInit {
         switch (evt.key) {                                                     
 
             case 'ArrowDown':  
-                if (evt.ctrlKey) {
-                    // Copy the field down
-                } else {
-                    // Navigate down one field
+
+                if (evt.ctrlKey) { // Copy field down
+
+                    this.context.record.insertFieldsAfter(
+                        this.field, 
+                        this.context.record.cloneField(this.field)
+                    );
+
+                } else { // Jump to next tag
+
                     const field = this.record.getNextField(this.field.fieldId);
                     if (field) {
                         this.context.requestFieldFocus(field.fieldId);
@@ -153,10 +159,16 @@ export class EditableContentComponent implements OnInit, AfterViewInit {
                 break;
 
             case 'ArrowUp':
-                if (evt.ctrlKey) {
-                    // Copy the field up
-                } else {
-                    // Navigate upone field
+
+                if (evt.ctrlKey) { // Copy field up
+
+                    this.context.record.insertFieldsBefore(
+                        this.field, 
+                        this.context.record.cloneField(this.field)
+                    );
+
+                } else { // Jump to previous tag
+
                     const field = this.record.getPreviousField(this.field.fieldId);
                     if (field) {
                         this.context.requestFieldFocus(field.fieldId);
index 31705a9..990fd79 100644 (file)
@@ -1,5 +1,5 @@
 import {EventEmitter} from '@angular/core';
-import {MarcRecord} from './marcrecord';
+import {MarcRecord, MarcField} from './marcrecord';
 import {NgbPopover} from '@ng-bootstrap/ng-bootstrap';
 
 /* Per-instance MARC editor context. */
index 58ec9f1..9be8122 100644 (file)
@@ -7,6 +7,20 @@ declare var MARC21;
 // MARC breaker delimiter
 const DELIMITER = '$';
 
+// This acts as a veneer over a Marc.Field object.
+export interface MarcField {
+    fieldId?: number;
+    data?: string;
+    tag?: string;
+    ind1?: string;
+    ind2?: string;
+
+    // [[sfCode, sfValue], [sfCode, sfValue], ...]
+    subfields?: string[][]; 
+
+    isControlfield(): boolean;
+}
+
 export class MarcRecord {
 
     id: number; // Database ID when known.
@@ -26,11 +40,11 @@ export class MarcRecord {
         this.record.leader = l;
     }
 
-    get fields(): any[] {
+    get fields(): MarcField[] {
        return this.record.fields;
     }
 
-    set fields(f: any[]) {
+    set fields(f: MarcField[]) {
         this.record.fields = f;
     }
 
@@ -69,15 +83,30 @@ export class MarcRecord {
 
     // Give each field an identifier so it may be referenced later.
     stampFieldIds() {
-        this.fields.forEach(f => 
-            f.fieldId = Math.floor(Math.random() * 100000));
+        this.fields.forEach(f => {
+            if (!f.fieldId) {
+                f.fieldId = Math.floor(Math.random() * 100000)
+            }
+        });
+    }
+
+    insertFieldsBefore(field: MarcField, ...newFields: MarcField[]) {
+        this.record.insertFieldsBefore.apply(
+            this.record, [field].concat(newFields));
+        this.stampFieldIds();
+    }
+
+    insertFieldsAfter(field: MarcField, ...newFields: MarcField[]) {
+        this.record.insertFieldsAfter.apply(
+            this.record, [field].concat(newFields));
+        this.stampFieldIds();
     }
 
-    getField(id: number) {
+    getField(id: number): MarcField {
         return this.fields.filter(f => f.fieldId === id)[0];
     }
 
-    getPreviousField(id: number) {
+    getPreviousField(id: number): MarcField {
         for (let idx = 0; idx < this.fields.length; idx++) {
             if (this.fields[idx].fieldId === id) {
                 return this.fields[idx - 1];
@@ -85,12 +114,33 @@ export class MarcRecord {
         }
     }
 
-    getNextField(id: number) {
+    getNextField(id: number): MarcField {
         for (let idx = 0; idx < this.fields.length; idx++) {
             if (this.fields[idx].fieldId === id) {
                 return this.fields[idx + 1];
             }
         }
     }
+
+    cloneField(field: MarcField): MarcField {
+        const newField: any = {tag: field.tag};
+
+        if (field.isControlfield()) {
+            newField.data = field.data;
+            return new MARC21.Field(newField);
+        }
+
+        newField.ind1 = field.ind1;
+        newField.ind2 = field.ind2;
+        newField.subfields = this.cloneSubfields(field.subfields);
+
+        return new MARC21.Field(newField);
+    }
+
+    cloneSubfields(subfields: string[][]): string[][] {
+        const root = [];
+        subfields.forEach(sf => root.push([].concat(sf)));
+        return root;
+    }
 }
 
index 7532e6f..906a919 100644 (file)
@@ -3,7 +3,7 @@ import {Component, Input, Output, OnInit, AfterViewInit, EventEmitter,
 import {IdlService} from '@eg/core/idl.service';
 import {OrgService} from '@eg/core/org.service';
 import {TagTableService} from './tagtable.service';
-import {MarcRecord} from './marcrecord';
+import {MarcRecord, MarcField} from './marcrecord';
 import {MarcEditContext} from './editor-context';
 
 
@@ -46,11 +46,11 @@ export class MarcRichEditorComponent implements OnInit {
         ]).then(_ => this.dataLoaded = true);
     }
 
-    controlFields(): any[] {
+    controlFields(): MarcField[] {
         return this.record.fields.filter(f => f.isControlfield());
     }
 
-    dataFields(): any[] {
+    dataFields(): MarcField[] {
         return this.record.fields.filter(f => !f.isControlfield());
     }
 }