})
export class EgAccessKeyDirective implements OnInit {
+ // Space-separated list of key combinations
+ // E.g. "ctrl+h", "alt+h ctrl+y"
@Input() keySpec: string;
+
+ // Description to display in the accesskey info dialog
@Input() keyDesc: string;
+
+ // Context info to display in the accesskey info dialog
+ // E.g. "navbar"
@Input() keyCtx: string;
constructor(
private keyService: EgAccessKeyService
) { }
-
ngOnInit() {
- /*
- console.debug(
- `EgAccessKey assigning '${this.keySpec}' => ${this.keyDesc}`);
- */
-
- this.keyService.assign({
- key: this.keySpec,
- desc: this.keyDesc,
- ctx: this.keyCtx,
- action: () => {this.elm.nativeElement.click()}
- });
+ if (!this.keySpec) {
+ console.warn("EgAccessKey no keySpec provided");
+ return;
+ }
+
+ this.keySpec.split(/ /).forEach(keySpec => {
+ this.keyService.assign({
+ key: keySpec,
+ desc: this.keyDesc,
+ ctx: this.keyCtx,
+ action: () => {this.elm.nativeElement.click()}
+ });
+ })
}
}
<label for="rec-{{field.name}}">{{field.label}}</label>
</div>
<div class="col-lg-7">
- <!-- TODO custom field templates -->
- <span *ngIf="field.datatype == 'id' && !pkeyIsEditable">
- {{record[field.name]()}}
- </span>
-
- <input *ngIf="field.datatype == 'id' && pkeyIsEditable"
- class="form-control"
- [name]="field.name"
- [readonly]="field.readOnly"
- [required]="field.isRequired()"
- [ngModel]="record[field.name]()"
- (ngModelChange)="record[field.name]($event)"/>
- <input *ngIf="field.datatype == 'text'"
- class="form-control"
- [name]="field.name"
- [readonly]="field.readOnly"
- [required]="field.isRequired()"
- [ngModel]="record[field.name]()"
- (ngModelChange)="record[field.name]($event)"/>
-
- <input *ngIf="field.datatype == 'int'"
- class="form-control"
- type="number"
- [name]="field.name"
- [readonly]="field.readOnly"
- [required]="field.isRequired()"
- [ngModel]="record[field.name]()"
- (ngModelChange)="record[field.name]($event)"/>
+ <span *ngIf="field.template">
+ <ng-container
+ *ngTemplateOutlet="field.template; context:customTemplateFieldContext(field)">
+ </ng-container>
+ </span>
- <input *ngIf="field.datatype == 'float'"
- class="form-control"
- type="number" step="0.1"
- [name]="field.name"
- [readonly]="field.readOnly"
- [required]="field.isRequired()"
- [ngModel]="record[field.name]()"
- (ngModelChange)="record[field.name]($event)"/>
+ <span *ngIf="!field.template">
- <span *ngIf="field.datatype == 'money'">
- <!-- in read-only mode display the local-aware currency -->
- <input *ngIf="field.readOnly"
+ <span *ngIf="field.datatype == 'id' && !pkeyIsEditable">
+ {{record[field.name]()}}
+ </span>
+
+ <input *ngIf="field.datatype == 'id' && pkeyIsEditable"
class="form-control"
- type="number" step="0.1"
- [name]="field.name"
+ name="{{field.name}}"
[readonly]="field.readOnly"
[required]="field.isRequired()"
- [ngModel]="record[field.name]() | currency"/>
-
- <input *ngIf="!field.readOnly"
+ [ngModel]="record[field.name]()"
+ (ngModelChange)="record[field.name]($event)"/>
+
+ <input *ngIf="field.datatype == 'text'"
class="form-control"
- type="number" step="0.1"
- [name]="field.name"
+ name="{{field.name}}"
[readonly]="field.readOnly"
[required]="field.isRequired()"
[ngModel]="record[field.name]()"
(ngModelChange)="record[field.name]($event)"/>
- </span>
-
- <input *ngIf="field.datatype == 'bool'"
- class="form-check-input"
- type="checkbox"
- [name]="field.name"
- [readonly]="field.readOnly"
- [ngModel]="record[field.name]()"
- (ngModelChange)="record[field.name]($event)"/>
-
- <span *ngIf="field.datatype == 'link'"
- [ngClass]="{nullable : !field.isRequired()}">
- <select
+
+ <input *ngIf="field.datatype == 'int'"
+ class="form-control"
+ type="number"
+ name="{{field.name}}"
+ [readonly]="field.readOnly"
+ [required]="field.isRequired()"
+ [ngModel]="record[field.name]()"
+ (ngModelChange)="record[field.name]($event)"/>
+
+ <input *ngIf="field.datatype == 'float'"
class="form-control"
- [name]="field.name"
- [disabled]="field.readOnly"
+ type="number" step="0.1"
+ name="{{field.name}}"
+ [readonly]="field.readOnly"
[required]="field.isRequired()"
[ngModel]="record[field.name]()"
- (ngModelChange)="record[field.name]($event)">
- <option *ngFor="let item of field.linkedValues"
- [value]="item.id">{{item.name}}</option>
- </select>
- </span>
-
- <eg-org-select *ngIf="field.datatype == 'org_unit'"
- [placeholder]="field.label"
- [applyDefault]="field.orgDefaultAllowed"
- [initialOrgId]="record[field.name]()"
- (onChange)="record[field.name]($event)">
- </eg-org-select>
+ (ngModelChange)="record[field.name]($event)"/>
+
+ <span *ngIf="field.datatype == 'money'">
+ <!-- in read-only mode display the local-aware currency -->
+ <input *ngIf="field.readOnly"
+ class="form-control"
+ type="number" step="0.1"
+ name="{{field.name}}"
+ [readonly]="field.readOnly"
+ [required]="field.isRequired()"
+ [ngModel]="record[field.name]() | currency"/>
+
+ <input *ngIf="!field.readOnly"
+ class="form-control"
+ type="number" step="0.1"
+ name="{{field.name}}"
+ [readonly]="field.readOnly"
+ [required]="field.isRequired()"
+ [ngModel]="record[field.name]()"
+ (ngModelChange)="record[field.name]($event)"/>
+ </span>
+
+ <input *ngIf="field.datatype == 'bool'"
+ class="form-check-input"
+ type="checkbox"
+ name="{{field.name}}"
+ [readonly]="field.readOnly"
+ [ngModel]="record[field.name]()"
+ (ngModelChange)="record[field.name]($event)"/>
+
+ <span *ngIf="field.datatype == 'link'"
+ [ngClass]="{nullable : !field.isRequired()}">
+ <select
+ class="form-control"
+ name="{{field.name}}"
+ [disabled]="field.readOnly"
+ [required]="field.isRequired()"
+ [ngModel]="record[field.name]()"
+ (ngModelChange)="record[field.name]($event)">
+ <option *ngFor="let item of field.linkedValues"
+ [value]="item.id">{{item.name}}</option>
+ </select>
+ </span>
+
+ <eg-org-select *ngIf="field.datatype == 'org_unit'"
+ [placeholder]="field.label"
+ [applyDefault]="field.orgDefaultAllowed"
+ [initialOrgId]="record[field.name]()"
+ (onChange)="record[field.name]($event)">
+ </eg-org-select>
+ </span>
</div>
</div>
</form>
-import {Component, OnInit, Input, Output, ViewChild, EventEmitter} from '@angular/core';
+import {Component, OnInit, Input,
+ Output, EventEmitter, TemplateRef} from '@angular/core';
import {EgIdlService, EgIdlObject} from '@eg/core/idl.service';
import {EgAuthService} from '@eg/core/auth.service';
import {EgPcrudService} from '@eg/core/pcrud.service';
import {EgDialogComponent} from '@eg/share/dialog/dialog.component';
import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap';
+interface CustomFieldTemplate {
+ template: TemplateRef<any>,
+
+ // Allow the caller to pass in a free-form context blob to
+ // be addedto the caller's custom template context, along
+ // with our stock context.
+ context?: [fields: string]: any
+}
+
+interface CustomFieldContext {
+ // Current create/edit/view record
+ record: EgIdlObject,
+
+ // IDL field definition blob
+ field: any,
+
+ // additional context values passed via CustomFieldTemplate
+ [fields: string]: any;
+}
+
@Component({
selector: 'fm-record-editor',
templateUrl: './fm-editor.component.html'
// mode: 'create' for creating a new record,
// 'update' for editing an existing record
// 'view' for viewing an existing record without editing
- @Input() mode: string;
+ @Input() mode: 'create' | 'update' | 'view' = 'create';
- // Record ID to view/update. Value is dynamic.
+ // Record ID to view/update. Value is dynamic. Records are not
+ // fetched until .open() is called.
recId: any;
@Input() set recordId(id: any) {
if (id) this.recId = id;
}
// IDL record we are editing
- // TODO: allow this to be provided by the caller?
+ // TODO: allow this to be update in real time by the caller?
record: EgIdlObject;
- // TODO
- // customFieldTemplates
+ @Input() customFieldTemplates:
+ {[fieldName:string] : CustomFieldTemplate} = {};
// list of fields that should not be displayed
@Input() hiddenFieldsList: string[] = [];
this.orgDefaultAllowedList.includes(field.name);
}
- // TODO custom field templates
+ if (this.customFieldTemplates[field.name]) {
+ field.template = this.customFieldTemplates[field.name].template;
+ field.context = this.customFieldTemplates[field.name].context;
+ }
+
});
// Wait for all network calls to complete
return Promise.all(promises);
}
+ // Returns a context object to be inserted into a custom
+ // field template.
+ customTemplateFieldContext(fieldDef: any): FmEditorCustomFieldContext {
+ return Object.assign(
+ { record : this.record,
+ field: fieldDef // from this.fields
+ }, fieldDef.context || {}
+ );
+ }
+
save() {
let recToSave = this.idl.clone(this.record);
this.convertDatatypesToIdl(recToSave);
<fieldset>
<legend class="mb-0" i18n>Sign In</legend>
<hr class="mt-1"/>
- <form (ngSubmit)="handleSubmit()" #loginForm="ngForm">
+ <form (ngSubmit)="handleSubmit()" #loginForm="ngForm" class="form-validated">
<div class="form-group row">
<label class="col-lg-4 text-right font-weight-bold" for="username" i18n>Username</label>
}
/* move the caret closer to the dropdown text */
-#staff-navbar .dropdown-toggle::after {
- margin-left:0px;
+#staff-navbar {
+ padding-left: 0px;
}
#staff-navbar {
}
#staff-navbar .navbar-nav {
- padding: 3px;
+ padding: 4px;
}
/* align top of dropdown w/ bottom of nav */
<div class="navbar-nav mr-auto"></div>
- <div class="navbar-nav">
+ <div class="navbar-nav" *ngIf="user">
<span i18n>{{user}} @ {{workstation}}</span>
</div>
- <div class="navbar-nav">
+ <div class="navbar-nav" *ngIf="user">
<div ngbDropdown class="nav-item dropdown" placement="bottom-right">
<a ngbDropdownToggle i18n
i18n-title
title="Log out and more..."
class="nav-link dropdown-toggle no-caret with-material-icon">
- <i class="material-icons">more_vert</i>
+ <i class="material-icons">list</i>
</a>
<div class="dropdown-menu" ngbDropdownMenu>
<a class="dropdown-item" (click)="logout()">
<eg-staff-banner bannerText="Sandbox" i18n-bannerText>
</eg-staff-banner>
-<!--
-idlClass="cmrcfld"
-idlClass="cbt"
--->
-<fm-record-editor #fmRecordEditor
- idlClass="cmrcfld" mode="create"
- recordId="1" orgDefaultAllowed="owner">
-</fm-record-editor>
-<button class="btn btn-dark" (click)="fmRecordEditor.open({size:'lg'})">
- Fm Record Editor
-</button>
+<!-- FM Editor Experiments ----------------------------- -->
+<div class="row mb-3">
+ <ng-template #descriptionTemplate
+ let-field="field" let-record="record" let-hello="hello">
+ <!-- example custom template for editing the 'description' field -->
+ <textarea
+ placeholder="{{hello}}"
+ class="form-control"
+ name="{{field.name}}"
+ [readonly]="field.readOnly"
+ [required]="field.isRequired()"
+ [ngModel]="record[field.name]()"
+ (ngModelChange)="record[field.name]($event)">
+ </textarea>
+ </ng-template>
+ <fm-record-editor #fmRecordEditor
+ idlClass="cmrcfld" mode="create"
+ [customFieldTemplates]="{description:{template:descriptionTemplate,context:{'hello':'goodbye'}}}"
+ recordId="1" orgDefaultAllowed="owner">
+ </fm-record-editor>
+ <button class="btn btn-dark" (click)="fmRecordEditor.open({size:'lg'})">
+ Fm Record Editor
+ </button>
+</div>
+<!-- / FM Editor Experiments ----------------------------- -->
-<!-- ----- -->
-<br/><br/>
-<eg-progress-dialog #progressDialog>
-</eg-progress-dialog>
-<button class="btn btn-light" (click)="showProgress()">Test Progress Dialog</button>
+<!-- Progress Dialog Experiments ----------------------------- -->
+<div class="row mb-3">
+ <eg-progress-dialog #progressDialog>
+ </eg-progress-dialog>
+ <button class="btn btn-light" (click)="showProgress()">Test Progress Dialog</button>
+</div>
+<!-- /Progress Dialog Experiments ----------------------------- -->
background-color: #007a54;
color: #fff;
}
+
+ /* Match the ang1 splash page */
+ .card-header {
+ color: #3c763d;
+ background-color: #dff0d8;
+ border-color: #d6e9c6;
+ }
</style>
<div class="container">
<div class="row" id="splash-nav">
<div class="col-lg-4">
<div class="card">
- <div class="card-header bg-evergreen">
+ <div class="card-header">
<div class="panel-title text-center">Circulation and Patrons</div>
</div>
<div class="card-body">
<div class="col-lg-4">
<div class="card">
- <div class="card-header bg-evergreen">
+ <div class="card-header">
<div class="panel-title text-center">Item Search and Cataloging</div>
</div>
<div class="card-body">
<div class="col-lg-4">
<div class="card">
- <div class="card-header bg-evergreen">
+ <div class="card-header">
<div class="panel-title text-center">Administration</div>
</div>
<div class="card-body">