blob: f34696e8809e24d16003948514865cbf81bd2b74 [file]
const allGuides = []
const guideClassName = 'guide'
const mobileQueryInputFieldId = 'mobile-query'
const multiGuideClassName = 'multi-guide'
const queryInputFieldId = 'query'
const searchStatusId = 'guides-search-status'
const elementsClassNames = [
'training',
'latest-guides',
'guide-group',
'versions-by-grails',
'tags-by-topic',
'guides-suggestion',
'guides-catalogue',
]
window.addEventListener('load', () => {
let elements = document.getElementsByClassName(guideClassName)
for (let i = 0; i < elements.length; i++) {
allGuides.push({
href: elements[i].getAttribute('href'),
title: elements[i].text,
tags: tagsAtGuide(elements[i].parentNode)
})
}
elements = document.getElementsByClassName(multiGuideClassName)
for (let i = 0; i < elements.length; i++) {
allGuides.push({
title: titleAtMultiGuide(elements[i]),
versions: versionsAtMultiGuide(elements[i])
})
}
if (document.getElementById(queryInputFieldId)) {
document.getElementById(queryInputFieldId)
.addEventListener('input', onQueryChanged)
}
if (document.getElementById(mobileQueryInputFieldId)) {
document.getElementById(mobileQueryInputFieldId)
.addEventListener('input', onQueryChanged)
}
})
function hideElementsToDisplaySearchResults() {
for (let i = 0; i < elementsClassNames.length; i++) {
hideElementsByClassName(elementsClassNames[i])
}
}
function showElementsToDisplaySearchResults() {
for (let i = 0; i < elementsClassNames.length; i++) {
showElementsByClassName(elementsClassNames[i])
}
}
function hideElementsByClassName(className) {
const elements = document.getElementsByClassName(className)
for (let i = 0; i < elements.length; i++) {
elements[i].style.display = 'none'
}
}
function showElementsByClassName(className) {
const elements = document.getElementsByClassName(className)
for (let i = 0; i < elements.length; i++) {
elements[i].style.display = ''
}
}
function hasClass(node, className) {
if (!node || node.nodeType !== 1) {
return false
}
if (node.classList) {
return node.classList.contains(className)
}
const value = node.className || ''
return (' ' + value + ' ').indexOf(' ' + className + ' ') !== -1
}
function updateSearchStatus(message) {
const status = document.getElementById(searchStatusId)
if (status) {
status.textContent = message
}
}
function titleAtMultiGuide(element) {
for (let y = 0; y < element.childNodes.length; y++) {
if (hasClass(element.childNodes[y], 'title')) {
return element.childNodes[y].textContent
}
}
return ''
}
function versionsAtMultiGuide(element) {
const versions = []
for (let y = 0; y < element.childNodes.length; y++) {
if (hasClass(element.childNodes[y], 'align-left')) {
const versionDiv = element.childNodes[y]
let verEl
let hrefEl
const tagsArr = []
for (let x = 0; x < versionDiv.childNodes.length; x++) {
if (hasClass(versionDiv.childNodes[x], 'grails-version')) {
verEl = versionDiv.childNodes[x].textContent
hrefEl = versionDiv.childNodes[x].getAttribute('href')
}
if (hasClass(versionDiv.childNodes[x], 'tag')) {
tagsArr.push(versionDiv.childNodes[x].textContent);
}
}
versions.push({
grailsVersion: verEl,
href: hrefEl,
tags: tagsArr
})
}
}
return versions
}
function tagsAtGuide(element) {
const tags = []
for (let y = 0; y < element.childNodes.length; y++) {
if (hasClass(element.childNodes[y], 'tag')) {
tags.push(element.childNodes[y].textContent);
}
}
return tags
}
function onQueryChanged() {
const query = queryValue().trim()
const resultsDiv = document.getElementsByClassName('search-results')
if (!resultsDiv.length) {
return
}
if (query === '') {
showElementsToDisplaySearchResults()
resultsDiv[0].innerHTML = ''
updateSearchStatus('')
return
}
// Hide catalogue and other browse surfaces for every non-empty query
// before branching into matches vs no-results.
hideElementsToDisplaySearchResults()
const matchingGuides = []
for (let i = 0; i < allGuides.length; i++) {
let guide = allGuides[i]
if (doesGuideMatchQuery(guide, query) ) {
matchingGuides.push(guide)
}
}
if (matchingGuides.length > 0) {
resultsDiv[0].innerHTML = renderGuideGroup(matchingGuides, query)
const count = matchingGuides.length
updateSearchStatus(count === 1 ? '1 guide found' : count + ' guides found')
} else {
resultsDiv[0].innerHTML =
"<div class='guide-group'><div class='guide-group-header'><h3>No results found</h3></div></div>"
updateSearchStatus('No results found')
}
}
function doesTagsMatchQuery(tags, query) {
for (let x = 0; x < tags.length; x++) {
if (tags[x].toLowerCase().indexOf(query.toLowerCase()) !== -1) {
return true
}
}
return false
}
function doesTitleMatchQuery(title, query) {
if (title.toLowerCase().indexOf(query.toLowerCase()) !== -1) {
return true
}
}
function doesGuideMatchQuery(guide, query) {
if (doesTitleMatchQuery(guide.title, query)) {
return true
}
if (guide.tags === undefined || guide.tags === null) {
for (let i = 0; i < guide.versions.length; i++) {
const version = guide.versions[i]
if (doesTagsMatchQuery(version.tags, query)) {
return true
}
}
} else {
if (doesTagsMatchQuery(guide.tags, query)) {
return true
}
}
return false
}
function queryValue() {
const value = document.getElementById(queryInputFieldId).value.trim()
if (value === '') {
if (document.getElementById(mobileQueryInputFieldId)) {
return document.getElementById(mobileQueryInputFieldId).value.trim()
}
}
return value
}
function renderGuideGroup(guides, query) {
const items = guides.map(g => renderGuideAsHtmlLi(g, query)).join('');
return `
<div class="guide-group">
<div class="guide-group-header">
<h3>Guides Filtered by: ${queryValue()}</h3>
</div>
<ul>
${items}
</ul>
</div>
`;
}
function renderGuideAsHtmlLi(guide, query) {
const hiddenTags = (tags = []) =>
tags.map(tag => `<span class="tag">${tag}</span>`).join('')
// Multi-guide (no guide.tags)
if (guide.tags == null) {
const titleMatched = doesTitleMatchQuery(guide.title, query)
const versionsHtml = guide.versions
.filter(v => titleMatched || doesTagsMatchQuery(v.tags, query))
.map(v => `
<div class="align-left guides-version-chip">
<a class="grails-version" href="${v.href}">${v.grailsVersion}</a>
${hiddenTags(v.tags)}
</div>`
)
.join('')
return `<li>
<div class="multi-guide">
<span class="title">${guide.title}</span>
${versionsHtml}
</div>
</li>`;
}
// Single guide (has guide.tags)
return `<li>
<a class="${guideClassName}" href="${guide.href}">${guide.title}</a>
${hiddenTags(guide.tags)}
</li>`;
}