focusSub: Subscription;
undoRedoSub: Subscription;
+ isLeader: boolean; // convenience
constructor(
private renderer: Renderer2,
}
focusRequestIsMe(req: FieldFocusRequest): boolean {
- if (!this.field) { return false; } // LDR
- if (req.fieldId !== this.field.fieldId) { return false; }
if (req.target !== this.fieldType) { return false; }
+ if (this.field) {
+ if (req.fieldId !== this.field.fieldId) { return false; }
+ } else if (req.target === 'ldr') {
+ return this.isLeader;
+ }
+
if (req.sfOffset !== undefined &&
req.sfOffset !== this.subfield[2]) {
// this is not the subfield you are looking for.
// clicking, etc. Model the event as a focus request
// so it can be tracked the same.
req = {
- fieldId: this.field.fieldId,
+ fieldId: this.field ? this.field.fieldId : -1,
target: this.fieldType,
sfOffset: this.subfield ? this.subfield[2] : undefined
};
switch (this.fieldType) {
case 'ldr':
+ this.isLeader = true;
if (content) { this.maxLength = content.length; }
+ this.watchForFocusRequests();
+ this.watchForUndoRedoRequests();
break;
case 'tag':
// These are served dynamically to handle cases where a tag or
// subfield is modified in place.
contextMenuEntries(): ContextMenuEntry[] {
- if (!this.field) { return; } // LDR tag
+ if (this.isLeader) { return; }
switch(this.fieldType) {
case 'tag':
// Route keydown events to the appropriate handler
inputKeyDown(evt: KeyboardEvent) {
-
+
+ switch(evt.key) {
+ case 'y':
+ if (evt.ctrlKey) { // redo
+ this.context.requestRedo();
+ evt.preventDefault();
+ }
+ return;
+
+ case 'z':
+ if (evt.ctrlKey) { // undo
+ this.context.requestUndo();
+ evt.preventDefault();
+ }
+ return;
+
+ case 'F6':
+ if (evt.shiftKey) {
+ // shift+F6 => add 006
+ this.context.add00X('006');
+ evt.preventDefault();
+ evt.stopPropagation();
+ }
+ return;
+
+ case 'F7':
+ if (evt.shiftKey) {
+ // shift+F7 => add 007
+ this.context.add00X('007');
+ evt.preventDefault();
+ evt.stopPropagation();
+ }
+ return;
+
+ case 'F8':
+ if (evt.shiftKey) {
+ // shift+F8 => add/replace 008
+ this.context.insertReplace008();
+ evt.preventDefault();
+ evt.stopPropagation();
+ }
+ return;
+ }
+
+ // None of the remaining key combos are supported by the LDR.
if (this.fieldType === 'ldr') { return; }
switch (evt.key) {
evt.preventDefault();
break;
-
- case 'F6':
- if (evt.shiftKey) {
- // shift+F6 => add 006
- this.context.add00X('006');
- evt.preventDefault();
- evt.stopPropagation();
- }
- break;
-
- case 'F7':
- if (evt.shiftKey) {
- // shift+F7 => add 007
- this.context.add00X('007');
- 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) {
evt.preventDefault();
}
break;
-
- case 'y':
- if (evt.ctrlKey) { // redo
- this.context.requestRedo();
- evt.preventDefault();
- }
- break;
-
- case 'z':
- if (evt.ctrlKey) { // undo
- this.context.requestUndo();
- evt.preventDefault();
- }
- break;
-
}
}
// Position preceding the modified position to mark the position
// of deletion recovery.
prevPosition: FieldFocusRequest;
+
+ // Location of the cursor at time of initial action.
+ prevFocus: FieldFocusRequest;
}
requestFieldFocus(req: FieldFocusRequest) {
// timeout allows for new components to be built before the
// focus request is emitted.
- setTimeout(() => {
- console.log('focusing ', req);
- this.fieldFocusRequest.emit(req);
- });
+ setTimeout(() => this.fieldFocusRequest.emit(req));
+ }
+
+ resetUndos() {
+ this.undoStack = [];
+ this.redoStack = [];
}
requestUndo() {
// Remove the added field
if (action.subfield) {
-
const prevPos = action.subfield[2] - 1;
action.field.deleteExactSubfields(action.subfield);
this.focusSubfield(action.field, prevPos);
} else {
this.record.deleteFields(action.field);
-
- if (this.lastFocused.fieldId === action.field.fieldId) {
- // If the field we are deleting is currently focused,
- // move focus to the previous field. Otherwse, leave
- // the focus where it is.
- this.requestFieldFocus(action.prevPosition);
- }
}
+ // When deleting chunks, always return focus to the
+ // pre-insert position.
+ this.requestFieldFocus(action.prevFocus);
+
} else {
// Re-insert the removed field and focus it.
// Focus the newly recovered field.
this.requestFieldFocus(action.position);
}
+
+ // When inserting chunks, track the location where the
+ // insert was requested so we can return the cursor so we
+ // can return the cursor to the scene of the crime if the
+ // undo is re-done or vice versa. This is primarily useful
+ // when performing global inserts like add00X, which can be
+ // done without the 00X field itself having focus.
+ action.prevFocus = this.lastFocused;
}
action.wasAddition = !action.wasAddition;
action.position = position;
action.prevPosition = prevPos;
+ // For bulk adds (e.g. add a whole row) the field focused at
+ // time of action will be different than the added field.
+ action.prevFocus = this.lastFocused;
+
this.undoStack.unshift(action);
}
// Remember the last used tab as the preferred tab.
tabChange(evt: NgbTabChangeEvent) {
+
+ // Avoid undo persistence across tabs since that could result
+ // in changes getting lost.
+ this.context.resetUndos();
+
if (evt.nextId === 'flat') {
this.store.setItem('cat.marcedit.flateditor', true);
} else {
<input
[attr.aria-labelledby]="'label-' + randId"
class="form-control rounded-0 flex-5" type="text"
- (change)="valueChange()"
- [(ngModel)]="fieldValue"
+ (change)="valueChange($event.target.value)"
+ [ngModel]="fieldValue"
[attr.maxlength]="fieldLength" [attr.size]="fieldLength"
[egContextMenu]="fieldValues"
(menuItemSelected)="valueChange($event.value)"
<!-- LEADER -->
<div class="row pt-0 pb-0 pl-3 form-horizontal">
<eg-marc-editable-content [context]="context" fieldType="tag"
- fieldText="LDR" i18n-fieldText moreClasses="p-1">
+ fieldText="LDR" i18n-fieldText moreClasses="p-1 pr-2">
</eg-marc-editable-content>
<eg-marc-editable-content [context]="context" fieldType="ldr"