forked from github/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
filter-cards.js
136 lines (117 loc) · 4.26 KB
/
filter-cards.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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) {
const allValues = card.dataset[attribute].split(',')
return allValues.some(key => key === value)
}
return false
}
export default function cardsFilter () {
const inputFilter = document.querySelector('.js-filter-card-filter')
const dropdownFilters = document.querySelectorAll('.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 noFilter = () => {
showMoreButton.classList.remove('d-none')
for (let index = 0; index < cards.length; index++) {
const card = cards[index]
// Hide all but the first n number of cards
if (index > maxCards - 1) {
card.classList.add('d-none')
} else {
card.classList.remove('d-none')
}
}
}
const filterEventHandler = (evt) => {
const { currentTarget } = evt
const value = currentTarget.value
showMoreButton.classList.add('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]
let cardMatches = false
if (currentTarget.tagName === 'INPUT') {
// Filter was emptied
if (!value) {
noFilter()
// return hasMatches = true, so we don't show the "No results" blurb
hasMatches = true
continue
}
cardMatches = matchCardBySearch(card, value)
}
if (currentTarget.tagName === 'SELECT' && currentTarget.name) {
const matches = []
// check all the other dropdowns
dropdownFilters.forEach(({ name, value }) => {
if (!name || !value) return
matches.push(matchCardByAttribute(card, name, value))
})
// if none of the filters is selected
if (matches.length === 0) {
noFilter()
// return hasMatches = true, so we don't show the "No results" blurb
hasMatches = true
continue
}
cardMatches = matches.every(value => 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 (dropdownFilters) {
dropdownFilters.forEach(filter => filter.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')
}
})
}
}