/** * Utils */ function createEl(className = false, elName = "div") { let el = document.createElement(elName); if (className != false) { el.className = className; } return el; } /** * Nav management */ let navOpened = false; let oldNavText = ""; let oldNavIcon = ""; let navEnabler = document.getElementById('nav-enabler'); let navEnablerText = document.getElementById('nav-enabler-text'); let navEnablerIcon = document.getElementById('nav-enabler-icon'); let navContent = document.getElementById('nav-content'); let navAll = document.getElementById('nav-all') let mosaic = document.getElementById('mosaic'); let mosaicCount = document.getElementById('mosaic-count'); let tags = [] let navEnablerExists = false function closeMenu() { navEnablerText.textContent = oldNavText; navEnablerIcon.style.transform = "rotate(0deg)"; navContent.style.maxHeight = null; } navEnabler.onclick = async () => { navEnablerExists = true if (!navOpened) { // open the menu oldNavText = navEnablerText.textContent; navEnablerText.textContent = "Minimiser le menu"; navEnablerIcon.style.transform = "rotate(90eg)"; navContent.style.maxHeight = navContent.scrollHeight + "px"; } else { closeMenu() } navOpened = !navOpened } /** * Content rendering */ /** * Shuffle organization */ function shuffle(array, seed = {}) { let newSeed = {} let currentIndex = array.length, temporaryValue, randomIndex while (0 !== currentIndex) { if (seed[currentIndex] === undefined) { randomIndex = Math.floor(Math.random() * currentIndex) } else { randomIndex = seed[currentIndex.toString()] } newSeed[currentIndex.toString()] = randomIndex currentIndex -= 1 temporaryValue = array[currentIndex] array[currentIndex] = array[randomIndex] array[randomIndex] = temporaryValue } if (newSeed.length == 0) { newSeed = null } return [array, newSeed] } /** * Filter & Sort actions */ const randomBtn = document.getElementById('random-btn') const sortBtn = document.getElementById('sort-btn') const seedStorageKey = 'fva_shuffle_seed' let originalRandom = '' let sort = false let seed = {} // the user want to sort randomly randomBtn.onclick = () => { if (sort) { organizations = JSON.parse(originalRandom) enableTag(currentTag, true) sort = false randomBtn.classList.add('enabled') sortBtn.classList.remove('enabled') } } // the user want to sort by name sortBtn.onclick = () => { if (!sort) { // sort by name organizations = organizations.sort((a, b) => { var textA = a.name.toUpperCase() var textB = b.name.toUpperCase() return (textA < textB) ? -1 : (textA > textB) ? 1 : 0; }) enableTag(currentTag, true) sort = true sortBtn.classList.add('enabled') randomBtn.classList.remove('enabled') } } function renderNavItem(tag) { /*
*/ let navItem = createEl('nav-item'); let navIcon = createEl('nav-icon'); let icon = createEl(tag.icon, 'i'); navIcon.appendChild(icon); navItem.appendChild(navIcon); let navItemContent = createEl('nav-item-content'); let navTitle = createEl('nav-title'); navTitle.textContent = tag.name; navItemContent.appendChild(navTitle); let navAccess = createEl('nav-access'); let chevronIcon = createEl('fas fa-chevron-right', 'i'); navAccess.appendChild(chevronIcon); navItemContent.appendChild(navTitle); navItemContent.appendChild(navAccess); navItem.appendChild(navItemContent); return navItem; } function setAttributes(node, attrs) { for (var key in attrs) { attr = document.createAttribute(key) attr.value = attrs[key] node.attributes.setNamedItem(attr) } } function renderCard(organization) { let card = createEl('card', 'a') // image let image = createEl('card-image-container') let imageTag = createEl('card-image') imageTag.style = `background-image: url('${mediaBaseUrl + '/' + organization.thumbnail}')` image.appendChild(imageTag) card.appendChild(image) let content = createEl('card-content') let upperContent = createEl() let titleContainer = createEl('card-title-container') let title = createEl('card-title', 'h2') title.textContent = organization.name titleContainer.appendChild(title) let icon = createEl('card-icon') if (Array.isArray(organization.tags) && organization.tags.length > 0) { let tag = tags.filter(tag => organization.tags[0] === tag._id)[0] // icon.innerHTML = `` icon.innerHTML = tag.iconHTML } titleContainer.appendChild(icon) upperContent.appendChild(titleContainer) let description = createEl('card-description') description.textContent = organization.description let goTo = "/association/" + organization.slug if (isProposed) { goTo += "?version=proposed" } // let link = createEl('card-link') // let aTag = createEl('card-link', 'a') // aTag.href = // aTag.textContent = "En savoir plus" // description.appendChild(aTag) upperContent.appendChild(description) //link.appendChild(aTag) content.appendChild(upperContent) //content.appendChild(link) card.appendChild(content) card.href = goTo card.setAttribute('data-organization-id', organization._id) // card.onclick = () => { // window.location = goTo // } card.onclick = (e) => { e.preventDefault() window.sessionStorage[scrollPointStorageKey] = organization._id window.location.href = goTo } return card } let currentTag = null let currentCardContainer = null function enableTag(node, sortOperation = false, initialOperation = false) { let all = node.id === 'nav-all' let tagId = '' if (!all) { tagId = node.attributes['data-tag-id'].value } let data = organizations .filter(orga => orga.tags.filter(id => id === tagId).length > 0 || all) renderMosaic(data) node.className += ' enabled' if (currentTag !== null) { currentTag.className = currentTag.className.replace('enabled', '') } currentTag = node if (!sortOperation) { if (data === undefined || data === null || data.length <= 0) { mosaicCount.textContent = "Aucune association listée" } else if (data.length === 1) { mosaicCount.textContent = "Une association listée" } else { mosaicCount.textContent = data.length + " associations listées" } // close the menu if on mobile if (navEnablerExists && !initialOperation) { navOpened = !navOpened closeMenu() document.getElementsByClassName('content')[0].scrollIntoView(true) } else { if (window.scrollY() > 300 && !initialOperation) { document.getElementsByClassName('content')[0].scrollIntoView(true) } } } } /*** * Is a element in the view ? */ function posY(elm) { var test = elm, top = 0; while(!!test && test.tagName.toLowerCase() !== "body") { top += test.offsetTop; test = test.offsetParent; } return top; } function viewPortHeight() { var de = document.documentElement; if(!!window.innerWidth) { return window.innerHeight; } else if( de && !isNaN(de.clientHeight) ) { return de.clientHeight; } return 0; } function scrollY() { if( window.pageYOffset ) { return window.pageYOffset; } return Math.max(document.documentElement.scrollTop, document.body.scrollTop); } function isVisible(elm) { var vpH = viewPortHeight(), // Viewport Height st = scrollY(), // Scroll Top y = posY(elm); return !(y > (vpH + st)); } /** * RenderMosaic * (take all the organizations we want to render) * Render only the first 5 elements * Set the focus point on the last - 1 of theses elements * When the focus point is on screen we load the next 5 elements */ let rendering = true let page = 0 let elementsPerPage = 5 let focusPoint = null let focusElementPos = 2 let cardContainer = null let currentOrganizations = [] let pageCount = 0 function renderPage() { rendering = true let data = currentOrganizations.slice(page * elementsPerPage, (page + 1) * elementsPerPage) data.forEach((orga, index) => { let card = renderCard(orga) cardContainer.appendChild(card) if (index === data.length - focusElementPos) { focusPoint = card } }) rendering = false } function renderMosaic(data) { cardContainer = createEl('card-container') // 1 - parse all the data // 2 - for each currentOrganizations = data page = 0 pageCount = Math.floor(data.length / elementsPerPage) renderPage() if (currentCardContainer !== null) { mosaic.removeChild(currentCardContainer) } currentCardContainer = cardContainer mosaic.appendChild(cardContainer) } const scrollPointStorageKey = 'fva_scroll_point' window.onscroll = () => { //window.sessionStorage[scrollPointStorageKey] = window.scrollY() if (focusPoint != null && isVisible(focusPoint) && !rendering) { if (page + 1 < pageCount + 1) { page++ renderPage() } } } /** * Fetch tags and register click handler */ window.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('#nav-content .nav-item').forEach(node => { node.onclick = () => enableTag(node) if (node.id === 'nav-all') { return } tags.push({ _id: node.attributes['data-tag-id'].value, iconHTML: node.querySelector('.nav-icon').innerHTML }) }) // by default we render the cards with the random behaviour seed = window.sessionStorage[seedStorageKey] == null ? {} : JSON.parse(window.sessionStorage[seedStorageKey]) let res = shuffle(organizations, seed) organizations = res[0] originalRandom = JSON.stringify(organizations) seed = res[1] enableTag(navAll, false, true) window.sessionStorage.setItem(seedStorageKey, JSON.stringify(seed)) // if (window.sessionStorage[scrollPointStorageKey] != null) { // let organizationFocus = document // .querySelectorAll('.card-container .card') // console.log(organizationFocus) // organizationFocus = organizationFocus // .filter(e => e.getAttribute('data-organization-id') === window.sessionStorage[scrollPointStorageKey]) // if (organizationFocus.length > 0) { // organizationFocus.scrollIntoView(true) // } // } })