Refactor js
This commit is contained in:
commit
5de596c38a
28 changed files with 859 additions and 0 deletions
157
js/content.js
Normal file
157
js/content.js
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
const createPageFactory = ({
|
||||
nameId,
|
||||
pictureId,
|
||||
aboutId,
|
||||
timelineId,
|
||||
emailId,
|
||||
photoId,
|
||||
photoViewerId,
|
||||
}) => {
|
||||
const createPage = async (src) => {
|
||||
const {config, header, timeline, footer} = await getData(src);
|
||||
processHeader(header);
|
||||
processTimeline(timeline, config);
|
||||
processFooter(footer);
|
||||
setupGlobals(config);
|
||||
};
|
||||
|
||||
const processHeader = ({name, picture, about}) => {
|
||||
document.title = name;
|
||||
getElement(nameId).textContent = name;
|
||||
getElement(pictureId).src = picture;
|
||||
getElement(pictureId).onclick = () => showPhoto(picture);
|
||||
getElement(aboutId).innerHTML = listToHtml(about);
|
||||
};
|
||||
|
||||
const listToHtml = list => list.map(element => {
|
||||
if (!element.type || element.type === 'p') {
|
||||
return `<p>${element}</p>`;
|
||||
} else if (element.type === 'a') {
|
||||
return `<a href="${element.href}" target="_blank"> ${element.text} </a>`;
|
||||
} else if (element.type === 'video') {
|
||||
return `<video controls><source src="${element.src}" /></video>`;
|
||||
} else return '';
|
||||
}).join('\n');
|
||||
|
||||
const processTimeline = (timeline, {showMore}) => {
|
||||
getElement(timelineId).innerHTML = timeline.map(
|
||||
element => timelineElementToHTML(element, createId(), showMore)
|
||||
).join('\n');
|
||||
};
|
||||
|
||||
const timelineElementToHTML = ({date, title, picture, description, more, link}, id, showMore) => `
|
||||
<section>
|
||||
<div class="line">
|
||||
${date ? `<p class="date-wide-screen">${date}</p>` : ''}
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>${title}</h2>
|
||||
${date ? `<p class="date-narrow-screen">${date}</p>` : ''}
|
||||
${picture ? `<img src="${picture}" onclick="showPhoto('${picture}');" alt="${picture}"/>` : ''}
|
||||
${description ? `<p class="description">${description}</p>` : ''}
|
||||
${more ? `
|
||||
<div class="collapsed" id="${idToActivityId(id)}">
|
||||
${listToHtml(more)}
|
||||
</div>
|
||||
<a id="${idToButtonId(id)}" onclick="toggleLongDescription(${id})">
|
||||
${showMore}
|
||||
</a>
|
||||
`
|
||||
: (link ? `<a href="http://${link}" target="_blank">${link}</a>` : '')}
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
|
||||
const processFooter = ({email}) => {
|
||||
getElement(emailId).href = `mailto:${email}`;
|
||||
getElement(emailId).textContent = email;
|
||||
};
|
||||
|
||||
const hideFrame = () => {
|
||||
getElement(photoViewerId).style['z-index'] = -1;
|
||||
getElement(photoViewerId).style.opacity = '0';
|
||||
};
|
||||
|
||||
const showPhoto = src => {
|
||||
getElement(photoId).src = src;
|
||||
getElement(photoViewerId).style['z-index'] = 1000;
|
||||
getElement(photoViewerId).style.opacity = '1';
|
||||
};
|
||||
|
||||
const setupGlobals = config => {
|
||||
window.toggleLongDescription = toggleLongDescriptionFactory(config);
|
||||
window.showPhoto = showPhoto;
|
||||
|
||||
window.hideFrame = hideFrame;
|
||||
getElement(photoViewerId).addEventListener('click', hideFrame);
|
||||
|
||||
window.addEventListener('resize', onResize);
|
||||
document.body.addEventListener('keydown', handleEscape);
|
||||
};
|
||||
|
||||
const toggleLongDescriptionFactory = ({showMore, showLess}) => (id) => {
|
||||
const button = getElement(idToButtonId(id));
|
||||
const element = getElement(idToActivityId(id));
|
||||
|
||||
if (isClosed(element)) {
|
||||
open(element);
|
||||
button.textContent = showLess;
|
||||
} else {
|
||||
close(element);
|
||||
button.textContent = showMore;
|
||||
}
|
||||
};
|
||||
|
||||
const onResize = () => {
|
||||
const elements = document.getElementsByClassName('collapsed');
|
||||
Array.prototype.forEach.call(elements, element => {
|
||||
if (isOpen(element)) {
|
||||
element.style.height = 'auto';
|
||||
setTimeout(() => open(element), 100);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const isClosed = element => ['0px', '0', 0, ''].includes(element.style.height);
|
||||
|
||||
const isOpen = element => !isClosed(element);
|
||||
|
||||
const close = element => element.style.height = '0';
|
||||
|
||||
const open = element => element.style.height = `${element.scrollHeight}px`;
|
||||
|
||||
const handleEscape = event => {
|
||||
if (event.key === 'Escape') {
|
||||
hideFrame();
|
||||
}
|
||||
};
|
||||
|
||||
const getElementFactory = () => {
|
||||
const foundElements = {};
|
||||
return id => {
|
||||
if (!(id in foundElements)) {
|
||||
foundElements[id] = document.getElementById(id);
|
||||
}
|
||||
return foundElements[id];
|
||||
}
|
||||
};
|
||||
const getElement = getElementFactory();
|
||||
|
||||
const getData = async (src) => await (await fetch(src, {
|
||||
method: 'GET',
|
||||
mode: 'cors',
|
||||
cache: 'no-cache'
|
||||
})).json();
|
||||
|
||||
const createIdFactory = () => {
|
||||
let id = 0;
|
||||
return () => id++;
|
||||
};
|
||||
const createId = createIdFactory();
|
||||
|
||||
const idToButtonId = (id) => `button_${id}`;
|
||||
|
||||
const idToActivityId = (id) => `activity_${id}`;
|
||||
|
||||
return createPage;
|
||||
};
|
||||
15
js/main.js
Normal file
15
js/main.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
(async () => {
|
||||
const src = 'content-en.json';
|
||||
const ids = {
|
||||
pictureId: 'header-pic',
|
||||
nameId: 'name',
|
||||
aboutId: 'about',
|
||||
timelineId: 'timeline',
|
||||
emailId: 'email',
|
||||
photoViewerId: 'photo-viewer',
|
||||
photoId: 'photo'
|
||||
};
|
||||
|
||||
await createPageFactory(ids)(src);
|
||||
document.body.style.visibility = 'visible';
|
||||
})();
|
||||
Loading…
Add table
Add a link
Reference in a new issue