372 lines
9.1 KiB
JavaScript
372 lines
9.1 KiB
JavaScript
/**
|
|
* 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) {
|
|
var currentIndex = array.length, temporaryValue, randomIndex
|
|
while (0 !== currentIndex) {
|
|
randomIndex = Math.floor(Math.random() * currentIndex)
|
|
currentIndex -= 1
|
|
|
|
temporaryValue = array[currentIndex]
|
|
array[currentIndex] = array[randomIndex]
|
|
array[randomIndex] = temporaryValue
|
|
}
|
|
|
|
return array
|
|
}
|
|
|
|
/**
|
|
* Filter & Sort actions
|
|
*/
|
|
const randomBtn = document.getElementById('random-btn')
|
|
const sortBtn = document.getElementById('sort-btn')
|
|
|
|
// by default we render the cards with the random behaviour
|
|
let sort = false
|
|
organizations = shuffle(organizations)
|
|
|
|
// the user want to sort randomly
|
|
randomBtn.onclick = () => {
|
|
if (sort) {
|
|
organizations = shuffle(organizations)
|
|
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) {
|
|
/*
|
|
<div class="nav-item">
|
|
<div class="nav-icon">
|
|
<i class="fas fa-music"></i>
|
|
</div>
|
|
<div class="nav-item-content">
|
|
<div class="nav-title">
|
|
Danse et musique
|
|
</div>
|
|
<div class="nav-access">
|
|
<i class="fas fa-chevron-right"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
*/
|
|
|
|
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 = `<svg
|
|
// aria-hidden="true"
|
|
// focusable="false"
|
|
// role="img"
|
|
// xmlns="http://www.w3.org/2000/svg"
|
|
// viewBox="0 0 ${tag.icon.width} ${tag.icon.height}">
|
|
// <path fill="currentColor" d="${tag.icon.path}"></path>
|
|
// </svg>`
|
|
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.onclick = () => {
|
|
// window.location = goTo
|
|
// }
|
|
return card
|
|
}
|
|
|
|
|
|
let currentTag = null
|
|
let currentCardContainer = null
|
|
|
|
function enableTag(node, sortOperation = 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) {
|
|
navOpened = !navOpened
|
|
closeMenu()
|
|
document.getElementsByClassName('content')[0].scrollIntoView(true)
|
|
} else {
|
|
if (window.scrollY() > 300) {
|
|
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)
|
|
}
|
|
|
|
window.onscroll = () => {
|
|
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
|
|
})
|
|
})
|
|
enableTag(navAll)
|
|
})
|