LPXXX editor continued
authorBill Erickson <berickxx@gmail.com>
Thu, 21 Nov 2019 23:05:12 +0000 (18:05 -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/fixed-field.component.html
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.html

index 1dcbbf0..0eaf5e9 100644 (file)
@@ -1,7 +1,7 @@
 import {ElementRef, Component, Input, Output, OnInit, EventEmitter, 
     AfterViewInit, Renderer2} from '@angular/core';
 import {filter} from 'rxjs/operators';
-import {MarcRecord, MarcField} from './marcrecord';
+import {MarcRecord, MarcField, MarcSubfield} from './marcrecord';
 import {MarcEditContext, FieldFocusRequest} from './editor-context';
 
 /**
@@ -27,7 +27,7 @@ export class EditableContentComponent implements OnInit, AfterViewInit {
     @Input() fieldText: string = null;
 
     // array of subfield code and subfield value
-    @Input() subfield: string[]; // [code, value]
+    @Input() subfield: MarcSubfield;
 
     // space-separated list of additional CSS classes to append
     @Input() moreClasses: string;
@@ -60,7 +60,7 @@ export class EditableContentComponent implements OnInit, AfterViewInit {
         ).subscribe((req: FieldFocusRequest) => {
 
             if (req.sfOffset !== undefined && 
-                req.sfOffset !== Number(this.subfield[2])) {
+                req.sfOffset !== this.subfield[2]) {
                 // subfield focus request, but we are not this subfield
                 return;
             }
@@ -153,6 +153,11 @@ export class EditableContentComponent implements OnInit, AfterViewInit {
     focusBigText() {
         const targetNode = this.editInput.firstChild;
 
+        if (!targetNode) {
+            // Div contains no text content, nothing to select
+            return;
+        }
+
         const range = document.createRange();
         range.setStart(targetNode, 0);
         range.setEnd(targetNode, targetNode.length);
@@ -172,9 +177,44 @@ export class EditableContentComponent implements OnInit, AfterViewInit {
             case 'Delete': return this.keyDelete(evt);
             case 'ArrowDown': return this.keyArrowDown(evt);
             case 'ArrowUp': return this.keyArrowUp(evt);
-            case 'F6': return this.keyF6(evt);
-            case 'F7': return this.keyF7(evt);
-            case 'F8': return this.keyF8(evt);
+
+            case 'F6': 
+                if (evt.shiftKey) {
+                    // shift+F6 => add 006
+                    this.context.add006();
+                    evt.preventDefault();
+                    evt.stopPropagation();
+                }
+                break;
+
+            case 'F7': 
+                if (evt.shiftKey) {
+                    // shift+F7 => add 007
+                    this.context.add007();
+                    evt.preventDefault();
+                    evt.stopPropagation();
+                }
+                break;
+
+            case 'F8': 
+                if (evt.shiftKey) {
+                    // shift+F8 => add/replace 008
+                    this.context.insertReplace008();
+                    evt.preventDefault();
+                    evt.stopPropagation();
+                }
+                break;
+
+            case 'd': // thunk
+            case 'i':
+                if (evt.ctrlKey) {
+                    // ctrl+i / ctrl+d == insert subfield
+                    const pos = this.subfield ? this.subfield[2] + 1 : 0;
+                    this.context.insertSubfield(this.field, pos);
+                    evt.preventDefault();
+                }
+                break;
+
         }
     }
 
@@ -184,13 +224,13 @@ export class EditableContentComponent implements OnInit, AfterViewInit {
 
         if (evt.ctrlKey) {
 
-            const newField = this.context.record.newField(
-                {tag: '999', subfields: [[' ', '', '0']]});
+            const newField = this.record.newField(
+                {tag: '999', subfields: [[' ', '', 0]]});
 
             if (evt.shiftKey) {
-                this.context.record.insertFieldsBefore(this.field, newField);
+                this.record.insertFieldsBefore(this.field, newField);
             } else {
-                this.context.record.insertFieldsAfter(this.field, newField);
+                this.record.insertFieldsAfter(this.field, newField);
             }
 
             this.context.requestFieldFocus(
@@ -221,7 +261,7 @@ export class EditableContentComponent implements OnInit, AfterViewInit {
 
             // If subfields remain, focus the previous subfield.
             // otherwise focus our tag.
-            const sfpos = Number(this.subfield[2]) - 1;
+            const sfpos = this.subfield[2] - 1;
 
             this.field.deleteExactSubfields(this.subfield);
 
@@ -245,10 +285,8 @@ export class EditableContentComponent implements OnInit, AfterViewInit {
 
         if (evt.ctrlKey) { // Copy field down
 
-            this.context.record.insertFieldsAfter(
-                this.field, 
-                this.context.record.cloneField(this.field)
-            );
+            this.record.insertFieldsAfter(
+                this.field, this.record.cloneField(this.field));
         }
 
         const field = this.record.getNextField(this.field.fieldId);
@@ -266,10 +304,8 @@ export class EditableContentComponent implements OnInit, AfterViewInit {
 
         if (evt.ctrlKey) {
 
-            this.context.record.insertFieldsBefore(
-                this.field, 
-                this.context.record.cloneField(this.field)
-            );
+            this.record.insertFieldsBefore(
+                this.field, this.record.cloneField(this.field));
         }
 
         const field = this.record.getPreviousField(this.field.fieldId);
@@ -280,35 +316,6 @@ export class EditableContentComponent implements OnInit, AfterViewInit {
 
         evt.preventDefault();
     }
-
-    keyF6(evt: KeyboardEvent) {
-        console.log('f6');
-
-        if (evt.shiftKey) {
-
-            evt.preventDefault();
-            evt.stopPropagation();
-        }
-    }
-
-    keyF7(evt: KeyboardEvent) {
-        console.log('f7');
-
-        if (evt.shiftKey) {
-
-            evt.preventDefault();
-            evt.stopPropagation();
-        }
-    }
-
-    keyF8(evt: KeyboardEvent) {
-        console.log('f8');
-
-        if (evt.shiftKey) {
-            evt.preventDefault();
-            evt.stopPropagation();
-        }
-    }
 }
 
 
index f446948..c0ece94 100644 (file)
@@ -1,5 +1,5 @@
 import {EventEmitter} from '@angular/core';
-import {MarcRecord, MarcField} from './marcrecord';
+import {MarcRecord, MarcField, MarcSubfield} from './marcrecord';
 import {NgbPopover} from '@ng-bootstrap/ng-bootstrap';
 
 /* Per-instance MARC editor context. */
@@ -48,5 +48,60 @@ export class MarcEditContext {
         // focus request is emitted.
         setTimeout(() => this.fieldFocusRequest.emit(req));
     }
+
+    add006() {
+        this.record.insertOrderedFields(
+            this.record.newField({
+                tag : '006',
+                data : '                                        '
+            })
+        );
+    }
+
+
+    add007() {
+        this.record.insertOrderedFields(
+            this.record.newField({
+                tag : '007',
+                data : '                                        '
+            })
+        );
+    }
+
+    insertReplace008() {
+
+        // delete all of the 008s
+        [].concat(this.record.field('008', true)).forEach(
+            f => this.record.deleteFields(f));
+
+        // add a new 008
+        this.record.insertOrderedFields(
+            this.record.newField({
+                tag : '008',
+                data : this.record.generate008()
+            })
+        );
+    }
+
+    // Adds a new empty subfield to the provided field at the
+    // requested subfield position
+    insertSubfield(field: MarcField, position: number) {
+
+        // array index 3 contains that position of the subfield
+        // in the MARC field.  When splicing a new subfield into
+        // the set, be sure the any that come after the new one
+        // have their positions bumped to reflect the shift.
+        field.subfields.forEach(
+            sf => {if (sf[2] >= position) { sf[2]++; }});
+
+        const newSf: MarcSubfield = [' ', '', position];
+        field.subfields.splice(position, 0, newSf);
+
+        this.requestFieldFocus({
+            fieldId: field.fieldId, 
+            target: 'sfc',
+            sfOffset: position
+        });
+    }
 }
 
