From f382d2ac89eea8f849bd72655bc29cbc056ce92d Mon Sep 17 00:00:00 2001 From: supahgreg Date: Thu, 16 Oct 2025 17:38:12 +0000 Subject: [PATCH] Gracefully handle a feed icon failing to load. --- gulpfile.js | 6 +++--- js/FeedTree.js | 6 ++++++ js/Feeds.js | 10 ++++++++-- themes/compact.css | 3 +++ themes/compact_night.css | 3 +++ themes/light-high-contrast.css | 3 +++ themes/light.css | 3 +++ themes/light/tt-rss.less | 3 +++ themes/night.css | 3 +++ themes/night_blue.css | 3 +++ 10 files changed, 38 insertions(+), 5 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 9d09e984e..c40d95847 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,7 +1,7 @@ // Less configuration -const gulp = require('gulp'); -const less = require('gulp-less'); -const touch = require('gulp-touch-fd'); +import gulp from 'gulp'; +import less from 'gulp-less'; +import touch from 'gulp-touch-fd'; function swallowError(error) { console.log(error.toString()) diff --git a/js/FeedTree.js b/js/FeedTree.js index 06ebceff2..d5f777fab 100755 --- a/js/FeedTree.js +++ b/js/FeedTree.js @@ -58,6 +58,9 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co } else { iconNode.src = 'images/blank_icon.gif'; } + iconNode.onerror = () => { + Feeds._handleIconError(iconNode); + }; } } @@ -342,6 +345,9 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co if (icon) { icon.src = src; + icon.onerror = () => { + Feeds._handleIconError(icon); + }; return true; } diff --git a/js/Feeds.js b/js/Feeds.js index af7a6cc54..66360255a 100644 --- a/js/Feeds.js +++ b/js/Feeds.js @@ -747,10 +747,16 @@ const Feeds = { }, renderIcon: function(feed_id, exists) { - const icon_url = App.getInitParam("icons_url") + '?' + dojo.objectToQuery({op: 'feed_icon', id: feed_id}); + const icon_url = App.getInitParam('icons_url') + '?' + dojo.objectToQuery({op: 'feed_icon', id: feed_id}); return feed_id && exists ? - `` : + `feed icon` : `rss_feed`; + }, + _handleIconError: (img) => { + const icon = document.createElement('i'); + icon.className = 'icon-no-feed material-icons'; + icon.textContent = 'rss_feed'; + img.replaceWith(icon); } }; diff --git a/themes/compact.css b/themes/compact.css index df5c000ef..bae92d6a2 100644 --- a/themes/compact.css +++ b/themes/compact.css @@ -880,6 +880,9 @@ body.ttrss_main img.icon { line-height: 16px; vertical-align: middle; display: inline-block; + aspect-ratio: 1; + flex-shrink: 0; + object-fit: contain; } body.ttrss_main ul#filterDlg_Matches, body.ttrss_main ul#filterDlg_Actions { diff --git a/themes/compact_night.css b/themes/compact_night.css index 8d141beba..ada4c7f77 100644 --- a/themes/compact_night.css +++ b/themes/compact_night.css @@ -880,6 +880,9 @@ body.ttrss_main img.icon { line-height: 16px; vertical-align: middle; display: inline-block; + aspect-ratio: 1; + flex-shrink: 0; + object-fit: contain; } body.ttrss_main ul#filterDlg_Matches, body.ttrss_main ul#filterDlg_Actions { diff --git a/themes/light-high-contrast.css b/themes/light-high-contrast.css index 6fac41435..3d567a365 100644 --- a/themes/light-high-contrast.css +++ b/themes/light-high-contrast.css @@ -880,6 +880,9 @@ body.ttrss_main img.icon { line-height: 16px; vertical-align: middle; display: inline-block; + aspect-ratio: 1; + flex-shrink: 0; + object-fit: contain; } body.ttrss_main ul#filterDlg_Matches, body.ttrss_main ul#filterDlg_Actions { diff --git a/themes/light.css b/themes/light.css index f1971e227..5c149656c 100644 --- a/themes/light.css +++ b/themes/light.css @@ -880,6 +880,9 @@ body.ttrss_main img.icon { line-height: 16px; vertical-align: middle; display: inline-block; + aspect-ratio: 1; + flex-shrink: 0; + object-fit: contain; } body.ttrss_main ul#filterDlg_Matches, body.ttrss_main ul#filterDlg_Actions { diff --git a/themes/light/tt-rss.less b/themes/light/tt-rss.less index a39f6677b..0b40196ee 100644 --- a/themes/light/tt-rss.less +++ b/themes/light/tt-rss.less @@ -1041,6 +1041,9 @@ body.ttrss_main { line-height : 16px; vertical-align : middle; display : inline-block; + aspect-ratio: 1; + flex-shrink: 0; + object-fit: contain; } ul#filterDlg_Matches, ul#filterDlg_Actions { diff --git a/themes/night.css b/themes/night.css index 7d3727c7a..b82294fa8 100644 --- a/themes/night.css +++ b/themes/night.css @@ -881,6 +881,9 @@ body.ttrss_main img.icon { line-height: 16px; vertical-align: middle; display: inline-block; + aspect-ratio: 1; + flex-shrink: 0; + object-fit: contain; } body.ttrss_main ul#filterDlg_Matches, body.ttrss_main ul#filterDlg_Actions { diff --git a/themes/night_blue.css b/themes/night_blue.css index a3c76ebb4..9791f5a70 100644 --- a/themes/night_blue.css +++ b/themes/night_blue.css @@ -881,6 +881,9 @@ body.ttrss_main img.icon { line-height: 16px; vertical-align: middle; display: inline-block; + aspect-ratio: 1; + flex-shrink: 0; + object-fit: contain; } body.ttrss_main ul#filterDlg_Matches, body.ttrss_main ul#filterDlg_Actions {