PageSourceSearch

https://thejns.org/assets/shared/zfb8a630e/js/dist/myContentAndMySearches.js

js thejns.org collected 2026-09-24 08:38:45 UTC 14,682 bytes, 413 lines download raw bytes

1"use strict";
2
3/*
4	Recently Viewed Searches
5*/
6
7// Read's the body tag for classes matching `site-foobar`.
8function getSiteNameFromBody() {
9	return document.querySelector("body").dataset.siteName;
10}
11
12function saveRecentlyViewedSearch(item) {
13	fetch('/rest/personalization/v1/saved-searches', {
14		method: "POST",
15		headers: {
16			'Content-Type': 'application/json'
17		},
18		body: JSON.stringify({
19			searchParameters: item.searchParameterMap,
20			title: item.title,
21			resultCount: parseInt(item.resultCount.replace(/,/g, '')),
22			siteName: item.siteName
23		})
24	}).then(function (response) {
25		return response.text();
26	}).then(function (data) {
27		location.reload();
28	}).catch(function (error) {
29		console.error('Error: ', error);
30	});
31}
32
33var qsa = function qsa(sel) {
34	return Array.from(document.querySelectorAll(sel));
35};
36function initializeRecentlyViewedSearches() {
37	var allrecentlyViewedSearches = qsa('.recentlyViewedSearches');
38	var siteName = getSiteNameFromBody();
39	// <span data-resulttotal="127" id="resultTotal" class="count">127</span>
40	var resultTotal = document.getElementById('resultTotal');
41	var resultCount = '';
42	if (resultTotal) {
43		resultCount = resultTotal.dataset.resulttotal;
44	}
45	// <ul> ...
46	var recentlyViewedSearches = document.querySelector('.recentlyViewedSearches');
47	var resultLabel = '';
48	var isSearching = false;
49	if (recentlyViewedSearches) {
50		resultLabel = recentlyViewedSearches.dataset.resultregionlabel;
51		isSearching = recentlyViewedSearches.dataset.issearching == 'true';
52	}
53
54	// .recentlyViewedSearches > <li> <span class="criteria"> ... <a>save icon
55	var recentlyViewedSearchTemplate = document.querySelector('.recentlyViewedSearchTemplate');
56	if (recentlyViewedSearchTemplate) {
57		recentlyViewedSearchTemplate = recentlyViewedSearchTemplate.cloneNode(true);
58		allrecentlyViewedSearches.forEach(function (el) {
59			var temel = el.querySelector('.recentlyViewedSearchTemplate');
60			if (temel) {
61				el.removeChild(temel);
62			}
63		});
64	}
65
66	var getTitleWithResult = function getTitleWithResult(title, resultCount) {
67		return title !== null && title.length > 25 ? title.substring(0, 22) + '... (' + resultCount + ' ' + resultLabel + ') ' : title + ' (' + resultCount + ' ' + resultLabel + ') ';
68	};
69
70	var getTemplate = function getTemplate(title, href, searchParameterMap, resultCount) {
71		var templateElement = recentlyViewedSearchTemplate.cloneNode(true);
72		var button = templateElement.querySelector('[data-component="saveButton"]');
73		button.dataset.searchparametermap = JSON.stringify(searchParameterMap);
74		button.setAttribute('href', href);
75		button.innerHTML = getTitleWithResult(title, resultCount);
76		return templateElement;
77	};
78
79	// Deserialize sessionStorage
80	var searchesFromSessionStorage = sessionStorage.getItem('recentlyViewedSearches');
81	if (!searchesFromSessionStorage) {
82		searchesFromSessionStorage = [];
83	} else {
84		searchesFromSessionStorage = JSON.parse(searchesFromSessionStorage);
85	}
86
87	// if template exist, retrieve info from it
88	if (recentlyViewedSearches && recentlyViewedSearchTemplate) {
89
90		// Serialize the data of the current template
91		var button = recentlyViewedSearchTemplate.querySelector('[data-component="saveButton"]');
92
93		var templateData = {
94			searchParameterMap: JSON.parse(button.dataset.searchparametermap),
95			title: button.getAttribute('title'),
96			href: button.getAttribute('href'),
97			resultCount: resultCount,
98			siteName: siteName
99		};
100
101		// if href is unique among stored searches, add to front
102		if (isSearching && searchesFromSessionStorage.filter(function (e) {
103			return button.getAttribute('href') === e.href;
104		}).length === 0) {
105			searchesFromSessionStorage.unshift(templateData);
106		}
107	}
108
109	// check if all fields exist. discard otherwise
110	var properties = ['title', 'href', 'searchParameterMap', 'resultCount', 'siteName'];
111	searchesFromSessionStorage = searchesFromSessionStorage.filter(function (item) {
112		var hasAllProperties = true;
113		var propertiesLength = properties.length;
114		for (var i = 0; i < propertiesLength && hasAllProperties; i++) {
115			hasAllProperties = item.hasOwnProperty(properties[i]);
116		}
117		return hasAllProperties;
118	});
119
120	// Update the count strings on the page
121	var recentlyViewedSearchesCount = qsa('.count.recentlyViewedSearchesCount');
122	var mySearchesButtonCount = document.querySelector('.mySearches .count');
123
124	var totalCount = 0;
125	if (mySearchesButtonCount) {
126		totalCount = parseInt(mySearchesButtonCount.innerHTML.replace(/\D/g, ''));
127	}
128	totalCount += searchesFromSessionStorage.length;
129
130	if (recentlyViewedSearchesCount && mySearchesButtonCount) {
131		recentlyViewedSearchesCount.forEach(function (el) {
132			el.innerHTML = '(' + searchesFromSessionStorage.length + ')';
133		});
134
135		mySearchesButtonCount.innerHTML = '(' + totalCount + ')';
136	}
137
138	// if recently viewed searches exist, deserialize array from session storage and add the entries
139	if (recentlyViewedSearches) {
140		recentlyViewedSearches.innerHTML = '';
141		searchesFromSessionStorage.filter(function (item) {
142			return item.siteName === siteName;
143		}
143).forEach(function (item) {
144			var template = getTemplate(item.title, item.href, item.searchParameterMap, item.resultCount);
145			allrecentlyViewedSearches.forEach(function (el) {
146				el.appendChild(template);
147			});
148			if (document.querySelector('body').classList.contains('loggedin')) {
149				template.querySelector('a.save').addEventListener('click', function (event) {
150					event.preventDefault();
151					saveRecentlyViewedSearch(item);
152				});
153				template.querySelector('a.save').addEventListener('keydown', function (event) {
154					if (event.keyCode == 13) {
155						event.preventDefault();
156						saveRecentlyViewedSearch(item);
157					}
158				});
159			} else {
160				template.querySelector('a.save').remove();
161			}
162		});
163	}
164
165	// Reserialize the array and store it in sessionStorage
166	sessionStorage.setItem('recentlyViewedSearches', JSON.stringify(searchesFromSessionStorage));
167}
168
169// Return the first element of a list that starts with "start"
170var pickItem = function pickItem(elements, start) {
171	var result = Array.from(elements).filter(function (item) {
172		return item.startsWith(start);
173	});
174	if (result.length > 0) {
175		return result[0];
176	} else {
177		return null;
178	}
179};
180
181// test 2
182var hasItem = function hasItem(elements, start) {
183	return pickItem(elements, start) !== null;
184};
185
186function saveRecentlyViewedEntry(item) {
187	fetch('/rest/v1/savedContent', {
188		method: "POST",
189		headers: {
190			'Content-Type': 'application/json'
191		},
192		body: JSON.stringify({
193			uri: item.uri,
194			title: item.title,
195			siteName: item.siteName
196		})
197	}).then(function (response) {
198		return response.text();
199	}).then(function (data) {
200		location.reload();
201	}).catch(function (error) {
202		console.error('Error: ', error);
203	});
204}
205
206function initializeRecentlyViewedEntries() {
207	var body = document.querySelector('body');
208	var siteName = getSiteNameFromBody();
209	var allrecentlyViewedEntries = qsa('.recentlyViewedEntries');
210	var isContentPage = hasItem(body.classList, 'page-content') || hasItem(body.classList, 'page-view') || hasItem(body.classList, 'nonConfigurableViewPage');
211
212	var isNonConfigurable = hasItem(body.classList, 'nonConfigurableViewPage');
213
214	var nonConfigurableTitle = body.dataset.myContentTitle;
215
216	var titleEl = document.querySelector('.component-content-title .title');
217	var pageTitle = document.getElementById('pagetitle'); // alternative source in OUP sites
218	var recentlyViewedEntries = document.querySelector('.recentlyViewedEntries');
219	var contentTitle = document.body.dataset.myContentTitle ? document.body.dataset.myContentTitle : titleEl ? titleEl.innerText : nonConfigurableTitle ? nonConfigurableTitle : pageTitle ? pageTitle.childElementCount === 0 ? pageTitle.innerText : pageTitle.firstChild.innerText : null;
220
221	if (pageTitle && (nonConfigurableTitle === undefined || nonConfigurableTitle === null)) {
222		if (pageTitle.childElementCount > 0 && pageTitle.firstChild.textContent !== undefined) {
223			contentTitle = pageTitle.firstChild.textContent;
224		}
225	}
226
227	if (contentTitle == null) {
228		var tempTitle = document.querySelector('#mainTitle');
229		if (tempTitle) {
230			contentTitle = tempTitle.innerText;
231		}
232	}
233
234	var recentlyViewedEntriesCount = document.querySelector('.recentlyViewedEntriesCount');
235	var myEntriesButtonCount = document.querySelector('#savedEntries .count');
236	var allEntriesButtonCount = qsa('#savedEntries .count');
237	var allrecentlyViewedEntriesCount = qsa('.recentlyViewedEntriesCount');
238
239	var getTemplate = function getTemplate(title, href) {
240		var templateElement = recentlyViewedEntryTemplate.cloneNode(true);
241		var button = templateElement.querySelector('[data-component="saveButton"]');
242		button.setAttribute('href', href);
243		button.innerHTML = title.length > 25 ? title.substr(0, 22) + "..." : title;
244		return templateElement;
245	};
246
247	// Deserialize sessionStorage
248	var entriesFromSessionStorage = sessionStorage.getItem('recentlyViewedEntries');
249
250	if (!entriesFromSessionStorage) {
251		entriesFromSessionStorage = [];
252	} else {
253		entriesFromSessionStorage = JSON.parse(entriesFromSessionStorage);
254	}
255
256	var recentlyViewedEntryTemplate = document.querySelector('.recentlyViewedEntryTemplate');
257	if (recentlyViewedEntryTemplate) {
258		recentlyViewedEntryTemplate = recentlyViewedEntryTemplate.cloneNode(true);
259		allrecentlyViewedEntries.forEach(function (el) {
260			var temel = el.querySelector('.recentlyViewedEntryTemplate');
261			if (temel) {
262				el.removeChild(temel);
263			}
264		});
265	}
266
267	// if template exist, retrieve info from it
268	if (isContentPage && recentlyViewedEntries && recentlyViewedEntryTemplate) {
269		var button = recentlyViewedEntryTemplate.querySelector('[data-component="saveButton"]');
270
271		var templateData = {
272			title: contentTitle,
273			link: button !== undefined && button !== null ? button.href : window.location.pathname,
274			uri: button !== undefined && button !== null ? button.dataset.uri : window.location.pathname !== null ? window.location.pathname.substring(window.location.pathname.indexOf("/view/") + 5) : window.location.pathname,
275			siteName: siteName
276		};
277
278		if (isContentPage && entriesFromSessionStorage.filter(function (e) {
279			return button.dataset.uri === e.uri;
280		}).length === 0) {
281			entriesFromSessionStorage.unshift(templateData);
282		}
283
284		while (entriesFromSessionStorage.length > 10) {
285			entriesFromSessionStorage.pop();
286		}
287	}
288
289	// check if all fields exist. discard otherwise
290	var properties = ['title', 'link', 'uri', 'siteName'];
291	entriesFromSessionStorage = entriesFromSessionStorage.filter(function (item) {
292		var hasAllProperties = true;
293		var propertiesLength = properties.length;
294		for (var i = 0; i < propertiesLength && hasAllProperties; i++) {
295			hasAllProperties = item.hasOwnProperty(properties[i]);
296		}
297		return hasAllProperties;
298	});
299
300	if (isNonConfigurable && !recentlyViewedEntryTemplate && contentTitle !== undefined && contentTitle !== null && contentTitle.length > 0) {
301		var uriJs = window.location.pathname !== null ? window.location.pathname.substring(window.location.pathname.indexOf("/view/") + 5) : window.location.pathname;
302
303		var _templateData = {
304			title: contentTitle,
305			link: window.location.pathname,
306			uri: uriJs,
307			siteName: siteName
308		};
309
310		if (isContentPage && entriesFromSessionStorage.filter(function (e) {
311			return uriJs === e.uri;
312		}).length === 0) {
313			entriesFromSessionStorage.unshift(_templateData);
314		}
315
316		while (entriesFromSessionStorage.length > 10) {
317			entriesFromSessionStorage.pop();
318		}
319	}
320
321	if (recentlyViewedEntries) {
322		recentlyViewedEntries.innerHTML = '';
323		var recentlyViewedEntriesForSite = 0;
324		entriesFromSessionStorage.filter(function (item) {
325			return item.siteName === getSiteNameFromBody();
326		}).forEach(function (item) {
327			if (siteName !== null && item.siteName !== null && siteName.length > 0 && siteName.length == item.siteName.length && siteName.indexOf(item.siteName) === 0) {
328				var template = getTemplate(item.title, item.link);
329				allrecentlyViewedEntries.forEach(function (el) {
330					el.appendChild(template);
331				});
332				//recentlyViewedEntries.appendChild(template);
333				if (document.querySelector('body').classList.contains('loggedin')) {
334					template.querySelector('a.save').addEventListener('click', function (event) {
335						event.preventDefault();
336						saveRecentlyViewedEntry(item);
337					});
338					template.querySelector('a.save').addEventListener('keydown', function (event) {
339						if (event.keyCode == 13) {
340							event.preventDefault();
341							saveRecentlyViewedEntry(item);
342						}
343					});
344				} else {
345					template.querySelector('a.save').remove();
346				}
347				recentlyViewedEntriesForSite++;
348			}
349		});
350
351		if (allrecentlyViewedEntriesCount.length > 1) {
352			allrecentlyViewedEntriesCount.forEach(function (el) {
353				el.innerHTML = '(' + recentlyViewedEntriesForSite + ')';
354			});
355		} else {
356			recentlyViewedEntriesCount.innerHTML = '(' + recentlyViewedEntriesForSite + ')';
357		}
358		var totalCount = parseInt(myEntriesButtonCount.innerHTML.replace(/\D/g, ''));
359		totalCount += recentlyViewedEntriesForSite;
360		if (allEntriesButtonCount.length > 1) {
361			allEntriesButtonCount.forEach(function (el) {
362				if (el.classList.contains('recentlyViewedEntriesCount')) {
363					el.innerHTML = '(' + recentlyViewedEntriesForSite + ')';
364				} else {
365					el.innerHTML = '(' + totalCount + ')';
366				}
367			});
368		} else {
369			myEntriesButtonCount.innerHTML = '(' + totalCount + ')';
370		}
371	}
372
373	// Reserialize the array and store it in sessionStorage
374	sessionStorage.setItem('recentlyViewedEntries', JSON.stringify(entriesFromSessionStorage));
375
376	// Scrolling fix
377	var chapterBody = document.querySelector(".container-chapterBody");
378	if (chapterBody) {
379		var lastScroll = 0;
380		document.querySelector(".content-page").addEventListener('click', function (e) {
381			var anchor = e.target.closest('a');
382			if (anchor !== null) {
383				if (anchor.hasChildNodes()) {
384					var path = anchor.hash;
385					path = path.split("#")[1];
386					var el = document.getElementById(path);
387					if (el) {
388						var children = anchor.childNodes;
389						for (var i = 0; i < children.length; i++) {
390							//if(children[0].tagName === "SUP"){
391							if (anchor.hash) {
392								e.preventDefault();
393								var yOffset = document.querySelector(".c-Appbar").offsetHeight;
394								var y = el.getBoundingClientRect().top + window.pageYOffset;
395								//el.scrollIntoView(true);
396								if (y < lastScroll) {
397									y = el.getBoundingClientRect().top + window.pageYOffset - yOffset;
398									window.scrollTo({ top: y, behavior: 'smooth' });
399								} else {
400									window.scrollTo({ top: y, behavior: 'smooth' });
401								}
402								lastScroll = y;
403							}
404						}
405					}
406				}
407			}
408		}, false);
409	}
410}
411
412initializeRecentlyViewedSearches();
413initializeRecentlyViewedEntries();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.