@ucd-lib/theme-elements 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/brand/ucd-theme-header/ucd-theme-header.js +47 -3
- package/package.json +1 -1
- package/ucdlib/ucdlib-icons/utils.js +3 -2
- package/ucdlib/ucdlib-iconset/ucdlib-iconset.js +14 -0
- package/ucdlib/ucdlib-sils-search-redirect/ucdlib-sils-search-redirect.js +138 -0
- package/ucdlib/ucdlib-sils-search-redirect/ucdlib-sils-search-redirect.tpl.js +108 -0
- package/utils/controllers/index.js +5 -0
- package/utils/controllers/popstate-observer.js +51 -0
- package/utils/controllers/sils-primo.js +124 -0
|
@@ -4,6 +4,7 @@ import {render, styles} from "./ucd-theme-header.tpl.js";
|
|
|
4
4
|
import {
|
|
5
5
|
IntersectionObserverController,
|
|
6
6
|
MutationObserverController,
|
|
7
|
+
PopStateObserverController,
|
|
7
8
|
WaitController } from '../../utils/controllers';
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -51,10 +52,12 @@ export default class UcdThemeHeader extends LitElement {
|
|
|
51
52
|
preventFixed: {type: Boolean, attribute: "prevent-fixed"},
|
|
52
53
|
isDemo: {type: Boolean, attribute: "is-demo"},
|
|
53
54
|
_transitioning: {type: Boolean, state: true},
|
|
55
|
+
_hasPrimaryNav: {type: Boolean, state: true},
|
|
54
56
|
_hasSlottedBranding: {type: Boolean, state: true},
|
|
55
57
|
_hasQuickLinks: {type: Boolean, state: true},
|
|
56
58
|
_hasSearch: {type: Boolean, state: true},
|
|
57
|
-
_brandingBarInView: {type: Boolean, state: true}
|
|
59
|
+
_brandingBarInView: {type: Boolean, state: true},
|
|
60
|
+
_components: {type: Object, state: true}
|
|
58
61
|
};
|
|
59
62
|
}
|
|
60
63
|
|
|
@@ -68,6 +71,7 @@ export default class UcdThemeHeader extends LitElement {
|
|
|
68
71
|
|
|
69
72
|
this.mutationObserver = new MutationObserverController(this);
|
|
70
73
|
this.wait = new WaitController(this);
|
|
74
|
+
new PopStateObserverController(this, "_onLocationChange");
|
|
71
75
|
|
|
72
76
|
this.siteName = "";
|
|
73
77
|
this.siteUrl = "/";
|
|
@@ -77,14 +81,21 @@ export default class UcdThemeHeader extends LitElement {
|
|
|
77
81
|
this.isDemo = false;
|
|
78
82
|
|
|
79
83
|
this._transitioning = false;
|
|
84
|
+
this._hasPrimaryNav = false;
|
|
80
85
|
this._hasSlottedBranding = false;
|
|
81
86
|
this._hasQuickLinks = false;
|
|
82
87
|
this._hasSearch = false;
|
|
83
88
|
this._animationDuration = 500;
|
|
84
89
|
this._brandingBarInView = false;
|
|
90
|
+
this._slottedComponents = {};
|
|
85
91
|
|
|
86
92
|
}
|
|
87
93
|
|
|
94
|
+
/**
|
|
95
|
+
* @method connectedCallback
|
|
96
|
+
* @private
|
|
97
|
+
* @description Custom element lifecycle method
|
|
98
|
+
*/
|
|
88
99
|
connectedCallback(){
|
|
89
100
|
super.connectedCallback();
|
|
90
101
|
if ( !this.preventFixed ) {
|
|
@@ -92,6 +103,11 @@ export default class UcdThemeHeader extends LitElement {
|
|
|
92
103
|
}
|
|
93
104
|
}
|
|
94
105
|
|
|
106
|
+
/**
|
|
107
|
+
* @method firstUpdated
|
|
108
|
+
* @private
|
|
109
|
+
* @description Lit lifecycle hook
|
|
110
|
+
*/
|
|
95
111
|
firstUpdated(){
|
|
96
112
|
if ( !this.preventFixed ) {
|
|
97
113
|
let aboveNav = this.renderRoot.getElementById('branding-bar-container');
|
|
@@ -99,11 +115,33 @@ export default class UcdThemeHeader extends LitElement {
|
|
|
99
115
|
}
|
|
100
116
|
}
|
|
101
117
|
|
|
118
|
+
/**
|
|
119
|
+
* @method _onLocationChange
|
|
120
|
+
* @description Called when url changes by popstate controller
|
|
121
|
+
*/
|
|
122
|
+
_onLocationChange(){
|
|
123
|
+
this.close();
|
|
124
|
+
if ( this._hasQuickLinks ){
|
|
125
|
+
this._slottedComponents.quickLinks.close();
|
|
126
|
+
}
|
|
127
|
+
if ( this._hasSearch ){
|
|
128
|
+
this._slottedComponents.search.close();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @method _onBrandingBarIntersection
|
|
134
|
+
* @private
|
|
135
|
+
* @description Called by intersection observer when branding bar enters/exits screen
|
|
136
|
+
* @param {*} entries
|
|
137
|
+
*/
|
|
102
138
|
_onBrandingBarIntersection(entries){
|
|
103
139
|
let offSetValue = 0;
|
|
104
140
|
try {
|
|
105
141
|
offSetValue = this.renderRoot.getElementById('nav-bar').getBoundingClientRect().height;
|
|
106
|
-
} catch (error) {
|
|
142
|
+
} catch (error) {
|
|
143
|
+
//
|
|
144
|
+
}
|
|
107
145
|
if ( offSetValue > 150 ) offSetValue = 0;
|
|
108
146
|
entries.forEach(entry => {
|
|
109
147
|
this._brandingBarInView = entry.isIntersecting;
|
|
@@ -112,7 +150,7 @@ export default class UcdThemeHeader extends LitElement {
|
|
|
112
150
|
} else {
|
|
113
151
|
this.style.marginBottom = offSetValue + "px";
|
|
114
152
|
}
|
|
115
|
-
})
|
|
153
|
+
});
|
|
116
154
|
}
|
|
117
155
|
|
|
118
156
|
/**
|
|
@@ -232,14 +270,18 @@ export default class UcdThemeHeader extends LitElement {
|
|
|
232
270
|
let primaryNav = this.querySelector('ucd-theme-primary-nav');
|
|
233
271
|
if ( primaryNav ) {
|
|
234
272
|
primaryNav.setAttribute('slot', 'primary-nav');
|
|
273
|
+
this._hasPrimaryNav = true;
|
|
274
|
+
this._slottedComponents.primaryNav = primaryNav;
|
|
235
275
|
} else {
|
|
236
276
|
console.warn("No 'ucd-theme-primary-nav' child element found!");
|
|
277
|
+
this._hasPrimaryNav = false;
|
|
237
278
|
}
|
|
238
279
|
|
|
239
280
|
let quickLinks = this.querySelector('ucd-theme-quick-links');
|
|
240
281
|
if ( quickLinks ) {
|
|
241
282
|
quickLinks.setAttribute('slot', 'quick-links');
|
|
242
283
|
this._hasQuickLinks = true;
|
|
284
|
+
this._slottedComponents.quickLinks = quickLinks;
|
|
243
285
|
} else {
|
|
244
286
|
this._hasQuickLinks = false;
|
|
245
287
|
}
|
|
@@ -248,6 +290,7 @@ export default class UcdThemeHeader extends LitElement {
|
|
|
248
290
|
if ( search ) {
|
|
249
291
|
search.setAttribute('slot', 'search');
|
|
250
292
|
this._hasSearch = true;
|
|
293
|
+
this._slottedComponents.search = search;
|
|
251
294
|
} else {
|
|
252
295
|
this._hasSearch = false;
|
|
253
296
|
}
|
|
@@ -256,6 +299,7 @@ export default class UcdThemeHeader extends LitElement {
|
|
|
256
299
|
if ( UcdlibBrandingBar ) {
|
|
257
300
|
UcdlibBrandingBar.setAttribute('slot', 'branding-bar');
|
|
258
301
|
this._hasSlottedBranding = true;
|
|
302
|
+
this._slottedComponents.brandingBar = UcdlibBrandingBar;
|
|
259
303
|
} else if ( this.querySelector("*[slot='branding-bar']") ){
|
|
260
304
|
this._hasSlottedBranding = true;
|
|
261
305
|
} else {
|
package/package.json
CHANGED
|
@@ -8,8 +8,9 @@ import { html, render } from "lit-html";
|
|
|
8
8
|
* @param {TemplateResult} icons - SVG html string of icons
|
|
9
9
|
* @param {String} name - name of iconset.
|
|
10
10
|
* @param {Number} size - size of icons
|
|
11
|
+
* @param {String} label - Friendly name of iconset
|
|
11
12
|
*/
|
|
12
|
-
function renderIconSet(icons, name, size=24){
|
|
13
|
+
function renderIconSet(icons, name, size=24, label=""){
|
|
13
14
|
const containerId = `ucdlib-icons--${name}`;
|
|
14
15
|
let container = document.getElementById(containerId);
|
|
15
16
|
if ( !container ){
|
|
@@ -19,7 +20,7 @@ function renderIconSet(icons, name, size=24){
|
|
|
19
20
|
document.head.appendChild(container);
|
|
20
21
|
}
|
|
21
22
|
const template = html`
|
|
22
|
-
<ucdlib-iconset name=${name} size=${size}>
|
|
23
|
+
<ucdlib-iconset name=${name} size=${size} label=${label}>
|
|
23
24
|
${icons}
|
|
24
25
|
</ucdlib-iconset>
|
|
25
26
|
`;
|
|
@@ -9,6 +9,7 @@ import { MutationObserverController } from '../../utils/controllers';
|
|
|
9
9
|
*
|
|
10
10
|
* @property {String} name - Name of the icon set. Usage: <ucdlib-icon icon="{thisProperty}:{icon}"></ucdlib-icon>
|
|
11
11
|
* @property {Number} size - The size of an individual icon. Note that icons must be square.
|
|
12
|
+
* @property {String} label - Optional friendly label for iconset.
|
|
12
13
|
* @example
|
|
13
14
|
* <ucdlib-iconset name="arrows">
|
|
14
15
|
<svg>
|
|
@@ -26,6 +27,7 @@ export default class UcdlibIconset extends Mixin(LitElement)
|
|
|
26
27
|
return {
|
|
27
28
|
name: {type: String},
|
|
28
29
|
size: {type: Number},
|
|
30
|
+
label: {type: String},
|
|
29
31
|
_iconMap: {type: Object, state: true}
|
|
30
32
|
};
|
|
31
33
|
}
|
|
@@ -35,6 +37,7 @@ export default class UcdlibIconset extends Mixin(LitElement)
|
|
|
35
37
|
this.mutationObserver = new MutationObserverController(this, {subtree: true, childList: true});
|
|
36
38
|
|
|
37
39
|
this.name = "";
|
|
40
|
+
this.label = "";
|
|
38
41
|
this.size = 24;
|
|
39
42
|
this._iconMap = {};
|
|
40
43
|
this.style.display = "none";
|
|
@@ -63,6 +66,17 @@ export default class UcdlibIconset extends Mixin(LitElement)
|
|
|
63
66
|
return Object.keys(this._iconMap);
|
|
64
67
|
}
|
|
65
68
|
|
|
69
|
+
/**
|
|
70
|
+
* @method getLabel
|
|
71
|
+
* @description Returns a friendly label of iconset
|
|
72
|
+
* @returns {String}
|
|
73
|
+
*/
|
|
74
|
+
getLabel(){
|
|
75
|
+
if ( this.label ) return this.label;
|
|
76
|
+
|
|
77
|
+
return this.name.replace(/-/g, " ");
|
|
78
|
+
}
|
|
79
|
+
|
|
66
80
|
/**
|
|
67
81
|
* @method applyIcon
|
|
68
82
|
* @description Adds icon to ucdlib-icon element from iconset
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
import {render, styles} from "./ucdlib-sils-search-redirect.tpl.js";
|
|
3
|
+
|
|
4
|
+
import { SilsPrimoController } from '../../utils/controllers';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @class UcdlibSilsSearchRedirect
|
|
8
|
+
* @classdesc Search widget that redirects a user's query to SILS Primo
|
|
9
|
+
* @property {String} query - The search query
|
|
10
|
+
* @property {Boolean} ucdOnly - Limits search to UC Davis libraries only
|
|
11
|
+
* @property {Boolean} darkBackground - Adjusts colors for display on a dark background
|
|
12
|
+
* @property {Boolean} preventRedirect - Will not send user to Primo on form submission
|
|
13
|
+
* @property {String} headingText - Text to display above main text input
|
|
14
|
+
* @property {String} inputPlaceholder - Placeholder for main text input
|
|
15
|
+
* @property {String} host - Primo host
|
|
16
|
+
*/
|
|
17
|
+
export default class UcdlibSilsSearchRedirect extends LitElement {
|
|
18
|
+
|
|
19
|
+
static get properties() {
|
|
20
|
+
return {
|
|
21
|
+
query: {type: String},
|
|
22
|
+
ucdOnly: {type: Boolean, attribute: "ucd-only"},
|
|
23
|
+
darkBackground: {type: Boolean, attribute: "dark-background"},
|
|
24
|
+
preventRedirect: {type: Boolean, attribute: "prevent-redirect"},
|
|
25
|
+
headingText: {type: String, attribute: "heading-text"},
|
|
26
|
+
inputPlaceholder: {type: String, attribute: "input-placeholder"},
|
|
27
|
+
host: {type: String},
|
|
28
|
+
role: {type: String, reflect: true},
|
|
29
|
+
ariaLabel: {type: String, attribute: "aria-label", reflect: true}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static get styles() {
|
|
34
|
+
return styles();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
constructor() {
|
|
38
|
+
super();
|
|
39
|
+
this.render = render.bind(this);
|
|
40
|
+
this.query = "";
|
|
41
|
+
this.ucdOnly = false;
|
|
42
|
+
this.darkBackground = false;
|
|
43
|
+
this.headingText = "Search UC Library Materials";
|
|
44
|
+
this.inputPlaceholder = "All UC books, journals, articles + more";
|
|
45
|
+
this.role = "form";
|
|
46
|
+
this.ariaLabel = "Search UC Library Materials";
|
|
47
|
+
this.host = "";
|
|
48
|
+
this._updatePrimoController();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @method willUpdate
|
|
53
|
+
* @description Lit lifecycle hook
|
|
54
|
+
* @private
|
|
55
|
+
* @param {Map} props - Properties that have changed
|
|
56
|
+
*/
|
|
57
|
+
willUpdate(props){
|
|
58
|
+
this._updatePrimoController(props);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @method _onQueryChange
|
|
63
|
+
* @private
|
|
64
|
+
* @description Attached to primary text input
|
|
65
|
+
* @param {Event} e - Input event
|
|
66
|
+
*/
|
|
67
|
+
_onQueryChange(e){
|
|
68
|
+
let text = e.target.value ? e.target.value : "";
|
|
69
|
+
this.query = text;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @method _onCorpusChange
|
|
74
|
+
* @private
|
|
75
|
+
* @description Attached to ucd-only checkbox
|
|
76
|
+
* @param {Event} e - Input event
|
|
77
|
+
*/
|
|
78
|
+
_onCorpusChange(e){
|
|
79
|
+
this.ucdOnly = e.target.checked;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @method _onSubmit
|
|
84
|
+
* @description Called on form submit
|
|
85
|
+
* @private
|
|
86
|
+
* @param {Event} e - submit event
|
|
87
|
+
*/
|
|
88
|
+
_onSubmit(e){
|
|
89
|
+
e.preventDefault();
|
|
90
|
+
let corpus = this.ucdOnly ? "ucd" : "everything";
|
|
91
|
+
let advanced = e.submitter.id == "advanced-search";
|
|
92
|
+
|
|
93
|
+
let url = this.primo.makeSearchUrl(this.query, corpus, advanced);
|
|
94
|
+
if ( this.preventRedirect ) {
|
|
95
|
+
this.dispatchEvent(new CustomEvent('search', {
|
|
96
|
+
detail : {url}
|
|
97
|
+
}));
|
|
98
|
+
} else {
|
|
99
|
+
window.location = url;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @method _updatePrimoController
|
|
106
|
+
* @description Updates the config values of the Primo controller based on ele attributes
|
|
107
|
+
* @private
|
|
108
|
+
* @param {Map} props - Properties that have changed in current lifecycle
|
|
109
|
+
*/
|
|
110
|
+
_updatePrimoController(props){
|
|
111
|
+
let primoConfig = {};
|
|
112
|
+
|
|
113
|
+
// Get primo config values from ele attributes
|
|
114
|
+
const attrs = [
|
|
115
|
+
{ele: 'host', ctl: 'host'}
|
|
116
|
+
];
|
|
117
|
+
if ( props ){
|
|
118
|
+
attrs.forEach(attr => {
|
|
119
|
+
if ( props.has(attr.ele) && this[attr.ele] ) {
|
|
120
|
+
primoConfig[attr.ctl] = this[attr.ele];
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// instantiate or update controller
|
|
126
|
+
if ( !this.primo ) {
|
|
127
|
+
this.primo = new SilsPrimoController(
|
|
128
|
+
this,
|
|
129
|
+
primoConfig
|
|
130
|
+
);
|
|
131
|
+
} else {
|
|
132
|
+
this.primo.updateConfig(primoConfig);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
customElements.define('ucdlib-sils-search-redirect', UcdlibSilsSearchRedirect);
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { html, css, unsafeCSS } from 'lit';
|
|
2
|
+
|
|
3
|
+
import normalizeCss from "@ucd-lib/theme-sass/normalize.css.js";
|
|
4
|
+
import headingCss from "@ucd-lib/theme-sass/1_base_html/_headings.css";
|
|
5
|
+
import headingClassesCss from "@ucd-lib/theme-sass/2_base_class/_headings.css";
|
|
6
|
+
import formsCss from "@ucd-lib/theme-sass/1_base_html/_forms.css";
|
|
7
|
+
import formsClassesCss from "@ucd-lib/theme-sass/2_base_class/_forms.css";
|
|
8
|
+
import buttonCss from "@ucd-lib/theme-sass/2_base_class/_buttons.css";
|
|
9
|
+
import spacingUtilityCss from "@ucd-lib/theme-sass/6_utility/_u-space.css";
|
|
10
|
+
import { categoryBrands } from "@ucd-lib/theme-sass/colors";
|
|
11
|
+
|
|
12
|
+
export function styles() {
|
|
13
|
+
const elementStyles = css`
|
|
14
|
+
:host {
|
|
15
|
+
display: block;
|
|
16
|
+
max-width: 500px;
|
|
17
|
+
margin: auto;
|
|
18
|
+
}
|
|
19
|
+
h2 {
|
|
20
|
+
text-align: center;
|
|
21
|
+
}
|
|
22
|
+
.search-bar {
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-flow: row nowrap;
|
|
25
|
+
}
|
|
26
|
+
.search-bar button {
|
|
27
|
+
font-family: "Font Awesome 5 Free";
|
|
28
|
+
min-width: unset;
|
|
29
|
+
font-size: 1.2rem;
|
|
30
|
+
padding: 0 .75rem;
|
|
31
|
+
min-height: 0;
|
|
32
|
+
}
|
|
33
|
+
.search-bar button:hover {
|
|
34
|
+
padding-right: .75rem;
|
|
35
|
+
padding-left: .75rem;
|
|
36
|
+
}
|
|
37
|
+
.search-bar input {
|
|
38
|
+
flex-grow: 1;
|
|
39
|
+
}
|
|
40
|
+
.search-options {
|
|
41
|
+
display: flex;
|
|
42
|
+
flex-flow: row wrap;
|
|
43
|
+
align-items: center;
|
|
44
|
+
justify-content: space-between;
|
|
45
|
+
}
|
|
46
|
+
.search-options label {
|
|
47
|
+
color: ${unsafeCSS(categoryBrands.primary.hex)};
|
|
48
|
+
padding-bottom: 0;
|
|
49
|
+
}
|
|
50
|
+
input[type=checkbox] {
|
|
51
|
+
margin-right: 0;
|
|
52
|
+
}
|
|
53
|
+
.search-options button {
|
|
54
|
+
border: none;
|
|
55
|
+
background-color: inherit;
|
|
56
|
+
color: ${unsafeCSS(categoryBrands.primary.hex)};
|
|
57
|
+
text-decoration: underline;
|
|
58
|
+
padding: 0;
|
|
59
|
+
font-family: inherit;
|
|
60
|
+
}
|
|
61
|
+
.dark h2 {
|
|
62
|
+
color: ${unsafeCSS(categoryBrands.secondary.hex)}
|
|
63
|
+
}
|
|
64
|
+
.dark .search-options label {
|
|
65
|
+
color: #fff;
|
|
66
|
+
}
|
|
67
|
+
.dark .search-options button {
|
|
68
|
+
color: #fff;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
`;
|
|
72
|
+
|
|
73
|
+
return [
|
|
74
|
+
normalizeCss,
|
|
75
|
+
headingCss,
|
|
76
|
+
headingClassesCss,
|
|
77
|
+
formsCss,
|
|
78
|
+
formsClassesCss,
|
|
79
|
+
buttonCss,
|
|
80
|
+
spacingUtilityCss,
|
|
81
|
+
elementStyles];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function render() {
|
|
85
|
+
return html`
|
|
86
|
+
<form
|
|
87
|
+
@submit=${this._onSubmit}
|
|
88
|
+
aria-label=${this.ariaLabel}
|
|
89
|
+
class="${this.darkBackground ? 'dark' : 'light'}">
|
|
90
|
+
|
|
91
|
+
${this.headingText ? html`
|
|
92
|
+
<h2 class="heading--highlight u-space-mb">${this.headingText}</h2>
|
|
93
|
+
` : html``}
|
|
94
|
+
|
|
95
|
+
<div class="search-bar">
|
|
96
|
+
<input type="text" .value=${this.query} @input=${this._onQueryChange} placeholder=${this.inputPlaceholder}>
|
|
97
|
+
<button id="simple-search" type="submit" class="btn btn--primary-input"> </button>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<div class="search-options">
|
|
101
|
+
<div class="checkbox u-space-mr--small u-space-mt--small">
|
|
102
|
+
<input id="corpus" type="checkbox" ?checked=${this.ucdOnly} @input=${this._onCorpusChange}><label for="corpus">UC Davis libraries only</label>
|
|
103
|
+
</div>
|
|
104
|
+
<button id="advanced-search" class="u-space-mt--small" type="submit">Advanced Search</button>
|
|
105
|
+
</div>
|
|
106
|
+
</form>
|
|
107
|
+
|
|
108
|
+
`;}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { BreakPointsController } from "./break-points";
|
|
2
2
|
import { IntersectionObserverController } from "./intersection-observer";
|
|
3
3
|
import { MutationObserverController } from "./mutation-observer";
|
|
4
|
+
import { PopStateObserverController } from "./popstate-observer";
|
|
5
|
+
import { SilsPrimoController } from "./sils-primo";
|
|
4
6
|
import { WaitController } from "./wait";
|
|
5
7
|
|
|
8
|
+
|
|
6
9
|
export {
|
|
7
10
|
BreakPointsController,
|
|
8
11
|
IntersectionObserverController,
|
|
9
12
|
MutationObserverController,
|
|
13
|
+
PopStateObserverController,
|
|
14
|
+
SilsPrimoController,
|
|
10
15
|
WaitController,
|
|
11
16
|
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @class PopStateObserverController
|
|
3
|
+
* @classdesc Controller for attaching a popstate event listener to a Lit element.
|
|
4
|
+
*
|
|
5
|
+
* @property {LitElement} host - 'this' from a Lit element
|
|
6
|
+
* @property {String} callback - Name of element method called on popstate. Default: '_onPopstate'
|
|
7
|
+
*
|
|
8
|
+
* @examples
|
|
9
|
+
* // Instantiate this controller in the constructor of your element
|
|
10
|
+
* new PopStateObserverController(this, "_onLocationChange");
|
|
11
|
+
*/
|
|
12
|
+
export class PopStateObserverController{
|
|
13
|
+
|
|
14
|
+
constructor(host, callback="_onPopstate"){
|
|
15
|
+
(this.host = host).addController(this);
|
|
16
|
+
this.callback = callback;
|
|
17
|
+
this._onPopstate = this._onPopstate.bind(this);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
hostConnected(){
|
|
21
|
+
window.addEventListener('popstate', this._onPopstate);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
hostDisconnected(){
|
|
25
|
+
window.removeEventListener('popstate', this._onPopstate);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
_onPopstate(e){
|
|
29
|
+
if ( !this.host[this.callback]){
|
|
30
|
+
console.warn(
|
|
31
|
+
`Element has no '${this.callback}' method.
|
|
32
|
+
Either add this method, or change the 'callback' argument on instantiation.`
|
|
33
|
+
);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
let locationObject = this._getLocationObject();
|
|
37
|
+
this.host[this.callback](locationObject, e);
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
_getLocationObject(){
|
|
42
|
+
let location = {
|
|
43
|
+
fullpath : window.location.href.replace(window.location.origin, '').replace(/^\/+/, '/'),
|
|
44
|
+
pathname : window.location.pathname.replace(/^\/+/, '/'),
|
|
45
|
+
path : window.location.pathname.replace(/(^\/+|\/+$)/g, '').split('/'),
|
|
46
|
+
query : new URLSearchParams(window.location.search),
|
|
47
|
+
hash : window.location.hash.replace(/^#/, '')
|
|
48
|
+
};
|
|
49
|
+
return location;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @class SilsPrimoController
|
|
3
|
+
* @classdesc Utility for interacting with UC Libraries' discovery tool
|
|
4
|
+
*
|
|
5
|
+
* @property {LitElement} host - 'this' from a Lit element
|
|
6
|
+
* @property {Object} config - Basic Primo configuration values (host, uris, etc)
|
|
7
|
+
*/
|
|
8
|
+
export class SilsPrimoController{
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @method constructor
|
|
12
|
+
* @description Called on instantiation
|
|
13
|
+
* @param {LitElement} host - Element
|
|
14
|
+
* @param {Object} config - Config values
|
|
15
|
+
*/
|
|
16
|
+
constructor(host, config={}){
|
|
17
|
+
(this.host = host).addController(this);
|
|
18
|
+
this.updateConfig(config);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @method updateConfig
|
|
23
|
+
* @description Updates the config property.
|
|
24
|
+
* @param {Object} config - Values to overide the default.
|
|
25
|
+
*/
|
|
26
|
+
updateConfig(config){
|
|
27
|
+
const UCD_TAB = "LibraryCatalog";
|
|
28
|
+
let _config = {
|
|
29
|
+
host: "https://search.library.ucdavis.edu",
|
|
30
|
+
paths: {
|
|
31
|
+
search: "discovery/search",
|
|
32
|
+
browse: "discovery/browse"
|
|
33
|
+
},
|
|
34
|
+
defaultParams: {
|
|
35
|
+
vid: "01UCD_INST:UCD"
|
|
36
|
+
},
|
|
37
|
+
corpora: {
|
|
38
|
+
everything: {
|
|
39
|
+
tab: "UCSILSDefaultSearch",
|
|
40
|
+
scope: "DN_and_CI"
|
|
41
|
+
},
|
|
42
|
+
uc: {
|
|
43
|
+
tab: "UCSDiscoveryNetwork",
|
|
44
|
+
scope: "UCSDiscoveryNetwork"
|
|
45
|
+
},
|
|
46
|
+
ucd: {
|
|
47
|
+
tab: UCD_TAB,
|
|
48
|
+
scope: "MyInstitution",
|
|
49
|
+
},
|
|
50
|
+
specialCollections: {
|
|
51
|
+
tab: UCD_TAB,
|
|
52
|
+
scope: "SSPEC"
|
|
53
|
+
},
|
|
54
|
+
medical: {
|
|
55
|
+
tab: UCD_TAB,
|
|
56
|
+
scope: "BLAISDELL"
|
|
57
|
+
},
|
|
58
|
+
healthSciences: {
|
|
59
|
+
tab: UCD_TAB,
|
|
60
|
+
scope: "CARLSON"
|
|
61
|
+
},
|
|
62
|
+
law: {
|
|
63
|
+
tab: UCD_TAB,
|
|
64
|
+
scope: "Mabie"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
this.config = Object.assign(_config, config);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @method makeSearchUrl
|
|
74
|
+
* @description Makes a Primo Search URL
|
|
75
|
+
* @param {String} query - A search term or phrase
|
|
76
|
+
* @param {String} corpus - The bib corpus to search against.
|
|
77
|
+
* Sets 'tab' and 'search_scope' params. Must be a recognized keyword in the corpora config object:
|
|
78
|
+
* everything, uc, ucd, specialCollections, medical, healthSciences, law
|
|
79
|
+
* @param {Boolean} advanced - Expands the advanced search interface
|
|
80
|
+
* @param {Object} additionalParams - Any additional url params. Has the final say.
|
|
81
|
+
* @returns
|
|
82
|
+
*/
|
|
83
|
+
makeSearchUrl( query, corpus="everything", advanced=false, additionalParams={} ){
|
|
84
|
+
let url = `${this._trailingSlashIt(this.config.host)}${this.config.paths.search}`;
|
|
85
|
+
|
|
86
|
+
let params = Object.assign({}, this.config.defaultParams);
|
|
87
|
+
|
|
88
|
+
if ( advanced ) {
|
|
89
|
+
params['mode'] = 'advanced';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if ( query ) {
|
|
93
|
+
params['query'] = 'any,contains,' + query.replace(/,/g, ' ');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if ( this.config.corpora[corpus] ) {
|
|
97
|
+
params['tab'] = this.config.corpora[corpus].tab;
|
|
98
|
+
params['search_scope'] = this.config.corpora[corpus].scope;
|
|
99
|
+
} else {
|
|
100
|
+
console.warn(`${corpus} is not a recognized corpus`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if ( additionalParams ){
|
|
104
|
+
Object.assign(params, additionalParams);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
params = new URLSearchParams(params);
|
|
108
|
+
return `${url}?${params.toString()}`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @method _trailingSlashIt
|
|
113
|
+
* @description Adds trailing slash to string if not already present
|
|
114
|
+
* @private
|
|
115
|
+
* @param {String} str
|
|
116
|
+
* @returns
|
|
117
|
+
*/
|
|
118
|
+
_trailingSlashIt(str){
|
|
119
|
+
if ( str.endsWith('/') ){
|
|
120
|
+
return str;
|
|
121
|
+
}
|
|
122
|
+
return str + "/";
|
|
123
|
+
}
|
|
124
|
+
}
|