import {Injectable} from '@angular/core';
import {ParamMap} from '@angular/router';
import {OrgService} from '@eg/core/org.service';
-import {CatalogSearchContext, FacetFilter} from './search-context';
+import {CatalogSearchContext, CatalogBrowseContext, CatalogMarcContext,
+ CatalogTermContext, FacetFilter} from './search-context';
import {CATALOG_CCVM_FILTERS} from './catalog.service';
@Injectable()
toUrlParams(context: CatalogSearchContext):
{[key: string]: string | string[]} {
- const params = {
- query: [],
- fieldClass: [],
- joinOp: [],
- matchOp: [],
- facets: [],
- identQuery: null,
- identQueryType: null,
- org: null,
- limit: null,
- offset: null,
- copyLocations: null,
- browsePivot: null,
- hasBrowseEntry: null,
- marcTag: [''],
- marcSubfield: [''],
- marcValue: ['']
- };
-
- params.org = context.searchOrg.id();
-
- params.limit = context.pager.limit;
+ const params: any = {};
+
+ if (context.searchOrg) {
+ params.org = context.searchOrg.id();
+ }
+
+ if (context.pager.limit) {
+ params.limit = context.pager.limit;
+ }
+
if (context.pager.offset) {
params.offset = context.pager.offset;
}
// These fields can be copied directly into place
- ['format', 'sort', 'available', 'global', 'identQuery',
- 'identQueryType', 'basket', 'browsePivot', 'hasBrowseEntry']
+ ['limit', 'offset', 'sort', 'global', 'showBasket', 'sort']
.forEach(field => {
if (context[field]) {
// Only propagate applied values to the URL.
}
});
- if (params.identQuery) {
- // Ident queries (e.g. tcn search) discards all remaining filters
- return params;
- } else {
- // Avoid propagating the type when it's not used.
- delete params.identQueryType;
+ if (context.marcSearch.isSearchable()) {
+ const ms = context.marcSearch;
+ params.marcTag = [];
+ params.marcSubfield = [];
+ params.marcValue = [];
+
+ ms.values.forEach((val, idx) => {
+ if (val !== '') {
+ params.marcTag.push(ms.tags[idx]);
+ params.marcSubfield.push(ms.subfields[idx]);
+ params.marcValue.push(ms.values[idx]);
+ }
+ });
}
- context.query.filter(q => q !== '').forEach((q, idx) => {
- ['query', 'fieldClass', 'joinOp', 'matchOp'].forEach(field => {
- // Propagate all array-based fields regardless of
- // whether a value is applied to ensure correct
- // correlation between values
- params[field][idx] = context[field][idx];
- });
- });
+ if (context.identSearch.isSearchable()) {
+ params.identQuery = context.identSearch.value;
+ params.identQueryType = context.identSearch.queryType;
+ }
- context.marcValue.filter(v => v !== '').forEach((val, idx) => {
- ['marcValue', 'marcTag', 'marcSubfield'].forEach(field => {
- params[field][idx] = context[field][idx];
- });
- });
+ if (context.browseSearch.isSearchable()) {
+ params.browseTerm = context.browseSearch.value;
+ params.browseClass = context.browseSearch.fieldClass;
+ if (context.browseSearch.pivot) {
+ params.browsePivot = context.browseSearch.pivot;
+ }
+ }
+
+ if (context.termSearch.isSearchable()) {
+
+ const ts = context.termSearch;
- // CCVM filters are encoded as comma-separated lists
- Object.keys(context.ccvmFilters).forEach(code => {
- if (context.ccvmFilters[code] &&
- context.ccvmFilters[code][0] !== '') {
- params[code] = context.ccvmFilters[code].join(',');
+ params.query = [];
+ params.fieldClass = [];
+ params.joinOp = [];
+ params.matchOp = [];
+
+ if (ts.format) {
+ params.format = ts.format;
}
- });
- // Each facet is a JSON encoded blob of class, name, and value
- context.facetFilters.forEach(facet => {
- params.facets.push(JSON.stringify({
- c : facet.facetClass,
- n : facet.facetName,
- v : facet.facetValue
- }));
- });
+ if (ts.available) {
+ params.available = ts.available;
+ }
+
+ if (ts.hasBrowseEntry) {
+ params.hasBrowseEntry = ts.hasBrowseEntry;
+ }
+
+ ts.query.forEach((val, idx) => {
+ if (val !== '') {
+ params.query.push(ts.query[idx]);
+ params.fieldClass.push(ts.fieldClass[idx]);
+ params.joinOp.push(ts.joinOp[idx]);
+ params.matchOp.push(ts.matchOp[idx]);
+ }
+ });
- if (context.copyLocations.length && context.copyLocations[0] !== '') {
- params.copyLocations = context.copyLocations.join(',');
+ // CCVM filters are encoded as comma-separated lists
+ Object.keys(ts.ccvmFilters).forEach(code => {
+ if (ts.ccvmFilters[code] &&
+ ts.ccvmFilters[code][0] !== '') {
+ params[code] = ts.ccvmFilters[code].join(',');
+ }
+ });
+
+ // Each facet is a JSON encoded blob of class, name, and value
+ if (ts.facetFilters.length) {
+ params.facets = [];
+ ts.facetFilters.forEach(facet => {
+ params.facets.push(JSON.stringify({
+ c : facet.facetClass,
+ n : facet.facetName,
+ v : facet.facetValue
+ }));
+ });
+ }
+
+ if (ts.copyLocations.length && ts.copyLocations[0] !== '') {
+ params.copyLocations = ts.copyLocations.join(',');
+ }
}
return params;
// Reset query/filter args. The will be reconstructed below.
context.reset();
+ let val;
- // These fields can be copied directly into place
- ['format', 'sort', 'available', 'global', 'identQuery',
- 'identQueryType', 'basket', 'browsePivot', 'hasBrowseEntry']
- .forEach(field => {
- const val = params.get(field);
- if (val !== null) {
- context[field] = val;
- }
- });
+ if (params.get('org')) {
+ context.searchOrg = this.org.get(+params.get('org'));
+ }
+
+ if (val = params.get('limit')) {
+ context.pager.limit = +val;
+ }
+
+ if (val = params.get('offset')) {
+ context.pager.offset = +val;
+ }
+
+ if (val = params.get('sort')) {
+ context.sort = val;
+ }
+
+ if (val = params.get('global')) {
+ context.global = val;
+ }
+
+ if (val = params.get('showBasket')) {
+ context.showBasket = val;
+ }
- if (params.get('limit')) {
- context.pager.limit = +params.get('limit');
+ if (params.get('marcValue')) {
+ context.marcSearch.tags = params.getAll('marcTag');
+ context.marcSearch.subfields = params.getAll('marcSubfield');
+ context.marcSearch.values = params.getAll('marcValue');
}
- if (params.get('offset')) {
- context.pager.offset = +params.get('offset');
+ if (params.get('identQuery')) {
+ context.identSearch.value = params.get('identQuery');
+ context.identSearch.queryType = params.get('identQueryType');
}
- ['query', 'fieldClass', 'joinOp', 'matchOp'].forEach(field => {
- const arr = params.getAll(field);
- if (arr && arr.length) {
- context[field] = arr;
+ if (params.get('browseTerm')) {
+ context.browseSearch.value = params.get('browseTerm');
+ context.browseSearch.fieldClass = params.get('browseClass');
+ if (params.has('browsePivot')) {
+ context.browseSearch.pivot = +params.get('browsePivot');
}
- });
+ }
+
+ const ts = context.termSearch;
- ['marcValue', 'marcTag', 'marcSubfield'].forEach(field => {
- const arr = params.getAll(field);
- if (arr && arr.length) {
- context[field] = arr;
+ if (params.has('hasBrowseEntry')) {
+ ts.hasBrowseEntry = params.get('hasBrowseEntry');
+
+ } else if (params.has('query')) {
+
+ if (params.has('format')) {
+ ts.format = params.get('format');
}
- });
- CATALOG_CCVM_FILTERS.forEach(code => {
- const val = params.get(code);
- if (val) {
- context.ccvmFilters[code] = val.split(/,/);
- } else {
- context.ccvmFilters[code] = [''];
+ if (params.get('available')) {
+ ts.available = Boolean(params.get('available'));
}
- });
- params.getAll('facets').forEach(blob => {
- const facet = JSON.parse(blob);
- context.addFacet(new FacetFilter(facet.c, facet.n, facet.v));
- });
+ ['query', 'fieldClass', 'joinOp', 'matchOp'].forEach(field => {
+ const arr = params.getAll(field);
+ if (params.has(field)) {
+ ts[field] = params.getAll(field); // array
+ }
+ });
- if (params.get('org')) {
- context.searchOrg = this.org.get(+params.get('org'));
- }
+ CATALOG_CCVM_FILTERS.forEach(code => {
+ const val = params.get(code);
+ if (val) {
+ ts.ccvmFilters[code] = val.split(/,/);
+ } else {
+ ts.ccvmFilters[code] = [''];
+ }
+ });
+
+ params.getAll('facets').forEach(blob => {
+ const facet = JSON.parse(blob);
+ ts.addFacet(new FacetFilter(facet.c, facet.n, facet.v));
+ });
- if (params.get('copyLocations')) {
- context.copyLocations = params.get('copyLocations').split(/,/);
+ if (params.get('copyLocations')) {
+ ts.copyLocations = params.get('copyLocations').split(/,/);
+ }
}
}
}
+
+
search(ctx: CatalogSearchContext): Promise<void> {
ctx.searchState = CatalogSearchState.SEARCHING;
- if (ctx.basket) {
+ if (ctx.showBasket) {
return this.basketSearch(ctx);
- } else if (ctx.marcValue[0] !== '') {
+ } else if (ctx.marcSearch.isSearchable()) {
return this.marcSearch(ctx);
- } else if (ctx.identQueryType === 'item_barcode') {
+ } else if (ctx.identSearch.isSearchable() &&
+ ctx.identSearch.queryType === 'item_barcode') {
return this.barcodeSearch(ctx);
} else {
return this.querySearch(ctx);
return this.net.request(
'open-ils.search',
'open-ils.search.multi_home.bib_ids.by_barcode',
- ctx.identQuery
+ ctx.identSearch.value
).toPromise().then(ids => {
const result = {
count: ids.length,
let method = 'open-ils.search.biblio.marc';
if (ctx.isStaff) { method += '.staff'; }
- const queryStruct = ctx.compileMarcSearch();
+ const queryStruct = ctx.compileMarcSearchArgs();
return this.net.request('open-ils.search', method, queryStruct)
.toPromise().then(result => {
}
querySearch(ctx: CatalogSearchContext): Promise<void> {
- const fullQuery = ctx.compileSearch();
+ let fullQuery;
+
+ if (ctx.identSearch.isSearchable()) {
+ console.log('IDENT IS SEARCHABLE');
+ fullQuery = ctx.compileIdentSearchQuery();
+ } else {
+ fullQuery = ctx.compileTermSearchQuery();
+ }
console.debug(`search query: ${fullQuery}`);
return Promise.reject('Cannot fetch facets without results');
}
+ if (!ctx.result.facet_key) {
+ return Promise.resolve();
+ }
+
if (this.lastFacetKey === ctx.result.facet_key) {
ctx.result.facetData = this.lastFacetData;
return Promise.resolve();
browse(ctx: CatalogSearchContext): Observable<any> {
ctx.searchState = CatalogSearchState.SEARCHING;
+ const bs = ctx.browseSearch;
let method = 'open-ils.search.browse';
if (ctx.isStaff) {
return this.net.request(
'open-ils.search',
'open-ils.search.browse.staff', {
- browse_class: ctx.fieldClass[0],
- term: ctx.query[0],
+ browse_class: bs.fieldClass,
+ term: bs.value,
limit : ctx.pager.limit,
- pivot: ctx.browsePivot,
+ pivot: bs.pivot,
org_unit: ctx.searchOrg.id()
}
).pipe(tap(result => {
}
}
-// Not an angular service.
-// It's conceviable there could be multiple contexts.
-export class CatalogSearchContext {
+export class CatalogSearchResults {
+ ids: number[];
+ count: number;
+ [misc: string]: any;
- // Search options and filters
- available = false;
- global = false;
- sort: string;
+ constructor() {
+ this.ids = [];
+ this.count = 0;
+ }
+}
+
+export class CatalogBrowseContext {
+ value: string;
+ pivot: number;
+ fieldClass: string;
+
+ reset() {
+ this.value = '';
+ this.pivot = null;
+ this.fieldClass = 'title';
+ }
+
+ isSearchable(): boolean {
+ return (
+ this.value !== '' &&
+ this.fieldClass !== ''
+ );
+ }
+}
+
+export class CatalogMarcContext {
+ tags: string[];
+ subfields: string[];
+ values: string[];
+
+ reset() {
+ this.tags = [''];
+ this.values = [''];
+ this.subfields = [''];
+ }
+
+ isSearchable() {
+ return (
+ this.tags[0] !== '' &&
+ this.values[0] !== ''
+ );
+ }
+
+}
+
+export class CatalogIdentContext {
+ value: string;
+ queryType: string;
+
+ reset() {
+ this.value = '';
+ this.queryType = '';
+ }
+
+ isSearchable() {
+ return (
+ this.value !== ''
+ && this.queryType !== ''
+ );
+ }
+
+}
+
+export class CatalogTermContext {
fieldClass: string[];
query: string[];
- identQuery: string;
- identQueryType: string; // isbn, issn, etc.
joinOp: string[];
matchOp: string[];
format: string;
- searchOrg: IdlObject;
+ available = false;
ccvmFilters: {[ccvmCode: string]: string[]};
facetFilters: FacetFilter[];
- isStaff: boolean;
- basket = false;
copyLocations: string[]; // ID's, but treated as strings in the UI.
- browsePivot: number;
- hasBrowseEntry: string; // "entryId,fieldId"
- marcTag: string[];
- marcSubfield: string[];
- marcValue: string[];
isMetarecord: boolean; // TODO
+ hasBrowseEntry: string; // "entryId,fieldId"
+
+ reset() {
+ this.query = [''];
+ this.fieldClass = ['keyword'];
+ this.matchOp = ['contains'];
+ this.joinOp = [''];
+ this.ccvmFilters = {};
+ this.facetFilters = [];
+ this.copyLocations = [''];
+ this.format = '';
+ this.hasBrowseEntry = '';
+ }
+
+ isSearchable(): boolean {
+ return (
+ this.query[0] !== ''
+ || this.hasBrowseEntry !== ''
+ );
+ }
+
+ hasFacet(facet: FacetFilter): boolean {
+ return Boolean(
+ this.facetFilters.filter(f => f.equals(facet))[0]
+ );
+ }
+
+ removeFacet(facet: FacetFilter): void {
+ this.facetFilters = this.facetFilters.filter(f => !f.equals(facet));
+ }
+
+ addFacet(facet: FacetFilter): void {
+ if (!this.hasFacet(facet)) {
+ this.facetFilters.push(facet);
+ }
+ }
+
+ toggleFacet(facet: FacetFilter): void {
+ if (this.hasFacet(facet)) {
+ this.removeFacet(facet);
+ } else {
+ this.facetFilters.push(facet);
+ }
+ }
+
+}
+
+
+
+// Not an angular service.
+// It's conceviable there could be multiple contexts.
+export class CatalogSearchContext {
+
+ // Attributes that are used across different contexts.
+ sort: string;
+ isStaff: boolean;
+ showBasket: boolean;
+ searchOrg: IdlObject;
+ global: boolean;
+
+ termSearch: CatalogTermContext;
+ marcSearch: CatalogMarcContext;
+ identSearch: CatalogIdentContext;
+ browseSearch: CatalogBrowseContext;
// Result from most recent search.
- result: any = {};
+ result: CatalogSearchResults;
searchState: CatalogSearchState = CatalogSearchState.PENDING;
// List of IDs in page/offset context.
- resultIds: number[] = [];
+ resultIds: number[];
// Utility stuff
pager: Pager;
constructor() {
this.pager = new Pager();
+ this.termSearch = new CatalogTermContext();
+ this.marcSearch = new CatalogMarcContext();
+ this.identSearch = new CatalogIdentContext();
+ this.browseSearch = new CatalogBrowseContext();
this.reset();
}
+ /**
+ * Return search context to its default state, resetting search
+ * parameters and clearing any cached result data.
+ */
+ reset(): void {
+ this.pager.offset = 0;
+ this.sort = '';
+ this.showBasket = false;
+ this.result = new CatalogSearchResults();
+ this.resultIds = [];
+ this.searchState = CatalogSearchState.PENDING;
+ this.termSearch.reset();
+ this.marcSearch.reset();
+ this.identSearch.reset();
+ this.browseSearch.reset();
+ }
+
+ isSearchable(): boolean {
+ return (
+ this.showBasket ||
+ this.termSearch.isSearchable() ||
+ this.marcSearch.isSearchable() ||
+ this.identSearch.isSearchable() ||
+ this.browseSearch.isSearchable()
+ );
+ }
+
// List of result IDs for the current page of data.
currentResultIds(): number[] {
const ids = [];
return null;
}
- /**
- * Return search context to its default state, resetting search
- * parameters and clearing any cached result data.
- * This does not reset global filters like limit-to-available
- * search-global, or search-org.
- */
- reset(): void {
- this.pager.offset = 0;
- this.format = '';
- this.sort = '';
- this.query = [''];
- this.identQuery = null;
- this.identQueryType = 'identifier|isbn';
- this.fieldClass = ['keyword'];
- this.matchOp = ['contains'];
- this.joinOp = [''];
- this.ccvmFilters = {};
- this.facetFilters = [];
- this.result = {};
- this.resultIds = [];
- this.searchState = CatalogSearchState.PENDING;
- this.basket = false;
- this.copyLocations = [''];
- this.marcTag = [''];
- this.marcSubfield = [''];
- this.marcValue = [''];
- }
-
- // Returns true if we have enough information to perform a search.
- isSearchable(): boolean {
- return this.searchType() !== null;
- }
-
- // Returns the type of search that would be performed from this
- // context object if a search were run now.
- // Returns NULL if no search is possible.
- searchType(): string {
-
- if (this.basket) {
- return 'basket';
- }
-
- if (this.identQuery && this.identQueryType) {
- return 'ident';
- }
-
- if (this.marcTag[0] !== '' && this.marcValue[0] !== '') {
- // MARC field search
- return 'marc';
- }
-
- // searchOrg required for all following search scenarios
- if (this.searchOrg === null) {
- return null;
- }
-
- if (this.hasBrowseEntry) {
- // Limit results by records that link to browse entry
- return 'browse';
- }
-
- // Query search
- if (this.query.length && this.query[0] !== '') {
- return 'query';
- }
-
- return null;
- }
-
- // Returns true if we have enough information to perform a browse.
- isBrowsable(): boolean {
- return this.fieldClass.length
- && this.fieldClass[0] !== ''
- && this.query.length
- && this.query[0] !== ''
- && this.searchOrg !== null;
- }
-
- compileMarcSearch(): any {
+ compileMarcSearchArgs(): any {
const searches: any = [];
-
- this.marcValue.filter(v => v !== '').forEach((val, idx) => {
- searches.push({
- restrict: [{
- subfield: this.marcSubfield[idx],
- tag: this.marcTag[idx]
- }],
- term: this.marcValue[idx]
- });
+ const ms = this.marcSearch;
+
+ ms.values.forEach((val, idx) => {
+ if (val !== '') {
+ searches.push({
+ restrict: [{
+ subfield: ms.subfields[idx],
+ tag: ms.tags[idx]
+ }],
+ term: ms.values[idx]
+ });
+ }
});
const args: any = {
return args;
}
- compileSearch(): string {
- let str = '';
-
- if (this.available) {
- str += '#available';
- }
-
- if (this.sort) {
- // e.g. title, title.descending
- const parts = this.sort.split(/\./);
- if (parts[1]) { str += ' #descending'; }
- str += ' sort(' + parts[0] + ')';
- }
-
- if (this.identQuery && this.identQueryType) {
- if (str) { str += ' '; }
- str += this.identQueryType + ':' + this.identQuery;
-
- } else {
-
- // -------
- // Compile boolean sub-query components
- if (str.length) { str += ' '; }
- const qcount = this.query.length;
-
- // if we multiple boolean query components, wrap them in parens.
- if (qcount > 1) { str += '('; }
- this.query.forEach((q, idx) => {
- str += this.compileBoolQuerySet(idx);
- });
- if (qcount > 1) { str += ')'; }
- // -------
- }
-
- if (this.hasBrowseEntry) {
- // stored as a comma-separated string of "entryId,fieldId"
- str += ` has_browse_entry(${this.hasBrowseEntry})`;
- }
-
- if (this.format) {
- str += ' format(' + this.format + ')';
- }
-
- if (this.global) {
- str += ' depth(' +
- this.org.root().ou_type().depth() + ')';
- }
-
- if (this.copyLocations[0] !== '') {
- str += ' locations(' + this.copyLocations + ')';
- }
-
- str += ' site(' + this.searchOrg.shortname() + ')';
+ compileIdentSearchQuery(): string {
- Object.keys(this.ccvmFilters).forEach(field => {
- if (this.ccvmFilters[field][0] !== '') {
- str += ' ' + field + '(' + this.ccvmFilters[field] + ')';
- }
- });
-
- this.facetFilters.forEach(f => {
- str += ' ' + f.facetClass + '|'
- + f.facetName + '[' + f.facetValue + ']';
- });
-
- return str;
+ let str = ' site(' + this.searchOrg.shortname() + ')';
+ return str + ' ' +
+ this.identSearch.queryType + ':' + this.identSearch.value;
}
- stripQuotes(query: string): string {
- return query.replace(/"/g, '');
- }
-
- stripAnchors(query: string): string {
- return query.replace(/[\^\$]/g, '');
- }
-
- addQuotes(query: string): string {
- if (query.match(/ /)) {
- return '"' + query + '"';
- }
- return query;
- }
compileBoolQuerySet(idx: number): string {
- let query = this.query[idx];
- const joinOp = this.joinOp[idx];
- const matchOp = this.matchOp[idx];
- const fieldClass = this.fieldClass[idx];
+ const ts = this.termSearch;
+ let query = ts.query[idx];
+ const joinOp = ts.joinOp[idx];
+ const matchOp = ts.matchOp[idx];
+ const fieldClass = ts.fieldClass[idx];
let str = '';
if (!query) { return str; }
return str + query + ')';
}
- hasFacet(facet: FacetFilter): boolean {
- return Boolean(
- this.facetFilters.filter(f => f.equals(facet))[0]
- );
+ stripQuotes(query: string): string {
+ return query.replace(/"/g, '');
}
- removeFacet(facet: FacetFilter): void {
- this.facetFilters = this.facetFilters.filter(f => !f.equals(facet));
+ stripAnchors(query: string): string {
+ return query.replace(/[\^\$]/g, '');
}
- addFacet(facet: FacetFilter): void {
- if (!this.hasFacet(facet)) {
- this.facetFilters.push(facet);
+ addQuotes(query: string): string {
+ if (query.match(/ /)) {
+ return '"' + query + '"';
}
+ return query;
}
- toggleFacet(facet: FacetFilter): void {
- if (this.hasFacet(facet)) {
- this.removeFacet(facet);
- } else {
- this.facetFilters.push(facet);
+ compileTermSearchQuery(): string {
+ const ts = this.termSearch;
+ let str = '';
+
+ if (ts.available) {
+ str += '#available';
}
+
+ if (this.sort) {
+ // e.g. title, title.descending
+ const parts = this.sort.split(/\./);
+ if (parts[1]) { str += ' #descending'; }
+ str += ' sort(' + parts[0] + ')';
+ }
+
+ // -------
+ // Compile boolean sub-query components
+ if (str.length) { str += ' '; }
+ const qcount = ts.query.length;
+
+ // if we multiple boolean query components, wrap them in parens.
+ if (qcount > 1) { str += '('; }
+ ts.query.forEach((q, idx) => {
+ str += this.compileBoolQuerySet(idx);
+ });
+ if (qcount > 1) { str += ')'; }
+ // -------
+
+ if (ts.hasBrowseEntry) {
+ // stored as a comma-separated string of "entryId,fieldId"
+ str += ` has_browse_entry(${ts.hasBrowseEntry})`;
+ }
+
+ if (ts.format) {
+ str += ' format(' + ts.format + ')';
+ }
+
+ if (this.global) {
+ str += ' depth(' +
+ this.org.root().ou_type().depth() + ')';
+ }
+
+ if (ts.copyLocations[0] !== '') {
+ str += ' locations(' + ts.copyLocations + ')';
+ }
+
+ str += ' site(' + this.searchOrg.shortname() + ')';
+
+ Object.keys(ts.ccvmFilters).forEach(field => {
+ if (ts.ccvmFilters[field][0] !== '') {
+ str += ' ' + field + '(' + ts.ccvmFilters[field] + ')';
+ }
+ });
+
+ ts.facetFilters.forEach(f => {
+ str += ' ' + f.facetClass + '|'
+ + f.facetName + '[' + f.facetValue + ']';
+ });
+
+ return str;
}
}
-
<div class="col-lg-4 pr-1">
<div class="float-right">
<!-- note basket view link does not propagate search params -->
- <a routerLink="/staff/catalog/search" [queryParams]="{basket: true}"
+ <a routerLink="/staff/catalog/search" [queryParams]="{showBasket: true}"
class="label-with-material-icon">
<span class="material-icons">shopping_basket</span>
<span i18n>({{basketCount()}})</span>
-<eg-catalog-browse-form></eg-catalog-browse-form>
+<eg-catalog-search-form></eg-catalog-search-form>
<eg-catalog-browse-results><eg-catalog-browse-results>
+++ /dev/null
-<div id='staffcat-browse-form' class='pb-2 mb-3 row'>
- <div class="col-lg-10 form-inline">
- <label for="field-class" i18n>Browse for</label>
- <select class="form-control ml-2" name="field-class"
- [(ngModel)]="searchContext.fieldClass[0]">
- <option i18n value='title'>Title</option>
- <option i18n value='author'>Author</option>
- <option i18n value='subject'>Subject</option>
- <option i18n value='series'>Series</option>
- </select>
- <label for="query" class="ml-2"> starting with </label>
- <input type="text" class="form-control ml-2"
- id='browse-term-input'
- [(ngModel)]="searchContext.query[0]"
- (keyup.enter)="formEnter('query')"
- placeholder="Browse for..."/>
- <label for="browse-org" class="ml-2"> in </label>
- <eg-org-select name="browse-org" class="ml-2"
- (onChange)="orgOnChange($event)"
- [initialOrg]="searchContext.searchOrg"
- [placeholder]="'Library'" >
- </eg-org-select>
- <button class="btn btn-success ml-2" type="button"
- [disabled]="searchIsActive()"
- (click)="searchContext.pager.offset=0; browseByForm()" i18n>
- Browse
- </button>
- </div>
- <div class="col-lg-2">
- <div class="float-right">
- <button class="btn btn-info"
- type="button" (click)="goToSearch()" i18n>Search</button>
- </div>
- </div>
-</div>
-
+++ /dev/null
-import {Component, OnInit, AfterViewInit, Renderer2} from '@angular/core';
-import {Router} from '@angular/router';
-import {IdlObject} from '@eg/core/idl.service';
-import {OrgService} from '@eg/core/org.service';
-import {CatalogService} from '@eg/share/catalog/catalog.service';
-import {CatalogSearchContext, CatalogSearchState} from '@eg/share/catalog/search-context';
-import {StaffCatalogService} from '../catalog.service';
-
-@Component({
- selector: 'eg-catalog-browse-form',
- templateUrl: 'form.component.html'
-})
-export class BrowseFormComponent implements OnInit, AfterViewInit {
-
- searchContext: CatalogSearchContext;
- ccvmMap: {[ccvm: string]: IdlObject[]} = {};
- cmfMap: {[cmf: string]: IdlObject} = {};
-
- constructor(
- private renderer: Renderer2,
- private router: Router,
- private org: OrgService,
- private cat: CatalogService,
- private staffCat: StaffCatalogService
- ) {
- }
-
- ngOnInit() {
- this.ccvmMap = this.cat.ccvmMap;
- this.cmfMap = this.cat.cmfMap;
- this.searchContext = this.staffCat.searchContext;
- }
-
- ngAfterViewInit() {
- this.renderer.selectRootElement('#browse-term-input').focus();
- }
-
- orgName(orgId: number): string {
- return this.org.get(orgId).shortname();
- }
-
- formEnter(source) {
- this.searchContext.pager.offset = 0;
- this.browseByForm();
- }
-
- browseByForm(): void {
- this.staffCat.browse();
- }
-
- searchIsActive(): boolean {
- return this.searchContext.searchState === CatalogSearchState.SEARCHING;
- }
-
- goToSearch() {
- this.router.navigate(['/staff/catalog/search']);
- }
-
- orgOnChange = (org: IdlObject): void => {
- this.searchContext.searchOrg = org;
- }
-}
-
-
browseByUrl(params: ParamMap): void {
this.catUrl.applyUrlParams(this.searchContext, params);
+ const bs = this.searchContext.browseSearch;
// SearchContext applies a default fieldClass value of 'keyword'.
// Replace with 'title', since there is no 'keyword' browse.
- if (this.searchContext.fieldClass[0] === 'keyword') {
- this.searchContext.fieldClass = ['title'];
+ if (bs.fieldClass === 'keyword') {
+ bs.fieldClass = 'title';
}
- if (this.searchContext.isBrowsable()) {
+ if (bs.isSearchable()) {
this.results = [];
this.cat.browse(this.searchContext)
.subscribe(result => this.addResult(result))
prevPage() {
const firstResult = this.results[0];
if (firstResult) {
- this.searchContext.browsePivot = firstResult.pivot_point;
+ this.searchContext.browseSearch.pivot = firstResult.pivot_point;
this.staffCat.browse();
}
}
nextPage() {
const lastResult = this.results[this.results.length - 1];
if (lastResult) {
- this.searchContext.browsePivot = lastResult.pivot_point;
+ this.searchContext.browseSearch.pivot = lastResult.pivot_point;
this.staffCat.browse();
}
}
searchByBrowseEntry(result) {
- // avoid propagating the browse query to the search form
- this.searchContext.query[0] = '';
+ // Avoid propagating browse values to term search.
+ this.searchContext.browseSearch.reset();
- this.searchContext.hasBrowseEntry =
+ this.searchContext.termSearch.hasBrowseEntry =
result.browse_entry + ',' + result.fields;
this.staffCat.search();
}
// NOTE: to test unauthorized heading display in concerto
// browse for author = kab
newBrowseFromHeading(heading) {
- this.searchContext.query[0] = heading.heading;
+ this.searchContext.browseSearch.value = heading.heading;
this.staffCat.browse();
}
}
import {PartsComponent} from './record/parts.component';
import {PartMergeDialogComponent} from './record/part-merge-dialog.component';
import {BrowseComponent} from './browse.component';
-import {BrowseFormComponent} from './browse/form.component';
import {BrowseResultsComponent} from './browse/results.component';
@NgModule({
PartsComponent,
PartMergeDialogComponent,
BrowseComponent,
- BrowseFormComponent,
BrowseResultsComponent
],
imports: [
* execute the actual browse.
*/
browse(): void {
- if (!this.searchContext.isBrowsable()) { return; }
+ if (!this.searchContext.browseSearch.isSearchable()) { return; }
const params = this.catUrl.toUrlParams(this.searchContext);
}
facetIsApplied(cls: string, name: string, value: string): boolean {
- return this.searchContext.hasFacet(new FacetFilter(cls, name, value));
+ return this.searchContext.termSearch.hasFacet(new FacetFilter(cls, name, value));
}
applyFacet(cls: string, name: string, value: string): void {
- this.searchContext.toggleFacet(new FacetFilter(cls, name, value));
+ this.searchContext.termSearch.toggleFacet(new FacetFilter(cls, name, value));
this.searchContext.pager.offset = 0;
this.staffCat.search();
}
searchAuthor(summary: any) {
this.searchContext.reset();
- this.searchContext.fieldClass = ['author'];
- this.searchContext.query = [summary.display.author];
+ this.searchContext.termSearch.fieldClass = ['author'];
+ this.searchContext.termSearch.query = [summary.display.author];
this.staffCat.search();
}
<div id='staffcat-search-form' class="row pb-3 mb-3 ">
<div class="col-lg-8">
<ngb-tabset #searchTabs [activeId]="searchTab" (tabChange)="onTabChange($event)">
- <ngb-tab title="Term Search" i18n-title id="term">
+ <ngb-tab title="Keyword Search" i18n-title id="term">
<ng-template ngbTabContent>
<div class="row"
[ngClass]="{'mt-4': idx == 0, 'mt-1': idx > 0}"
- *ngFor="let q of searchContext.query; let idx = index; trackBy:trackByIdx">
+ *ngFor="let q of context.termSearch.query; let idx = index; trackBy:trackByIdx">
<div class="col-lg-2 pr-1">
<div *ngIf="idx == 0">
- <select class="form-control" [(ngModel)]="searchContext.format">
+ <select class="form-control" [(ngModel)]="context.termSearch.format">
<option i18n value=''>All Formats</option>
<option *ngFor="let fmt of ccvmMap.search_format"
value="{{fmt.code()}}">{{fmt.value()}}</option>
</div>
<div *ngIf="idx > 0">
<select class="form-control"
- [(ngModel)]="searchContext.joinOp[idx]">
+ [(ngModel)]="context.termSearch.joinOp[idx]">
<option i18n value='&&'>And</option>
<option i18n value='||'>Or</option>
</select>
</div>
<div class="col-lg-2 pl-0 pr-2">
<select class="form-control"
- [(ngModel)]="searchContext.fieldClass[idx]">
+ [(ngModel)]="context.termSearch.fieldClass[idx]">
<option i18n value='keyword'>Keyword</option>
<option i18n value='title'>Title</option>
<option i18n value='jtitle'>Journal Title</option>
</div>
<div class="col-lg-2 pl-0 pr-2">
<select class="form-control"
- [(ngModel)]="searchContext.matchOp[idx]">
+ [(ngModel)]="context.termSearch.matchOp[idx]">
<option i18n value='contains'>Contains</option>
<option i18n value='nocontains'>Does not contain</option>
<option i18n value='phrase'>Contains phrase</option>
<div *ngIf="idx == 0">
<input type="text" class="form-control"
id='first-query-input'
- [(ngModel)]="searchContext.query[idx]"
+ [(ngModel)]="context.termSearch.query[idx]"
(keyup.enter)="searchByForm()"
placeholder="Query..."/>
</div>
<div *ngIf="idx > 0">
<input type="text" class="form-control"
- [(ngModel)]="searchContext.query[idx]"
+ [(ngModel)]="context.termSearch.query[idx]"
(keyup.enter)="searchByForm()"
placeholder="Query..."/>
</div>
<span class="material-icons">add_circle_outline</span>
</button>
<button class="btn btn-sm material-icon-button"
- [disabled]="searchContext.query.length < 2"
+ [disabled]="context.termSearch.query.length < 2"
(click)="delSearchRow(idx)"
i18n-title title="Remove Search Row">
<span class="material-icons">remove_circle_outline</span>
</div>
<div class="row">
<div class="col-lg-12 form-inline">
- <select class="form-control mr-2" [(ngModel)]="searchContext.sort">
+ <select class="form-control mr-2" [(ngModel)]="context.sort">
<option value='' i18n>Sort by Relevance</option>
<optgroup label="Sort by Title" i18n-label>
<option value='titlesort' i18n>Title: A to Z</option>
</select>
<div class="checkbox pl-2 ml-2">
<label>
- <input type="checkbox" [(ngModel)]="searchContext.available"/>
+ <input type="checkbox" [(ngModel)]="context.termSearch.available"/>
<span class="pl-1" i18n>Limit to Available</span>
</label>
</div>
<div class="checkbox pl-3">
<label>
<input type="checkbox" [disabled]="true"
- [(ngModel)]="searchContext.isMetarecord"/>
+ [(ngModel)]="context.termSearch.isMetarecord"/>
<span class="pl-1" i18n>Group Formats/Editions</span>
</label>
</div>
<div class="checkbox pl-3">
<label>
- <input type="checkbox" [(ngModel)]="searchContext.global"/>
- <span class="pl-1" i18n>Show Results from All Libraries</span>
+ <input type="checkbox" [(ngModel)]="context.termSearch.global"/>
+ <span class="pl-1" i18n>Results from All Libraries</span>
</label>
</div>
</div>
<div class="row mt-3" *ngIf="showFilters()">
<div class="col-lg-3">
<select class="form-control" multiple="true"
- [(ngModel)]="searchContext.ccvmFilters.item_type">
+ [(ngModel)]="context.termSearch.ccvmFilters.item_type">
<option value='' i18n>All Item Types</option>
<option *ngFor="let itemType of ccvmMap.item_type"
value="{{itemType.code()}}">{{itemType.value()}}</option>
</div>
<div class="col-lg-3">
<select class="form-control" multiple="true"
- [(ngModel)]="searchContext.ccvmFilters.item_form">
+ [(ngModel)]="context.termSearch.ccvmFilters.item_form">
<option value='' i18n>All Item Forms</option>
<option *ngFor="let itemForm of ccvmMap.item_form"
value="{{itemForm.code()}}">{{itemForm.value()}}</option>
</div>
<div class="col-lg-3">
<select class="form-control"
- [(ngModel)]="searchContext.ccvmFilters.item_lang" multiple="true">
+ [(ngModel)]="context.termSearch.ccvmFilters.item_lang" multiple="true">
<option value='' i18n>All Languages</option>
<option *ngFor="let lang of ccvmMap.item_lang"
value="{{lang.code()}}">{{lang.value()}}</option>
</div>
<div class="col-lg-3">
<select class="form-control"
- [(ngModel)]="searchContext.ccvmFilters.audience" multiple="true">
+ [(ngModel)]="context.termSearch.ccvmFilters.audience" multiple="true">
<option value='' i18n>All Audiences</option>
<option *ngFor="let audience of ccvmMap.audience"
value="{{audience.code()}}">{{audience.value()}}</option>
<div class="row mt-3" *ngIf="showFilters()">
<div class="col-lg-3">
<select class="form-control"
- [(ngModel)]="searchContext.ccvmFilters.vr_format" multiple="true">
+ [(ngModel)]="context.termSearch.ccvmFilters.vr_format" multiple="true">
<option value='' i18n>All Video Formats</option>
<option *ngFor="let vrFormat of ccvmMap.vr_format"
value="{{vrFormat.code()}}">{{vrFormat.value()}}</option>
</div>
<div class="col-lg-3">
<select class="form-control"
- [(ngModel)]="searchContext.ccvmFilters.bib_level" multiple="true">
+ [(ngModel)]="context.termSearch.ccvmFilters.bib_level" multiple="true">
<option value='' i18n>All Bib Levels</option>
<option *ngFor="let bibLevel of ccvmMap.bib_level"
value="{{bibLevel.code()}}">{{bibLevel.value()}}</option>
</div>
<div class="col-lg-3">
<select class="form-control"
- [(ngModel)]="searchContext.ccvmFilters.lit_form" multiple="true">
+ [(ngModel)]="context.termSearch.ccvmFilters.lit_form" multiple="true">
<option value='' i18n>All Literary Forms</option>
<option *ngFor="let litForm of ccvmMap.lit_form"
value="{{litForm.code()}}">{{litForm.value()}}</option>
</div>
<div class="col-lg-3">
<select class="form-control"
- [(ngModel)]="searchContext.copyLocations" multiple="true">
+ [(ngModel)]="context.termSearch.copyLocations" multiple="true">
<option value='' i18n>All Copy Locations</option>
<option *ngFor="let loc of copyLocations" value="{{loc.id()}}" i18n>
{{loc.name()}} ({{orgName(loc.owning_lib())}})
<div class="form-inline">
<label for="ident-type" i18n>Query Type</label>
<select class="form-control ml-2" name="ident-type"
- [(ngModel)]="searchContext.identQueryType">
+ [(ngModel)]="context.identSearch.queryType">
<option i18n value="identifier|isbn">ISBN</option>
<option i18n value="identifier|issn">ISSN</option>
<option i18n disabled value="cnbrowse">Call Number (Shelf Browse)</option>
<label for="ident-value" class="ml-2" i18n>Value</label>
<input name="ident-value" id='ident-query-input'
type="text" class="form-control ml-2"
- [(ngModel)]="searchContext.identQuery"
+ [(ngModel)]="context.identSearch.value"
(keyup.enter)="searchByForm()"
placeholder="Numeric Query..."/>
- <button class="btn btn-success ml-2" type="button"
- [disabled]="searchIsActive()"
- (click)="searchByForm()" i18n>Search</button>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-lg-12">
<div class="form-inline mt-2"
- *ngFor="let q of searchContext.marcValue; let idx = index; trackBy:trackByIdx">
+ *ngFor="let q of context.marcSearch.values; let idx = index; trackBy:trackByIdx">
<label for="marc-tag-{{idx}}" i18n>Tag</label>
<input class="form-control ml-2" size="3" type="text"
name="marc-tag-{{idx}}" id="{{ idx == 0 ? 'first-marc-tag' : '' }}"
- [(ngModel)]="searchContext.marcTag[idx]"
+ [(ngModel)]="context.marcSearch.tags[idx]"
(keyup.enter)="searchByForm()"/>
<label for="marc-subfield-{{idx}}" class="ml-2" i18n>Subfield</label>
<input class="form-control ml-2" size="1" type="text"
name="marc-subfield-{{idx}}"
- [(ngModel)]="searchContext.marcSubfield[idx]"
+ [(ngModel)]="context.marcSearch.subfields[idx]"
(keyup.enter)="searchByForm()"/>
<label for="marc-value-{{idx}}" class="ml-2" i18n>Value</label>
<input class="form-control ml-2" type="text" name="marc-value-{{idx}}"
- [(ngModel)]="searchContext.marcValue[idx]"
+ [(ngModel)]="context.marcSearch.values[idx]"
(keyup.enter)="searchByForm()"/>
<button class="btn btn-sm material-icon-button ml-2"
(click)="addMarcSearchRow(idx + 1)">
<span class="material-icons">add_circle_outline</span>
</button>
<button class="btn btn-sm material-icon-button ml-2"
- [disabled]="searchContext.marcValue.length < 2"
+ [disabled]="context.marcSearch.values.length < 2"
(click)="delMarcSearchRow(idx)">
<span class="material-icons">remove_circle_outline</span>
</button>
- <button *ngIf="idx == 0" class="btn btn-success ml-2"
- (click)="searchByForm()" i18n>Submit</button>
</div>
</div>
</div>
</ng-template>
</ngb-tab>
+ <ngb-tab title="Browse" i18n-title id="browse">
+ <ng-template ngbTabContent>
+ <div class="row mt-4">
+ <div class="col-lg-12 form-inline">
+ <label for="field-class" i18n>Browse for</label>
+ <select class="form-control ml-2" name="field-class"
+ [(ngModel)]="context.browseSearch.fieldClass">
+ <option i18n value='title'>Title</option>
+ <option i18n value='author'>Author</option>
+ <option i18n value='subject'>Subject</option>
+ <option i18n value='series'>Series</option>
+ </select>
+ <label for="query" class="ml-2"> starting with </label>
+ <input type="text" class="form-control ml-2"
+ id='browse-term-input' name="query"
+ [(ngModel)]="context.browseSearch.value"
+ (keyup.enter)="searchByForm()"
+ placeholder="Browse for..."/>
+ </div>
+ </div>
+ </ng-template>
+ </ngb-tab>
</ngb-tabset>
</div>
<div class="col-lg-4">
<div class="row">
<div class="col-lg-12">
- <div class="float-right d-flex">
- <eg-org-select
- (onChange)="orgOnChange($event)"
- [initialOrg]="searchContext.searchOrg"
- [placeholder]="'Library'" >
- </eg-org-select>
- <button class="btn btn-success mr-1 ml-1" type="button"
- [disabled]="searchIsActive()"
- (click)="searchContext.pager.offset=0;searchByForm()" i18n>
- Search
- </button>
- <button class="btn btn-warning mr-1" type="button"
- [disabled]="searchIsActive()"
- (click)="searchContext.reset()" i18n>
- Reset Form
- </button>
- <button class="btn btn-info ml-1" type="button"
- (click)="goToBrowse()" i18n>Browse</button>
+ <div class="card">
+ <div class="card-body">
+ <div class="float-right d-flex">
+ <eg-org-select
+ (onChange)="orgOnChange($event)"
+ [initialOrg]="context.searchOrg"
+ [placeholder]="'Library'" >
+ </eg-org-select>
+ <button class="btn btn-success mr-1 ml-1" type="button"
+ [disabled]="searchIsActive()"
+ (click)="context.pager.offset=0;searchByForm()" i18n>
+ Search
+ </button>
+ <button class="btn btn-warning mr-1" type="button"
+ [disabled]="searchIsActive()"
+ (click)="context.reset()" i18n>
+ Reset Form
+ </button>
+ </div>
+ </div>
</div>
</div>
</div>
})
export class SearchFormComponent implements OnInit, AfterViewInit {
- searchContext: CatalogSearchContext;
+ context: CatalogSearchContext;
ccvmMap: {[ccvm: string]: IdlObject[]} = {};
cmfMap: {[cmf: string]: IdlObject} = {};
showSearchFilters = false;
copyLocations: IdlObject[];
searchTab: string;
- //@ViewChild('searchTabs') searchTabs: NgbTabset;
constructor(
private renderer: Renderer2,
ngOnInit() {
this.ccvmMap = this.cat.ccvmMap;
this.cmfMap = this.cat.cmfMap;
- this.searchContext = this.staffCat.searchContext;
+ this.context = this.staffCat.searchContext;
// Start with advanced search options open
// if any filters are active.
// Avoid changing the tab in the lifecycle hook thread.
setTimeout(() => {
- const st = this.searchContext.searchType();
- if (st === 'marc' || st === 'ident') {
- this.searchTab = st;
+ // Assumes that only one type of search will be searchable
+ // at any given time.
+ if (this.context.marcSearch.isSearchable()) {
+ this.searchTab = 'marc';
+ } else if (this.context.identSearch.isSearchable()) {
+ this.searchTab = 'ident';
+ } else if (this.context.browseSearch.isSearchable()) {
+ this.searchTab = 'browse';
} else {
+ // Default tab
this.searchTab = 'term';
+ this.refreshCopyLocations();
}
});
-
- this.refreshCopyLocations();
}
onTabChange(evt: NgbTabChangeEvent) {
case 'marc':
selector = '#first-marc-tag';
break;
+ case 'browse':
+ selector = '#browse-term-input';
+ break;
default:
+ this.refreshCopyLocations();
selector = '#first-query-input';
}
filtersActive(): boolean {
- if (this.searchContext.copyLocations[0] !== '') { return true; }
+ if (this.context.termSearch.copyLocations[0] !== '') { return true; }
// ccvm filters may be present without any filters applied.
// e.g. if filters were applied then removed.
let show = false;
- Object.keys(this.searchContext.ccvmFilters).forEach(ccvm => {
- if (this.searchContext.ccvmFilters[ccvm][0] !== '') {
+ Object.keys(this.context.termSearch.ccvmFilters).forEach(ccvm => {
+ if (this.context.termSearch.ccvmFilters[ccvm][0] !== '') {
show = true;
}
});
}
orgOnChange = (org: IdlObject): void => {
- this.searchContext.searchOrg = org;
+ this.context.searchOrg = org;
this.refreshCopyLocations();
}
if (!this.showFilters()) { return; }
// TODO: is this how we avoid displaying too many locations?
- const org = this.searchContext.searchOrg;
+ const org = this.context.searchOrg;
if (org.id() === this.org.root().id()) {
this.copyLocations = [];
return;
}
addSearchRow(index: number): void {
- this.searchContext.query.splice(index, 0, '');
- this.searchContext.fieldClass.splice(index, 0, 'keyword');
- this.searchContext.joinOp.splice(index, 0, '&&');
- this.searchContext.matchOp.splice(index, 0, 'contains');
+ this.context.termSearch.query.splice(index, 0, '');
+ this.context.termSearch.fieldClass.splice(index, 0, 'keyword');
+ this.context.termSearch.joinOp.splice(index, 0, '&&');
+ this.context.termSearch.matchOp.splice(index, 0, 'contains');
}
delSearchRow(index: number): void {
- this.searchContext.query.splice(index, 1);
- this.searchContext.fieldClass.splice(index, 1);
- this.searchContext.joinOp.splice(index, 1);
- this.searchContext.matchOp.splice(index, 1);
+ this.context.termSearch.query.splice(index, 1);
+ this.context.termSearch.fieldClass.splice(index, 1);
+ this.context.termSearch.joinOp.splice(index, 1);
+ this.context.termSearch.matchOp.splice(index, 1);
}
addMarcSearchRow(index: number): void {
- this.searchContext.marcTag.splice(index, 0, '');
- this.searchContext.marcSubfield.splice(index, 0, '');
- this.searchContext.marcValue.splice(index, 0, '');
+ this.context.marcSearch.tags.splice(index, 0, '');
+ this.context.marcSearch.subfields.splice(index, 0, '');
+ this.context.marcSearch.values.splice(index, 0, '');
}
delMarcSearchRow(index: number): void {
- this.searchContext.marcTag.splice(index, 1);
- this.searchContext.marcSubfield.splice(index, 1);
- this.searchContext.marcValue.splice(index, 1);
+ this.context.marcSearch.tags.splice(index, 1);
+ this.context.marcSearch.subfields.splice(index, 1);
+ this.context.marcSearch.values.splice(index, 1);
}
searchByForm(): void {
- // Starting a new search
- this.searchContext.pager.offset = 0;
+ this.context.pager.offset = 0; // New search
- // Trim the search context to necessary data only depending
- // on which tab the user is on, i.e. which type of search
- // the user is requesting.
-
- // A form search overrides an existing basket display request
- this.searchContext.basket = null;
+ // Form search overrides basket display
+ this.context.showBasket = false;
switch (this.searchTab) {
- case 'term': // main search form query input
-
- // Be sure a previous ident search does not take precedence
- // over the new term query submitted via Enter within
- // the search term/query box.
- this.searchContext.marcValue[0] = '';
- this.searchContext.identQuery = null;
+ case 'term': // AKA keyword search
+ this.context.marcSearch.reset();
+ this.context.browseSearch.reset();
+ this.context.identSearch.reset();
+ this.context.termSearch.hasBrowseEntry = '';
+ this.staffCat.search();
break;
- case 'ident': // identifier query input
- const iq = this.searchContext.identQuery;
- const qt = this.searchContext.identQueryType;
- if (iq) {
- // Ident queries ignore search-specific filters.
- this.searchContext.reset();
- this.searchContext.identQuery = iq;
- this.searchContext.identQueryType = qt;
- }
+ case 'ident':
+ this.context.marcSearch.reset();
+ this.context.browseSearch.reset();
+ this.context.termSearch.reset();
+ this.staffCat.search();
break;
case 'marc':
- this.searchContext.identQuery = null;
- this.searchContext.query[0] = ''; // prevent term queries
+ this.context.browseSearch.reset();
+ this.context.termSearch.reset();
+ this.context.identSearch.reset();
+ this.staffCat.search();
break;
- }
- this.staffCat.search();
+ case 'browse':
+ this.context.marcSearch.reset();
+ this.context.termSearch.reset();
+ this.context.identSearch.reset();
+ this.context.browseSearch.pivot = null;
+ this.staffCat.browse();
+ break;
+ }
}
// https://stackoverflow.com/questions/42322968/angular2-dynamic-input-field-lose-focus-when-input-changes
return index;
}
-
searchIsActive(): boolean {
- return this.searchContext.searchState === CatalogSearchState.SEARCHING;
+ return this.context.searchState === CatalogSearchState.SEARCHING;
}
goToBrowse() {