1
0
mirror of synced 2025-12-23 11:54:18 -05:00
Files
docs/javascripts/filter-cards.js
Vanessa Yuen b46da8dfc7 Sublanding page all guides section (#16869)
* get link liquid tag to accept variables as param

* new liquid tag `link_as_article_card`

* refactor link liquid tag slightly so we can control what props get rendered

* generalize filterCodeExample to use in all guides section

* pass in `js-filter-card-max` instead of hardcode max

* tweaks and add `data` to CSP for images

* add liquid tag tests

* add some browser tests for card filters

* we still need to rely on `getPathWithLanguage` for hrefs that already have the language code embedded


Co-authored-by: Emily Gould <4822039+emilyistoofunky@users.noreply.github.com>
2021-01-18 12:23:23 +00:00

123 lines
3.7 KiB
JavaScript

function matchCardBySearch (card, searchString) {
const matchReg = new RegExp(searchString, 'i')
// Check if this card matches - any `data-*` attribute contains the string
return Object.keys(card.dataset).some(key => matchReg.test(card.dataset[key]))
}
function matchCardByAttribute (card, attribute, value) {
if (attribute in card.dataset) {
return card.dataset[attribute] === value
}
return false
}
export default function cardsFilter () {
const inputFilter = document.querySelector('.js-filter-card-filter')
const dropdownFilter = document.querySelector('.js-filter-card-filter-dropdown')
const cards = Array.from(document.querySelectorAll('.js-filter-card'))
const showMoreButton = document.querySelector('.js-filter-card-show-more')
const noResults = document.querySelector('.js-filter-card-no-results')
// if jsFilterCardMax not set, assume no limit (well, at 99)
const maxCards = showMoreButton ? parseInt(showMoreButton.dataset.jsFilterCardMax || 99) : null
const filterEventHandler = (evt) => {
const { currentTarget } = evt
const value = currentTarget.value
// Show or hide the "Show more" button if there is a value
if (value) {
showMoreButton.classList.add('d-none')
} else {
showMoreButton.classList.remove('d-none')
}
// Track whether or not we had at least one match
let hasMatches = false
for (let index = 0; index < cards.length; index++) {
const card = cards[index]
// Filter was emptied
if (!value) {
// Make sure we don't show the "No results" blurb
hasMatches = true
// Hide all but the first n number of cards
if (index > maxCards - 1) {
card.classList.add('d-none')
} else {
card.classList.remove('d-none')
}
continue
}
let cardMatches = false
if (currentTarget.tagName === 'INPUT') {
cardMatches = matchCardBySearch(card, value)
}
if (currentTarget.tagName === 'SELECT' && currentTarget.name) {
cardMatches = matchCardByAttribute(card, currentTarget.name, value)
}
if (cardMatches) {
card.classList.remove('d-none')
hasMatches = true
} else {
card.classList.add('d-none')
}
}
// If there wasn't at least one match, show the "no results" text
if (!hasMatches) {
noResults.classList.remove('d-none')
} else {
noResults.classList.add('d-none')
}
return hasMatches
}
if (inputFilter) {
inputFilter.addEventListener('keyup', (evt) => {
const hasMatches = filterEventHandler(evt)
if (!hasMatches) {
document.querySelector('.js-filter-card-value').textContent = evt.currentTarget.value
}
})
}
if (dropdownFilter) {
dropdownFilter.addEventListener('change', filterEventHandler)
}
if (showMoreButton) {
showMoreButton.addEventListener('click', evt => {
// Number of cards that are currently visible
const numShown = cards.filter(card => !card.classList.contains('d-none')).length
// We want to show n more cards
const totalToShow = numShown + maxCards
for (let index = numShown; index < cards.length; index++) {
const card = cards[index]
// If the card we're at is less than the total number of cards
// we should show, show this one
if (index < totalToShow) {
card.classList.remove('d-none')
} else {
// Otherwise, we've shown the ones we intend to so exit the loop
break
}
}
// They're all shown now, we should hide the button
if (totalToShow >= cards.length) {
evt.currentTarget.classList.add('d-none')
}
})
}
}