Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Permit configurable replacement of search tracking with client session storage #2954

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
90 changes: 80 additions & 10 deletions app/assets/javascripts/blacklight/blacklight.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion app/assets/javascripts/blacklight/blacklight.js.map

Large diffs are not rendered by default.

90 changes: 80 additions & 10 deletions app/javascript/blacklight/search_context.js
Expand Up @@ -11,34 +11,42 @@ const SearchContext = (() => {

Blacklight.csrfToken = () => document.querySelector('meta[name=csrf-token]')?.content
Blacklight.csrfParam = () => document.querySelector('meta[name=csrf-param]')?.content
Blacklight.searchStorage = () => document.querySelector('meta[name=blacklight-search-storage]')?.content

// this is the Rails.handleMethod with a couple adjustments, described inline:
// first, we're attaching this directly to the event handler, so we can check for meta-keys
Blacklight.handleSearchContextMethod = function(event) {
jcoyne marked this conversation as resolved.
Show resolved Hide resolved
const link = this

// instead of using the normal href, we need to use the context href instead
let href = link.getAttribute('data-context-href')
let contextUrl = new URL(link.getAttribute('data-context-href'), window.location)
let target = link.getAttribute('target')
let csrfToken = Blacklight.csrfToken()
let csrfParam = Blacklight.csrfParam()
let form = document.createElement('form')
form.method = 'post'
form.action = href
form.action = contextUrl.pathname;
const formMethod = link.getAttribute('data-context-method') || 'post'
form.method = (formMethod == 'get') ? formMethod : 'post'

let formContent = ''
for (const [paramName, paramValue] of contextUrl.searchParams.entries()) {
formContent += `<input name="${paramName}" value="${paramValue}" type="hidden" />`
}
if (formMethod != 'get' && formMethod != 'post') formContent += `<input name="_method" value="${formMethod}" type="hidden" />`

let formContent = `<input name="_method" value="post" type="hidden" />
<input name="redirect" value="${link.getAttribute('href')}" type="hidden" />`

if (Blacklight.searchStorage() == 'client') {
sessionStorage.setItem("blacklightSearch", new URLSearchParams(new URL(window.location).search))
} else {
formContent += `<input name="redirect" value="${link.getAttribute('href')}" type="hidden" />`
if (csrfParam !== undefined && csrfToken !== undefined) {
formContent += `<input name="${csrfParam}" value="${csrfToken}" type="hidden" />`
}
}
// check for meta keys.. if set, we should open in a new tab
if(event.metaKey || event.ctrlKey) {
target = '_blank';
}

if (csrfParam !== undefined && csrfToken !== undefined) {
formContent += `<input name="${csrfParam}" value="${csrfToken}" type="hidden" />`
}

// Must trigger submit by click on a button, else "submit" event handler won't work!
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/submit
formContent += '<input type="submit" />'
Expand All @@ -54,6 +62,68 @@ const SearchContext = (() => {
};

Blacklight.doSearchContextBehavior();

const clientAppliedParams = function(storedSearch) {
barmintor marked this conversation as resolved.
Show resolved Hide resolved
if (storedSearch) {
let backToCatalogParams = new URLSearchParams();
for (const [paramName, paramValue] of storedSearch.entries()) {
backToCatalogParams.append(paramName, paramValue);
}
const appliedParams = document.querySelector('#appliedParams')
if (appliedParams) {
const backToCatalogEle = appliedParams.querySelector('.back-to-catalog')
if (backToCatalogEle) {
const backToCatalogUrl = new URL(backToCatalogEle.href)
backToCatalogEle.href = `${backToCatalogUrl.pathname}?${backToCatalogParams.toString()}`
backToCatalogEle.classList.remove('d-none')
}
}
}
}
const clientPrevNext = function(prevNextPath, storedSearch) {
barmintor marked this conversation as resolved.
Show resolved Hide resolved
const prevNextUrl = new URL(prevNextPath, window.location)
// prevNextUrl should have a counter param, but needs search params
let prevNextParams = new URLSearchParams(prevNextUrl.search);
if (storedSearch) {
for (const [paramName, paramValue] of storedSearch.entries()) {
prevNextParams.append(paramName, paramValue);
}
}
const setHrefOrDelete = function(linkEle, url) {
if (!linkEle) return;
if (url) {
linkEle.href = url
} else {
linkEle.remove()
}
}
const setContent = function(ele, content) {
if (!ele) return;
ele.innerHTML = content;
}
fetch(`${prevNextUrl.pathname}?${prevNextParams.toString()}`)
.then((response) => response.json())
.then(function(responseData) {
if (!responseData.prev && !responseData.next) return;
document.querySelectorAll('.page-links').forEach(function(pageLinks) {
setContent(pageLinks.querySelector('.pagination-counter-raw'), responseData.counterRaw)
setContent(pageLinks.querySelector('.pagination-counter-delimited'), responseData.counterDelimited)
setContent(pageLinks.querySelector('.pagination-total-raw'), responseData.totalRaw)
setContent(pageLinks.querySelector('.pagination-total-delimited'), responseData.totalDelimited)
setHrefOrDelete(pageLinks.querySelector("a[rel='prev']"), responseData.prev)
setHrefOrDelete(pageLinks.querySelector("a[rel='next']"), responseData.next)
pageLinks.classList.remove('d-none')
})
})
}
Blacklight.onLoad(function(){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary to use onLoad here or can this function be called by doSearchContextBehavior? I think it's confusing to depend on both approaches.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doSearchContextBehavior adds an event listener for clicks, which doesn't inspect the DOM (yet). The "page links" behavior in the show view depends on DOM content. I'm trying to refactor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, pushed a refactor up. I think that I have to either piggyback on Blacklight.onLoad 's event detection, or I would have to reimplement it. I at least relocated the event handler attachment and the onload addition to doSearchContextBehavior.

let clientPageLinks = document.querySelectorAll('.page-links[data-page-links-url]')
if (clientPageLinks[0]) {
const storedSearch = new URLSearchParams(sessionStorage.getItem("blacklightSearch"))
clientAppliedParams(storedSearch)
clientPrevNext(clientPageLinks[0].getAttribute('data-page-links-url'), storedSearch)
}
})
})()

export default SearchContext
7 changes: 5 additions & 2 deletions app/views/catalog/_show_main_content.html.erb
@@ -1,5 +1,8 @@
<%= render(Blacklight::SearchContextComponent.new(search_context: @search_context, search_session: search_session, current_document: @document)) %>

<% if blacklight_config.track_search_session == 'client' -%>
<%= render Blacklight::SearchContext::ClientItemPaginationComponent.new(counter: params.permit(:counter)[:counter]) -%>
<% else -%>
<%= render Blacklight::SearchContextComponent.new(search_context: @search_context, search_session: search_session, current_document: @document) -%>
<% end -%>
<% @page_title = t('blacklight.search.show.title', document_title: document_presenter(@document).html_title, application_name: application_name).html_safe %>
<% content_for(:head) { render_link_rel_alternates } %>

Expand Down
3 changes: 3 additions & 0 deletions app/views/catalog/index.html.erb
@@ -1,3 +1,6 @@
<% content_for(:head) do %>
<meta name="blacklight-search-storage" content="<%= blacklight_config.track_search_session %>">
<% end %>
<% content_for(:sidebar) do %>
<% conf = blacklight_config.view_config(document_index_view_type) %>
<%= render conf.sidebar_component.new(blacklight_config: blacklight_config,
Expand Down
2 changes: 1 addition & 1 deletion app/views/catalog/show.html.erb
@@ -1,4 +1,4 @@
<%= render Blacklight::SearchContext::ServerAppliedParamsComponent.new %>
<%= render (blacklight_config.track_search_session == 'client' ? Blacklight::SearchContext::ClientAppliedParamsComponent : Blacklight::SearchContext::ServerAppliedParamsComponent).new %>

<%= render 'show_main_content' %>

Expand Down