index 3cd6d73..287a70e 100644 (file)
   </ng-template>
 
   <div class="form-inline d-flex">
-    <div class="pr-2 flex-1">
+    <div class="flex-4">
       <span id='label-{{randId}}' class="text-left font-weight-bold">
         {{fieldLabel}}
       </span>
     </div>
     <input 
       [attr.aria-labelledby]="'label-' + randId"
-      class="form-control rounded-0 flex-1 pl-1" type="text" 
+      class="form-control rounded-0 flex-5" type="text" 
       (change)="valueChange()"
       [(ngModel)]="fieldValue" 
       [attr.maxlength]="fieldLength" [attr.size]="fieldLength"
index 52445a4..61b7169 100644 (file)
@@ -7,20 +7,21 @@ declare var MARC21;
 // MARC breaker delimiter
 const DELIMITER = '$';
 
-// This acts as a veneer over a Marc.Field object.
+export interface MarcSubfield  // code, value, position
+    extends Array<string|number>{0: string; 1: string; 2: number}
+
+// Only contains the attributes/methods we need so far.
 export interface MarcField {
     fieldId?: number;
     data?: string;
     tag?: string;
     ind1?: string;
     ind2?: string;
-
-    // [[sfCode, sfValue], [sfCode, sfValue], ...]
-    subfields?: string[][]; 
+    subfields?: MarcSubfield[]; 
 
     isControlfield(): boolean;
 
-    deleteExactSubfields(subfields: string[]): number;
+    deleteExactSubfields(...subfield: MarcSubfield[]): number;
 }
 
 export class MarcRecord {
@@ -94,6 +95,10 @@ export class MarcRecord {
         }
     }
 
+    field(spec: string, wantArray?: boolean): MarcField | MarcField[] {
+        return this.record.field(spec, wantArray);
+    }
+
     insertFieldsBefore(field: MarcField, ...newFields: MarcField[]) {
         this.record.insertFieldsBefore.apply(
             this.record, [field].concat(newFields));
@@ -106,6 +111,16 @@ export class MarcRecord {
         this.stampFieldIds();
     }
 
+    insertOrderedFields(...newFields: MarcField[]) {
+        this.record.insertOrderedFields.apply(this.record, newFields);
+        this.stampFieldIds();
+    }
+
+    generate008(): MarcField {
+        return this.record.generate008();
+    }
+
+
     deleteFields(...fields: MarcField[]) {
         this.record.deleteFields.apply(this.record, fields);
     }
@@ -152,7 +167,7 @@ export class MarcRecord {
         return this.newField(props);
     }
 
-    cloneSubfields(subfields: string[][]): string[][] {
+    cloneSubfields(subfields: MarcSubfield[]): MarcSubfield[] {
         const root = [];
         subfields.forEach(sf => root.push([].concat(sf)));
         return root;
index dd494ba..464844a 100644 (file)
@@ -6,7 +6,7 @@
 <ng-container *ngIf="dataLoaded">
   <div class="mt-3 text-monospace"
     (contextmenu)="$event.preventDefault()">
-    <div class="row pb-2">
+    <div class="row pb-2 mb-2 border-bottom border-muted">
       <div class="col-lg-9 fixed-fields-container">
         <eg-fixed-fields-editor [context]="context"></eg-fixed-fields-editor>
       </div>