From 89c60aee5a602ed5bfd73a9d5bcbbf9945aac44f Mon Sep 17 00:00:00 2001 From: Andinus Date: Sat, 11 Jun 2022 11:58:29 +0530 Subject: Scope css, improve image error handling, show progress bar - Errors are shown if some images fail to load. - Progress bar is shown while images are loading. - .pack is called after all images have been loaded. --- resources/css/style.css | 12 +++++- resources/js/gallery.js | 96 ++++++++++++++++++++++++++++++------------------ templates/gallery.crotmp | 8 ++++ templates/login.crotmp | 2 +- 4 files changed, 81 insertions(+), 37 deletions(-) diff --git a/resources/css/style.css b/resources/css/style.css index a380707..76af98e 100644 --- a/resources/css/style.css +++ b/resources/css/style.css @@ -47,7 +47,7 @@ img { var(--fg-inactive) 0px 0px 0px 1px inset; } -input, .alert { +#login-form input, .alert { color: var(--fg-main); background-color: var(--bg-main); border: 1px var(--bg-active) solid; @@ -109,3 +109,13 @@ img, .text { width: 400px; } .alert { background-color: var(--red-subtle-bg); } +#loading-progress, #loading-error { margin-bottom: 2em; } +#loading-error { display: none; } +#loading-error button { + float: right; + color: var(--fg-main); + background-color: var(--bg-main); + border: 1px var(--bg-active) solid; + padding: 0.25em 1em; +} +#loading-progress { width: 100%; } diff --git a/resources/js/gallery.js b/resources/js/gallery.js index bab4d1d..2a608f5 100644 --- a/resources/js/gallery.js +++ b/resources/js/gallery.js @@ -1,68 +1,94 @@ 'use strict'; +const round = Math.round; + // image width. const imgW = 400; // Gallery using bricks.js //////////////////////////////////////////////////// -// mq - the minimum viewport width (String CSS unit: em, px, rem) -// columns - the number of vertical columns -// gutter - the space (in px) between the columns and grid items const sizes = [ { columns: 1, gutter: 30 }, - { mq: Math.round((imgW * 2.2) + 40) + "px", columns: 2, gutter: 35 }, - { mq: Math.round((imgW * 3.5) + 50) + "px", columns: 3, gutter: 50 }, - { mq: Math.round((imgW * 4.4) + 50) + "px", columns: 4, gutter: 50 }, + { mq: round((imgW * 2.2) + 40) + "px", columns: 2, gutter: 35 }, + { mq: round((imgW * 3.5) + 50) + "px", columns: 3, gutter: 50 }, + { mq: round((imgW * 4.4) + 50) + "px", columns: 4, gutter: 50 }, ]; -const instance = Bricks({ +const bricks = Bricks({ container: '#gallery', packed: 'data-packed', sizes: sizes }); -instance +bricks .on('pack', () => console.log('ALL grid items packed.')) .on('update', () => console.log('NEW grid items packed.')) .on('resize', size => console.log( 'The grid has be re-packed to accommodate a new BREAKPOINT.', size )); -// start it up, when the DOM is ready. note that if images are in the -// grid, you may need to wait for document.readyState === 'complete'. document.addEventListener('DOMContentLoaded', event => { - instance.resize(true).pack(); // bind resize handler & pack initial items -}); -document.addEventListener('readystatechange', event => { - if (event.target.readyState === 'complete') { - instance.pack(); - } + bricks.resize(true); // bind resize handler }); -// Re-packing after loading images //////////////////////////////////////////// +// Packing after loading images //////////////////////////////////////////// + +const onImagesLoaded = (container, event) => { + const images = container.getElementsByTagName("img"); + const progressBar = document.getElementById("loading-progress"); + + // failed keeps track of images that failed to load. + let failed = 0; + let remaining = images.length; -function onImagesLoaded(container, event) { - let images = container.getElementsByTagName("img"); - let loaded = images.length; for (let i = 0; i < images.length; i++) { - if (images[i].complete) { - loaded--; - } + if (images[i].complete) + remaining--; else { + // Add listeners to images that have to be loaded. images[i].addEventListener("load", function () { - loaded--; - if (loaded == 0) { - event(); - } + remaining--; + progressBar.value = round( + ((images.length - remaining) / images.length) * 100 + ); + if (remaining === failed) + event(remaining, failed, progressBar); }); + + // If loading fails then we increment failed, an error + // will be shown later. + images[i].addEventListener("error", function () { + failed++; + if (remaining === failed) + event(remaining, failed, progressBar); + }); + } - if (loaded == 0) { - event(); - } + if (remaining == failed) + event(remaining, failed, progressBar); } -} +}; -const container = document.getElementById("gallery"); -onImagesLoaded(container, function () { - instance.pack(); -}); +const gallery = document.getElementById("gallery"); +const imagesLoaded = (remaining, failed, progressBar) => { + bricks.pack(); + + progressBar.value = 100; + document.getElementById("loading").style.display = "none"; + + // Show error on failure. + const loadError = document.getElementById("loading-error"); + const loadErrorText = document.getElementById("loading-error-text"); + const loadErrorDismiss = document.getElementById("loading-error-dismiss"); + if (failed !== 0) { + loadError.style.display = "block"; + const t = failed === 1 ? "image" : "images"; + loadErrorText.innerHTML = `${failed} ${t} failed to load.`; + + loadErrorDismiss.addEventListener('click', function(){ + loadError.style.display = "none"; + }); + } +}; + +onImagesLoaded(gallery, imagesLoaded); diff --git a/templates/gallery.crotmp b/templates/gallery.crotmp index 6afef0a..6aead73 100644 --- a/templates/gallery.crotmp +++ b/templates/gallery.crotmp @@ -1,5 +1,13 @@ <:use 'templates/base.crotmp'> <|page(.title)> +
+ + +
+