feat: add lazy loading of card on home page

feat: add universal organization store
fix: optimization for JSON data loaded in home page HTML
This commit is contained in:
lefuturiste 2020-07-26 13:35:03 +00:00
parent 2e6e64a6d3
commit ecf9a0720e
8 changed files with 224 additions and 87 deletions

View file

@ -1,3 +1,6 @@
/**
* Nav management
*/
let navOpened = false;
let oldNavText = "";
let oldNavIcon = "";
@ -9,6 +12,7 @@ let navContent = document.getElementById('nav-content');
let mosaic = document.getElementById('mosaic');
let mosaicHeader = document.getElementById('mosaic-header');
let tags = []
navEnabler.onclick = async () => {
if (!navOpened) {
@ -34,6 +38,9 @@ function createEl(className = false, elName = "div") {
return el;
}
/**
* Render
*/
function renderNavItem(tag) {
/*
<div class="nav-item">
@ -87,6 +94,7 @@ function renderCard(organization) {
// image
let image = createEl('card-image-container')
let imageTag = createEl('card-image')
//mediaBaseUrl + '/' +
imageTag.style = `background-image: url('${organization.thumbnail}')`
image.appendChild(imageTag)
card.appendChild(image)
@ -102,14 +110,15 @@ function renderCard(organization) {
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 = `<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)
@ -117,8 +126,8 @@ function renderCard(organization) {
let description = createEl('card-description')
description.textContent = organization.description
let goTo = "/association/" + organization.slugs[organization.slugs.length - 1]
if (organization.isProposed) {
let goTo = "/association/" + organization.slug
if (isProposed) {
goTo += "?version=proposed"
}
// let link = createEl('card-link')
@ -141,13 +150,6 @@ function renderCard(organization) {
return card
}
function renderMosaic(data) {
let cardContainer = createEl('card-container')
data.forEach(orga => {
cardContainer.appendChild(renderCard(orga))
})
return cardContainer
}
let currentTag = null
let currentCardContainer = null
@ -159,12 +161,7 @@ function enableTag(node) {
tagId = node.attributes['data-tag-id'].value
}
let data = organizations.filter(orga => orga.tags.filter(id => id === tagId).length > 0 || all)
let cards = renderMosaic(data)
if (currentCardContainer !== null) {
mosaic.removeChild(currentCardContainer)
}
currentCardContainer = cards
mosaic.appendChild(cards)
renderMosaic(data)
node.className += ' enabled'
if (currentTag !== null) {
currentTag.className = currentTag.className.replace('enabled', '')
@ -177,10 +174,115 @@ function enableTag(node) {
} else {
mosaicHeader.textContent = data.length + " associations listées"
}
}
}
navContent.childNodes.forEach(node => {
node.onclick = () => enableTag(node)
/***
* 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
pageCount = Math.floor(data.length / elementsPerPage)
renderPage()
if (currentCardContainer !== null) {
mosaic.removeChild(currentCardContainer)
}
currentCardContainer = cardContainer
mosaic.appendChild(cardContainer)
}
window.onscroll = () => {
if (focusPoint != null) {
//console.log(isVisible(focusPoint))
if (isVisible(focusPoint) && !rendering) {
if ((page + 1) < pageCount) {
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(document.getElementById('nav-all'))
})
enableTag(document.getElementById('nav-all'))

View file

@ -1 +1 @@
let navOpened=!1,oldNavText="",oldNavIcon="",navEnabler=document.getElementById("nav-enabler"),navEnablerText=document.getElementById("nav-enabler-text"),navEnablerIcon=document.getElementById("nav-enabler-icon"),navContent=document.getElementById("nav-content"),mosaic=document.getElementById("mosaic"),mosaicHeader=document.getElementById("mosaic-header");function createEl(e=!1,t="div"){let n=document.createElement(t);return 0!=e&&(n.className=e),n}function renderNavItem(e){let t=createEl("nav-item"),n=createEl("nav-icon"),a=createEl(e.icon,"i");n.appendChild(a),t.appendChild(n);let r=createEl("nav-item-content"),l=createEl("nav-title");l.textContent=e.name,r.appendChild(l);let i=createEl("nav-access"),c=createEl("fas fa-chevron-right","i");return i.appendChild(c),r.appendChild(l),r.appendChild(i),t.appendChild(r),t}function setAttributes(e,t){for(var n in t)attr=document.createAttribute(n),attr.value=t[n],e.attributes.setNamedItem(attr)}function renderCard(e){let t=createEl("card","a"),n=createEl("card-image-container"),a=createEl("card-image");a.style=`background-image: url('${e.thumbnail}')`,n.appendChild(a),t.appendChild(n);let r=createEl("card-content"),l=createEl(),i=createEl("card-title-container"),c=createEl("card-title","h2");c.textContent=e.name,i.appendChild(c);let d=createEl("card-icon");if(Array.isArray(e.tags)&&e.tags.length>0){let t=tags.filter(t=>e.tags[0]===t._id)[0];d.innerHTML=`<svg\n aria-hidden="true"\n focusable="false"\n role="img"\n xmlns="http://www.w3.org/2000/svg"\n viewBox="0 0 ${t.icon.width} ${t.icon.height}">\n <path fill="currentColor" d="${t.icon.path}"></path>\n </svg>`}i.appendChild(d),l.appendChild(i);let o=createEl("card-description");o.textContent=e.description;let s="/association/"+e.slugs[e.slugs.length-1];return e.isProposed&&(s+="?version=proposed"),l.appendChild(o),r.appendChild(l),t.appendChild(r),t.href=s,t}function renderMosaic(e){let t=createEl("card-container");return e.forEach(e=>{t.appendChild(renderCard(e))}),t}navEnabler.onclick=async()=>{navOpened?(navEnablerText.textContent=oldNavText,navEnablerIcon.style.transform="rotate(0deg)",navContent.style.maxHeight=null):(oldNavText=navEnablerText.textContent,navEnablerText.textContent="Minimiser le menu",navEnablerIcon.style.transform="rotate(90eg)",navContent.style.maxHeight=navContent.scrollHeight+"px"),navOpened=!navOpened};let currentTag=null,currentCardContainer=null;function enableTag(e){let t="nav-all"===e.id,n="";t||(n=e.attributes["data-tag-id"].value);let a=organizations.filter(e=>e.tags.filter(e=>e===n).length>0||t),r=renderMosaic(a);null!==currentCardContainer&&mosaic.removeChild(currentCardContainer),currentCardContainer=r,mosaic.appendChild(r),e.className+=" enabled",null!==currentTag&&(currentTag.className=currentTag.className.replace("enabled","")),currentTag=e,null==a||a.length<=0?mosaicHeader.textContent="Aucune associations listées":1===a.length?mosaicHeader.textContent="Une association listée":mosaicHeader.textContent=a.length+" associations listées"}navContent.childNodes.forEach(e=>{e.onclick=()=>enableTag(e)}),enableTag(document.getElementById("nav-all"));
let navOpened=!1,oldNavText="",oldNavIcon="",navEnabler=document.getElementById("nav-enabler"),navEnablerText=document.getElementById("nav-enabler-text"),navEnablerIcon=document.getElementById("nav-enabler-icon"),navContent=document.getElementById("nav-content"),mosaic=document.getElementById("mosaic"),mosaicHeader=document.getElementById("mosaic-header"),tags=[];function createEl(e=!1,n="div"){let t=document.createElement(n);return 0!=e&&(t.className=e),t}function renderNavItem(e){let n=createEl("nav-item"),t=createEl("nav-icon"),a=createEl(e.icon,"i");t.appendChild(a),n.appendChild(t);let r=createEl("nav-item-content"),l=createEl("nav-title");l.textContent=e.name,r.appendChild(l);let o=createEl("nav-access"),i=createEl("fas fa-chevron-right","i");return o.appendChild(i),r.appendChild(l),r.appendChild(o),n.appendChild(r),n}function setAttributes(e,n){for(var t in n)attr=document.createAttribute(t),attr.value=n[t],e.attributes.setNamedItem(attr)}function renderCard(e){let n=createEl("card","a"),t=createEl("card-image-container"),a=createEl("card-image");a.style=`background-image: url('${e.thumbnail}')`,t.appendChild(a),n.appendChild(t);let r=createEl("card-content"),l=createEl(),o=createEl("card-title-container"),i=createEl("card-title","h2");i.textContent=e.name,o.appendChild(i);let c=createEl("card-icon");if(Array.isArray(e.tags)&&e.tags.length>0){let n=tags.filter(n=>e.tags[0]===n._id)[0];c.innerHTML=n.iconHTML}o.appendChild(c),l.appendChild(o);let d=createEl("card-description");d.textContent=e.description;let s="/association/"+e.slug;return isProposed&&(s+="?version=proposed"),l.appendChild(d),r.appendChild(l),n.appendChild(r),n.href=s,n}navEnabler.onclick=async()=>{navOpened?(navEnablerText.textContent=oldNavText,navEnablerIcon.style.transform="rotate(0deg)",navContent.style.maxHeight=null):(oldNavText=navEnablerText.textContent,navEnablerText.textContent="Minimiser le menu",navEnablerIcon.style.transform="rotate(90eg)",navContent.style.maxHeight=navContent.scrollHeight+"px"),navOpened=!navOpened};let currentTag=null,currentCardContainer=null;function enableTag(e){let n="nav-all"===e.id,t="";n||(t=e.attributes["data-tag-id"].value);let a=organizations.filter(e=>e.tags.filter(e=>e===t).length>0||n);renderMosaic(a),e.className+=" enabled",null!==currentTag&&(currentTag.className=currentTag.className.replace("enabled","")),currentTag=e,null==a||a.length<=0?mosaicHeader.textContent="Aucune associations listées":1===a.length?mosaicHeader.textContent="Une association listée":mosaicHeader.textContent=a.length+" associations listées"}function posY(e){for(var n=e,t=0;n&&"body"!==n.tagName.toLowerCase();)t+=n.offsetTop,n=n.offsetParent;return t}function viewPortHeight(){var e=document.documentElement;return window.innerWidth?window.innerHeight:e&&!isNaN(e.clientHeight)?e.clientHeight:0}function scrollY(){return window.pageYOffset?window.pageYOffset:Math.max(document.documentElement.scrollTop,document.body.scrollTop)}function isVisible(e){var n=viewPortHeight(),t=scrollY();return!(posY(e)>n+t)}let rendering=!0,page=0,elementsPerPage=5,focusPoint=null,focusElementPos=2,cardContainer=null,currentOrganizations=[],pageCount=0;function renderPage(){rendering=!0;let e=currentOrganizations.slice(page*elementsPerPage,(page+1)*elementsPerPage);e.forEach((n,t)=>{let a=renderCard(n);cardContainer.appendChild(a),t===e.length-focusElementPos&&(focusPoint=a)}),rendering=!1}function renderMosaic(e){cardContainer=createEl("card-container"),currentOrganizations=e,pageCount=Math.floor(e.length/elementsPerPage),renderPage(),null!==currentCardContainer&&mosaic.removeChild(currentCardContainer),currentCardContainer=cardContainer,mosaic.appendChild(cardContainer)}window.onscroll=()=>{null!=focusPoint&&isVisible(focusPoint)&&!rendering&&page+1<pageCount&&(page++,renderPage())},window.addEventListener("DOMContentLoaded",()=>{document.querySelectorAll("#nav-content .nav-item").forEach(e=>{e.onclick=()=>enableTag(e),"nav-all"!==e.id&&tags.push({_id:e.attributes["data-tag-id"].value,iconHTML:e.querySelector(".nav-icon").innerHTML})}),enableTag(document.getElementById("nav-all"))});

File diff suppressed because one or more lines are too long