@Input() allowFreeText = false;
+ @Input() inputSize: number = null;
+
// Add a 'required' attribute to the input
isRequired: boolean;
@Input() set required(r: boolean) {
import {EventEmitter} from '@angular/core';
import {MarcRecord} from './marcrecord';
+import {NgbPopover} from '@ng-bootstrap/ng-bootstrap';
export class MarcEditContext {
recordChange: EventEmitter<MarcRecord>;
+ popOvers: NgbPopover[] = [];
+
private _record: MarcRecord;
set record(r: MarcRecord) {
if (r !== this._record) {
}
get record(): MarcRecord {
- return this._record;
+ return this._record;
}
constructor() {
this.recordChange = new EventEmitter<MarcRecord>();
}
+ // NgbPopovers don't always close when we want them to,
+ // specifcially when context-clicking.
+ closePopovers() {
+ this.popOvers.forEach(p => p.close());
+ }
+
}
}
@Input() set recordXml(xml: string) {
- if (xml) {
- this.fromXml(xml);
+ if (xml) {
+ this.fromXml(xml);
}
}
ngOnInit() {
// Default to flat for now since it's all that's supported.
- //this.editorTab = 'flat';
+ // this.editorTab = 'flat';
this.pcrud.retrieveAll('cbs').subscribe(
src => this.sources.push({id: +src.id(), label: src.source()}),
--- /dev/null
+
+:host >>> .popover {
+ font-family: monospace;
+ font-size: 120%;
+ max-width: 550px;
+}
+
+:host >>> .popover-body {
+ max-height: 400px;
+ overflow-y: auto;
+ overflow-x: auto;
+}
+
+:host >>> .popover-body .menu-entry {
+ white-space: nowrap;
+}
+
+:host >>> .popover-body .menu-entry:hover {
+ background-color: lightgrey;
+}
+
<ng-container *ngIf="fieldMeta">
+
+ <ng-template #menuContent>
+ <div *ngFor="let value of fieldValues" class="menu-entry">
+ <a (click)="fieldValue=value.value">
+ <span class="font-monospace">{{value.label}}</span>
+ </a>
+ </div>
+ </ng-template>
+
<div class="form-inline d-flex border-bottom">
- <label for='fixed-field-input-{{field}}' class="pr-2 flex-1">{{fieldLabel}}</label>
+ <label for='fixed-field-input-{{field}}' class="pr-2 flex-1">
+ {{fieldLabel}}
+ </label>
+
<input id='fixed-field-input-{{field}}' type="text"
(change)="valueChange($event)"
class="form-control p-1 flex-1" [(ngModel)]="fieldValue"
- [attr.maxlength]="fieldSize" [attr.size]="fieldSize"/>
+ [attr.maxlength]="fieldSize" [attr.size]="fieldSize"
+ [ngbPopover]="menuContent"
+ #p="ngbPopover" triggers="manual"
+ (contextmenu)="contextMenu($event, p)"
+ />
</div>
</ng-container>
-import {Component, Input, Output, OnInit, AfterViewInit, EventEmitter,
- OnDestroy} from '@angular/core';
+import {Component, Input, Output, OnInit, EventEmitter} from '@angular/core';
import {MarcRecord} from './marcrecord';
import {MarcEditContext} from './editor-context';
import {TagTableService} from './tagtable.service';
+import {NgbPopover} from '@ng-bootstrap/ng-bootstrap';
/**
* MARC Fixed Field Editing Component
*/
+interface FixedFieldValue {
+ value: string;
+ label: string;
+}
+
@Component({
selector: 'eg-fixed-field',
- templateUrl: './fixed-field.component.html'
+ templateUrl: './fixed-field.component.html',
+ styleUrls: ['fixed-field.component.css']
})
export class FixedFieldComponent implements OnInit {
fieldValue: string;
fieldMeta: any;
- fieldSize = 4;
+ fieldSize: number = null;
+ fieldValues: FixedFieldValue[] = null;
+ popOver: NgbPopover;
constructor(
private tagTable: TagTableService
) {}
ngOnInit() {
- this.init().then(_ =>
- this.context.recordChange.subscribe(_ => this.init()));
+ this.init().then(_ =>
+ this.context.recordChange.subscribe(__ => this.init()));
}
init(): Promise<any> {
if (!this.record) { return Promise.resolve(); }
+ this.fieldValues = null;
return this.tagTable.getFFPosTable(this.record.recordType())
.then(table => {
// Note the AngJS MARC editor stores the full POS table
- // for all record types in every copy of the table, hence
+ // for all record types in every copy of the table, hence
// the seemingly extraneous check in recordType.
- this.fieldMeta = table.filter(
- field => field.fixed_field === this.fieldCode
- && field.rec_type === this.record.recordType())[0];
+ this.fieldMeta = table.filter(field =>
+ field.fixed_field === this.fieldCode
+ && field.rec_type === this.record.recordType())[0];
if (!this.fieldMeta) {
// Not all record types have all field types.
}
this.fieldSize = this.fieldMeta.length || 1;
- this.fieldValue =
+ this.fieldValue =
this.context.record.extractFixedField(this.fieldCode);
- // Shuffling may occur wht our fixed field value based on
+ // Shuffling may occur with our fixed field as a result of
// external changes.
- this.record.fixedFieldChange.subscribe(_ =>
- this.fieldValue =
+ this.record.fixedFieldChange.subscribe(_ =>
+ this.fieldValue =
this.context.record.extractFixedField(this.fieldCode)
);
+
+ return this.tagTable.getFFValueTable(this.record.recordType());
+
+ }).then(values => {
+ if (!values || !values[this.fieldCode]) { return; }
+
+ // extract the canned set of possible values for our
+ // fixed field. Ignore those whose value exceeds the
+ // specified field length.
+ this.fieldValues = values[this.fieldCode]
+ .filter(val => val[0].length <= val[2])
+ .map(val => ({value: val[0], label: `${val[0]}: ${val[1]}`}))
+ .sort((a, b) => a.label < b.label ? -1 : 1);
});
}
valueChange(newVal) {
this.context.record.setFixedField(this.fieldCode, this.fieldValue);
}
+
+ contextMenu($event, popOver: NgbPopover) {
+ $event.preventDefault();
+ this.context.closePopovers();
+
+ if (this.fieldValues) {
+ if (!this.popOver) {
+ this.popOver = popOver;
+ this.context.popOvers.push(popOver);
+ }
+ this.popOver.open();
+ }
+ }
}
-<div class="mt-3">
- <div class="row">
- <div class="col-lg-10">
- <eg-fixed-fields-editor [context]="context"></eg-fixed-fields-editor>
+<ng-container *ngIf="!dataLoaded">
+ <eg-progress-inline></eg-progress-inline>
+</ng-container>
+
+<ng-container *ngIf="dataLoaded">
+ <div class="mt-3" class="text-monospace"
+ (contextmenu)="$event.preventDefault()">
+ <div class="row">
+ <div class="col-lg-10">
+ <eg-fixed-fields-editor [context]="context"></eg-fixed-fields-editor>
+ </div>
</div>
</div>
-</div>
+</ng-container>
@Input() context: MarcEditContext;
get record(): MarcRecord { return this.context.record; }
+ dataLoaded: boolean;
+
constructor(
private idl: IdlService,
private org: OrgService,
) {}
ngOnInit() {
- this.init().then(_ =>
- this.context.recordChange.subscribe(_ => this.init()));
+ this.init().then(_ =>
+ this.context.recordChange.subscribe(__ => this.init()));
}
init(): Promise<any> {
+ this.dataLoaded = false;
+
if (!this.record) { return Promise.resolve(); }
return Promise.all([
this.tagTable.getFFPosTable(this.record.recordType()),
this.tagTable.getFFValueTable(this.record.recordType())
- ]);
+ ]).then(_ => this.dataLoaded = true);
}
}
ffPosMap: {[rtype: string]: any[]} = {};
ffValueMap: {[rtype: string]: any} = {};
- promiseCache: {[ptype: string]: Promise<any>} = {};
constructor(
private store: StoreService,
return Promise.resolve(this.ffPosMap[rtype]);
}
- if (this.promiseCache[storeKey]) {
- return this.promiseCache[storeKey];
- }
-
- this.promiseCache[storeKey] = this.net.request(
+ return this.net.request(
'open-ils.fielder', 'open-ils.fielder.cmfpm.atomic',
{query: {tag: {'!=' : '006'}, rec_type: rtype}}
- ).toPromise().then(table => {
+ ).toPromise().then(table => {
this.store.setLocalItem(storeKey, table);
- delete this.promiseCache[storeKey];
return this.ffPosMap[rtype] = table;
});
-
- return this.promiseCache[storeKey];
}
getFFValueTable(rtype: string): Promise<any> {
return Promise.resolve(this.ffValueMap[rtype]);
}
- if (this.promiseCache[storeKey]) {
- return this.promiseCache[storeKey];
- }
-
- this.promiseCache[storeKey] = this.net.request(
+ return this.net.request(
'open-ils.cat',
'open-ils.cat.biblio.fixed_field_values.by_rec_type', rtype
+
).toPromise().then(table => {
- delete this.promiseCache[storeKey];
this.store.setLocalItem(storeKey, table);
return this.ffValueMap[rtype] = table;
});
-
- return this.promiseCache[storeKey];
}
}