From 509c8cae6381ec46af7c8303eb92fda6ce496a4a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 4 Jul 2022 09:53:26 +0200 Subject: Dynamic OPML (#4407) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Dynamic OPML draft #fix https://github.com/FreshRSS/FreshRSS/issues/4191 * Export dynamic OPML http://opml.org/spec2.opml#1629043127000 * Restart with simpler approach * Minor revert * Export dynamic OPML also for single feeds * Special category type for importing dynamic OPML * Parameter for excludeMutedFeeds * Details * More draft * i18n * Fix update * Draft manual import working * Working manual refresh * Draft automatic update * Working Web refresh + fixes * Import/export dynamic OPML settings * Annoying numerous lines in SQL logs * Fix minor JavaScript error * Fix auto adding new columns * Add require * Add missing 🗲 * Missing space * Disable adding new feeds to dynamic categories * Link from import * i18n typo * Improve theme icon function * Fix pink-dark --- p/scripts/extra.js | 7 +-- p/scripts/feed.js | 21 ++++++++- p/scripts/main.js | 131 +++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 122 insertions(+), 37 deletions(-) (limited to 'p/scripts') diff --git a/p/scripts/extra.js b/p/scripts/extra.js index 39f9d049a..7be235aa4 100644 --- a/p/scripts/extra.js +++ b/p/scripts/extra.js @@ -202,8 +202,8 @@ function updateHref(ev) { } // set event listener on "show url" buttons -function init_url_observers() { - document.querySelectorAll('.open-url').forEach(function (btn) { +function init_url_observers(parent) { + parent.querySelectorAll('.open-url').forEach(function (btn) { btn.addEventListener('mouseover', updateHref); btn.addEventListener('click', updateHref); }); @@ -276,7 +276,6 @@ function init_extra_afterDOM() { if (!['normal', 'global', 'reader'].includes(context.current_view)) { init_crypto_form(); init_password_observers(document.body); - init_url_observers(); init_select_observers(); init_configuration_alert(); @@ -284,8 +283,10 @@ function init_extra_afterDOM() { if (slider) { init_slider(slider); init_archiving(slider); + init_url_observers(slider); } else { init_archiving(document.body); + init_url_observers(document.body); } } diff --git a/p/scripts/feed.js b/p/scripts/feed.js index 2a213b422..a5e43c614 100644 --- a/p/scripts/feed.js +++ b/p/scripts/feed.js @@ -1,6 +1,6 @@ // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0 'use strict'; -/* globals init_archiving, init_configuration_alert, init_password_observers, init_slider */ +/* globals init_archiving, init_configuration_alert, init_password_observers, init_slider, init_url_observers */ // let popup = null; @@ -64,6 +64,22 @@ function init_popup_preview_selector() { }); } +/** + * Allow a to hide/show elements defined by */ @@ -120,7 +136,9 @@ function init_feed_afterDOM() { init_popup(); init_popup_preview_selector(); init_select_show(slider); + init_disable_elements_on_update(slider); init_password_observers(slider); + init_url_observers(slider); init_valid_xpath(slider); }); init_slider(slider); @@ -130,6 +148,7 @@ function init_feed_afterDOM() { init_popup(); init_popup_preview_selector(); init_select_show(document.body); + init_disable_elements_on_update(document.body); init_password_observers(document.body); init_valid_xpath(document.body); } diff --git a/p/scripts/main.js b/p/scripts/main.js index 1eb8a1ff8..461dc1b10 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -115,9 +115,10 @@ function incUnreadsFeed(article, feed_id, nb) { } // Update unread: category - elem = document.getElementById(feed_id).closest('.category'); - feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0; + elem = document.getElementById(feed_id); + elem = elem ? elem.closest('.category') : null; if (elem) { + feed_unreads = str2int(elem.getAttribute('data-unread')); elem.setAttribute('data-unread', feed_unreads + nb); elem = elem.querySelector('.title'); if (elem) { @@ -147,7 +148,7 @@ function incUnreadsFeed(article, feed_id, nb) { // Update unread: title document.title = document.title.replace(/^((?:\([\s0-9]+\) )?)/, function (m, p1) { const feed = document.getElementById(feed_id); - if (article || feed.closest('.active')) { + if (article || (feed && feed.closest('.active'))) { isCurrentView = true; return incLabel(p1, nb, true); } else if (document.querySelector('.all.active')) { @@ -1287,9 +1288,11 @@ function loadDynamicTags(div) { } // -let feed_processed = 0; +let feeds_processed = 0; +let categories_processed = 0; +let to_process = 0; -function updateFeed(feeds, feeds_count) { +function refreshFeed(feeds, feeds_count) { const feed = feeds.pop(); if (!feed) { return; @@ -1297,14 +1300,15 @@ function updateFeed(feeds, feeds_count) { const req = new XMLHttpRequest(); req.open('POST', feed.url, true); req.onloadend = function (e) { + feeds_processed++; if (this.status != 200) { - return badAjax(false); + badAjax(false); + } else { + const div = document.getElementById('actualizeProgress'); + div.querySelector('.progress').innerHTML = (categories_processed + feeds_processed) + ' / ' + to_process; + div.querySelector('.title').innerHTML = feed.title; } - feed_processed++; - const div = document.getElementById('actualizeProgress'); - div.querySelector('.progress').innerHTML = feed_processed + ' / ' + feeds_count; - div.querySelector('.title').innerHTML = feed.title; - if (feed_processed === feeds_count) { + if (feeds_processed === feeds_count) { // Empty request to commit new articles const req2 = new XMLHttpRequest(); req2.open('POST', './?c=feed&a=actualize&id=-1&ajax=1', true); @@ -1317,7 +1321,7 @@ function updateFeed(feeds, feeds_count) { noCommit: 0, })); } else { - updateFeed(feeds, feeds_count); + refreshFeed(feeds, feeds_count); } }; req.setRequestHeader('Content-Type', 'application/json'); @@ -1327,8 +1331,73 @@ function updateFeed(feeds, feeds_count) { })); } +function refreshFeeds(json) { + feeds_processed = 0; + if (!json.feeds || json.feeds.length === 0) { + // Empty request to commit new articles + const req2 = new XMLHttpRequest(); + req2.open('POST', './?c=feed&a=actualize&id=-1&ajax=1', true); + req2.onloadend = function (e) { + context.ajax_loading = false; + }; + req2.setRequestHeader('Content-Type', 'application/json'); + req2.send(JSON.stringify({ + _csrf: context.csrf, + noCommit: 0, + })); + } else { + const feeds_count = json.feeds.length; + for (let i = 10; i > 0; i--) { + refreshFeed(json.feeds, feeds_count); + } + } +} + +function refreshDynamicOpml(categories, categories_count, next) { + const category = categories.pop(); + if (!category) { + return; + } + const req = new XMLHttpRequest(); + req.open('POST', category.url, true); + req.onloadend = function (e) { + categories_processed++; + if (this.status != 200) { + badAjax(false); + } else { + const div = document.getElementById('actualizeProgress'); + div.querySelector('.progress').innerHTML = (categories_processed + feeds_processed) + ' / ' + to_process; + div.querySelector('.title').innerHTML = category.title; + } + if (categories_processed === categories_count) { + if (next) { next(); } + } else { + refreshDynamicOpml(categories, categories_count, next); + } + }; + req.setRequestHeader('Content-Type', 'application/json'); + req.send(JSON.stringify({ + _csrf: context.csrf, + noCommit: 1, + })); +} + +function refreshDynamicOpmls(json, next) { + categories_processed = 0; + if (json.categories && json.categories.length > 0) { + const categories_count = json.categories.length; + for (let i = 10; i > 0; i--) { + refreshDynamicOpml(json.categories, categories_count, next); + } + } else { + if (next) { next(); } + } +} + function init_actualize() { let auto = false; + let nbCategoriesFirstRound = 0; + let skipCategories = false; const actualize = document.getElementById('actualize'); if (!actualize) { @@ -1352,33 +1421,29 @@ function init_actualize() { if (!json) { return badAjax(false); } - if (auto && json.feeds.length < 1) { + if (auto && json.categories.length < 1 && json.feeds.length < 1) { auto = false; context.ajax_loading = false; return false; } - if (json.feeds.length === 0) { + to_process = json.categories.length + json.feeds.length + nbCategoriesFirstRound; + if (json.categories.length + json.feeds.length > 0 && !document.getElementById('actualizeProgress')) { + document.body.insertAdjacentHTML('beforeend', '
' + + json.feedback_actualize + '
/
0 / ' + + to_process + '
'); + } else { openNotification(json.feedback_no_refresh, 'good'); - // Empty request to commit new articles - const req2 = new XMLHttpRequest(); - req2.open('POST', './?c=feed&a=actualize&id=-1&ajax=1', true); - req2.onloadend = function (e) { - context.ajax_loading = false; - }; - req2.setRequestHeader('Content-Type', 'application/json'); - req2.send(JSON.stringify({ - _csrf: context.csrf, - noCommit: 0, - })); - return; } - // Progress bar - const feeds_count = json.feeds.length; - document.body.insertAdjacentHTML('beforeend', '
' + - json.feedback_actualize + '
/
0 / ' + - feeds_count + '
'); - for (let i = 10; i > 0; i--) { - updateFeed(json.feeds, feeds_count); + if (json.categories.length > 0 && !skipCategories) { + skipCategories = true; // To avoid risk of infinite loop + nbCategoriesFirstRound = json.categories.length; + // If some dynamic OPML categories are refreshed, need to reload the list of feeds before updating them + refreshDynamicOpmls(json, () => { + context.ajax_loading = false; + actualize.click(); + }); + } else { + refreshFeeds(json); } }; req.setRequestHeader('Content-Type', 'application/json'); -- cgit v1.2.3