diff options
Diffstat (limited to 'p/scripts/main.js')
| -rw-r--r-- | p/scripts/main.js | 2060 |
1 files changed, 963 insertions, 1097 deletions
diff --git a/p/scripts/main.js b/p/scripts/main.js index 6cab2e55a..f59976b39 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1,30 +1,61 @@ "use strict"; -/* globals $, jQuery, context, i18n, shortcut, shortcuts, url */ -/* jshint strict:global */ - -var $stream = null, - isCollapsed = true, - shares = 0, - ajax_loading = false; - -function redirect(url, new_tab) { - if (url) { - if (new_tab) { - window.open(url); - } else { - location.href = url; - } +/* jshint esversion:6, strict:global */ + +//<Polyfills> +if (!NodeList.prototype.forEach) NodeList.prototype.forEach = Array.prototype.forEach; +if (!Element.prototype.matches) Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.webkitMatchesSelector; +if (!Element.prototype.closest) Element.prototype.closest = function (s) { + let el = this; + do { + if (el.matches(s)) return el; + el = el.parentElement; + } while (el); + return null; + }; +if (!Element.prototype.remove) Element.prototype.remove = function () { if (this.parentNode) this.parentNode.removeChild(this); }; +//</Polyfills> + +//<Utils> +function xmlHttpRequestJson(req) { + let json = req.response; + if (req.responseType !== 'json') { //IE11 + try { json = JSON.parse(req.responseText); } + catch (ex) { json = null; } } + return json; } +//</Utils> + +//<Global context> +var context; -function needsScroll($elem) { - var $win = $(window), - winTop = $win.scrollTop(), - winHeight = $win.height(), - winBottom = winTop + winHeight, - elemTop = $elem.offset().top, - elemBottom = elemTop + $elem.outerHeight(); - return (elemTop < winTop || elemBottom > winBottom) ? elemTop - (winHeight / 2) : 0; +(function parseJsonVars() { + const jsonVars = document.getElementById('jsonVars'), + json = JSON.parse(jsonVars.innerHTML); + jsonVars.outerHTML = ''; + context = json.context; + context.ajax_loading = false; + context.i18n = json.i18n; + context.shortcuts = json.shortcuts; + context.urls = json.urls; + context.icons = json.icons; + context.icons.read = decodeURIComponent(context.icons.read); + context.icons.unread = decodeURIComponent(context.icons.unread); +}()); +//</Global context> + +function badAjax() { + openNotification(context.i18n.notif_request_failed, 'bad'); + location.reload(); + return true; +} + +function needsScroll(elem) { + const winBottom = document.documentElement.scrollTop + document.documentElement.clientHeight, + elemTop = elem.offsetParent.offsetTop + elem.offsetTop, + elemBottom = elemTop + elem.offsetHeight; + return (elemTop < document.documentElement.scrollTop || elemBottom > winBottom) ? + elemTop - (document.documentElement.clientHeight / 2) : 0; } function str2int(str) { @@ -40,10 +71,10 @@ function numberFormat(nStr) { } // http://www.mredkj.com/javascript/numberFormat.html nStr += ''; - var x = nStr.split('.'), - x1 = x[0], + const x = nStr.split('.'), x2 = x.length > 1 ? '.' + x[1] : '', rgx = /(\d+)(\d{3})/; + let x1 = x[0]; while (rgx.test(x1)) { x1 = x1.replace(rgx, '$1' + ' ' + '$2'); } @@ -51,29 +82,29 @@ function numberFormat(nStr) { } function incLabel(p, inc, spaceAfter) { - var i = str2int(p) + inc; + const i = str2int(p) + inc; return i > 0 ? ((spaceAfter ? '' : ' ') + '(' + numberFormat(i) + ')' + (spaceAfter ? ' ' : '')) : ''; } function incUnreadsFeed(article, feed_id, nb) { //Update unread: feed - var elem = $('#' + feed_id).get(0), + let elem = document.getElementById(feed_id), feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0, feed_priority = elem ? str2int(elem.getAttribute('data-priority')) : 0; if (elem) { elem.setAttribute('data-unread', feed_unreads + nb); - elem = $(elem).children('.item-title').get(0); + elem = elem.querySelector('.item-title'); if (elem) { elem.setAttribute('data-unread', numberFormat(feed_unreads + nb)); } } //Update unread: category - elem = $('#' + feed_id).parents('.category').get(0); + elem = document.getElementById(feed_id).closest('.category'); feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0; if (elem) { elem.setAttribute('data-unread', feed_unreads + nb); - elem = $(elem).find('.title').get(0); + elem = elem.querySelector('.title'); if (elem) { elem.setAttribute('data-unread', numberFormat(feed_unreads + nb)); } @@ -81,7 +112,7 @@ function incUnreadsFeed(article, feed_id, nb) { //Update unread: all if (feed_priority > 0) { - elem = $('#aside_feed .all .title').get(0); + elem = document.querySelector('#aside_feed .all .title'); if (elem) { feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0; elem.setAttribute('data-unread', numberFormat(feed_unreads + nb)); @@ -89,22 +120,22 @@ function incUnreadsFeed(article, feed_id, nb) { } //Update unread: favourites - if (article && article.closest('div').hasClass('favorite')) { - elem = $('#aside_feed .favorites .title').get(0); + if (article && article.closest('div').classList.contains('favorite')) { + elem = document.querySelector('#aside_feed .favorites .title'); if (elem) { feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0; elem.setAttribute('data-unread', numberFormat(feed_unreads + nb)); } } - var isCurrentView = false; + let isCurrentView = false; // Update unread: title document.title = document.title.replace(/^((?:\([ 0-9]+\) )?)/, function (m, p1) { - var $feed = $('#' + feed_id); - if (article || ($feed.closest('.active').length > 0 && $feed.siblings('.active').length === 0)) { + const feed = document.getElementById(feed_id); + if (article || feed.closest('.active')) { isCurrentView = true; return incLabel(p1, nb, true); - } else if ($('.all.active').length > 0) { + } else if (document.querySelector('.all.active')) { isCurrentView = feed_priority > 0; return incLabel(p1, feed_priority > 0 ? nb : 0, true); } else { @@ -115,126 +146,191 @@ function incUnreadsFeed(article, feed_id, nb) { } function incUnreadsTag(tag_id, nb) { - var $t = $('#t_' + tag_id); - var unreads = str2int($t.attr('data-unread')); - $t.attr('data-unread', unreads + nb) - .children('.item-title').attr('data-unread', numberFormat(unreads + nb)); - - $t = $('.category.tags').find('.title'); - unreads = str2int($t.attr('data-unread')); - $t.attr('data-unread', numberFormat(unreads + nb)); -} - -var pending_entries = {}; -function mark_read(active, only_not_read) { - if ((active.length === 0) || (!active.attr('id')) || - context.anonymous || - (only_not_read && !active.hasClass("not_read"))) { - return false; + let t = document.getElementById(tag_id); + if (t) { + let unreads = str2int(t.getAttribute('data-unread')); + t.setAttribute('data-unread', unreads + nb); + t.querySelector('.item-title').setAttribute('data-unread', numberFormat(unreads + nb)); } - - if (pending_entries[active.attr('id')]) { - return false; + t = document.querySelector('.category.tags .title'); + if (t) { + let unreads = str2int(t.getAttribute('data-unread')); + t.setAttribute('data-unread', numberFormat(unreads + nb)); } - pending_entries[active.attr('id')] = true; +} - var url = '.?c=entry&a=read&id=' + active.attr('id').replace(/^flux_/, '') + - (active.hasClass('not_read') ? '' : '&is_read=0'); +var pending_entries = {}, + mark_read_queue = []; - $.ajax({ - type: 'POST', - url: url, - data: { +function send_mark_read_queue(queue, asRead, callback) { + const req = new XMLHttpRequest(); + req.open('POST', '.?c=entry&a=read' + (asRead ? '' : '&is_read=0'), true); + req.responseType = 'json'; + req.onerror = function (e) { + openNotification(context.i18n.notif_request_failed, 'bad'); + for (let i = queue.length - 1; i >= 0; i--) { + delete pending_entries['flux_' + queue[i]]; + } + if (this.status == 403) { + badAjax(); + } + }; + req.onload = function (e) { + if (this.status != 200) { + return req.onerror(e); + } + const json = xmlHttpRequestJson(this); + for (let i = queue.length - 1; i >= 0; i--) { + const div = document.getElementById('flux_' + queue[i]), + myIcons = context.icons; + let inc = 0; + if (div.classList.contains('not_read')) { + div.classList.remove('not_read'); + div.querySelectorAll('a.read').forEach(function (a) { + a.href = a.href.replace('&is_read=0', '') + '&is_read=1'; + }); + div.querySelectorAll('a.read > .icon').forEach(function (img) { img.outerHTML = myIcons.read; }); + inc--; + } else { + div.classList.add('not_read'); + div.classList.add('keep_unread'); //Split for IE11 + div.querySelectorAll('a.read').forEach(function (a) { + a.href = a.href.replace('&is_read=1', ''); + }); + div.querySelectorAll('a.read > .icon').forEach(function (img) { img.outerHTML = myIcons.unread; }); + inc++; + } + let feed_link = div.querySelector('.website > a, a.website'); + if (feed_link) { + const feed_url = feed_link.href, + feed_id = feed_url.substr(feed_url.lastIndexOf('f_')); + incUnreadsFeed(div, feed_id, inc); + } + delete pending_entries['flux_' + queue[i]]; + } + faviconNbUnread(); + if (json.tags) { + const tagIds = Object.keys(json.tags); + for (let i = tagIds.length - 1; i >= 0; i--) { + let tagId = tagIds[i]; + incUnreadsTag(tagId, (asRead ? -1 : 1) * json.tags[tagId].length); + } + } + onScroll(); + if (callback) { + callback(); + } + }; + req.setRequestHeader('Content-Type', 'application/json'); + req.send(JSON.stringify({ ajax: true, _csrf: context.csrf, - }, - }).done(function (data) { - var $r = active.find("a.read").attr("href", data.url), - inc = 0; - if (active.hasClass("not_read")) { - active.removeClass("not_read"); - inc--; - } else { - active.addClass("not_read"); - active.addClass("keep_unread"); - inc++; - } - $r.find('.icon').replaceWith(data.icon); + id: queue, + })); +} - var feed_url = active.find(".website>a").attr("href"); - if (feed_url) { - var feed_id = feed_url.substr(feed_url.lastIndexOf('f_')); - incUnreadsFeed(active, feed_id, inc); - } - faviconNbUnread(); +var send_mark_read_queue_timeout = 0; - if (data.tags) { - for (var i = data.tags.length - 1; i >= 0; i--) { - incUnreadsTag(data.tags[i], inc); - } - } +function send_mark_queue_tick(callback) { + send_mark_read_queue_timeout = 0; + const queue = mark_read_queue.slice(0); + mark_read_queue = []; + send_mark_read_queue(queue, true, callback); +} - delete pending_entries[active.attr('id')]; - }).fail(function (data) { - openNotification(i18n.notif_request_failed, 'bad'); - delete pending_entries[active.attr('id')]; - }); +function delayedClick(a) { + if (a) { + send_mark_queue_tick(function () { a.click(); }); + } } -function mark_favorite(active) { - if (active.length === 0) { +function mark_read(div, only_not_read) { + if (!div || !div.id || context.anonymous || + (only_not_read && !div.classList.contains('not_read'))) { + return false; + } + if (pending_entries[div.id]) { return false; } + pending_entries[div.id] = true; + + const asRead = div.classList.contains('not_read'), + entryId = div.id.replace(/^flux_/, ''); + if (asRead) { + mark_read_queue.push(entryId); + if (send_mark_read_queue_timeout == 0) { + send_mark_read_queue_timeout = setTimeout(function () { send_mark_queue_tick(null); }, 1000); + } + } else { + const queue = [ entryId ]; + send_mark_read_queue(queue, asRead); + } +} - var url = active.find("a.bookmark").attr("href"); - if (url === undefined) { +function mark_favorite(div) { + if (!div) { return false; } - if (pending_entries[active.attr('id')]) { + let a = div.querySelector('a.bookmark'), + url = a ? a.href : ''; + if (!url) { return false; } - pending_entries[active.attr('id')] = true; - $.ajax({ - type: 'POST', - url: url, - data: { - ajax: true, - _csrf: context.csrf, - }, - }).done(function (data) { - var $b = active.find("a.bookmark").attr("href", data.url), - inc = 0; - if (active.hasClass("favorite")) { - active.removeClass("favorite"); - inc--; - } else { - active.addClass("favorite").find('.bookmark'); - inc++; - } - $b.find('.icon').replaceWith(data.icon); + if (pending_entries[div.id]) { + return false; + } + pending_entries[div.id] = true; + + const req = new XMLHttpRequest(); + req.open('POST', url, true); + req.responseType = 'json'; + req.onerror = function (e) { + openNotification(context.i18n.notif_request_failed, 'bad'); + delete pending_entries[div.id]; + if (this.status == 403) { + badAjax(); + } + }; + req.onload = function (e) { + if (this.status != 200) { + return req.onerror(e); + } + const json = xmlHttpRequestJson(this); + let inc = 0; + if (div.classList.contains('favorite')) { + div.classList.remove('favorite'); + inc--; + } else { + div.classList.add('favorite'); + inc++; + } + div.querySelectorAll('a.bookmark').forEach(function (a) { a.href = json.url; }); + div.querySelectorAll('a.bookmark > .icon').forEach(function (img) { img.outerHTML = json.icon; }); - var favourites = $('#aside_feed .favorites .title').contents().last().get(0); - if (favourites && favourites.textContent) { - favourites.textContent = favourites.textContent.replace(/((?: \([ 0-9]+\))?\s*)$/, function (m, p1) { - return incLabel(p1, inc, false); - }); - } + const favourites = document.querySelector('#aside_feed .favorites .title'); + if (favourites) { + favourites.textContent = favourites.textContent.replace(/((?: \([ 0-9]+\))?\s*)$/, function (m, p1) { + return incLabel(p1, inc, false); + }); + } - if (active.closest('div').hasClass('not_read')) { - var elem = $('#aside_feed .favorites .title').get(0), - feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0; - if (elem) { - elem.setAttribute('data-unread', numberFormat(feed_unreads + inc)); + if (div.classList.contains('not_read')) { + const elem = document.querySelector('#aside_feed .favorites .title'), + feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0; + if (elem) { + elem.setAttribute('data-unread', numberFormat(feed_unreads + inc)); + } } - } - delete pending_entries[active.attr('id')]; - }).fail(function (data) { - openNotification(i18n.notif_request_failed, 'bad'); - delete pending_entries[active.attr('id')]; - }); + delete pending_entries[div.id]; + }; + req.setRequestHeader('Content-Type', 'application/json'); + req.send(JSON.stringify({ + ajax: true, + _csrf: context.csrf, + })); } var freshrssOpenArticleEvent = document.createEvent('Event'); @@ -242,208 +338,198 @@ freshrssOpenArticleEvent.initEvent('freshrss:openArticle', true, true); function toggleContent(new_active, old_active, skipping) { // If skipping, move current without activating or marking as read - if (new_active.length === 0) { + if (!new_active) { return; } if (context.does_lazyload && !skipping) { - new_active.find('img[data-original], iframe[data-original]').each(function () { - this.setAttribute('src', this.getAttribute('data-original')); - this.removeAttribute('data-original'); + new_active.querySelectorAll('img[data-original], iframe[data-original]').forEach(function (el) { + el.src = el.getAttribute('data-original'); + el.removeAttribute('data-original'); }); } - if (old_active[0] !== new_active[0]) { - if (isCollapsed && !skipping) { // BUG?: isCollapsed can only ever be true - new_active.addClass("active"); + if (old_active !== new_active) { + if (!skipping) { + new_active.classList.add('active'); } - old_active.removeClass("active current"); - new_active.addClass("current"); - if (context.auto_remove_article && !old_active.hasClass('not_read') && !skipping) { - auto_remove(old_active); + new_active.classList.add('current'); + if (old_active) { + old_active.classList.remove('active'); + old_active.classList.remove('current'); //Split for IE11 } - } else { // collapse_entry calls toggleContent(flux_current, flux_current, false) - new_active.toggleClass('active'); + } else { + new_active.classList.toggle('active'); } - var relative_move = context.current_view === 'global', - box_to_move = $(relative_move ? "#panel" : "html,body"); + const relative_move = context.current_view === 'global', + box_to_move = relative_move ? document.getElementById('panel') : document.documentElement; if (context.sticky_post) { - var prev_article = new_active.prevAll('.flux'), - new_pos = new_active.offset().top, - old_scroll = box_to_move.scrollTop(); + let prev_article = new_active.previousElementSibling, + new_pos = new_active.offsetTop + document.documentElement.scrollTop, + old_scroll = box_to_move.scrollTop; - if (prev_article.length > 0 && new_pos - prev_article.offset().top <= 150) { - new_pos = prev_article.offset().top; + if (prev_article && new_active.offsetTop - prev_article.offsetTop <= 150) { + new_pos = prev_article.offsetTop; if (relative_move) { - new_pos -= box_to_move.offset().top; + new_pos -= box_to_move.offsetTop; } } if (skipping) { // when skipping, this feels more natural if it's not so near the top - new_pos -= $(window).height() / 4; + new_pos -= document.body.clientHeight / 4; } - if (context.hide_posts) { - if (relative_move) { - new_pos += old_scroll; - } - - new_active.children(".flux_content").first().each(function () { - box_to_move.scrollTop(new_pos).scrollTop(); - }); - } else { - if (relative_move) { - new_pos += old_scroll; - } - - box_to_move.scrollTop(new_pos).scrollTop(); + if (relative_move) { + new_pos += old_scroll; } + box_to_move.scrollTop = new_pos; } - if (new_active.hasClass('active') && !skipping) { + if (new_active.classList.contains('active') && !skipping) { if (context.auto_mark_article) { mark_read(new_active, true); } - new_active[0].dispatchEvent(freshrssOpenArticleEvent); + new_active.dispatchEvent(freshrssOpenArticleEvent); } + onScroll(); } -function auto_remove(element) { - var p = element.prev(); - var n = element.next(); - if (p.hasClass('day') && n.hasClass('day')) { - p.remove(); - } - element.remove(); - $('#stream > .flux:not(.not_read):not(.active)').remove(); -} - -function prev_entry() { - var old_active = $(".flux.current"), - new_active = old_active.length === 0 ? $(".flux:last") : old_active.prevAll(".flux:first"); - toggleContent(new_active, old_active, false); -} - -function next_entry() { - var old_active = $(".flux.current"), - new_active = old_active.length === 0 ? $(".flux:first") : old_active.nextAll(".flux:first"); - toggleContent(new_active, old_active, false); - - if (new_active.nextAll().length < 3) { - load_more_posts(); +function prev_entry(skipping) { + const old_active = document.querySelector('.flux.current'); + let new_active = old_active; + if (new_active) { + do new_active = new_active.previousElementSibling; + while (new_active && !new_active.classList.contains('flux')); + if (!new_active) { + prev_feed(); + } + } else { + new_active = document.querySelector('.flux'); } + toggleContent(new_active, old_active, skipping); } -function skip_prev_entry() { - var old_active = $(".flux.current"), - new_active = old_active.length === 0 ? $(".flux:last") : old_active.prevAll(".flux:first"); - toggleContent(new_active, old_active, true); -} - -function skip_next_entry() { - var old_active = $(".flux.current"), - new_active = old_active.length === 0 ? $(".flux:first") : old_active.nextAll(".flux:first"); - toggleContent(new_active, old_active, true); - - if (new_active.nextAll().length < 3) { - load_more_posts(); +function next_entry(skipping) { + const old_active = document.querySelector('.flux.current'); + let new_active = old_active; + if (new_active) { + do new_active = new_active.nextElementSibling; + while (new_active && !new_active.classList.contains('flux')); + if (!new_active) { + next_feed(); + } + } else { + new_active = document.querySelector('.flux'); } + toggleContent(new_active, old_active, skipping); } function prev_feed() { - var active_feed = $("#aside_feed .tree-folder-items .item.active"); - if (active_feed.length > 0) { - active_feed.prevAll(':visible:first').find('a').each(function(){this.click();}); - } else { + let found = false; + const feeds = document.querySelectorAll('#aside_feed .feed'); + for (let i = feeds.length - 1; i >= 0; i--) { + const feed = feeds[i]; + if (found && getComputedStyle(feed).display !== 'none') { + delayedClick(feed.querySelector('a.item-title')); + break; + } else if (feed.classList.contains('active')) { + found = true; + } + } + if (!found) { last_feed(); } } function next_feed() { - var active_feed = $("#aside_feed .tree-folder-items .item.active"); - if (active_feed.length > 0) { - active_feed.nextAll(':visible:first').find('a').each(function(){this.click();}); - } else { + let found = false; + const feeds = document.querySelectorAll('#aside_feed .feed'); + for (let i = 0; i < feeds.length; i++) { + const feed = feeds[i]; + if (found && getComputedStyle(feed).display !== 'none') { + delayedClick(feed.querySelector('a.item-title')); + break; + } else if (feed.classList.contains('active')) { + found = true; + } + } + if (!found) { first_feed(); } } function first_feed() { - var feed = $("#aside_feed .tree-folder-items.active .item:visible:first"); - if (feed.length > 0) { - feed.find('a')[1].click(); - } + const a = document.querySelector('#aside_feed .category.active .feed:not([data-unread="0"]) a.item-title'); + delayedClick(a); } function last_feed() { - var feed = $("#aside_feed .tree-folder-items.active .item:visible:last"); - if (feed.length > 0) { - feed.find('a')[1].click(); + const links = document.querySelectorAll('#aside_feed .category.active .feed:not([data-unread="0"]) a.item-title'); + if (links && links.length > 0) { + delayedClick(links[links.length - 1]); } } function prev_category() { - var active_cat = $("#aside_feed .tree-folder.active"); - - if (active_cat.length > 0) { - var prev_cat = active_cat.prevAll(':visible:first').find('.tree-folder-title .title'); - if (prev_cat.length > 0) { - prev_cat[0].click(); + const active_cat = document.querySelector('#aside_feed .category.active'); + if (active_cat) { + let cat = active_cat; + do cat = cat.previousElementSibling; + while (cat && getComputedStyle(cat).display === 'none'); + if (cat) { + delayedClick(cat.querySelector('a.title')); } } else { last_category(); } - return; } function next_category() { - var active_cat = $("#aside_feed .tree-folder.active"); - - if (active_cat.length > 0) { - var next_cat = active_cat.nextAll(':visible:first').find('.tree-folder-title .title'); - if (next_cat.length > 0) { - next_cat[0].click(); + const active_cat = document.querySelector('#aside_feed .category.active'); + if (active_cat) { + let cat = active_cat; + do cat = cat.nextElementSibling; + while (cat && getComputedStyle(cat).display === 'none'); + if (cat) { + delayedClick(cat.querySelector('a.title')); } } else { first_category(); } - return; } function first_category() { - var cat = $("#aside_feed .tree-folder:visible:first"); - if (cat.length > 0) { - cat.find('.tree-folder-title .title')[0].click(); - } + const a = document.querySelector('#aside_feed .category:not([data-unread="0"]) a.title'); + delayedClick(a); } function last_category() { - var cat = $("#aside_feed .tree-folder:visible:last"); - if (cat.length > 0) { - cat.find('.tree-folder-title .title')[0].click(); + const links = document.querySelectorAll('#aside_feed .category:not([data-unread="0"]) a.title'); + if (links && links.length > 0) { + delayedClick(links[links.length - 1]); } } function collapse_entry() { - var flux_current = $(".flux.current"); + const flux_current = document.querySelector('.flux.current'); toggleContent(flux_current, flux_current, false); } function user_filter(key) { - var filter = $('#dropdown-query'); - var filters = filter.siblings('.dropdown-menu').find('.item.query a'); - if (typeof key === "undefined") { - if (!filter.length) { + const filter = document.getElementById('dropdown-query'), + filters = filter.parentElement.querySelectorAll('.dropdown-menu > .query > a'); + if (typeof key === 'undefined') { + if (!filters.length) { return; } // Display the filter div - window.location.hash = filter.attr('id'); + location.hash = filter.id; // Force scrolling to the filter div - var scroll = needsScroll($('.header')); + const scroll = needsScroll(document.querySelector('.header')); if (scroll !== 0) { - $('html,body').scrollTop(scroll); + document.documentElement.scrollTop = scroll; } // Force the key value if there is only one action, so we can trigger it automatically if (filters.length === 1) { @@ -460,18 +546,18 @@ function user_filter(key) { } function auto_share(key) { - var share = $(".flux.current.active").find('.dropdown-target[id^="dropdown-share"]'); - var shares = share.siblings('.dropdown-menu').find('.item a'); - if (typeof key === "undefined") { - if (!share.length) { - return; - } + const share = document.querySelector('.flux.current.active .dropdown-target[id^="dropdown-share"]'); + if (!share) { + return; + } + const shares = share.parentElement.querySelectorAll('.dropdown-menu .item a'); + if (typeof key === 'undefined') { // Display the share div - window.location.hash = share.attr('id'); + location.hash = share.id; // Force scrolling to the share div - var scroll = needsScroll(share.closest('.bottom')); - if (scroll !== 0) { - $('html,body').scrollTop(scroll); + const scrollTop = needsScroll(share.closest('.bottom')); + if (scrollTop !== 0) { + document.documentElement.scrollTop = scrollTop; } // Force the key value if there is only one action, so we can trigger it automatically if (shares.length === 1) { @@ -484,52 +570,70 @@ function auto_share(key) { key = parseInt(key); if (key <= shares.length) { shares[key - 1].click(); - share.siblings('.dropdown-menu').find('.dropdown-close a')[0].click(); + share.parentElement.querySelector('.dropdown-menu .dropdown-close a').click(); } } -function scrollAsRead(box_to_follow) { - var minTop = 40 + (context.current_view === 'global' ? box_to_follow.offset().top : box_to_follow.scrollTop()); - $('.not_read:not(.keep_unread):visible').each(function () { - var $this = $(this); - if ($this.offset().top + $this.height() < minTop) { - mark_read($this, true); - } - }); +var box_to_follow; + +function onScroll() { + if (!box_to_follow) { + return; + } + if (context.auto_mark_scroll) { + const minTop = 40 + box_to_follow.scrollTop; + document.querySelectorAll('.not_read:not(.keep_unread)').forEach(function (div) { + if (div.offsetHeight > 0 && + div.offsetParent.offsetTop + div.offsetTop + div.offsetHeight < minTop) { + mark_read(div, true); + } + }); + } + if (context.auto_remove_article) { + let maxTop = box_to_follow.scrollTop, + scrollOffset = 0; + document.querySelectorAll('.flux:not(.active):not(.keep_unread)').forEach(function (div) { + if (!pending_entries[div.id] && div.offsetHeight > 0 && + div.offsetParent.offsetTop + div.offsetTop + div.offsetHeight < maxTop) { + const p = div.previousElementSibling, + n = div.nextElementSibling; + if (p && p.classList.contains('day') && n && n.classList.contains('day')) { + p.remove(); + } + maxTop -= div.offsetHeight; + scrollOffset -= div.offsetHeight; + div.remove(); + } + }); + if (scrollOffset != 0) { + box_to_follow.scrollTop += scrollOffset; + return; //onscroll will be called again + } + } + if (context.auto_load_more) { + const pagination = document.getElementById('mark-read-pagination'); + if (pagination && box_to_follow.offsetHeight > 0 && + box_to_follow.scrollTop + box_to_follow.offsetHeight + (window.innerHeight / 2) >= pagination.offsetTop) { + load_more_posts(); + } + } } function init_posts() { - var box_to_follow = context.current_view === 'global' ? $("#panel") : $(window); - - if (context.auto_mark_scroll) { - var lastScroll = 0, //Throttle + if (context.auto_load_more || context.auto_mark_scroll || context.auto_remove_article) { + box_to_follow = context.current_view === 'global' ? document.getElementById('panel') : document.documentElement; + let lastScroll = 0, //Throttle timerId = 0; - box_to_follow.scroll(function () { - window.clearTimeout(timerId); + (box_to_follow === document.documentElement ? window : box_to_follow).onscroll = function () { + clearTimeout(timerId); if (lastScroll + 500 < Date.now()) { lastScroll = Date.now(); - scrollAsRead(box_to_follow); + onScroll(); } else { - timerId = window.setTimeout(function() { - scrollAsRead(box_to_follow); - }, 500); + timerId = setTimeout(onScroll, 500); } - }); - } - - if (context.auto_load_more) { - box_to_follow.scroll(function () { - var load_more = $("#load_more"); - if (!load_more.is(':visible')) { - return; - } - var boxBot = box_to_follow.scrollTop() + box_to_follow.height(), - load_more_top = load_more.offset().top; - if (boxBot >= load_more_top) { - load_more_posts(); - } - }); - box_to_follow.scroll(); + }; + onScroll(); } } @@ -538,482 +642,481 @@ function init_column_categories() { return; } - $('#aside_feed').on('click', '.tree-folder>.tree-folder-title>a.dropdown-toggle', function () { - $(this).children().each(function() { - if (this.alt === '▽') { - this.src = this.src.replace('/icons/down.', '/icons/up.'); - this.alt = '△'; + document.getElementById('aside_feed').onclick = function (ev) { + let a = ev.target.closest('.tree-folder > .tree-folder-title > a.dropdown-toggle'); + if (a) { + const img = a.querySelector('img'); + if (img.alt === '▽') { + img.src = img.src.replace('/icons/down.', '/icons/up.'); + img.alt = '△'; } else { - this.src = this.src.replace('/icons/up.', '/icons/down.'); - this.alt = '▽'; + img.src = img.src.replace('/icons/up.', '/icons/down.'); + img.alt = '▽'; } - }); - $(this).parent().next(".tree-folder-items").slideToggle(300, function () { - //Workaround for Gecko bug 1514498 in Firefox 64 - var sidebar = document.getElementById('sidebar'); - if (sidebar && sidebar.scrollHeight > sidebar.clientHeight && //if needs scrollbar - sidebar.scrollWidth >= sidebar.offsetWidth) { //but no scrollbar - sidebar.style['overflow-y'] = 'scroll'; //then force scrollbar - setTimeout(function () { sidebar.style['overflow-y'] = ''; }, 0); + + const ul = a.closest('li').querySelector('.tree-folder-items'); + let nbVisibleItems = 0; + for (let i = ul.children.length - 1; i >= 0; i--) { + if (ul.children[i].offsetHeight) { + nbVisibleItems++; + } } - }); - return false; - }); + ul.classList.toggle('active'); + //CSS transition does not work on max-height:auto + ul.style.maxHeight = ul.classList.contains('active') ? (nbVisibleItems * 4) + 'em' : 0; + return false; + } - $('#aside_feed').on('click', '.tree-folder-items .feed .dropdown-toggle', function () { - var itemId = $(this).closest('.item').attr('id'), - templateId = itemId.substring(0, 2) === 't_' ? 'tag_config_template' : 'feed_config_template', - id = itemId.substr(2), - feed_web = $(this).data('fweb'), - template = $('#' + templateId) - .html().replace(/------/g, id).replace('http://example.net/', feed_web); - if ($(this).next('.dropdown-menu').length === 0) { - $(this).attr('href', '#dropdown-' + id).prev('.dropdown-target').attr('id', 'dropdown-' + id).parent() - .append(template).find('button.confirm').removeAttr('disabled'); - } else { - if ($(this).next('.dropdown-menu').css('display') === 'none') { - id = $(this).closest('.item').attr('id').substr(2); - $(this).attr('href', '#dropdown-' + id); + a = ev.target.closest('.tree-folder-items > .feed .dropdown-toggle'); + if (a) { + const itemId = a.closest('.item').id, + templateId = itemId.substring(0, 2) === 't_' ? 'tag_config_template' : 'feed_config_template', + id = itemId.substr(2), + feed_web = a.getAttribute('data-fweb'), + div = a.parentElement, + dropdownMenu = div.querySelector('.dropdown-menu'), + template = document.getElementById(templateId) + .innerHTML.replace(/------/g, id).replace('http://example.net/', feed_web); + if (!dropdownMenu) { + a.href = '#dropdown-' + id; + div.querySelector('.dropdown-target').id = 'dropdown-' + id; + div.insertAdjacentHTML('beforeend', template); + div.querySelector('button.confirm').disabled = false; + } else if (getComputedStyle(dropdownMenu).display === 'none') { + const id2 = div.closest('.item').id.substr(2); + a.href = '#dropdown-' + id2; } else { - $(this).attr('href', "#close"); + a.href = '#close'; } + return true; } - }); + + return true; + }; } function init_shortcuts() { - if (!(window.shortcut && window.shortcuts)) { - if (window.console) { - console.log('FreshRSS waiting for shortcut.js…'); - } - window.setTimeout(init_shortcuts, 200); - return; - } - // Manipulation shortcuts - shortcut.add(shortcuts.mark_read, function () { - // Toggle the read state - var active = $(".flux.current"); - mark_read(active, false); - }, { - 'disable_in_input': true - }); - shortcut.add("shift+" + shortcuts.mark_read, function () { - // Mark everything as read - $(".nav_menu .read_all").click(); - }, { - 'disable_in_input': true - }); - shortcut.add(shortcuts.mark_favorite, function () { - // Toggle the favorite state - var active = $(".flux.current"); - mark_favorite(active); - }, { - 'disable_in_input': true - }); - shortcut.add(shortcuts.collapse_entry, function () { - // Toggle the collapse state - collapse_entry(); - }, { - 'disable_in_input': true - }); - shortcut.add(shortcuts.auto_share, function () { - // Display the share options - auto_share(); - }, { - 'disable_in_input': true - }); + Object.keys(context.shortcuts).forEach(function (k) { + context.shortcuts[k] = (context.shortcuts[k] || '').toUpperCase(); + }); - shortcut.add(shortcuts.user_filter, function () { - // Display the user filters - user_filter(); - }, { - 'disable_in_input': true - }); + document.body.onkeydown = function (ev) { + if (ev.target.closest('input, textarea') || + ev.ctrlKey || ev.metaKey || (ev.altKey && ev.shiftKey)) { + return true; + } - function addShortcut(evt) { - if ($('#dropdown-query').siblings('.dropdown-menu').is(':visible')) { - user_filter(String.fromCharCode(evt.keyCode)); - } else { - auto_share(String.fromCharCode(evt.keyCode)); - } - } - for (var i = 1; i < 10; i++) { - shortcut.add(i.toString(), addShortcut, { - 'disable_in_input': true - }); - } + const s = context.shortcuts, + k = (ev.key.trim() || ev.code).toUpperCase(); + if (location.hash.match(/^#dropdown-/)) { + const n = parseInt(k); + if (n) { + if (location.hash === '#dropdown-query') { + user_filter(n); + } else { + auto_share(n); + } + return false; + } + } + if (k === s.next_entry) { + if (ev.altKey) { + next_category(); + } else if (ev.shiftKey) { + next_feed(); + } else { + next_entry(false); + } + return false; + } + if (k === s.prev_entry) { + if (ev.altKey) { + prev_category(); + } else if (ev.shiftKey) { + prev_feed(); + } else { + prev_entry(false); + } + return false; + } + if (k === s.mark_read) { + if (ev.altKey) { + return true; + } else if (ev.shiftKey) { // Mark everything as read + document.querySelector('.nav_menu .read_all').click(); + } else { // Toggle the read state + mark_read(document.querySelector('.flux.current'), false); + } + return false; + } + if (k === s.first_entry) { + if (ev.altKey) { + first_category(); + } else if (ev.shiftKey) { + first_feed(); + } else { + const old_active = document.querySelector('.flux.current'), + first = document.querySelector('.flux'); + if (first.classList.contains('flux')) { + toggleContent(first, old_active, false); + } + } + return false; + } + if (k === s.last_entry) { + if (ev.altKey) { + last_category(); + } else if (ev.shiftKey) { + last_feed(); + } else { + const old_active = document.querySelector('.flux.current'), + last = document.querySelector('.flux:last-of-type'); + if (last.classList.contains('flux')) { + toggleContent(last, old_active, false); + } + } + return false; + } - // Entry navigation shortcuts - shortcut.add(shortcuts.prev_entry, prev_entry, { - 'disable_in_input': true - }); - shortcut.add(shortcuts.skip_prev_entry, skip_prev_entry, { - 'disable_in_input': true - }); - shortcut.add(shortcuts.first_entry, function () { - var old_active = $(".flux.current"), - first = $(".flux:first"); + if (ev.altKey || ev.shiftKey) { + return true; + } + if (k === s.mark_favorite) { // Toggle the favorite state + mark_favorite(document.querySelector('.flux.current')); + return false; + } + if (k === s.go_website) { + if (context.auto_mark_site) { + mark_read(document.querySelector('.flux.current'), true); + } + window.open(document.querySelector('.flux.current a.go_website').href); + return false; + } + if (k === s.skip_next_entry) { next_entry(true); return false; } + if (k === s.skip_prev_entry) { prev_entry(true); return false; } + if (k === s.collapse_entry) { collapse_entry(); return false; } + if (k === s.auto_share) { auto_share(); return false; } + if (k === s.user_filter) { user_filter(); return false; } + if (k === s.load_more) { load_more_posts(); return false; } + if (k === s.close_dropdown) { location.hash = null; return false; } + if (k === s.help) { window.open(context.urls.help); return false; } + if (k === s.focus_search) { document.getElementById('search').focus(); return false; } + if (k === s.normal_view) { delayedClick(document.querySelector('#nav_menu_views .view-normal')); return false; } + if (k === s.reading_view) { delayedClick(document.querySelector('#nav_menu_views .view-reader')); return false; } + if (k === s.global_view) { delayedClick(document.querySelector('#nav_menu_views .view-global')); return false; } + if (k === s.rss_view) { delayedClick(document.querySelector('#nav_menu_views .view-rss')); return false; } + return true; + }; +} - if (first.hasClass("flux")) { - toggleContent(first, old_active, false); +function init_stream(stream) { + stream.onclick = function (ev) { + let el = ev.target.closest('.flux a.read'); + if (el) { + mark_read(el.closest('.flux'), false); + return false; } - }, { - 'disable_in_input': true - }); - shortcut.add(shortcuts.next_entry, next_entry, { - 'disable_in_input': true - }); - shortcut.add(shortcuts.skip_next_entry, skip_next_entry, { - 'disable_in_input': true - }); - shortcut.add(shortcuts.last_entry, function () { - var old_active = $(".flux.current"), - last = $(".flux:last"); - if (last.hasClass("flux")) { - toggleContent(last, old_active, false); + el = ev.target.closest('.flux a.bookmark'); + if (el) { + mark_favorite(el.closest('.flux')); + return false; } - }, { - 'disable_in_input': true - }); - // Feed navigation shortcuts - shortcut.add("shift+" + shortcuts.prev_entry, prev_feed, { - 'disable_in_input': true - }); - shortcut.add("shift+" + shortcuts.next_entry, next_feed, { - 'disable_in_input': true - }); - shortcut.add("shift+" + shortcuts.first_entry, first_feed, { - 'disable_in_input': true - }); - shortcut.add("shift+" + shortcuts.last_entry, last_feed, { - 'disable_in_input': true - }); - // Category navigation shortcuts - shortcut.add("alt+" + shortcuts.prev_entry, prev_category, { - 'disable_in_input': true - }); - shortcut.add("alt+" + shortcuts.next_entry, next_category, { - 'disable_in_input': true - }); - shortcut.add("alt+" + shortcuts.first_entry, first_category, { - 'disable_in_input': true - }); - shortcut.add("alt+" + shortcuts.last_entry, last_category, { - 'disable_in_input': true - }); - - shortcut.add(shortcuts.go_website, function () { - var url_website = $('.flux.current a.go_website').attr("href"); - if (context.auto_mark_site) { - $(".flux.current").each(function () { - mark_read($(this), true); - }); + el = ev.target.closest('.dynamictags'); + if (el) { + loadDynamicTags(el); + return true; } - redirect(url_website, true); - }, { - 'disable_in_input': true - }); - - shortcut.add(shortcuts.load_more, function () { - load_more_posts(); - }, { - 'disable_in_input': true - }); - - shortcut.add(shortcuts.focus_search, function () { - focus_search(); - }, { - 'disable_in_input': true - }); - - shortcut.add(shortcuts.help, function () { - redirect(url.help, true); - }, { - 'disable_in_input': true - }); - - shortcut.add(shortcuts.close_dropdown, function () { - window.location.hash = null; - }, { - 'disable_in_input': true - }); - - shortcut.add(shortcuts.normal_view, function () { - $('#nav_menu_views .view-normal').get(0).click(); - }, { - 'disable_in_input': true - }); - - shortcut.add(shortcuts.global_view, function () { - $('#nav_menu_views .view-global').get(0).click(); - }, { - 'disable_in_input': true - }); - - shortcut.add(shortcuts.reading_view, function () { - $('#nav_menu_views .view-reader').get(0).click(); - }, { - 'disable_in_input': true - }); - - shortcut.add(shortcuts.rss_view, function () { - $('#nav_menu_views .view-rss').get(0).click(); - }, { - 'disable_in_input': true - }); -} - -function init_stream(divStream) { - divStream.on('click', '.flux_header,.flux_content', function (e) { //flux_toggle - if ($(e.target).closest('.content, .item.website, .item.link, .dropdown-menu').length > 0) { - return; + el = ev.target.closest('.item.title > a'); + if (el) { // Allow default control-click behaviour such as open in backround-tab + return ev.ctrlKey; } - if (!context.sides_close_article && $(e.target).is('div.flux_content')) { - // setting for not-closing after clicking outside article area - return; - } - var old_active = $(".flux.current"), - new_active = $(this).parent(); - isCollapsed = true; - if (e.target.tagName.toUpperCase() === 'A') { //Leave real links alone - if (context.auto_mark_article) { - mark_read(new_active, true); + + el = ev.target.closest('.flux .content a'); + if (el) { + if (!el.closest('div').classList.contains('author')) { + el.target = '_blank'; + el.rel = 'noreferrer'; } return true; } - toggleContent(new_active, old_active, false); - }); - divStream.on('click', '.flux a.read', function () { - var active = $(this).parents(".flux"); - if (context.auto_remove_article && active.hasClass('not_read')) { - auto_remove(active); + el = ev.target.closest('.item.share > a[href="#"]'); + if (el) { //Print + const content = '<html><head><style>' + + 'body { font-family: Serif; text-align: justify; }' + + 'a { color: #000; text-decoration: none; }' + + 'a:after { content: " [" attr(href) "]"}' + + '</style></head><body>' + + el.closest('.flux_content').querySelector('.content').innerHTML + + '</body></html>'; + const tmp_window = window.open(); + tmp_window.document.writeln(content); + tmp_window.document.close(); + tmp_window.focus(); + tmp_window.print(); + tmp_window.close(); + return false; } - mark_read(active, false); - return false; - }); - - divStream.on('click', '.flux a.bookmark', function () { - var active = $(this).parents(".flux"); - mark_favorite(active); - return false; - }); - divStream.on('click', '.item.title > a', function (e) { - // Allow default control-click behaviour such as open in backround-tab. - return e.ctrlKey; - }); - divStream.on('mouseup', '.item.title > a', function (e) { - // Mouseup enables us to catch middle click. - if (e.ctrlKey) { - // CTRL+click, it will be manage by previous rule. - return; + el = ev.target.closest('.item.share > a[href="POST"]'); + if (el) { //Share by POST + const f = el.parentElement.querySelector('form'); + f.disabled = false; + f.submit(); + return false; } - if (e.which == 2) { - // If middle click, we want same behaviour as CTRL+click. - var ev = jQuery.Event("click"); - ev.ctrlKey = true; - $(this).trigger(ev); - } else if(e.which == 1) { - // Normal click, just toggle article. - $(this).parent().click(); + el = ev.target.closest('.flux_header, .flux_content'); + if (el) { //flux_toggle + if (ev.target.closest('.content, .item.website, .item.link, .dropdown-menu')) { + return true; + } + if (!context.sides_close_article && ev.target.matches('div.flux_content')) { + // setting for not-closing after clicking outside article area + return false; + } + const old_active = document.querySelector('.flux.current'), + new_active = el.parentNode; + if (ev.target.tagName.toUpperCase() === 'A') { //Leave real links alone + if (context.auto_mark_article) { + mark_read(new_active, true); + } + return true; + } + toggleContent(new_active, old_active, false); + return false; } - }); + }; - divStream.on('click', '.flux .content a', function () { - if (!$(this).closest('div').hasClass('author')) { - $(this).attr('target', '_blank').attr('rel', 'noreferrer'); + stream.onmouseup = function (ev) { // Mouseup enables us to catch middle click + let el = ev.target.closest('.item.title > a'); + if (el) { + if (ev.ctrlKey) { + return; // CTRL+click, it will be manage by previous rule. + } + if (ev.which == 2) { + // If middle click, we want same behaviour as CTRL+click. + const evc = document.createEvent('click'); + evc.ctrlKey = true; + el.dispatchEvent(evc); + } else if (ev.which == 1) { + // Normal click, just toggle article. + el.parentElement.click(); + } } - }); - if (context.auto_mark_site) { - // catch mouseup instead of click so we can have the correct behaviour - // with middle button click (scroll button). - divStream.on('mouseup', '.flux .link > a', function (e) { - if (e.which == 3) { - return; + if (context.auto_mark_site) { + // catch mouseup instead of click so we can have the correct behaviour + // with middle button click (scroll button). + el = ev.target.closest('.flux .link > a'); + if (el) { + if (ev.which == 3) { + return; + } + mark_read(el.closest('.flux'), true); } + } + }; - mark_read($(this).parents(".flux"), true); - }); - } + stream.onchange = function (ev) { + const checkboxTag = ev.target.closest('.checkboxTag'); + if (checkboxTag) { //Dynamic tags + ev.stopPropagation(); + const isChecked = checkboxTag.checked, + tagId = checkboxTag.name.replace(/^t_/, ''), + tagName = checkboxTag.nextElementSibling ? checkboxTag.nextElementSibling.value : '', + entry = checkboxTag.closest('div.flux'), + entryId = entry.id.replace(/^flux_/, ''); + checkboxTag.disabled = true; + + const req = new XMLHttpRequest(); + req.open('POST', './?c=tag&a=tagEntry', true); + req.responseType = 'json'; + req.onerror = function (e) { + checkboxTag.checked = !isChecked; + if (this.status == 403) { + badAjax(); + } + }; + req.onload = function (e) { + if (this.status != 200) { + return req.onerror(e); + } + if (entry.classList.contains('not_read')) { + incUnreadsTag('t_' + tagId, isChecked ? 1 : -1); + } + }; + req.onloadend = function (e) { + checkboxTag.disabled = false; + if (tagId == 0) { + loadDynamicTags(checkboxTag.closest('div.dropdown')); + } + }; + req.setRequestHeader('Content-Type', 'application/json'); + req.send(JSON.stringify({ + _csrf: context.csrf, + id_tag: tagId, + name_tag: tagId == 0 ? tagName : '', + id_entry: entryId, + checked: isChecked, + })); + } + }; } -var $nav_entries = null; - function init_nav_entries() { - $nav_entries = $('#nav_entries'); - $nav_entries.find('.previous_entry').click(function () { - prev_entry(); - return false; - }); - $nav_entries.find('.next_entry').click(function () { - next_entry(); - return false; - }); - $nav_entries.find('.up').click(function () { - var active_item = $(".flux.current"), - windowTop = $(window).scrollTop(), - item_top = active_item.offset().top; - - if (windowTop > item_top) { - $("html,body").scrollTop(item_top); - } else { - $("html,body").scrollTop(0); - } - return false; - }); -} + const nav_entries = document.getElementById('nav_entries'); + if (nav_entries) { + nav_entries.querySelector('.previous_entry').onclick = function (e) { + prev_entry(false); + return false; + }; + nav_entries.querySelector('.next_entry').onclick = function (e) { + next_entry(false); + return false; + }; + nav_entries.querySelector('.up').onclick = function (e) { + const active_item = document.querySelector('.flux.current'), + windowTop = document.documentElement.scrollTop, + item_top = active_item.offsetParent.offsetTop + active_item.offsetTop; -function loadDynamicTags($div) { - $div.removeClass('dynamictags'); - $div.find('li.item').remove(); - var entryId = $div.closest('div.flux').attr('id').replace(/^flux_/, ''); - $.getJSON('./?c=tag&a=getTagsForEntry&id_entry=' + entryId) - .done(function (data) { - var $ul = $div.find('.dropdown-menu'); - $ul.append('<li class="item"><label><input class="checkboxTag" name="t_0" type="checkbox" /> <input type="text" name="newTag" /></label></li>'); - if (data && data.length) { - for (var i = 0; i < data.length; i++) { - var tag = data[i]; - $ul.append('<li class="item"><label><input class="checkboxTag" name="t_' + tag.id + '" type="checkbox"' + - (tag.checked ? ' checked="checked"' : '') + '> ' + tag.name + '</label></li>'); - } - } - }) - .fail(function () { - $div.find('li.item').remove(); - $div.addClass('dynamictags'); - }); + document.documentElement.scrollTop = windowTop > item_top ? item_top : 0; + return false; + }; + } } -function init_dynamic_tags() { - $stream.on('click', '.dynamictags', function () { - loadDynamicTags($(this)); - }); +function loadDynamicTags(div) { + div.classList.remove('dynamictags'); + div.querySelectorAll('li.item').forEach(function (li) { li.remove(); }); + const entryId = div.closest('div.flux').id.replace(/^flux_/, ''); - $stream.on('change', '.checkboxTag', function (ev) { - var $checkbox = $(this); - $checkbox.prop('disabled', true); - var isChecked = $checkbox.prop('checked'); - var tagId = $checkbox.attr('name').replace(/^t_/, ''); - var tagName = $checkbox.siblings('input[name]').val(); - var $entry = $checkbox.closest('div.flux'); - var entryId = $entry.attr('id').replace(/^flux_/, ''); - $.ajax({ - type: 'POST', - url: './?c=tag&a=tagEntry', - data: { - _csrf: context.csrf, - id_tag: tagId, - name_tag: tagId == 0 ? tagName : '', - id_entry: entryId, - checked: isChecked, - }, - }) - .done(function () { - if ($entry.hasClass('not_read')) { - incUnreadsTag(tagId, isChecked ? 1 : -1); - } - }) - .fail(function () { - $checkbox.prop('checked', !isChecked); - }) - .always(function () { - $checkbox.prop('disabled', false); - if (tagId == 0) { - loadDynamicTags($checkbox.closest('div.dropdown')); + const req = new XMLHttpRequest(); + req.open('GET', './?c=tag&a=getTagsForEntry&id_entry=' + entryId, true); + req.responseType = 'json'; + req.onerror = function (e) { + div.querySelectorAll('li.item').forEach(function (li) { li.remove(); }); + div.classList.add('dynamictags'); + }; + req.onload = function (e) { + if (this.status != 200) { + return req.onerror(e); + } + const json = xmlHttpRequestJson(this); + let html = '<li class="item"><label><input class="checkboxTag" name="t_0" type="checkbox" /> <input type="text" name="newTag" /></label></li>'; + if (json && json.length) { + for (let i = 0; i < json.length; i++) { + const tag = json[i]; + html += '<li class="item"><label><input class="checkboxTag" name="t_' + tag.id + '" type="checkbox"' + + (tag.checked ? ' checked="checked"' : '') + '> ' + tag.name + '</label></li>'; } - }); - }); + } + div.querySelector('.dropdown-menu').insertAdjacentHTML('beforeend', html); + }; + req.send(); } // <actualize> var feed_processed = 0; function updateFeed(feeds, feeds_count) { - var feed = feeds.pop(); + const feed = feeds.pop(); if (!feed) { return; } - $.ajax({ - type: 'POST', - url: feed.url, - data: { - _csrf: context.csrf, - noCommit: 1, - }, - }).always(function (data) { - feed_processed++; - $("#actualizeProgress .progress").html(feed_processed + " / " + feeds_count); - $("#actualizeProgress .title").html(feed.title); - - if (feed_processed === feeds_count) { - $.ajax({ //Empty request to commit new articles - type: 'POST', - url: './?c=feed&a=actualize&id=-1&ajax=1', - data: { + const req = new XMLHttpRequest(); + req.open('POST', feed.url, true); + req.onloadend = function (e) { + if (this.status != 200) { + return badAjax(); + } + 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) { + //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) { + location.reload(); + }; + req2.setRequestHeader('Content-Type', 'application/json'); + req2.send(JSON.stringify({ _csrf: context.csrf, noCommit: 0, - }, - }).always(function (data) { - window.location.reload(); - }); - } else { - updateFeed(feeds, feeds_count); - } - }); + })); + } else { + updateFeed(feeds, feeds_count); + } + }; + req.setRequestHeader('Content-Type', 'application/json'); + req.send(JSON.stringify({ + _csrf: context.csrf, + noCommit: 1, + })); } function init_actualize() { - var auto = false; + let auto = false; - $("#actualize").click(function () { - if (ajax_loading) { + document.getElementById('actualize').onclick = function () { + if (context.ajax_loading) { return false; } - ajax_loading = true; - - $.getJSON('./?c=javascript&a=actualize').done(function (data) { - if (auto && data.feeds.length < 1) { - auto = false; - ajax_loading = false; - return false; - } - if (data.feeds.length === 0) { - openNotification(data.feedback_no_refresh, "good"); - $.ajax({ //Empty request to force refresh server database cache - type: 'POST', - url: './?c=feed&a=actualize&id=-1&ajax=1', - data: { - _csrf: context.csrf, - noCommit: 0, - }, - }).always(function (data) { - ajax_loading = false; - }); - return; - } - //Progress bar - var feeds_count = data.feeds.length; - $('body').after('<div id="actualizeProgress" class="notification good">' + data.feedback_actualize + - '<br /><span class="title">/</span><br /><span class="progress">0 / ' + feeds_count + - '</span></div>'); - for (var i = 10; i > 0; i--) { - updateFeed(data.feeds, feeds_count); - } - }); + context.ajax_loading = true; + + const req = new XMLHttpRequest(); + req.open('POST', './?c=javascript&a=actualize', true); + req.responseType = 'json'; + req.onload = function (e) { + if (this.status != 200) { + return badAjax(); + } + const json = xmlHttpRequestJson(this); + if (auto && json.feeds.length < 1) { + auto = false; + context.ajax_loading = false; + return false; + } + if (json.feeds.length === 0) { + 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); + } + }; + req.setRequestHeader('Content-Type', 'application/json'); + req.send(JSON.stringify({ + _csrf: context.csrf, + })); return false; - }); + }; if (context.auto_actualize_feeds) { auto = true; - $("#actualize").click(); + document.getElementById('actualize').click(); } } // </actualize> @@ -1027,39 +1130,31 @@ function openNotification(msg, status) { if (notification_working === true) { return false; } - notification_working = true; + notification.querySelector('.msg').innerHTML = msg; + notification.className = 'notification'; + notification.classList.add(status); - notification.removeClass(); - notification.addClass("notification"); - notification.addClass(status); - notification.find(".msg").html(msg); - notification.fadeIn(300); - - notification_interval = window.setTimeout(closeNotification, 4000); + notification_interval = setTimeout(closeNotification, 4000); } function closeNotification() { - notification.fadeOut(600, function() { - notification.removeClass(); - notification.addClass('closed'); - - window.clearInterval(notification_interval); - notification_working = false; - }); + notification.classList.add('closed'); + clearInterval(notification_interval); + notification_working = false; } function init_notifications() { - notification = $("#notification"); + notification = document.getElementById('notification'); - notification.find("a.close").click(function () { - closeNotification(); - return false; - }); + notification.querySelector('a.close').onclick = function () { + closeNotification(); + return false; + }; - if (notification.find(".msg").html().length > 0) { + if (notification.querySelector('.msg').innerHTML.length > 0) { notification_working = true; - notification_interval = window.setTimeout(closeNotification, 4000); + notification_interval = setTimeout(closeNotification, 4000); } } // </notification> @@ -1078,24 +1173,24 @@ function notifs_html5_ask_permission() { } function notifs_html5_show(nb) { - if (notifs_html5_permission !== "granted") { + if (notifs_html5_permission !== 'granted') { return; } - var notification = new window.Notification(i18n.notif_title_articles, { - icon: "../themes/icons/favicon-256.png", - body: i18n.notif_body_articles.replace('%d', nb), - tag: "freshRssNewArticles" + const notification = new window.Notification(context.i18n.notif_title_articles, { + icon: '../themes/icons/favicon-256.png', + body: context.i18n.notif_body_articles.replace('%d', nb), + tag: 'freshRssNewArticles', }); - notification.onclick = function() { - window.location.reload(); + notification.onclick = function () { + location.reload(); window.focus(); notification.close(); }; if (context.html5_notif_timeout !== 0) { - setTimeout(function() { + setTimeout(function () { notification.close(); }, context.html5_notif_timeout * 1000); } @@ -1111,84 +1206,117 @@ function init_notifs_html5() { // </notifs html5> function refreshUnreads() { - $.getJSON('./?c=javascript&a=nbUnreadsPerFeed').done(function (data) { - var isAll = $('.category.all.active').length > 0, - new_articles = false; - - $.each(data.feeds, function(feed_id, nbUnreads) { - feed_id = 'f_' + feed_id; - var elem = $('#' + feed_id).get(0), - feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0; - - if ((incUnreadsFeed(null, feed_id, nbUnreads - feed_unreads) || isAll) && //Update of current view? - (nbUnreads - feed_unreads > 0)) { - $('#new-article').attr('aria-hidden', 'false').show(); - new_articles = true; - } - }); + const req = new XMLHttpRequest(); + req.open('GET', './?c=javascript&a=nbUnreadsPerFeed', true); + req.responseType = 'json'; + req.onload = function (e) { + const json = xmlHttpRequestJson(this); + const isAll = document.querySelector('.category.all.active'); + let new_articles = false; + + Object.keys(json.feeds).forEach(function (feed_id) { + const nbUnreads = json.feeds[feed_id]; + feed_id = 'f_' + feed_id; + const elem = document.getElementById(feed_id), + feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0; + + if ((incUnreadsFeed(null, feed_id, nbUnreads - feed_unreads) || isAll) && //Update of current view? + (nbUnreads - feed_unreads > 0)) { + const newArticle = document.getElementById('new-article'); + newArticle.setAttribute('aria-hidden', 'false'); + newArticle.style.display = 'block'; + new_articles = true; + } + }); - var nbUnreadTags = 0; + let nbUnreadTags = 0; - $.each(data.tags, function(tag_id, nbUnreads) { - nbUnreadTags += nbUnreads; - $('#t_' + tag_id).attr('data-unread', nbUnreads) - .children('.item-title').attr('data-unread', numberFormat(nbUnreads)); - }); + Object.keys(json.tags).forEach(function (tag_id) { + const nbUnreads = json.tags[tag_id]; + nbUnreadTags += nbUnreads; + const tag = document.getElementById('t_' + tag_id); + if (tag) { + tag.setAttribute('data-unread', nbUnreads); + tag.querySelector('.item-title').setAttribute('data-unread', numberFormat(nbUnreads)); + } + }); - $('.category.tags').attr('data-unread', nbUnreadTags) - .find('.title').attr('data-unread', numberFormat(nbUnreadTags)); + const tags = document.querySelector('.category.tags'); + if (tags) { + tags.setAttribute('data-unread', nbUnreadTags); + tags.querySelector('.title').setAttribute('data-unread', numberFormat(nbUnreadTags)); + } - var nb_unreads = str2int($('.category.all .title').attr('data-unread')); + const title = document.querySelector('.category.all .title'), + nb_unreads = title ? str2int(title.getAttribute('data-unread')) : 0; - if (nb_unreads > 0 && new_articles) { - faviconNbUnread(nb_unreads); - notifs_html5_show(nb_unreads); - } - }); + if (nb_unreads > 0 && new_articles) { + faviconNbUnread(nb_unreads); + notifs_html5_show(nb_unreads); + } + }; + req.send(); } //<endless_mode> -var url_load_more = "", +var url_load_more = '', load_more = false, box_load_more = null; function load_more_posts() { - if (load_more || url_load_more === '' || box_load_more === null) { + if (load_more || !url_load_more || !box_load_more) { return; } - load_more = true; - $('#load_more').addClass('loading'); - $.get(url_load_more, function (data) { - box_load_more.children('.flux:last').after($('#stream', data).children('.flux, .day')); - $('.pagination').replaceWith($('.pagination', data)); - if (context.display_order === 'ASC') { - $('#nav_menu_read_all .read_all').attr( - 'formaction', $('#bigMarkAsRead').attr('formaction') - ); - } else { - $('#bigMarkAsRead').attr( - 'formaction', $('#nav_menu_read_all .read_all').attr('formaction') - ); - } + document.getElementById('load_more').classList.add('loading'); + + const req = new XMLHttpRequest(); + req.open('GET', url_load_more, true); + req.responseType = 'document'; + req.onload = function (e) { + const html = this.response, + formPagination = document.getElementById('mark-read-pagination'); + + const streamAdopted = document.adoptNode(html.getElementById('stream')); + streamAdopted.querySelectorAll('.flux, .day').forEach(function (div) { + box_load_more.insertBefore(div, formPagination); + }); + + const paginationOld = formPagination.querySelector('.pagination'), + paginationNew = streamAdopted.querySelector('.pagination'); + formPagination.replaceChild(paginationNew, paginationOld); - $('[id^=day_]').each(function (i) { - var ids = $('[id="' + this.id + '"]'); - if (ids.length > 1) { - $('[id="' + this.id + '"]:gt(0)').remove(); + if (context.display_order === 'ASC') { + document.querySelector('#nav_menu_read_all .read_all').formAction = + document.getElementById('bigMarkAsRead').formAction; + } else { + const bigMarkAsRead = document.getElementById('bigMarkAsRead'); + if (bigMarkAsRead) { + bigMarkAsRead.formAction = document.querySelector('#nav_menu_read_all .read_all').formAction; + } } - }); - init_load_more(box_load_more); + document.querySelectorAll('[id^=day_]').forEach(function (div) { + const ids = document.querySelectorAll('[id="' + div.id + '"]'); + for (let i = ids.length - 1; i > 0; i--) { //Keep only the first + ids[i].remove(); + } + }); - $('#load_more').removeClass('loading'); - $('#bigMarkAsRead').removeAttr('disabled'); - load_more = false; - }); -} + init_load_more(box_load_more); -function focus_search() { - $('#search').focus(); + const bigMarkAsRead = document.getElementById('bigMarkAsRead'), + div_load_more = document.getElementById('load_more'); + if (bigMarkAsRead) { + bigMarkAsRead.removeAttribute('disabled'); + } + if (div_load_more) { + div_load_more.classList.remove('loading'); + } + + load_more = false; + }; + req.send(); } var freshrssLoadMoreEvent = document.createEvent('Event'); @@ -1198,208 +1326,52 @@ function init_load_more(box) { box_load_more = box; document.body.dispatchEvent(freshrssLoadMoreEvent); - var $next_link = $("#load_more"); - if (!$next_link.length) { + const next_link = document.getElementById('load_more'); + if (!next_link) { // no more article to load - url_load_more = ""; + url_load_more = ''; return; } - url_load_more = $next_link.attr("href"); + url_load_more = next_link.href; - $next_link.click(function () { - load_more_posts(); - return false; - }); + next_link.onclick = function (e) { + load_more_posts(); + return false; + }; } //</endless_mode> -//<crypto form (Web login)> -function poormanSalt() { //If crypto.getRandomValues is not available - var text = '$2a$04$', - base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ.0123456789/abcdefghijklmnopqrstuvwxyz'; - for (var i = 22; i > 0; i--) { - text += base.charAt(Math.floor(Math.random() * 64)); - } - return text; -} - -function init_crypto_form() { - /* globals dcodeIO */ - var $crypto_form = $('#crypto-form'); - if ($crypto_form.length === 0) { - return; - } - - if (!(window.dcodeIO)) { - if (window.console) { - console.log('FreshRSS waiting for bcrypt.js…'); - } - window.setTimeout(init_crypto_form, 100); - return; - } - - $crypto_form.on('submit', function() { - var $submit_button = $(this).find('button[type="submit"]'); - $submit_button.attr('disabled', ''); - - var success = false; - $.ajax({ - url: './?c=javascript&a=nonce&user=' + $('#username').val(), - dataType: 'json', - async: false - }).done(function (data) { - if (!data.salt1 || !data.nonce) { - openNotification('Invalid user!', 'bad'); - } else { - try { - var strong = window.Uint32Array && window.crypto && (typeof window.crypto.getRandomValues === 'function'), - s = dcodeIO.bcrypt.hashSync($('#passwordPlain').val(), data.salt1), - c = dcodeIO.bcrypt.hashSync(data.nonce + s, strong ? dcodeIO.bcrypt.genSaltSync(4) : poormanSalt()); - $('#challenge').val(c); - if (!s || !c) { - openNotification('Crypto error!', 'bad'); - } else { - success = true; - } - } catch (e) { - openNotification('Crypto exception! ' + e, 'bad'); +function init_confirm_action() { + document.body.onclick = function (ev) { + const b = ev.target.closest('.confirm'); + if (b) { + let str_confirmation = this.getAttribute('data-str-confirm'); + if (!str_confirmation) { + str_confirmation = context.i18n.confirmation_default; } + return confirm(str_confirmation); } - }).fail(function() { - openNotification('Communication error!', 'bad'); - }); - - $submit_button.removeAttr('disabled'); - return success; - }); -} -//</crypto form (Web login)> - -function init_confirm_action() { - $('body').on('click', '.confirm', function () { - var str_confirmation = $(this).attr('data-str-confirm'); - if (!str_confirmation) { - str_confirmation = i18n.confirmation_default; - } - - return confirm(str_confirmation); - }); - $('button.confirm').removeAttr('disabled'); -} - -function init_print_action() { - $('.item.share > a[href="#"]').click(function (e) { - var content = "<html><head><style>" + - "body { font-family: Serif; text-align: justify; }" + - "a { color: #000; text-decoration: none; }" + - "a:after { content: ' [' attr(href) ']'}" + - "</style></head><body>" + - $(e.target).closest('.flux_content').find('.content').html() + - "</body></html>"; - - var tmp_window = window.open(); - tmp_window.document.writeln(content); - tmp_window.document.close(); - tmp_window.focus(); - tmp_window.print(); - tmp_window.close(); - - return false; - }); -} - -function init_post_action() { - $('.item.share > a[href="POST"]').click(function (event) { - event.preventDefault(); - var form = $(this).next('form'); - $.post(form.data('url'), form.serialize()); - }); -} - -function init_share_observers() { - shares = $('.group-share').length; - - $('.share.add').on('click', function(e) { - var opt = $(this).siblings('select').find(':selected'); - var row = $(this).parents('form').data(opt.data('form')); - row = row.replace(/##label##/g, opt.html().trim()); - row = row.replace(/##type##/g, opt.val()); - row = row.replace(/##help##/g, opt.data('help')); - row = row.replace(/##key##/g, shares); - row = row.replace(/##method##/g, opt.data('method')); - row = row.replace(/##field##/g, opt.data('field')); - $(this).parents('.form-group').before(row); - shares++; - - return false; - }); -} - -function init_stats_observers() { - $('.select-change').on('change', function(e) { - redirect($(this).find(':selected').data('url')); - }); -} - -function init_remove_observers() { - $('.post').on('click', 'a.remove', function(e) { - var remove_what = $(this).attr('data-remove'); - - if (remove_what !== undefined) { - var remove_obj = $('#' + remove_what); - remove_obj.remove(); - } - - return false; - }); -} - -function init_feed_observers() { - $('select[id="category"]').on('change', function() { - var detail = $('#new_category_name').parent(); - if ($(this).val() === 'nc') { - detail.attr('aria-hidden', 'false').show(); - detail.find('input').focus(); - } else { - detail.attr('aria-hidden', 'true').hide(); - } - }); -} - -function init_password_observers() { - $('.toggle-password').on('mousedown', function(e) { - var button = $(this); - var passwordField = $('#' + button.attr('data-toggle')); - passwordField.attr('type', 'text'); - button.addClass('active'); - - return false; - }).on('mouseup', function(e) { - var button = $(this); - var passwordField = $('#' + button.attr('data-toggle')); - passwordField.attr('type', 'password'); - button.removeClass('active'); - - return false; - }); + }; + document.querySelectorAll('button.confirm').forEach(function (b) { b.disabled = false; }); } function faviconNbUnread(n) { if (typeof n === 'undefined') { - n = str2int($('.category.all .title').attr('data-unread')); + const t = document.querySelector('.category.all .title'); + n = t ? str2int(t.getAttribute('data-unread')) : 0; } //http://remysharp.com/2010/08/24/dynamic-favicons/ - var canvas = document.createElement('canvas'), + const canvas = document.createElement('canvas'), link = document.getElementById('favicon').cloneNode(true); if (canvas.getContext && link) { canvas.height = canvas.width = 16; - var img = document.createElement('img'); + const img = document.createElement('img'); img.onload = function () { - var ctx = canvas.getContext('2d'); + const ctx = canvas.getContext('2d'); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); if (n > 0) { - var text = ''; + let text = ''; if (n < 1000) { text = n; } else if (n < 100000) { @@ -1414,167 +1386,61 @@ function faviconNbUnread(n) { ctx.fillText(text, 0, canvas.height - 1); } link.href = canvas.toDataURL('image/png'); - $('link[rel~=icon]').remove(); + document.querySelector('link[rel~=icon]').remove(); document.head.appendChild(link); }; img.src = '../favicon.ico'; } } -function init_slider_observers() { - var slider = $('#slider'), - closer = $('#close-slider'); - if (slider.length < 1) { - return; - } - - $('.post').on('click', '.open-slider', function() { - if (ajax_loading) { - return false; - } - - ajax_loading = true; - var url_slide = $(this).attr('href'); - - $.ajax({ - type: 'GET', - url: url_slide, - data: { ajax: true } - }).done(function (data) { - slider.html(data); - closer.addClass('active'); - slider.addClass('active'); - ajax_loading = false; - }); - - return false; - }); - - closer.on('click', function() { - closer.removeClass('active'); - slider.removeClass('active'); - return false; - }); -} - -function init_configuration_alert() { - $(window).on('submit', function(e) { - window.hasSubmit = true; - }); - $(window).on('beforeunload', function(e) { - if (window.hasSubmit) { - return; - } - var fields = $("[data-leave-validation]"); - for (var i = 0; i < fields.length; i++) { - if ($(fields[i]).attr('type') === 'checkbox' || $(fields[i]).attr('type') === 'radio') { - // The use of != is done on purpose to check boolean against integer - if ($(fields[i]).is(':checked') != $(fields[i]).attr('data-leave-validation')) { - return false; - } - } else { - if ($(fields[i]).attr('data-leave-validation') !== $(fields[i]).val()) { - return false; - } - } - } - return; - }); -} - -function init_subscription() { - $('body').on('click', '.bookmarkClick', function (e) { - return false; - }); -} - -function parseJsonVars() { - var jsonVars = document.getElementById('jsonVars'), - json = JSON.parse(jsonVars.innerHTML); - jsonVars.outerHTML = ''; - window.context = json.context; - window.shortcuts = json.shortcuts; - window.url = json.url; - window.i18n = json.i18n; - window.icons = json.icons; -} - function init_normal() { - $stream = $('#stream'); - if ($stream.length < 1) { + const stream = document.getElementById('stream'); + if (!stream) { if (window.console) { console.log('FreshRSS waiting for content…'); } - window.setTimeout(init_normal, 100); + setTimeout(init_normal, 100); return; } init_column_categories(); - init_stream($stream); + init_stream(stream); init_shortcuts(); init_actualize(); faviconNbUnread(); } function init_beforeDOM() { - if (!window.$) { - if (window.console) { - console.log('FreshRSS waiting for jQuery…'); - } - window.setTimeout(init_beforeDOM, 100); - return; - } if (['normal', 'reader', 'global'].indexOf(context.current_view) >= 0) { init_normal(); } } function init_afterDOM() { - if (!window.$) { - if (window.console) { - console.log('FreshRSS waiting again for jQuery…'); - } - window.setTimeout(init_afterDOM, 100); - return; - } init_notifications(); init_confirm_action(); - $stream = $('#stream'); - if ($stream.length > 0) { - init_load_more($stream); + const stream = document.getElementById('stream'); + if (stream) { + init_load_more(stream); init_posts(); init_nav_entries(); - init_dynamic_tags(); - init_print_action(); - init_post_action(); init_notifs_html5(); - window.setInterval(refreshUnreads, 120000); - } else { - init_subscription(); - init_crypto_form(); - init_share_observers(); - init_remove_observers(); - init_feed_observers(); - init_password_observers(); - init_stats_observers(); - init_slider_observers(); - init_configuration_alert(); + setInterval(refreshUnreads, 120000); } if (window.console) { - console.log('FreshRSS init done.'); + console.log('FreshRSS main init done.'); } } -parseJsonVars(); init_beforeDOM(); //Can be called before DOM is fully loaded if (document.readyState && document.readyState !== 'loading') { init_afterDOM(); -} else if (document.addEventListener) { +} else { document.addEventListener('DOMContentLoaded', function () { - if (window.console) { - console.log('FreshRSS waiting for DOMContentLoaded…'); - } - init_afterDOM(); - }, false); + if (window.console) { + console.log('FreshRSS waiting for DOMContentLoaded…'); + } + init_afterDOM(); + }, false); } |
