}
iconFormatLabel(code: string): string {
- if (this.ccvmMap) {
+ if (this.ccvmMap && this.ccvmMap.icon_format) {
const ccvm = this.ccvmMap.icon_format.filter(
format => format.code() === code)[0];
if (ccvm) {
<div class="d-flex">
<input type="text"
class="form-control"
- [ngClass]="{'text-success font-italic font-weight-bold': selected && selected.freetext}"
+ [ngClass]="{
+ 'text-success font-italic font-weight-bold': selected && selected.freetext,
+ 'form-control-sm': smallFormControl
+ }"
[placeholder]="placeholder"
[name]="name"
[disabled]="isDisabled"
@Input() inputSize: number = null;
+ // If true, applies form-control-sm CSS
+ @Input() smallFormControl = false;
+
// Add a 'required' attribute to the input
isRequired: boolean;
@Input() set required(r: boolean) {
import {VolCopyComponent} from './volcopy.component';
const routes: Routes = [{
- path: 'edit/item/:item_id',
+ path: 'edit/item/:copy_id',
component: VolCopyComponent
}, {
path: 'edit/session/:session',
--- /dev/null
+
+<div class="row bg-info">
+ <b>BATCH</b>
+</div>
+
+<div class="row d-flex mt-2 mb-2">
+ <div class="p-1" [ngStyle]="{flex: flexAt(1)}">
+ <label class="font-weight-bold" i18n>Owning Library</label>
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(2)}">
+ <label class="font-weight-bold" i18n>Call Numbers</label>
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(3)}">
+ <label class="font-weight-bold" i18n>Classification</label>
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(4)}">
+ <label class="font-weight-bold" i18n>Prefix</label>
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(5)}">
+ <label class="font-weight-bold" i18n>Call Number Label</label>
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(6)}">
+ <label class="font-weight-bold" i18n>Suffix</label>
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(7)}">
+ <label class="font-weight-bold" i18n>Items</label>
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(8)}">
+ <label class="font-weight-bold" i18n>Barcode</label>
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(9)}">
+ <label class="font-weight-bold" i18n>Item #</label>
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(10)}">
+ <label class="font-weight-bold" i18n>Part</label>
+ </div>
+</div>
+
+
+<ng-container *ngFor="let orgNode of context.orgNodes(); let orgIdx = index">
+ <ng-container *ngFor="let volNode of orgNode.children; let volIdx = index">
+ <ng-container *ngFor="let copyNode of volNode.children; let copyIdx = index">
+ <div class="row d-flex mt-1">
+ <div class="p-1" [ngStyle]="{flex: flexAt(1)}">
+ <span *ngIf="volIdx == 0">{{orgNode.target.shortname()}}</span>
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(2)}">
+ <ng-container *ngIf="volIdx == 0">
+ <input type="number" class="form-control form-control-sm"
+ [ngModel]="orgNode.children.length"
+ (ngModelChange)="volCountChanged(orgNode, $event)"/>
+ </ng-container>
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(3)}">
+ <ng-container *ngIf="copyIdx == 0">
+ <eg-combobox
+ [entries]="volClasses"
+ [smallFormControl]="true"
+ [required]="true"
+ (onChange)="volClassChanged(volNode, $event)">
+ </eg-combobox>
+ </ng-container>
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(4)}">
+ <ng-container *ngIf="copyIdx == 0">
+ <eg-combobox
+ [smallFormControl]="true"
+ (onChange)="volPrefixChanged(volNode, $event)">
+ <eg-combobox-entry entryId="-1" entryLabel="<Unset>"
+ i18n-entryLabel></eg-combobox-entry>
+ <eg-combobox-entry *ngFor="let pfx of volPrefixes"
+ [entryId]="pfx.id()" [entryLabel]="pfx.label()">
+ </eg-combobox-entry>
+ </eg-combobox>
+ </ng-container>
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(5)}">
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(6)}">
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(7)}">
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(8)}">
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(9)}">
+ </div>
+ <div class="p-1" [ngStyle]="{flex: flexAt(10)}">
+ </div>
+ </div>
+ </ng-container>
+ </ng-container>
+</ng-container>
+
--- /dev/null
+import {Component, OnInit, AfterViewInit, ViewChild, Input, Renderer2} from '@angular/core';
+import {Router, ActivatedRoute, ParamMap} from '@angular/router';
+import {IdlObject} from '@eg/core/idl.service';
+import {OrgService} from '@eg/core/org.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {VolCopyContext, HoldingsTreeNode} from './volcopy';
+import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
+import {HoldingsService} from '@eg/staff/share/holdings/holdings.service';
+
+@Component({
+ selector: 'eg-vol-edit',
+ templateUrl: 'vol-edit.component.html'
+})
+
+
+export class VolEditComponent implements OnInit {
+
+ @Input() context: VolCopyContext;
+
+ // There are 10 columns in the editor form. Set the flex values
+ // here so they don't have to be hard-coded and repeated in the
+ // markup. Changing a flex value here will propagate to all
+ // rows in the form.
+ flexSettings: {[column: number]: number} = {
+ 1: 1, 2: 1, 3: 2, 4: 1, 5: 2, 6: 1, 7: 1, 8: 2, 9: 1, 10: 1};
+
+ volClasses: IdlObject[] = null;
+ volPrefixes: IdlObject[] = null;
+ volSuffixes: IdlObject[] = null;
+
+ constructor(
+ private holdings: HoldingsService
+ ) {}
+
+ ngOnInit() {
+
+ // TODO: Filter these to only show org-scoped values
+ // plus any values otherwise needed for the current
+ // holdings tree.
+
+ this.holdings.fetchCallNumberClasses().then(
+ classes => this.volClasses = classes);
+
+ this.holdings.fetchCallNumberPrefixes().then(prefixes => {
+ this.volPrefixes = prefixes.filter(pfx => pfx.id() !== -1)
+ });
+
+ this.holdings.fetchCallNumberSuffixes().then(suffixes =>
+ this.volSuffixes = suffixes.filter(pfx => pfx.id() !== -1));
+ }
+
+ flexAt(column: number): number {
+ return this.flexSettings[column];
+ }
+
+ volCountChanged(orgNode: HoldingsTreeNode, value: number) {
+ console.log('vol set set to ', value);
+ }
+
+ applyVolValue(vol: IdlObject, key: string, value: any) {
+ if (vol[key]() !== value) {
+ vol[key](value);
+ vol.ischanged(true);
+ }
+ }
+
+ volClassChanged(volNode: HoldingsTreeNode, entry: ComboboxEntry) {
+ if (!entry) { return; }
+ this.applyVolValue(volNode.target, 'label_class', entry.id);
+ }
+
+ volPrefixChanged(volNode: HoldingsTreeNode, entry: ComboboxEntry) {
+ if (!entry) { return; }
+ this.applyVolValue(volNode.target, 'prefix', entry.id);
+ }
+
+ volSuffixChanged(volNode: HoldingsTreeNode, entry: ComboboxEntry) {
+ if (!entry) { return; }
+ this.applyVolValue(volNode.target, 'suffix', entry.id);
+ }
+}
+
+<eg-staff-banner bannerText="Holdings Editor" i18n-bannerText></eg-staff-banner>
-VOLCOPY
+<ng-container *ngIf="!loading">
+
+ <eg-bib-summary *ngIf="recordId" [recordId]="recordId"></eg-bib-summary>
+
+ <div class="mt-3">
+ <eg-vol-edit [context]="context"></eg-vol-edit>
+ </div>
+
+</ng-container>
import {IdlObject} from '@eg/core/idl.service';
import {OrgService} from '@eg/core/org.service';
import {PcrudService} from '@eg/core/pcrud.service';
+import {HoldingsService} from '@eg/staff/share/holdings/holdings.service';
import {VolCopyContext} from './volcopy';
-const ITEM_FLESH = {
+const copy_FLESH = {
flesh: 1,
flesh_fields: {
acp: ['call_number', 'location']
export class VolCopyComponent implements OnInit {
context: VolCopyContext;
- itemId: number;
+ recordId: number;
+ copyId: number;
session: string;
- loading = false;
+ loading = true;
constructor(
private router: Router,
private route: ActivatedRoute,
private renderer: Renderer2,
private org: OrgService,
- private pcrud: PcrudService
+ private pcrud: PcrudService,
+ private holdings: HoldingsService
) { }
ngOnInit() {
}
negotiateRoute(params: ParamMap) {
- const itemId = +params.get('item_id');
- if (itemId) {
- if (itemId !== this.itemId) {
- this.itemId = itemId;
+ const copyId = +params.get('copy_id');
+ if (copyId) {
+ if (copyId !== this.copyId) {
+ this.copyId = copyId;
this.load();
}
} else {
- this.itemId = null;
+ this.copyId = null;
}
}
this.loading = true;
this.context.reset();
this.fetchHoldings()
+ .then(_ => this.holdings.fetchCallNumberClasses())
+ .then(_ => this.holdings.fetchCallNumberPrefixes())
+ .then(_ => this.holdings.fetchCallNumberSuffixes())
+ .then(_ => this.context.sortHoldings())
.then(_ => this.loading = false);
}
fetchHoldings(): Promise<any> {
- if (this.itemId) {
- return this.fetchItem();
+ if (this.copyId) {
+ return this.fetchCopy();
}
}
- fetchItem(): Promise<any> {
- return this.pcrud.retrieve('acp', this.itemId, ITEM_FLESH)
- .toPromise().then(item => {
- this.context.findOrCreateItemNode(item);
+ fetchCopy(): Promise<any> {
+ return this.pcrud.retrieve('acp', this.copyId, copy_FLESH)
+ .toPromise().then(copy => {
+ this.recordId = copy.call_number().record();
+ this.context.findOrCreateCopyNode(copy);
});
}
}
import {HoldingsModule} from '@eg/staff/share/holdings/holdings.module';
import {VolCopyRoutingModule} from './routing.module';
import {VolCopyComponent} from './volcopy.component';
+import {VolEditComponent} from './vol-edit.component';
@NgModule({
declarations: [
- VolCopyComponent
+ VolCopyComponent,
+ VolEditComponent
],
imports: [
StaffCommonModule,
import {IdlObject} from '@eg/core/idl.service';
import {OrgService} from '@eg/core/org.service';
-class HoldingsTreeNode {
+export class HoldingsTreeNode {
children: HoldingsTreeNode[];
- nodeType: 'org' | 'callNum' | 'item';
+ nodeType: 'org' | 'vol' | 'copy';
target: any;
parentNode: HoldingsTreeNode;
constructor() {
return node;
}
- findOrCreateCallNumNode(callNum: IdlObject): HoldingsTreeNode {
- const orgId = callNum.owning_lib();
+ findOrCreateCallNumNode(vol: IdlObject): HoldingsTreeNode {
+ const orgId = vol.owning_lib();
const orgNode = this.findOrCreateOrgNode(orgId);
const existing = orgNode.children.filter(
- n => n.target.id() === callNum.id())[0];
+ n => n.target.id() === vol.id())[0];
if (existing) { return existing; }
const node: HoldingsTreeNode = new HoldingsTreeNode();
- node.nodeType = 'callNum';
- node.target = callNum;
+ node.nodeType = 'vol';
+ node.target = vol;
node.parentNode = orgNode;
orgNode.children.push(node);
}
- findOrCreateItemNode(item: IdlObject): HoldingsTreeNode {
+ findOrCreateCopyNode(copy: IdlObject): HoldingsTreeNode {
- const callNumNode = this.findOrCreateCallNumNode(item.call_number());
+ const volNode = this.findOrCreateCallNumNode(copy.call_number());
- const existing = callNumNode.children.filter(
- c => c.target.id() === item.id())[0];
+ const existing = volNode.children.filter(
+ c => c.target.id() === copy.id())[0];
if (existing) { return existing; }
const node: HoldingsTreeNode = new HoldingsTreeNode();
- node.nodeType = 'item';
- node.target = item.
- node.parentNode = callNumNode;
+ node.nodeType = 'copy';
+ node.target = copy;
+ node.parentNode = volNode;
- callNumNode.children.push(node);
+ volNode.children.push(node);
return node;
}
sortHoldings() {
this.orgNodes().forEach(orgNode => {
- orgNode.children.forEach(callNumNode => {
+ orgNode.children.forEach(volNode => {
- // Sort items by barcode code
- callNumNode.children = callNumNode.children.sort((c1, c2) =>
+ // Sort copys by barcode code
+ volNode.children = volNode.children.sort((c1, c2) =>
c1.target.barcode() < c2.target.barcode() ? -1 : 1);
});
c1.target.label() < c2.target.label() ? -1 : 1);
});
-
// sort org units by shortname
this.holdings.root.children = this.orgNodes().sort((o1, o2) =>
o1.target.shortname() < o2.target.shortname() ? -1 : 1);
}
+
+ // Sorted list of holdings tree nodes
+ /*
+ flattenHoldings(): HoldingsTreeNode[] {
+ this.sortHoldings();
+ let nodes: HoldingsTreeNode[] = [];
+
+ this.orgNodes().forEach(orgNode => {
+ nodes.push(orgNode);
+ orgNode.children.forEach(volNode => {
+ nodes.push(volNode);
+ nodes = nodes.concat(volNode.children);
+ });
+ });
+
+ return nodes;
+ }
+ */
}
ngOnInit() {
- if (this.summary) {
- this.summary.getBibCallNumber();
- } else {
- if (this.recordId) {
- this.loadSummary();
- }
- }
-
this.store.getItem('eg.cat.record.summary.collapse')
.then(value => this.expand = !value)
- .then(() => this.initDone = true);
+ .then(_ => this.cat.fetchCcvms())
+ .then(_ => {
+ if (this.summary) {
+ return this.summary.getBibCallNumber();
+ } else {
+ if (this.recordId) {
+ return this.loadSummary();
+ }
+ }
+ }).then(_ => this.initDone = true);
}
saveExpandState() {
this.store.setItem('eg.cat.record.summary.collapse', !this.expand);
}
- loadSummary(): void {
- this.bib.getBibSummary(this.recordId).toPromise()
+ loadSummary(): Promise<any> {
+ return this.bib.getBibSummary(this.recordId).toPromise()
.then(summary => {
- summary.getBibCallNumber();
- this.bib.fleshBibUsers([summary.record]);
this.summary = summary;
- });
+ return summary.getBibCallNumber();
+ }).then(_ => this.bib.fleshBibUsers([this.summary.record]));
}
orgName(orgId: number): string {
* Common code for mananging holdings
*/
import {Injectable, EventEmitter} from '@angular/core';
+import {IdlObject, IdlService} from '@eg/core/idl.service';
import {NetService} from '@eg/core/net.service';
import {AnonCacheService} from '@eg/share/util/anon-cache.service';
import {AuthService} from '@eg/core/auth.service';
import {EventService} from '@eg/core/event.service';
+import {PcrudService} from '@eg/core/pcrud.service';
interface NewCallNumData {
owner?: number;
@Injectable()
export class HoldingsService {
+ callNumberClasses: IdlObject[];
+ callNumberPrefixes: IdlObject[];
+ callNumberSuffixes: IdlObject[];
+
constructor(
private net: NetService,
private auth: AuthService,
+ private pcrud: PcrudService,
private evt: EventService,
private anonCache: AnonCacheService
) {}
});
});
}
+
+ // Returns a sorted list of call number classes
+ fetchCallNumberClasses(): Promise<IdlObject[]> {
+ if (this.callNumberClasses) {
+ return Promise.resolve(this.callNumberClasses);
+ }
+
+ return this.pcrud.retrieveAll('acnc', {}, {atomic: true})
+ .toPromise().then(classes => {
+ this.callNumberClasses = classes.sort(
+ (c1, c2) => c1.name() < c2.name() ? -1 : 1);
+ return this.callNumberClasses;
+ });
+ }
+
+ // Returns a sorted list of call number prefixes
+ fetchCallNumberPrefixes(): Promise<IdlObject[]> {
+ if (this.callNumberPrefixes) {
+ console.log('H2', this.callNumberPrefixes);
+ return Promise.resolve(this.callNumberPrefixes);
+ }
+
+ return this.pcrud.retrieveAll('acnp', {}, {atomic: true})
+ .toPromise().then(prefixes => {
+ this.callNumberPrefixes = prefixes.sort(
+ (c1, c2) => c1.label_sortkey() < c2.label_sortkey() ? -1 : 1);
+ console.log('H1', this.callNumberPrefixes);
+ return this.callNumberPrefixes;
+ });
+ }
+
+ // Returns a sorted list of call number suffixes
+ fetchCallNumberSuffixes(): Promise<IdlObject[]> {
+ if (this.callNumberSuffixes) {
+ return Promise.resolve(this.callNumberSuffixes);
+ }
+
+ return this.pcrud.retrieveAll('acns', {}, {atomic: true})
+ .toPromise().then(suffixes => {
+ this.callNumberSuffixes = suffixes.sort(
+ (c1, c2) => c1.label_sortkey() < c2.label_sortkey() ? -1 : 1);
+ return this.callNumberSuffixes;
+ });
+ }
+
}