diff --git a/frappe/public/scss/website.scss b/frappe/public/scss/website.scss index c3ff5ee338..7eba671388 100644 --- a/frappe/public/scss/website.scss +++ b/frappe/public/scss/website.scss @@ -101,3 +101,8 @@ img { height: 300px; background-color: $light; } + +.broken-image { + padding: 50% 0; + background-color: $light; +} diff --git a/frappe/website/js/website.js b/frappe/website/js/website.js index 099eb302eb..90f7fe26aa 100644 --- a/frappe/website/js/website.js +++ b/frappe/website/js/website.js @@ -330,6 +330,24 @@ $.extend(frappe, { add_switch_to_desk: function() { $('.switch-to-desk').removeClass('hidden'); }, + setup_404_images: function() { + function image_exists(src) { + return new Promise(resolve => { + var img = new Image(); + img.onload = () => resolve(true); + img.onerror = () => resolve(false); + img.src = src; + }) + } + $('img').each((_, img) => { + image_exists(img.src) + .then(exists => { + if (!exists) { + $(img).replaceWith('
'); + } + }); + }) + }, setup_lazy_images: function() { // Use IntersectionObserver to only load images that are visible in the viewport // Fallback for browsers that don't support it @@ -343,6 +361,7 @@ $.extend(frappe, { .map(key => `${key}="${attrs[key]}"`) .join(' '); $target.replaceWith(``); + frappe.setup_404_images(); } if (!window.IntersectionObserver) { @@ -424,6 +443,7 @@ $(document).ready(function() { frappe.render_user(); frappe.setup_lazy_images(); + frappe.setup_404_images(); $(document).trigger("page-change"); });