aboutsummaryrefslogtreecommitdiff
path: root/p/scripts/main.js
diff options
context:
space:
mode:
Diffstat (limited to 'p/scripts/main.js')
-rw-r--r--p/scripts/main.js208
1 files changed, 121 insertions, 87 deletions
diff --git a/p/scripts/main.js b/p/scripts/main.js
index f59976b39..d85a3ae15 100644
--- a/p/scripts/main.js
+++ b/p/scripts/main.js
@@ -2,6 +2,7 @@
/* jshint esversion:6, strict:global */
//<Polyfills>
+if (!document.scrollingElement) document.scrollingElement = document.documentElement;
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) {
@@ -44,18 +45,20 @@ var context;
}());
//</Global context>
-function badAjax() {
+function badAjax(reload) {
openNotification(context.i18n.notif_request_failed, 'bad');
- location.reload();
+ if (reload) {
+ setTimeout(function () { location.reload(); }, 2000);
+ }
return true;
}
function needsScroll(elem) {
- const winBottom = document.documentElement.scrollTop + document.documentElement.clientHeight,
+ const winBottom = document.scrollingElement.scrollTop + document.scrollingElement.clientHeight,
elemTop = elem.offsetParent.offsetTop + elem.offsetTop,
elemBottom = elemTop + elem.offsetHeight;
- return (elemTop < document.documentElement.scrollTop || elemBottom > winBottom) ?
- elemTop - (document.documentElement.clientHeight / 2) : 0;
+ return (elemTop < document.scrollingElement.scrollTop || elemBottom > winBottom) ?
+ elemTop - (document.scrollingElement.clientHeight / 2) : 0;
}
function str2int(str) {
@@ -159,6 +162,29 @@ function incUnreadsTag(tag_id, nb) {
}
}
+function removeArticle(div) {
+ if (!div || div.classList.contains('not_read') || (context.auto_mark_article && div.classList.contains('active'))) {
+ return;
+ }
+ let scrollTop = box_to_follow.scrollTop;
+ let dirty = false;
+ const p = div.previousElementSibling,
+ n = div.nextElementSibling;
+ if (p && p.classList.contains('day') && n && n.classList.contains('day')) {
+ scrollTop -= p.offsetHeight;
+ dirty = true;
+ p.remove();
+ }
+ if (div.offsetHeight > 0 && div.offsetParent.offsetTop + div.offsetTop + div.offsetHeight < scrollTop) {
+ scrollTop -= div.offsetHeight;
+ dirty = true;
+ }
+ div.remove();
+ if (dirty) {
+ box_to_follow.scrollTop = scrollTop;
+ }
+}
+
var pending_entries = {},
mark_read_queue = [];
@@ -167,19 +193,19 @@ function send_mark_read_queue(queue, asRead, callback) {
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();
- }
+ badAjax(this.status == 403);
};
req.onload = function (e) {
if (this.status != 200) {
return req.onerror(e);
}
const json = xmlHttpRequestJson(this);
+ if (!json) {
+ return req.onerror(e);
+ }
for (let i = queue.length - 1; i >= 0; i--) {
const div = document.getElementById('flux_' + queue[i]),
myIcons = context.icons;
@@ -191,6 +217,9 @@ function send_mark_read_queue(queue, asRead, callback) {
});
div.querySelectorAll('a.read > .icon').forEach(function (img) { img.outerHTML = myIcons.read; });
inc--;
+ if (context.auto_remove_article) {
+ removeArticle(div);
+ }
} else {
div.classList.add('not_read');
div.classList.add('keep_unread'); //Split for IE11
@@ -237,14 +266,15 @@ function send_mark_queue_tick(callback) {
mark_read_queue = [];
send_mark_read_queue(queue, true, callback);
}
+var delayedFunction = send_mark_queue_tick;
function delayedClick(a) {
if (a) {
- send_mark_queue_tick(function () { a.click(); });
+ delayedFunction(function () { a.click(); });
}
}
-function mark_read(div, only_not_read) {
+function mark_read(div, only_not_read, asBatch) {
if (!div || !div.id || context.anonymous ||
(only_not_read && !div.classList.contains('not_read'))) {
return false;
@@ -256,7 +286,7 @@ function mark_read(div, only_not_read) {
const asRead = div.classList.contains('not_read'),
entryId = div.id.replace(/^flux_/, '');
- if (asRead) {
+ if (asRead && asBatch) {
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);
@@ -287,17 +317,17 @@ function mark_favorite(div) {
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();
- }
+ badAjax(this.status == 403);
};
req.onload = function (e) {
if (this.status != 200) {
return req.onerror(e);
}
const json = xmlHttpRequestJson(this);
+ if (!json) {
+ return req.onerror(e);
+ }
let inc = 0;
if (div.classList.contains('favorite')) {
div.classList.remove('favorite');
@@ -357,21 +387,23 @@ function toggleContent(new_active, old_active, skipping) {
if (old_active) {
old_active.classList.remove('active');
old_active.classList.remove('current'); //Split for IE11
+ if (context.auto_remove_article) {
+ removeArticle(old_active);
+ }
}
} else {
new_active.classList.toggle('active');
}
const relative_move = context.current_view === 'global',
- box_to_move = relative_move ? document.getElementById('panel') : document.documentElement;
+ box_to_move = relative_move ? document.getElementById('panel') : document.scrollingElement;
- if (context.sticky_post) {
+ if (context.sticky_post) { //Stick the article to the top when opened
let prev_article = new_active.previousElementSibling,
- new_pos = new_active.offsetTop + document.documentElement.scrollTop,
- old_scroll = box_to_move.scrollTop;
+ new_pos = new_active.offsetParent.offsetTop + new_active.offsetTop;
if (prev_article && new_active.offsetTop - prev_article.offsetTop <= 150) {
- new_pos = prev_article.offsetTop;
+ new_pos = prev_article.offsetParent.offsetTop + prev_article.offsetTop;
if (relative_move) {
new_pos -= box_to_move.offsetTop;
}
@@ -382,14 +414,14 @@ function toggleContent(new_active, old_active, skipping) {
new_pos -= document.body.clientHeight / 4;
}
if (relative_move) {
- new_pos += old_scroll;
+ new_pos += box_to_move.scrollTop;
}
box_to_move.scrollTop = new_pos;
}
if (new_active.classList.contains('active') && !skipping) {
if (context.auto_mark_article) {
- mark_read(new_active, true);
+ mark_read(new_active, true, true);
}
new_active.dispatchEvent(freshrssOpenArticleEvent);
}
@@ -529,7 +561,7 @@ function user_filter(key) {
// Force scrolling to the filter div
const scroll = needsScroll(document.querySelector('.header'));
if (scroll !== 0) {
- document.documentElement.scrollTop = scroll;
+ document.scrollingElement.scrollTop = scroll;
}
// Force the key value if there is only one action, so we can trigger it automatically
if (filters.length === 1) {
@@ -557,7 +589,7 @@ function auto_share(key) {
// Force scrolling to the share div
const scrollTop = needsScroll(share.closest('.bottom'));
if (scrollTop !== 0) {
- document.documentElement.scrollTop = scrollTop;
+ document.scrollingElement.scrollTop = scrollTop;
}
// Force the key value if there is only one action, so we can trigger it automatically
if (shares.length === 1) {
@@ -585,30 +617,9 @@ function onScroll() {
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();
+ mark_read(div, true, true);
}
});
- 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');
@@ -621,10 +632,10 @@ function onScroll() {
function init_posts() {
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;
+ box_to_follow = context.current_view === 'global' ? document.getElementById('panel') : document.scrollingElement;
let lastScroll = 0, //Throttle
timerId = 0;
- (box_to_follow === document.documentElement ? window : box_to_follow).onscroll = function () {
+ (box_to_follow === document.scrollingElement ? window : box_to_follow).onscroll = function () {
clearTimeout(timerId);
if (lastScroll + 500 < Date.now()) {
lastScroll = Date.now();
@@ -681,7 +692,10 @@ function init_column_categories() {
a.href = '#dropdown-' + id;
div.querySelector('.dropdown-target').id = 'dropdown-' + id;
div.insertAdjacentHTML('beforeend', template);
- div.querySelector('button.confirm').disabled = false;
+ const b = div.querySelector('button.confirm');
+ if (b) {
+ b.disabled = false;
+ }
} else if (getComputedStyle(dropdownMenu).display === 'none') {
const id2 = div.closest('.item').id.substr(2);
a.href = '#dropdown-' + id2;
@@ -745,7 +759,7 @@ function init_shortcuts() {
} 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);
+ mark_read(document.querySelector('.flux.current'), false, false);
}
return false;
}
@@ -787,7 +801,7 @@ function init_shortcuts() {
}
if (k === s.go_website) {
if (context.auto_mark_site) {
- mark_read(document.querySelector('.flux.current'), true);
+ mark_read(document.querySelector('.flux.current'), true, false);
}
window.open(document.querySelector('.flux.current a.go_website').href);
return false;
@@ -813,7 +827,7 @@ function init_stream(stream) {
stream.onclick = function (ev) {
let el = ev.target.closest('.flux a.read');
if (el) {
- mark_read(el.closest('.flux'), false);
+ mark_read(el.closest('.flux'), false, false);
return false;
}
@@ -882,7 +896,7 @@ function init_stream(stream) {
new_active = el.parentNode;
if (ev.target.tagName.toUpperCase() === 'A') { //Leave real links alone
if (context.auto_mark_article) {
- mark_read(new_active, true);
+ mark_read(new_active, true, false);
}
return true;
}
@@ -891,21 +905,28 @@ function init_stream(stream) {
}
};
- stream.onmouseup = function (ev) { // Mouseup enables us to catch middle click
+ stream.onmouseup = function (ev) { // Mouseup enables us to catch middle click, and control+click in IE/Edge
+ if (ev.altKey || ev.metaKey || ev.shiftKey) {
+ return;
+ }
+
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 (ev.which == 1) {
+ if (ev.ctrlKey) { //Control+click
+ if (context.auto_mark_site) {
+ mark_read(el.closest('.flux'), true, false);
+ }
+ } else {
+ el.parentElement.click(); //Normal click, just toggle article.
+ }
+ } else if (ev.which == 2 && !ev.ctrlKey) { //Simple middle click: same behaviour as CTRL+click
+ if (context.auto_mark_article) {
+ const new_active = el.closest('.flux');
+ mark_read(new_active, true, false);
+ }
}
+ return;
}
if (context.auto_mark_site) {
@@ -916,7 +937,7 @@ function init_stream(stream) {
if (ev.which == 3) {
return;
}
- mark_read(el.closest('.flux'), true);
+ mark_read(el.closest('.flux'), true, false);
}
}
};
@@ -937,9 +958,7 @@ function init_stream(stream) {
req.responseType = 'json';
req.onerror = function (e) {
checkboxTag.checked = !isChecked;
- if (this.status == 403) {
- badAjax();
- }
+ badAjax(this.status == 403);
};
req.onload = function (e) {
if (this.status != 200) {
@@ -980,10 +999,10 @@ function init_nav_entries() {
};
nav_entries.querySelector('.up').onclick = function (e) {
const active_item = document.querySelector('.flux.current'),
- windowTop = document.documentElement.scrollTop,
+ windowTop = document.scrollingElement.scrollTop,
item_top = active_item.offsetParent.offsetTop + active_item.offsetTop;
- document.documentElement.scrollTop = windowTop > item_top ? item_top : 0;
+ document.scrollingElement.scrollTop = windowTop > item_top ? item_top : 0;
return false;
};
}
@@ -1006,6 +1025,9 @@ function loadDynamicTags(div) {
return req.onerror(e);
}
const json = xmlHttpRequestJson(this);
+ if (!json) {
+ return req.onerror(e);
+ }
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++) {
@@ -1031,7 +1053,7 @@ function updateFeed(feeds, feeds_count) {
req.open('POST', feed.url, true);
req.onloadend = function (e) {
if (this.status != 200) {
- return badAjax();
+ return badAjax(false);
}
feed_processed++;
const div = document.getElementById('actualizeProgress');
@@ -1042,7 +1064,7 @@ function updateFeed(feeds, feeds_count) {
const req2 = new XMLHttpRequest();
req2.open('POST', './?c=feed&a=actualize&id=-1&ajax=1', true);
req2.onloadend = function (e) {
- location.reload();
+ delayedFunction(function () { location.reload(); });
};
req2.setRequestHeader('Content-Type', 'application/json');
req2.send(JSON.stringify({
@@ -1074,9 +1096,12 @@ function init_actualize() {
req.responseType = 'json';
req.onload = function (e) {
if (this.status != 200) {
- return badAjax();
+ return badAjax(false);
}
const json = xmlHttpRequestJson(this);
+ if (!json) {
+ return badAjax(false);
+ }
if (auto && json.feeds.length < 1) {
auto = false;
context.ajax_loading = false;
@@ -1184,10 +1209,12 @@ function notifs_html5_show(nb) {
});
notification.onclick = function () {
- location.reload();
- window.focus();
- notification.close();
- };
+ delayedFunction(function() {
+ location.reload();
+ window.focus();
+ notification.close();
+ });
+ };
if (context.html5_notif_timeout !== 0) {
setTimeout(function () {
@@ -1211,6 +1238,9 @@ function refreshUnreads() {
req.responseType = 'json';
req.onload = function (e) {
const json = xmlHttpRequestJson(this);
+ if (!json) {
+ return badAjax(false);
+ }
const isAll = document.querySelector('.category.all.active');
let new_articles = false;
@@ -1286,12 +1316,11 @@ function load_more_posts() {
paginationNew = streamAdopted.querySelector('.pagination');
formPagination.replaceChild(paginationNew, paginationOld);
- 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) {
+ const bigMarkAsRead = document.getElementById('bigMarkAsRead');
+ if (bigMarkAsRead) {
+ if (context.display_order === 'ASC') {
+ document.querySelector('#nav_menu_read_all .read_all').formAction = bigMarkAsRead.formAction;
+ } else {
bigMarkAsRead.formAction = document.querySelector('#nav_menu_read_all .read_all').formAction;
}
}
@@ -1305,8 +1334,7 @@ function load_more_posts() {
init_load_more(box_load_more);
- const bigMarkAsRead = document.getElementById('bigMarkAsRead'),
- div_load_more = document.getElementById('load_more');
+ const div_load_more = document.getElementById('load_more');
if (bigMarkAsRead) {
bigMarkAsRead.removeAttribute('disabled');
}
@@ -1407,6 +1435,12 @@ function init_normal() {
init_shortcuts();
init_actualize();
faviconNbUnread();
+
+ window.onbeforeunload = function (e) {
+ if (mark_read_queue && mark_read_queue.length > 0) {
+ return false;
+ }
+ };
}
function init_beforeDOM() {