Skip to content

Commit 5a67f6c

Browse files
committed
feat(filter-assist-panel-component): adds external search urls that captures the users search terms and redirects them to another service
auto-asset-src.directive was updated and added as an import within app module BREAKING CHANGE:
1 parent c175d2a commit 5a67f6c

File tree

12 files changed

+635
-5
lines changed

12 files changed

+635
-5
lines changed

src/app/app.module.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ import {SHELL_ROUTER} from "./injection-tokens";
1414
export const AppModule = ({providers, shellRouter}: {providers:any, shellRouter: Router}) => {
1515
@NgModule({
1616
declarations: [
17-
AppComponent,
18-
AutoAssetSrcDirective
17+
AppComponent
1918
],
20-
exports: [AutoAssetSrcDirective],
2119
imports: [
2220
BrowserModule,
2321
CommonModule,
22+
AutoAssetSrcDirective,
2423
TranslateModule.forRoot({})
2524
],
25+
exports: [AutoAssetSrcDirective],
2626
providers: [...providers, {provide: SHELL_ROUTER, useValue: shellRouter}],
2727
bootstrap: []
2828
})

src/app/custom1-module/customComponentMappings.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { FilterAssistPanelComponent } from '../filter-assist-panel/filter-assist-panel.component';
12
import { Libraryh3lpComponent } from '../libraryh3lp/libraryh3lp.component';
23
import { NdeProblemReportCustom } from '../nde-problem-report-custom/nde-problem-report-custom.component';
34
import { PayFinesComponent } from '../pay-fines/pay-fines.component';
@@ -7,4 +8,5 @@ export const selectorComponentMap = new Map<string, any>([
78
['nde-footer-after', Libraryh3lpComponent],
89
['nde-account-section-results-before', PayFinesComponent],
910
['nde-full-display-service-container-after', NdeProblemReportCustom],
11+
['nde-filters-group-before', FilterAssistPanelComponent],
1012
]);
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { SearchTarget } from '../models/search-target.model';
2+
3+
/**
4+
* Helper function to extract and format search queries for external sources
5+
* Converts Primo query format to simple search terms
6+
* @param queries Array of Primo-formatted query strings
7+
* @returns URL-encoded search string
8+
*/
9+
function buildSearchQuery(queries: string[]): string {
10+
try {
11+
let fullSearchQuery = '';
12+
13+
// Process each query element
14+
queries.forEach((queryElement) => {
15+
// Primo query format: "field,operator,searchTerm,boolean"
16+
// Example: "any,contains,test search,AND"
17+
18+
const firstCommaIndex = queryElement.indexOf(',');
19+
const secondCommaIndex = queryElement.indexOf(',', firstCommaIndex + 1);
20+
let searchStr = queryElement.slice(secondCommaIndex + 1);
21+
22+
// Remove trailing boolean operators (,AND or ,OR)
23+
if (searchStr.endsWith(',AND') || searchStr.endsWith(',OR')) {
24+
const finalComma = searchStr.lastIndexOf(',');
25+
searchStr = searchStr.slice(0, finalComma);
26+
}
27+
28+
// Append to full query with space separator
29+
fullSearchQuery = fullSearchQuery.concat(searchStr + ' ');
30+
});
31+
32+
// Trim and encode for URL
33+
return encodeURIComponent(fullSearchQuery.trim());
34+
} catch (e) {
35+
console.error('Error building search query:', e);
36+
return '';
37+
}
38+
}
39+
40+
/**
41+
* Configuration array of external search sources
42+
* Each source can be clicked from the filter panel to search with current query
43+
*/
44+
export const EXTERNAL_SEARCH_SOURCES: SearchTarget[] = [
45+
{
46+
name: 'WorldCat',
47+
nameHe: 'WorldCat',
48+
url: 'https://kansasstateuniversity.on.worldcat.org/search?queryString=kw:',
49+
img: 'assets/images/external-sources/worldcat-logo.png',
50+
img_2: 'assets/images/external-sources/worldcat-logo.png',
51+
alt: 'Worldcat',
52+
mapping: (queries: string[], filters: string[]): string => {
53+
return buildSearchQuery(queries);
54+
}
55+
},
56+
{
57+
name: 'Google Scholar',
58+
nameHe: 'Google Scholar',
59+
url: 'https://scholar.google.com/scholar?q=',
60+
img: 'assets/images/external-sources/logo-googlescholar.png',
61+
img_2: 'assets/images/external-sources/logo-googlescholar.png',
62+
alt: 'Google Scholar',
63+
mapping: (queries: string[], filters: string[]): string => {
64+
return buildSearchQuery(queries);
65+
}
66+
},
67+
{
68+
name: 'EBSCO',
69+
nameHe: 'EBSCO',
70+
url: 'https://research.ebsco.com/c/b2utja/search/results?q=',
71+
img: 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/EBSCO_Information_Services_20xx_logo.svg/200px-EBSCO_Information_Services_20xx_logo.svg.png',
72+
img_2: 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/EBSCO_Information_Services_20xx_logo.svg/200px-EBSCO_Information_Services_20xx_logo.svg.png',
73+
alt: 'EBSCO',
74+
mapping: (queries: string[], filters: string[]): string => {
75+
return buildSearchQuery(queries);
76+
}
77+
}
78+
// Crossref is commented out in the original - can be added later if needed
79+
/*
80+
{
81+
name: 'Crossref',
82+
nameHe: 'Crossref',
83+
url: 'https://search.crossref.org/?from_ui=yes&q=',
84+
img: 'assets/images/external-sources/crossref_logo_16_16.png',
85+
img_2: 'assets/images/external-sources/crossref_logo_16_16.png',
86+
alt: 'Crossref',
87+
mapping: (queries: string[], filters: string[]): string => {
88+
return buildSearchQuery(queries);
89+
}
90+
}
91+
*/
92+
];
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<section
2+
class="external-search-panel"
3+
[attr.dir]="textDirection"
4+
*ngIf="shouldRender && hasSearchQuery()"
5+
role="complementary"
6+
aria-label="External search options">
7+
8+
<h3 class="external-search-panel__title">
9+
{{ panelTitle }}
10+
</h3>
11+
12+
<ul class="external-search-panel__list" role="list">
13+
<li
14+
*ngFor="let source of externalSources"
15+
class="external-search-panel__item">
16+
17+
<a
18+
[href]="buildExternalUrl(source)"
19+
target="_blank"
20+
rel="noopener noreferrer"
21+
class="external-search-panel__link"
22+
[attr.aria-label]="'Search in ' + getSourceName(source) + ' (opens in new window)'">
23+
24+
<img
25+
autoAssetSrc
26+
[src]="source.img"
27+
[alt]="source.alt"
28+
class="external-search-panel__icon"
29+
width="16"
30+
height="16">
31+
32+
<span class="external-search-panel__name">
33+
{{ getSourceName(source) }}
34+
</span>
35+
36+
<svg
37+
class="external-search-panel__external-icon"
38+
xmlns="http://www.w3.org/2000/svg"
39+
viewBox="0 0 24 24"
40+
width="12"
41+
height="12"
42+
fill="currentColor"
43+
aria-hidden="true">
44+
<path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/>
45+
</svg>
46+
</a>
47+
</li>
48+
</ul>
49+
</section>
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
.external-search-panel {
2+
background: #ffffff;
3+
border: 1px solid #e0e0e0;
4+
border-radius: 4px;
5+
padding: 12px 16px;
6+
margin-bottom: 16px;
7+
font-family: 'Roboto', 'Helvetica Neue', Arial, sans-serif;
8+
color: #424242;
9+
10+
// Title styling
11+
&__title {
12+
margin: 0 0 12px;
13+
font-size: 0.875rem;
14+
font-weight: 500;
15+
color: #616161;
16+
text-transform: uppercase;
17+
letter-spacing: 0.5px;
18+
}
19+
20+
// List container
21+
&__list {
22+
list-style: none;
23+
margin: 0;
24+
padding: 0;
25+
}
26+
27+
// Individual list item
28+
&__item {
29+
margin: 0;
30+
padding: 0;
31+
32+
&:not(:last-child) {
33+
margin-bottom: 2px;
34+
}
35+
}
36+
37+
// Link styling
38+
&__link {
39+
display: flex;
40+
align-items: center;
41+
padding: 4px 12px;
42+
text-decoration: none;
43+
color: #1976d2;
44+
border-radius: 4px;
45+
transition:
46+
background-color 0.2s ease,
47+
color 0.2s ease;
48+
font-size: 0.875rem;
49+
gap: 8px;
50+
51+
&:hover {
52+
background-color: #f5f5f5;
53+
color: #1565c0;
54+
}
55+
56+
&:focus {
57+
outline: 2px solid #1976d2;
58+
outline-offset: 2px;
59+
}
60+
61+
&:active {
62+
background-color: #e3f2fd;
63+
}
64+
}
65+
66+
// Icon (logo) styling
67+
&__icon {
68+
flex-shrink: 0;
69+
width: 16px;
70+
height: 16px;
71+
object-fit: contain;
72+
vertical-align: middle;
73+
}
74+
75+
// Source name text
76+
&__name {
77+
flex-grow: 1;
78+
font-weight: 400;
79+
line-height: 1.4;
80+
}
81+
82+
// External link icon (arrow)
83+
&__external-icon {
84+
flex-shrink: 0;
85+
opacity: 0.6;
86+
transition: opacity 0.2s ease;
87+
88+
.external-search-panel__link:hover & {
89+
opacity: 1;
90+
}
91+
}
92+
93+
// RTL support
94+
&[dir='rtl'] {
95+
.external-search-panel__link {
96+
// Reverse flex direction for RTL
97+
direction: rtl;
98+
}
99+
100+
.external-search-panel__external-icon {
101+
// Flip the external icon for RTL
102+
transform: scaleX(-1);
103+
}
104+
}
105+
106+
// Responsive design for mobile
107+
@media (max-width: 768px) {
108+
padding: 10px 12px;
109+
110+
&__title {
111+
font-size: 0.8125rem;
112+
margin-bottom: 10px;
113+
}
114+
115+
&__link {
116+
padding: 6px 10px;
117+
font-size: 0.8125rem;
118+
}
119+
}
120+
121+
// Dark mode support (if NDE implements it)
122+
/* @media (prefers-color-scheme: dark) {
123+
background: #2c2c2c;
124+
border-color: #444;
125+
color: #e0e0e0;
126+
127+
&__title {
128+
color: #b0b0b0;
129+
}
130+
131+
&__link {
132+
color: #64b5f6;
133+
134+
&:hover {
135+
background-color: #383838;
136+
color: #90caf9;
137+
}
138+
139+
&:active {
140+
background-color: #1e3a5f;
141+
}
142+
}
143+
} */
144+
}

0 commit comments

Comments
 (0)