summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndinus <andinus@nand.sh>2022-06-11 11:58:29 +0530
committerAndinus <andinus@nand.sh>2022-06-11 11:58:29 +0530
commit89c60aee5a602ed5bfd73a9d5bcbbf9945aac44f (patch)
treec734a88fc77c56faa6b68edfde3484f8859e9b73
parentbef200b4669f058ce43ec9c0a3583de7fac558e3 (diff)
downloadcrater-89c60aee5a602ed5bfd73a9d5bcbbf9945aac44f.tar.gz
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.
-rw-r--r--resources/css/style.css12
-rw-r--r--resources/js/gallery.js96
-rw-r--r--templates/gallery.crotmp8
-rw-r--r--templates/login.crotmp2
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)>
+    <div id="loading">
+      <label for="loading-progress">Loading Images:</label>
+      <progress id="loading-progress" max="100" value="0"></progress>
+    </div>
+    <div id="loading-error" class="alert" role="alert">
+      <span id="loading-error-text"></span>
+      <button id="loading-error-dismiss">Dismiss</button>
+    </div>
     <div id="gallery">
       <@gallery : $i>
         <?{ $i.<type> eq 'img' }>
diff --git a/templates/login.crotmp b/templates/login.crotmp
index 343f768..9a7acd4 100644
--- a/templates/login.crotmp
+++ b/templates/login.crotmp
@@ -1,6 +1,6 @@
 <:use 'templates/base.crotmp'>
   <|page('Log In')>
-    <form method="post" action="/login">
+    <form id="login-form" method="post" action="/login">
       <?.error>
       <div class="alert" role="alert">
         <.error>