blacklight-frontend
Advanced tools
Comparing version 8.7.0 to 8.8.0
@@ -113,2 +113,41 @@ /* Converts a "toggle" form, with single submit button to add/remove | ||
// Usage: | ||
// ``` | ||
// const basicFunction = (entry) => console.log(entry) | ||
// const debounced = debounce(basicFunction("I should only be called once")); | ||
// | ||
// debounced // does NOT print to the screen because it is invoked again less than 200 milliseconds later | ||
// debounced // does print to the screen | ||
// ``` | ||
function debounce(func, timeout = 200) { | ||
let timer; | ||
return (...args) => { | ||
clearTimeout(timer); | ||
timer = setTimeout(() => { func.apply(this, args); }, timeout); | ||
}; | ||
} | ||
const FacetSuggest = async (e) => { | ||
if (e.target.matches('.facet-suggest')) { | ||
const queryFragment = e.target.value?.trim(); | ||
const facetField = e.target.dataset.facetField; | ||
if (!facetField) { return; } | ||
const urlToFetch = `/catalog/facet_suggest/${facetField}/${queryFragment}`; | ||
const response = await fetch(urlToFetch); | ||
if (response.ok) { | ||
const blob = await response.blob(); | ||
const text = await blob.text(); | ||
const facetArea = document.querySelector('.facet-extended-list'); | ||
if (text && facetArea) { | ||
facetArea.innerHTML = text; | ||
} | ||
} | ||
} | ||
}; | ||
document.addEventListener('input', debounce(FacetSuggest)); | ||
/* | ||
@@ -264,9 +303,11 @@ The blacklight modal plugin can display some interactions inside a Bootstrap | ||
modal.setupModal = function() { | ||
// Register both trigger and preserve selectors in ONE event handler, combining | ||
// into one selector with a comma, so if something matches BOTH selectors, it | ||
// still only gets the event handler called once. | ||
// Register several click handlers in ONE event handler for efficiency | ||
// | ||
// * close button OR click on backdrop (modal.modalSelector) closes modal | ||
// * trigger and preserve link in modal functionality -- if somethign matches both trigger and | ||
// preserve, still only called once. | ||
document.addEventListener('click', (e) => { | ||
if (e.target.closest(`${modal.triggerLinkSelector}, ${modal.preserveLinkSelector}`)) | ||
modal.modalAjaxLinkClick(e); | ||
else if (e.target.closest('[data-bl-dismiss="modal"]')) | ||
else if (e.target.matches(`${modal.modalSelector}`) || e.target.closest('[data-bl-dismiss="modal"]')) | ||
modal.hide(); | ||
@@ -307,2 +348,63 @@ }); | ||
// The email and sms forms are displayed inside a modal. When the form is submitted, | ||
// this script closes the modal and puts the output on the main part of the page. | ||
// By default it is rendering catalog/sms_success and catalog/email_succcess. | ||
// These templates deliver a payload of the format used by turbo-streams. | ||
// See https://turbo.hotwired.dev/handbook/streams | ||
// That format allows a downstream application to override the template to define | ||
// multiple customizable areas of the page to get updated. | ||
class ModalForm { | ||
constructor(errorHandler, badRequestHandler, hideModal) { | ||
this.errorHandler = errorHandler; | ||
this.badRequestHandler = badRequestHandler; | ||
this.hideModal = hideModal; | ||
} | ||
get triggerFormSelector() { | ||
return 'form[data-blacklight-modal~=trigger]' | ||
} | ||
bind() { | ||
document.addEventListener('submit', (e) => { | ||
if (e.target.matches(this.triggerFormSelector)) | ||
this.onSubmit(e); | ||
}); | ||
} | ||
// This is like a light-weight version of turbo that only supports append presently. | ||
updateTurboStream(data) { | ||
this.hideModal(); | ||
const domparser = new DOMParser(); | ||
const dom = domparser.parseFromString(data, "text/html"); | ||
dom.querySelectorAll("turbo-stream[action='append']").forEach((node) => { | ||
const target = node.getAttribute('target'); | ||
const element = document.getElementById(target); | ||
if (element) | ||
element.append(node.querySelector('template').content.cloneNode(true)); | ||
else | ||
console.error(`Unable to find an element on the page with and ID of "${target}""`); | ||
}); | ||
} | ||
onSubmit(e) { | ||
e.preventDefault(); | ||
const form = e.target; | ||
fetch(form.action, { | ||
body: new FormData(form), | ||
headers: { "X-Requested-With": "XMLHttpRequest" }, // Ensures rails will return true when checking request.xhr? | ||
method: form.method, | ||
}) | ||
.then(response => { | ||
if (response.status === 422) { | ||
return response.text().then(content => this.badRequestHandler(content) ) | ||
} | ||
if (!response.ok) { | ||
throw new TypeError("Request failed"); | ||
} | ||
response.text().then(content => this.updateTurboStream(content)); | ||
}) | ||
.catch(error => this.errorHandler(error)); | ||
} | ||
} | ||
const SearchContext = (e) => { | ||
@@ -417,3 +519,5 @@ if (e.target.matches('[data-context-href]')) { | ||
ButtonFocus, | ||
FacetSuggest, | ||
Modal, | ||
ModalForm, | ||
SearchContext, | ||
@@ -420,0 +524,0 @@ Core, |
@@ -119,2 +119,41 @@ (function (global, factory) { | ||
// Usage: | ||
// ``` | ||
// const basicFunction = (entry) => console.log(entry) | ||
// const debounced = debounce(basicFunction("I should only be called once")); | ||
// | ||
// debounced // does NOT print to the screen because it is invoked again less than 200 milliseconds later | ||
// debounced // does print to the screen | ||
// ``` | ||
function debounce(func, timeout = 200) { | ||
let timer; | ||
return (...args) => { | ||
clearTimeout(timer); | ||
timer = setTimeout(() => { func.apply(this, args); }, timeout); | ||
}; | ||
} | ||
const FacetSuggest = async (e) => { | ||
if (e.target.matches('.facet-suggest')) { | ||
const queryFragment = e.target.value?.trim(); | ||
const facetField = e.target.dataset.facetField; | ||
if (!facetField) { return; } | ||
const urlToFetch = `/catalog/facet_suggest/${facetField}/${queryFragment}`; | ||
const response = await fetch(urlToFetch); | ||
if (response.ok) { | ||
const blob = await response.blob(); | ||
const text = await blob.text(); | ||
const facetArea = document.querySelector('.facet-extended-list'); | ||
if (text && facetArea) { | ||
facetArea.innerHTML = text; | ||
} | ||
} | ||
} | ||
}; | ||
document.addEventListener('input', debounce(FacetSuggest)); | ||
/* | ||
@@ -270,9 +309,11 @@ The blacklight modal plugin can display some interactions inside a Bootstrap | ||
modal.setupModal = function() { | ||
// Register both trigger and preserve selectors in ONE event handler, combining | ||
// into one selector with a comma, so if something matches BOTH selectors, it | ||
// still only gets the event handler called once. | ||
// Register several click handlers in ONE event handler for efficiency | ||
// | ||
// * close button OR click on backdrop (modal.modalSelector) closes modal | ||
// * trigger and preserve link in modal functionality -- if somethign matches both trigger and | ||
// preserve, still only called once. | ||
document.addEventListener('click', (e) => { | ||
if (e.target.closest(`${modal.triggerLinkSelector}, ${modal.preserveLinkSelector}`)) | ||
modal.modalAjaxLinkClick(e); | ||
else if (e.target.closest('[data-bl-dismiss="modal"]')) | ||
else if (e.target.matches(`${modal.modalSelector}`) || e.target.closest('[data-bl-dismiss="modal"]')) | ||
modal.hide(); | ||
@@ -313,2 +354,63 @@ }); | ||
// The email and sms forms are displayed inside a modal. When the form is submitted, | ||
// this script closes the modal and puts the output on the main part of the page. | ||
// By default it is rendering catalog/sms_success and catalog/email_succcess. | ||
// These templates deliver a payload of the format used by turbo-streams. | ||
// See https://turbo.hotwired.dev/handbook/streams | ||
// That format allows a downstream application to override the template to define | ||
// multiple customizable areas of the page to get updated. | ||
class ModalForm { | ||
constructor(errorHandler, badRequestHandler, hideModal) { | ||
this.errorHandler = errorHandler; | ||
this.badRequestHandler = badRequestHandler; | ||
this.hideModal = hideModal; | ||
} | ||
get triggerFormSelector() { | ||
return 'form[data-blacklight-modal~=trigger]' | ||
} | ||
bind() { | ||
document.addEventListener('submit', (e) => { | ||
if (e.target.matches(this.triggerFormSelector)) | ||
this.onSubmit(e); | ||
}); | ||
} | ||
// This is like a light-weight version of turbo that only supports append presently. | ||
updateTurboStream(data) { | ||
this.hideModal(); | ||
const domparser = new DOMParser(); | ||
const dom = domparser.parseFromString(data, "text/html"); | ||
dom.querySelectorAll("turbo-stream[action='append']").forEach((node) => { | ||
const target = node.getAttribute('target'); | ||
const element = document.getElementById(target); | ||
if (element) | ||
element.append(node.querySelector('template').content.cloneNode(true)); | ||
else | ||
console.error(`Unable to find an element on the page with and ID of "${target}""`); | ||
}); | ||
} | ||
onSubmit(e) { | ||
e.preventDefault(); | ||
const form = e.target; | ||
fetch(form.action, { | ||
body: new FormData(form), | ||
headers: { "X-Requested-With": "XMLHttpRequest" }, // Ensures rails will return true when checking request.xhr? | ||
method: form.method, | ||
}) | ||
.then(response => { | ||
if (response.status === 422) { | ||
return response.text().then(content => this.badRequestHandler(content) ) | ||
} | ||
if (!response.ok) { | ||
throw new TypeError("Request failed"); | ||
} | ||
response.text().then(content => this.updateTurboStream(content)); | ||
}) | ||
.catch(error => this.errorHandler(error)); | ||
} | ||
} | ||
const SearchContext = (e) => { | ||
@@ -423,3 +525,5 @@ if (e.target.matches('[data-context-href]')) { | ||
ButtonFocus, | ||
FacetSuggest, | ||
Modal, | ||
ModalForm, | ||
SearchContext, | ||
@@ -426,0 +530,0 @@ Core, |
import BookmarkToggle from 'blacklight/bookmark_toggle' | ||
import ButtonFocus from 'blacklight/button_focus' | ||
import FacetSuggest from 'blacklight/facet_suggest' | ||
import Modal from 'blacklight/modal' | ||
import ModalForm from 'blacklight/modalForm' | ||
import SearchContext from 'blacklight/search_context' | ||
@@ -10,3 +12,5 @@ import Core from 'blacklight/core' | ||
ButtonFocus, | ||
FacetSuggest, | ||
Modal, | ||
ModalForm, | ||
SearchContext, | ||
@@ -13,0 +17,0 @@ Core, |
@@ -55,3 +55,2 @@ /* | ||
*/ | ||
import ModalForm from 'blacklight/modalForm' | ||
@@ -153,9 +152,11 @@ const Modal = (() => { | ||
modal.setupModal = function() { | ||
// Register both trigger and preserve selectors in ONE event handler, combining | ||
// into one selector with a comma, so if something matches BOTH selectors, it | ||
// still only gets the event handler called once. | ||
// Register several click handlers in ONE event handler for efficiency | ||
// | ||
// * close button OR click on backdrop (modal.modalSelector) closes modal | ||
// * trigger and preserve link in modal functionality -- if somethign matches both trigger and | ||
// preserve, still only called once. | ||
document.addEventListener('click', (e) => { | ||
if (e.target.closest(`${modal.triggerLinkSelector}, ${modal.preserveLinkSelector}`)) | ||
modal.modalAjaxLinkClick(e) | ||
else if (e.target.closest('[data-bl-dismiss="modal"]')) | ||
else if (e.target.matches(`${modal.modalSelector}`) || e.target.closest('[data-bl-dismiss="modal"]')) | ||
modal.hide() | ||
@@ -162,0 +163,0 @@ }) |
{ | ||
"name": "blacklight-frontend", | ||
"version": "8.7.0", | ||
"version": "8.8.0", | ||
"description": "The frontend code and styles for Blacklight", | ||
@@ -5,0 +5,0 @@ "main": "app/assets/javascripts/blacklight", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Unstable ownership
Supply chain riskA new collaborator has begun publishing package versions. Package stability and security risk may be elevated.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
148942
40
1330
1
13