LPXXX editable divs for subfield values
authorBill Erickson <berickxx@gmail.com>
Tue, 19 Nov 2019 16:27:34 +0000 (11:27 -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.css [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/share/marc-edit/editable-content.component.html
Open-ILS/src/eg2/src/app/staff/share/marc-edit/editable-content.component.ts
Open-ILS/src/eg2/src/app/staff/share/marc-edit/rich-editor.component.html

diff --git a/Open-ILS/src/eg2/src/app/staff/share/marc-edit/editable-content.component.css b/Open-ILS/src/eg2/src/app/staff/share/marc-edit/editable-content.component.css
new file mode 100644 (file)
index 0000000..53d1011
--- /dev/null
@@ -0,0 +1,9 @@
+
+div[contenteditable] {
+   /* provide plenty of input space */
+   min-width: 2em;
+   /* match BS form-control border color */
+   border: 1px solid rgb(206, 212, 218);
+   /* match BS form-control input height */
+   min-height: calc(1.5em + .75rem + 2px);
+}
index 0f64141..b667c7a 100644 (file)
@@ -1,13 +1,25 @@
 
-<input 
-  id='marc-editable-content-{{randId}}' 
-  class="p-0 pl-1 rounded-0 form-control {{moreClasses}}"
-  [size]="inputSize()" 
-  [maxlength]="maxLength || ''"
-  [disabled]="readOnly" 
-  [attr.tabindex]="readOnly ? -1 : ''"
-  (focus)="$event.target.select()"
-  (blur)="propagateTouch()"
-  [(ngModel)]="content"
-/>
+<ng-container *ngIf="bigText">
+  <div contenteditable
+    id='{{randId}}' 
+    class="d-inline-block p-1 text-break {{moreClasses}}"
+    [attr.tabindex]="readOnly ? -1 : ''"
+    (focus)="focusDiv($event)"
+    (blur)="propagateTouch(); valueChange()">
+  </div>
+</ng-container>
+
+<ng-container *ngIf="!bigText">
+  <input 
+    id='{{randId}}' 
+    class="p-0 pl-1 text-break rounded-0 form-control {{moreClasses}}"
+    [size]="inputSize()" 
+    [maxlength]="maxLength || ''"
+    [disabled]="readOnly" 
+    [attr.tabindex]="readOnly ? -1 : ''"
+    (focus)="$event.target.select()"
+    (blur)="propagateTouch()"
+    [(ngModel)]="content"
+  />
+</ng-container>
 
index 791a55d..465832c 100644 (file)
@@ -1,4 +1,5 @@
-import {Component, Input, Output, OnInit, EventEmitter, forwardRef} from '@angular/core';
+import {ElementRef, Component, Input, Output, OnInit, EventEmitter, 
+    AfterViewInit, Renderer2, forwardRef} from '@angular/core';
 import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
 import {MarcRecord} from './marcrecord';
 import {MarcEditContext} from './editor-context';
@@ -10,6 +11,7 @@ import {MarcEditContext} from './editor-context';
 @Component({
   selector: 'eg-marc-editable-content',
   templateUrl: './editable-content.component.html',
+  styleUrls: ['./editable-content.component.css'],
   providers: [{
     provide: NG_VALUE_ACCESSOR,
     useExisting: forwardRef(() => EditableContentComponent),
@@ -17,40 +19,71 @@ import {MarcEditContext} from './editor-context';
   }]
 })
 
-export class EditableContentComponent implements OnInit, ControlValueAccessor {
+export class EditableContentComponent implements OnInit, AfterViewInit, ControlValueAccessor {
 
     @Input() context: MarcEditContext;
     @Input() readOnly: boolean;
     @Input() content: string;
     @Input() maxLength: number;
+    @Input() bigText: boolean;
 
     // space-separated list of additional CSS classes to append
     @Input() moreClasses: string;
 
     get record(): MarcRecord { return this.context.record; }
 
-    randId: string;
+    randId: number;
+    editDiv: any; // used for bigText
 
     // Stub functions required by ControlValueAccessor
     propagateChange = (_: any) => {};
     propagateTouch = () => {};
 
-    constructor() {
-        this.randId = Math.random().toFixed(5);
+    constructor(private renderer: Renderer2) {
+        this.randId = Math.floor(Math.random() * 100000);
     }
 
     ngOnInit() {}
 
+    ngAfterViewInit() {
+        if (this.bigText) {
+            this.editDiv = // numeric id requires [id=...] query selector
+                this.renderer.selectRootElement(`[id='${this.randId}']`);
+        }
+    }
+
     inputSize(): number {
-        return (this.content || ' ').length * 1.1;
+        // give at least 2 chars space and grow with the content
+        return Math.max(2, (this.content || '').length) * 1.1;
+    }
+
+    focusDiv($event) {
+        const targetNode = $event.srcElement.firstChild;
+
+        const range = document.createRange();
+        range.setStart(targetNode, 0);
+        range.setEnd(targetNode, targetNode.length);
+
+        const selection = window.getSelection();
+        selection.removeAllRanges();
+        selection.addRange(range);
     }
 
     valueChange() {
+        if (this.editDiv) {
+            this.content = this.editDiv.innerText;
+        }
         this.propagateChange(this.content);
     }
 
     writeValue(content: string) {
+        if (content === null || content === undefined) {
+            content = '';
+        }
         this.content = content;
+        if (this.editDiv) {
+            this.editDiv.innerText = content;
+        }
     }
 
     registerOnChange(fn) {
index 37a2f3b..6be1151 100644 (file)
 
       <ng-container *ngFor="let subfield of field.subfields">
 
-        <!-- subfield character -->
+        <!-- subfield decorator -->
         <eg-marc-editable-content [readOnly]="true" 
           moreClasses="text-primary border-right-0 bg-transparent" 
           i18n-ngModel [ngModel]="'‡'"></eg-marc-editable-content>
+
+        <!-- subfield character -->
         <eg-marc-editable-content [context]="context" [(ngModel)]="subfield[0]"
           moreClasses="text-info border-left-0"
           [maxLength]="1"></eg-marc-editable-content>
 
         <!-- subfield value -->
-        <eg-marc-editable-content [context]="context" [(ngModel)]="subfield[1]">
+        <eg-marc-editable-content [context]="context" 
+          [bigText]="true" [(ngModel)]="subfield[1]">
         </eg-marc-editable-content>
       </ng-container>
     </div>