/* Per-instance MARC editor context. */
+const STUB_DATA_00X = ' ';
+
export type MARC_EDITABLE_FIELD_TYPE =
'ldr' | 'tag' | 'cfld' | 'ind1' | 'ind2' | 'sfc' | 'sfv';
// recovery can extract what's needed.
field?: MarcField;
+ // If this is a subfield modification.
+ subfield?: MarcSubfield;
+
// Does this action track an addition or deletion.
wasAddition?: boolean;
- // Reference to position just before the modified position
- // in the record, so deletion recovery can correctly position.
- precedingPosition?: FieldFocusRequest;
+ // Position preceding the modified position to mark the position
+ // of deletion recovery.
+ prevPosition?: FieldFocusRequest;
+
+ // Where should focus be returned once the undo is processed?
+ prevFocus?: FieldFocusRequest;
}
export class MarcEditContext {
// timeout allows for new components to be built before the
// focus request is emitted.
setTimeout(() => {
+ console.log('focusing ', req);
this.fieldFocusRequest.emit(req);
});
}
}
}
- handleStructuralUndoRedo(action: UndoRedoAction, isRedo?: boolean) {
+ handleStructuralUndoRedo(action: UndoRedoAction) {
if (action.wasAddition) {
- this.record.deleteFields(action.field);
- this.requestFieldFocus(action.precedingPosition);
+ // Remove the added field and focus the field before it.
- } else {
- const fieldId = action.field.fieldId;
- const prevField =
- this.record.getField(action.precedingPosition.fieldId);
+ if (action.subfield) {
- this.record.insertFieldsAfter(prevField, action.field);
-
- // Recover the original fieldId, which gets re-stamped
- // in this.record.insertFields* calls.
- action.field.fieldId = fieldId;
+ const prevPos = action.subfield[2] - 1;
+ action.field.deleteExactSubfields(action.subfield);
+ this.focusSubfield(action.field, prevPos);
+
+ } else {
+ this.record.deleteFields(action.field);
+ this.requestFieldFocus(action.prevPosition);
+ }
+
+ } else {
+ // Re-insert the removed field and focus it
- // Focus the newly recovered field.
- this.requestFieldFocus(action.position);
+ if (action.subfield) {
+
+ this.insertSubfield(action.field, action.subfield, true);
+ this.focusSubfield(action.field, action.subfield[2]);
+
+ } else {
+
+ const fieldId = action.position.fieldId;
+ const prevField =
+ this.record.getField(action.prevPosition.fieldId);
+
+ this.record.insertFieldsAfter(prevField, action.field);
+
+ // Recover the original fieldId, which gets re-stamped
+ // in this.record.insertFields* calls.
+ action.field.fieldId = fieldId;
+
+ // Focus the newly recovered field.
+ this.requestFieldFocus(action.position);
+ }
}
action.wasAddition = !action.wasAddition;
- const moveTo = isRedo ? this.undoStack : this.redoStack;
+ const moveTo = action.isRedo ? this.undoStack : this.redoStack;
moveTo.unshift(action);
}
- add00X(tag: string) {
+ trackStructuralUndo(field: MarcField, isAddition: boolean, subfield?: MarcSubfield) {
- const field: MarcField = this.record.newField({
- tag : tag,
- data : ' '
- });
+ const position: FieldFocusRequest = {fieldId: field.fieldId, target: 'tag'};
- this.record.insertOrderedFields(field);
+ let prevPos: FieldFocusRequest = null;
- const focus: FieldFocusRequest =
- {fieldId: field.fieldId, target: 'tag'};
+ if (subfield) {
+ position.target = 'sfc';
+ position.sfOffset = subfield[2];
- const prevField = this.record.getPreviousField(field.fieldId);
+ } else {
+ // No need to track the previous field for subfield mods.
- let prevFocus: FieldFocusRequest;
- if (prevField) {
- prevFocus = {fieldId: prevField.fieldId, target: 'tag'};
+ const prevField = this.record.getPreviousField(field.fieldId);
+ if (prevField) {
+ prevPos = {fieldId: prevField.fieldId, target: 'tag'};
+ }
}
- this.undoStack.unshift({
- wasAddition: true,
+ const action = {
field: field,
- position: focus,
- precedingPosition: prevFocus
- });
+ subfield: subfield,
+ wasAddition: isAddition,
+ position: position,
+ prevPosition: prevPos,
+ prevFocus: this.lastFocused
+ };
+
+ this.undoStack.unshift(action);
+ }
- this.requestFieldFocus(focus);
+ deleteField(field: MarcField) {
+ this.trackStructuralUndo(field, false);
+
+ this.focusNextTag(field) || this.focusPreviousTag(field);
+
+ this.record.deleteFields(field);
+ }
+
+ add00X(tag: string) {
+
+ const field: MarcField =
+ this.record.newField({tag : tag, data : STUB_DATA_00X});
+
+ this.record.insertOrderedFields(field);
+
+ this.trackStructuralUndo(field, true);
+
+ this.focusTag(field);
}
insertReplace008() {
- //this.recordChanging();
// 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()
- })
- );
- }
+ [].concat(this.record.field('008', true)).forEach(f => {
+ this.trackStructuralUndo(f, false);
+ this.record.deleteFields(f);
+ });
- // Adds a new empty subfield to the provided field at the
- // requested subfield position
- insertSubfield(field: MarcField, position: number) {
- //this.recordChanging();
+ const field = this.record.newField({
+ tag : '008', data : this.record.generate008()});
- // 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]++; }});
+ this.record.insertOrderedFields(field);
- const newSf: MarcSubfield = [' ', '', position];
- field.subfields.splice(position, 0, newSf);
+ this.trackStructuralUndo(field, true);
- this.requestFieldFocus({
- fieldId: field.fieldId,
- target: 'sfc',
- sfOffset: position
- });
+ this.focusTag(field);
}
// Add stub field before or after the context field
}
insertField(contextField: MarcField, newField: MarcField, before?: boolean) {
- //this.recordChanging();
if (before) {
this.record.insertFieldsBefore(contextField, newField);
this.record.insertFieldsAfter(contextField, newField);
this.focusNextTag(contextField);
}
+
+ this.trackStructuralUndo(newField, true);
}
+ // Adds a new empty subfield to the provided field at the
+ // requested subfield position
+ insertSubfield(field: MarcField,
+ subfield: MarcSubfield, skipTracking?: boolean) {
+ const position = subfield[2];
- deleteField(field: MarcField) {
- //this.recordChanging();
- this.record.deleteFields(field);
- this.focusNextTag(field) || this.focusPreviousTag(field);
- }
+ // 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]++; }});
- deleteSubfield(field: MarcField, subfield: MarcSubfield) {
- //this.recordChanging();
- // If subfields remain, focus the previous subfield.
- // otherwise focus our tag.
- const sfpos = subfield[2] - 1;
+ field.subfields.splice(position, 0, subfield);
- field.deleteExactSubfields(subfield);
+ if (!skipTracking) {
+ this.focusSubfield(field, position);
+ this.trackStructuralUndo(field, true, subfield);
+ }
+ }
+
+ insertStubSubfield(field: MarcField, position: number) {
+ const newSf: MarcSubfield = [' ', '', position];
+ this.insertSubfield(field, newSf);
+ }
+
+ // Focus the requested subfield by its position. If its
+ // position is less than zero, focus the field's tag instead.
+ focusSubfield(field: MarcField, position: number) {
const focus: FieldFocusRequest = {fieldId: field.fieldId, target: 'tag'};
- if (sfpos >= 0) {
- focus.target = 'sfv';
- focus.sfOffset = sfpos;
+ if (position >= 0) {
+ // Focus the code instead of the value, because attempting to
+ // focus an empty (editable) div results in nothing getting focus.
+ focus.target = 'sfc';
+ focus.sfOffset = position;
}
this.requestFieldFocus(focus);
}
+ deleteSubfield(field: MarcField, subfield: MarcSubfield) {
+ const sfpos = subfield[2] - 1; // previous subfield
+
+ this.trackStructuralUndo(field, false, subfield);
+
+ field.deleteExactSubfields(subfield);
+
+ this.focusSubfield(field, sfpos);
+ }
+
+ focusTag(field: MarcField) {
+ this.requestFieldFocus({fieldId: field.fieldId, target: 'tag'});
+ }
+
// Returns true if the field has a next tag to focus
focusNextTag(field: MarcField) {
const nextField = this.record.getNextField(field.fieldId);
- if (nextField) {
- this.requestFieldFocus(
- {fieldId: nextField.fieldId, target: 'tag'});
+ if (nextField) {
+ this.focusTag(nextField);
return true;
}
return false;
focusPreviousTag(field: MarcField): boolean {
const prevField = this.record.getPreviousField(field.fieldId);
if (prevField) {
- this.requestFieldFocus(
- {fieldId: prevField.fieldId, target: 'tag'});
+ this.focusTag(prevField);
return true;
}
return false;
}
-
-
}