I need to get a live image gallery based on a permanently monitored folder. It will run on my local computer. Here is how it should work:
Based on some samples founded in Stackoverflow, I've done that. But it doesn't refresh img. And if I well understand the code, it will not remove an image if the file disappear. What do you think? (As you can see I'm not very used with new technologies... I'm an old html/css webmaster)
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Titre de la page</title>
<link rel="stylesheet" href="style.css">
<script>
function refresh(node)
{
var times = 1000; // gap in Milli Seconds;
(function startRefresh()
{
var address;
if(node.src.indexOf('?')>-1)
address = node.src.split('?')[0];
else
address = node.src;
node.src = address+"?time="+new Date().getTime();
setTimeout(startRefresh,times);
})();
}
window.onload = function()
{
var node = document.getElementsByClassName('img');
refresh(node);
// you can refresh as many images you want just repeat above steps
}
</script>
</head>
<body>
<div class="ajax-inserted-content">
<section class="section gallery grid layout-4-col">
<div class="container">
<div class="row" id='gallery-items'>
</div>
</div>
</section>
</div>
<script>
function doPortItem(n) {
let img = document.createElement('img');
img.src = './imgportfolio/test-' + n + '.jpg';
img.addEventListener('load', () => {
let div = `<div class="col-3 col-lg-4 col-md-6 col-sm-12">
<div class="gallery-item">
<div class="gallery-img">
<img class="img" data-lazy-image data-src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzIDIiPjwvc3ZnPg==" src="${img.src}" alt="Demo img">
</div>
</div>
</div>`;
document.querySelector('#gallery-items').innerHTML += div;
doPortItem(++n)
})
}
doPortItem(1)
</script>
</body>
</html>
In short: you can't read a directory completely client-based because this would be a security nightmare: you could easily crawl a user's file system.
If you really can't run a local server supporting server side scripts like php
your only chance is probably to deploy a consistent numeric image file-name scheme and hide non-existent images in the gallery view like img-1
to img-100
:
let dir = 'https://picsum.photos/id';
let suffix = '/100/100';
let start = -3;
let end = 3;
// init
loadImages(dir);
// reload
let interval = 60 * 1000;
setInterval(loadImages, interval);
function loadImages(dir) {
let html = '';
//reset content
imageGrid.innerHTML = '';
for (let i = start; i < end; i++) {
let src = `${dir}/${i}${suffix}`;
html +=
`<a href="${dir}/${i}${suffix}" data-lg-size="100-100">
<img onerror="this.parentNode.classList.add('broken-image')" src="${src}">
</a>`;
}
imageGrid.insertAdjacentHTML('beforeend', html);
}
.imageGrid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1em;
}
img {
width: 100%;
aspect-ratio: 1;
border: 1px solid #ccc;
}
.broken-image {
display: none;
}
<h3>3 images are hidden as they don't exist</h3>
<div id="imageGrid" class="imageGrid"></div>
If an image can't be loaded it is hidden via onerror
callback function.
If you have control of the file naming conventions – this is probably the best you can get from 100% client-side approach.
The directory-list updates would rely on a recurring method call like setInterval()
. You can't get a proper live-update and should probably avoid too many updates – for instance an update each minute (or every 5 minutes) is more reasonable than updating every second.
When updating the gallery you would usually need to initialize the gallery script (binding lightbox events etc.)
I highly recommend to install a local server providing e.g php
functionality. For instance via an application like xampp, mampp etc.
In this case you could write a php
script responding to a JS fetch()
call like so:
JavaScript
We're sending a POST request via fetch()
to a php script which return a file list for the specified directory including only certain file types.
// directory to search for image files
let dir = 'img';
// allowed file extensions
let extensions = ['webp', 'png', 'jpg', 'gif'];
// php script url for directory listing
let phpScan = 'filelist.php';
// update interval: ever minute = 60000ms
let interval = 60 * 1000;
let fileList;
// init async call
(async () => {
//init
fileList = await getFilelist(dir, phpScan, extensions);
updateGallery(fileList);
setInterval(async () => {
fileList = await getFilelist(dir, phpScan, extensions);
updateGallery(fileList)
}, interval)
})();
// dummy update function
function updateGallery(fileList) {
console.log(fileList);
}
/**
* retrieve file directory info
* via php script
*/
async function getFilelist(dir, phpScan, extensions) {
let list = await (await fetch(
phpScan,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
dir: dir,
extensions: extensions
})
})).json();
return list;
}
If you're using a local server you may also use this approach as described by fmacdee: "How to list files inside folder using fetch?".
This approach takes for granted your local server has directory listing enabled. In other words: the server will automatically generate a HTML table view you can "parse" via fetch result. Here is a modified version:
async function getDirectory(dir, extensions) {
let response = await fetch(dir);
let html = await response.text();
let doc = new DOMParser().parseFromString(html, 'text/html');
console.log(doc);
let files = [...doc.querySelectorAll("a")].map(a => {
// filter allowed extenstion
let ext = a.href.split('.').slice(-1)[0];
if (extensions.includes(ext)) {
let filename = a.href.split('/').slice(-1)[0];
let mod = a.parentNode.nextElementSibling.textContent.trim()
return { filename: filename, href: a.href, mod: mod }
}
return
}
).filter(Boolean)
return files;
}
All in all: I highly recommend to take the time to install a local server.
We certainly won't see any new JS features that allow client-side directory listing, as this would have huge security implications.