diff options
| author | 2022-07-04 09:53:26 +0200 | |
|---|---|---|
| committer | 2022-07-04 09:53:26 +0200 | |
| commit | 509c8cae6381ec46af7c8303eb92fda6ce496a4a (patch) | |
| tree | 653f7f44df842f9d7135decd89467879a0098c50 /p/scripts | |
| parent | 57d571230eeb2d3ede57e640b640f17c7a2298a2 (diff) | |
Dynamic OPML (#4407)
* 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
Diffstat (limited to 'p/scripts')
| -rw-r--r-- | p/scripts/extra.js | 7 | ||||
| -rw-r--r-- | p/scripts/feed.js | 21 | ||||
| -rw-r--r-- | p/scripts/main.js | 131 |
3 files changed, 122 insertions, 37 deletions
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 */ // <popup> let popup = null; @@ -67,6 +67,22 @@ function init_popup_preview_selector() { /** * Allow a <select class="select-show"> to hide/show elements defined by <option data-show="elem-id"></option> */ +function init_disable_elements_on_update(parent) { + const inputs = parent.querySelectorAll('input[data-disable-update]'); + for (const input of inputs) { + input.addEventListener('input', (e) => { + const elem = document.getElementById(e.target.dataset.disableUpdate); + if (elem) { + elem.disabled = true; + elem.remove(); + } + }); + } +} + +/** + * Allow a <select class="select-show"> to hide/show elements defined by <option data-show="elem-id"></option> + */ function init_select_show(parent) { const listener = (select) => { const options = select.querySelectorAll('option[data-show]'); @@ -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) { } // <actualize> -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', '<div id="actualizeProgress" class="notification good">' + + json.feedback_actualize + '<br /><span class="title">/</span><br /><span class="progress">0 / ' + + to_process + '</span></div>'); + } 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', '<div id="actualizeProgress" class="notification good">' + - json.feedback_actualize + '<br /><span class="title">/</span><br /><span class="progress">0 / ' + - feeds_count + '</span></div>'); - 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'); |
