miniflux-legacy/assets/js/all.js

1004 lines
34 KiB
JavaScript

/* AUTO GENERATED FILE, DO NOT MODIFY THIS FILE, USE 'make js' */
var Miniflux = {};
var DEBUG = false;
Miniflux.App = (function() {
return {
Log: function(message) {
if (DEBUG) {
console.log(message);
}
},
Run: function() {
Miniflux.Event.ListenKeyboardEvents();
Miniflux.Event.ListenMouseEvents();
Miniflux.Event.ListenVisibilityEvents();
Miniflux.Event.ListenTouchEvents();
this.FrontendUpdateCheck();
},
FrontendUpdateCheck: function() {
var request = new XMLHttpRequest();
request.onload = function() {
var response = JSON.parse(this.responseText);
if (response['frontend_updatecheck_interval'] > 0) {
Miniflux.App.Log('Frontend updatecheck interval in minutes: ' + response['frontend_updatecheck_interval']);
Miniflux.Item.CheckForUpdates();
setInterval(function(){ Miniflux.Item.CheckForUpdates(); }, response['frontend_updatecheck_interval']*60*1000);
}
else {
Miniflux.App.Log('Frontend updatecheck disabled');
}
};
request.open("POST", "?action=get-config", true);
request.send(JSON.stringify(['frontend_updatecheck_interval']));
}
};
})();
Miniflux.Feed = (function() {
// List of feeds currently updating
var queue = [];
// Number of concurrent requests when updating all feeds
var queue_length = 5;
return {
Update: function(feed, callback) {
var itemsCounter = feed.querySelector("span.items-count");
if (! itemsCounter) return;
var feed_id = feed.getAttribute("data-feed-id");
var heading = feed.querySelector("h2:first-of-type");
heading.className = "loading-icon";
var request = new XMLHttpRequest();
request.onload = function() {
heading.className = "";
feed.removeAttribute("data-feed-error");
var lastChecked = feed.querySelector(".feed-last-checked");
if (lastChecked) lastChecked.innerHTML = lastChecked.getAttribute("data-after-update");
var response = JSON.parse(this.responseText);
if (response['result']) {
itemsCounter.innerHTML = response['items_count']['items_unread'] + "/" + response['items_count']['items_total'];
} else {
feed.setAttribute("data-feed-error", "1");
}
if (callback) {
callback(response);
}
else {
Miniflux.Item.CheckForUpdates();
}
};
request.open("POST", "?action=refresh-feed&feed_id=" + feed_id, true);
request.send();
},
UpdateAll: function(nb_concurrent_requests) {
var feeds = Array.prototype.slice.call(document.querySelectorAll("article:not([data-feed-disabled])"));
// Check if a custom amount of concurrent requests was defined
if (nb_concurrent_requests) {
queue_length = nb_concurrent_requests;
}
var interval = setInterval(function() {
while (feeds.length > 0 && queue.length < queue_length) {
var feed = feeds.shift();
queue.push(parseInt(feed.getAttribute('data-feed-id'), 10));
Miniflux.Feed.Update(feed, function(response) {
var index = queue.indexOf(response['feed_id']);
if (index >= 0) queue.splice(index, 1);
if (feeds.length === 0 && queue.length === 0) {
clearInterval(interval);
Miniflux.Item.CheckForUpdates();
}
});
}
}, 100);
}
};
})();
Miniflux.Item = (function() {
// timestamp of the latest item per feed ever seen
var latest_feeds_items = {};
// indicator for new unread items
var unreadItems = false;
var nbUnreadItems = function() {
var navCounterElement = document.getElementById("nav-counter");
if (navCounterElement) {
return parseInt(navCounterElement.textContent, 10) || 0;
}
}();
var nbPageItems = function() {
var pageCounterElement = document.getElementById("page-counter");
if (pageCounterElement) {
return parseInt(pageCounterElement.textContent, 10) || 0;
}
}();
function simulateMouseClick(element)
{
var event = document.createEvent("MouseEvents");
event.initEvent("mousedown", true, true);
element.dispatchEvent(event);
event = document.createEvent("MouseEvents");
event.initEvent("mouseup", true, true);
element.dispatchEvent(event);
element.click();
}
function getItemID(item)
{
return item.getAttribute("data-item-id");
}
function changeLabel(links)
{
if (links.length === 0) {
return;
}
for (var i = 0; i < links.length; i++) {
var link = links[i];
if (link.hasAttribute("data-reverse-label")) {
var content = link.innerHTML;
link.innerHTML = link.getAttribute("data-reverse-label");
link.setAttribute("data-reverse-label", content);
}
if (link.hasAttribute("data-reverse-title")) {
var title = link.getAttribute("title");
link.setAttribute("title", link.getAttribute("data-reverse-title"));
link.setAttribute("data-reverse-title", title);
}
}
}
function changeAction(links, action)
{
if (links.length === 0) {
return;
}
for (var i = 0; i < links.length; i++) {
links[i].setAttribute("data-action", action);
}
}
function changeBookmarkLabel(item)
{
var links = item.querySelectorAll(".bookmark-icon, a.bookmark");
changeLabel(links);
}
function changeStatusLabel(item)
{
var links = item.querySelectorAll(".read-icon, a.mark");
changeLabel(links);
}
function showItemAsRead(item)
{
if (item.getAttribute("data-item-status") === 'read') {
return;
}
nbUnreadItems--;
if (item.getAttribute("data-hide")) {
hideItem(item);
return;
}
item.setAttribute("data-item-status", "read");
changeStatusLabel(item);
var links = item.querySelectorAll(".read-icon, a.mark");
changeAction(links, "mark-unread");
}
function showItemAsUnread(item)
{
if (item.getAttribute("data-item-status") === 'unread') {
return;
}
nbUnreadItems++;
if (item.getAttribute("data-hide")) {
hideItem(item);
return;
}
item.setAttribute("data-item-status", "unread");
changeStatusLabel(item);
var links = item.querySelectorAll(".read-icon, a.mark");
changeAction(links, "mark-read");
}
function hideItem(item)
{
if (Miniflux.Event.lastEventType !== "mouse") {
var items = document.getElementsByTagName("article");
if (items[items.length-1].id === "current-item") {
Miniflux.Nav.SelectPreviousItem();
}
else {
Miniflux.Nav.SelectNextItem();
}
}
item.parentNode.removeChild(item);
nbPageItems--;
}
function updateCounters()
{
var pageHeading = null;
// redirect to unread if we're on a nothing to read page
if (window.location.href.indexOf('nothing_to_read=1') > -1 && nbUnreadItems > 0) {
window.location.href = '?action=unread';
} // reload to get a nothing to read page
else if (nbPageItems === 0) {
window.location.reload();
}
var pageCounterElement = document.getElementById("page-counter");
if (pageCounterElement) pageCounterElement.textContent = nbPageItems || '';
var navCounterElement = document.getElementById("nav-counter");
navCounterElement.textContent = nbUnreadItems || '';
var pageHeadingElement = document.querySelector("div.page-header h2:first-of-type");
if (pageHeadingElement) {
pageHeading = pageHeadingElement.firstChild.nodeValue;
}
else {
// special handling while viewing an article.
// 1. The article does not have a page-header element
// 2. An article could be opened from any page and has the original
// page as data-item-page value
var itemHeading = document.querySelector("article.item h1:first-of-type");
if (itemHeading) {
document.title = itemHeading.textContent;
return;
}
}
// pagetitle depends on current page
var sectionElement = document.querySelector("section.page");
switch (sectionElement.getAttribute("data-item-page")) {
case "unread":
document.title = "Miniflux (" + nbUnreadItems + ")";
break;
case "feed-items":
document.title = "(" + nbPageItems + ") " + pageHeading;
break;
default:
if (pageCounterElement) {
document.title = pageHeading + " (" + nbPageItems + ")";
}
else {
document.title = pageHeading;
}
break;
}
}
function markAsRead(item)
{
var item_id = getItemID(item);
var request = new XMLHttpRequest();
request.onload = function() {
if (Miniflux.Nav.IsListing()) {
showItemAsRead(item);
updateCounters();
}
};
request.open("POST", "?action=mark-item-read&id=" + item_id, true);
request.send();
}
function markAsUnread(item)
{
var item_id = getItemID(item);
var request = new XMLHttpRequest();
request.onload = function() {
if (Miniflux.Nav.IsListing()) {
showItemAsUnread(item);
updateCounters();
}
};
request.open("POST", "?action=mark-item-unread&id=" + item_id, true);
request.send();
}
function markAsRemoved(item)
{
var item_id = getItemID(item);
var request = new XMLHttpRequest();
request.onload = function() {
if (Miniflux.Nav.IsListing()) {
hideItem(item);
if (item.getAttribute("data-item-status") === "unread") nbUnreadItems--;
updateCounters();
}
};
request.open("POST", "?action=mark-item-removed&id=" + item_id, true);
request.send();
}
return {
MarkAsRead: markAsRead,
MarkAsUnread: markAsUnread,
MarkAsRemoved: markAsRemoved,
SwitchBookmark: function(item) {
var item_id = getItemID(item);
var value = item.getAttribute("data-item-bookmark") === "1" ? "0" : "1";
var request = new XMLHttpRequest();
request.onload = function() {
var sectionElement = document.querySelector("section.page");
if (Miniflux.Nav.IsListing() && sectionElement.getAttribute("data-item-page") === "bookmarks") {
hideItem(item);
updateCounters();
} else {
item.setAttribute("data-item-bookmark", value);
changeBookmarkLabel(item);
}
};
request.open("POST", "?action=bookmark&id=" + item_id + "&value=" + value, true);
request.send();
},
SwitchStatus: function(item) {
var status = item.getAttribute("data-item-status");
if (status === "read") {
markAsUnread(item);
}
else if (status === "unread") {
markAsRead(item);
}
},
Show: function(item) {
var link = item.querySelector("a.show");
if (link) simulateMouseClick(link);
},
OpenOriginal: function(item) {
var link = item.querySelector("a.original");
if (link) simulateMouseClick(link)
},
DownloadContent: function(item) {
var container = document.getElementById("download-item");
if (! container) return;
container.innerHTML = " " + container.getAttribute("data-before-message");
container.className = "loading-icon";
var request = new XMLHttpRequest();
request.onload = function() {
var response = JSON.parse(request.responseText);
container.className = "";
if (response['result']) {
var content = document.getElementById("item-content");
if (content) content.innerHTML = response['content'];
container.innerHTML = container.getAttribute("data-after-message");
}
else {
container.innerHTML = container.getAttribute("data-failure-message");
}
};
var item_id = getItemID(item);
request.open("POST", "?action=download-item&id=" + item_id, true);
request.send();
},
MarkFeedAsRead: function(feed_id) {
var request = new XMLHttpRequest();
request.onload = function() {
var articles = document.getElementsByTagName("article");
for (var i = 0, ilen = articles.length; i < ilen; i++) {
showItemAsRead(articles[i]);
}
nbUnreadItems = this.responseText;
updateCounters();
};
request.open("POST", "?action=mark-feed-as-read&feed_id=" + feed_id, true);
request.send();
},
ToggleRTLMode: function() {
var tags = [
"#current-item h1",
"#item-content",
"#listing #current-item h2",
"#listing #current-item .preview",
"#listing #current-item .preview-full-content"
];
for (var i = 0; i < tags.length; i++) {
var tag = document.querySelector(tags[i]);
if (tag) {
tag.dir = tag.dir == "" ? "rtl" : "";
}
}
},
hasNewUnread: function() {
return unreadItems;
},
CheckForUpdates: function() {
if (document.hidden && unreadItems) {
Miniflux.App.Log('We already have updates, no need to check again');
return;
}
var request = new XMLHttpRequest();
request.onload = function() {
var first_run = (latest_feeds_items.length === 0);
var current_unread = false;
var response = JSON.parse(this.responseText);
var last_items_timestamps = response['last_items_timestamps'];
for (var i = 0; i < last_items_timestamps.length; i++) {
var current_feed = last_items_timestamps[i];
var feed_id = current_feed.feed_id;
if (! latest_feeds_items.hasOwnProperty(feed_id) || current_feed.updated > latest_feeds_items[feed_id]) {
latest_feeds_items[feed_id] = current_feed.updated;
current_unread = true;
}
}
Miniflux.App.Log('first_run: ' + first_run + ', current_unread: ' + current_unread + ', response.nbUnread: ' + response['nbUnread'] + ', nbUnreadItems: ' + nbUnreadItems);
if (! document.hidden && (response['nb_unread_items'] !== nbUnreadItems || unreadItems)) {
Miniflux.App.Log('Counter changed! Updating unread counter.');
unreadItems = false;
nbUnreadItems = response['nb_unread_items'];
updateCounters();
}
else if (document.hidden && ! first_run && current_unread) {
Miniflux.App.Log('New Unread! Updating pagetitle.');
unreadItems = true;
document.title = "↻ " + document.title;
}
else {
Miniflux.App.Log('No update.');
}
Miniflux.App.Log('unreadItems: ' + unreadItems);
};
request.open("GET", "?action=latest-feeds-items", true);
request.send();
}
};
})();
Miniflux.Event = (function() {
var queue = [];
function isEventIgnored(e)
{
if (e.keyCode !== 63 && e.which !== 63 && (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey)) {
return true;
}
// Do not handle events when there is a focus in form fields
var target = e.target || e.srcElement;
return !!(target.tagName === 'INPUT' || target.tagName === 'TEXTAREA');
}
return {
lastEventType: "",
ListenMouseEvents: function() {
document.onclick = function(e) {
if (e.target.hasAttribute("data-action") && e.target.className !== 'original') {
e.preventDefault();
}
};
document.onmouseup = function(e) {
// Ignore right mouse button (context menu)
if (e.button === 2) {
return;
}
// Auto-select input content
if (e.target.nodeName === "INPUT" && e.target.className === "auto-select") {
e.target.select();
return;
}
// Application actions
var action = e.target.getAttribute("data-action");
if (action) {
Miniflux.Event.lastEventType = "mouse";
var currentItem = function () {
var element = e.target;
while (element && element.parentNode) {
element = element.parentNode;
if (element.tagName && element.tagName.toLowerCase() === 'article') {
return element;
}
}
}();
switch (action) {
case 'refresh-all':
Miniflux.Feed.UpdateAll(e.target.getAttribute("data-concurrent-requests"));
break;
case 'refresh-feed':
currentItem && Miniflux.Feed.Update(currentItem);
break;
case 'mark-read':
currentItem && Miniflux.Item.MarkAsRead(currentItem);
break;
case 'mark-unread':
currentItem && Miniflux.Item.MarkAsUnread(currentItem);
break;
case 'mark-removed':
currentItem && Miniflux.Item.MarkAsRemoved(currentItem);
break;
case 'bookmark':
currentItem && Miniflux.Item.SwitchBookmark(currentItem);
break;
case 'download-item':
currentItem && Miniflux.Item.DownloadContent(currentItem);
break;
case 'mark-feed-read':
var feed_id = document.getElementById('listing').getAttribute('data-feed-id');
Miniflux.Item.MarkFeedAsRead(feed_id);
break;
case 'close-help':
Miniflux.Nav.CloseHelp();
break;
case 'show-search':
Miniflux.Nav.ShowSearch();
break;
case 'toggle-menu-more':
Miniflux.Nav.ToggleMenuMore();
break;
}
}
};
},
ListenKeyboardEvents: function() {
document.onkeypress = function(e) {
if (isEventIgnored(e)) {
return;
}
Miniflux.Event.lastEventType = "keyboard";
queue.push(e.key || e.which);
if (queue[0] === 'g' || queue[0] === 103) {
switch (queue[1]) {
case undefined:
break;
case 'u':
case 117:
window.location.href = "?action=unread";
queue = [];
break;
case 'b':
case 98:
window.location.href = "?action=bookmarks";
queue = [];
break;
case 'h':
case 104:
window.location.href = "?action=history";
queue = [];
break;
case 's':
case 115:
window.location.href = "?action=feeds";
queue = [];
break;
case 'p':
case 112:
window.location.href = "?action=config";
queue = [];
break;
default:
queue = [];
break;
}
}
else {
queue = [];
var currentItem = function () {
return document.getElementById("current-item");
}();
switch (e.key || e.which) {
case 'd':
case 100:
currentItem && Miniflux.Item.DownloadContent(currentItem);
break;
case 'p':
case 112:
case 'k':
case 107:
Miniflux.Nav.SelectPreviousItem();
break;
case 'n':
case 110:
case 'j':
case 106:
Miniflux.Nav.SelectNextItem();
break;
case 'v':
case 118:
currentItem && Miniflux.Item.OpenOriginal(currentItem);
break;
case 'o':
case 111:
currentItem && Miniflux.Item.Show(currentItem);
break;
case 'm':
case 109:
currentItem && Miniflux.Item.SwitchStatus(currentItem);
break;
case 'f':
case 102:
currentItem && Miniflux.Item.SwitchBookmark(currentItem);
break;
case 'h':
case 104:
Miniflux.Nav.OpenPreviousPage();
break;
case 'l':
case 108:
Miniflux.Nav.OpenNextPage();
break;
case 'r':
case 114:
Miniflux.Feed.UpdateAll();
break;
case '?':
case 63:
Miniflux.Nav.ShowHelp();
break;
case 'Q':
case 81: // Q
case 'q':
case 113: // q
Miniflux.Nav.CloseHelp();
break;
case 'z':
case 122:
Miniflux.Item.ToggleRTLMode();
break;
}
}
};
document.onkeydown = function(e) {
if (isEventIgnored(e)) {
return;
}
Miniflux.Event.lastEventType = "keyboard";
switch (e.key || e.which) {
case "ArrowLeft":
case "Left":
case 37:
Miniflux.Nav.SelectPreviousItem();
break;
case "ArrowRight":
case "Right":
case 39:
Miniflux.Nav.SelectNextItem();
break;
}
};
document.onkeyup = function(e) {
if (isEventIgnored(e)) {
return;
}
Miniflux.Event.lastEventType = "keyboard";
switch (e.key || e.which) {
case '/':
case 47:
Miniflux.Nav.ShowSearch();
break;
}
};
},
ListenVisibilityEvents: function() {
document.addEventListener('visibilitychange', function() {
Miniflux.App.Log('document.visibilityState: ' + document.visibilityState);
if (!document.hidden && Miniflux.Item.hasNewUnread()) {
Miniflux.App.Log('Need to update the unread counter with fresh values from the database');
Miniflux.Item.CheckForUpdates();
}
});
},
ListenTouchEvents: function() {
var touches = null;
var resetTouch = function () {
touches && touches.element && (touches.element.style.opacity = 1);
touches && touches.element && (touches.element.style.transform = "");
touches = {
"touchstart": {"x":-1, "y":-1},
"touchmove" : {"x":-1, "y":-1},
"touchend" : false,
"direction" : "undetermined",
"swipestarted" : false,
"element" : null
};
};
var horizontalSwipe = function () {
if((touches.touchstart.x > -1 && touches.touchmove.x > -1 &&
((touches.touchmove.x - touches.touchstart.x) > 30 | touches.swipestarted) &&
Math.abs(touches.touchmove.y - touches.touchstart.y) < 75)) {
touches.swipestarted = true;
return touches.touchmove.x - touches.touchstart.x;
}
return 0;
};
var closest = function(el, fn) {
return el && (fn(el) ? el : closest(el.parentNode, fn));
};
var getTouchElement = function() {
return touches.element ? touches.element :
closest(document.elementFromPoint(touches.touchstart.x, touches.touchstart.y),
function(el) {
return el.tagName === 'ARTICLE';
});
};
var drawElement = function(){
if(touches &&
(touches.touchend === true || touches.touchstart.x == -1)) {
return;
}
if(touches.element === null) {
touches.element = getTouchElement();
}
var swipedistance = horizontalSwipe();
if(swipedistance > 0) {
var element = getTouchElement();
if(!element) {resetTouch(); return;}
touches.element.style.opacity = 1 -
((swipedistance > 75) ? 0.9 : swipedistance/75 *0.9);
touches.element.style.transform = "translateX("+
(swipedistance > 75 ? 75 : swipedistance)+"px)";
touches.element = element;
}
window.requestAnimationFrame(drawElement);
};
var touchHandler = function (e) {
if (typeof e.touches != 'undefined' && e.touches.length <= 1) {
var touch = e.touches[0];
var swipedistance = null;
var element = null;
switch (e.type) {
case 'touchstart':
resetTouch();
touches[e.type].x = touch.clientX;
touches[e.type].y = touch.clientY;
drawElement();
break;
case 'touchmove':
touches[e.type].x = touch.clientX;
touches[e.type].y = touch.clientY;
break;
case 'touchend':
touches[e.type] = true;
element = getTouchElement();
swipedistance = horizontalSwipe();
if(swipedistance > 75) {
element && Miniflux.Item.MarkAsRead(element);
if(!element.getAttribute("data-hide")){
resetTouch();
}
} else {
resetTouch();
}
break;
case 'touchcancel':
resetTouch();
break;
default:
break;
}
} else {
resetTouch();
}
};
resetTouch();
document.addEventListener('touchstart', touchHandler, false);
document.addEventListener('touchmove', touchHandler, false);
document.addEventListener('touchend', touchHandler, false);
document.addEventListener('touchcancel', touchHandler, false);
}
};
})();
Miniflux.Nav = (function() {
function scrollPageTo(item)
{
var clientHeight = pageYOffset + document.documentElement.clientHeight;
var itemPosition = item.offsetTop + item.offsetHeight;
if (clientHeight - itemPosition < 0 || clientHeight - item.offsetTop > document.documentElement.clientHeight) {
window.scrollTo(0, item.offsetTop - 10);
}
}
function findNextItem()
{
var items = document.getElementsByTagName("article");
if (! document.getElementById("current-item")) {
items[0].id = "current-item";
scrollPageTo(items[0]);
}
else {
for (var i = 0, ilen = items.length; i < ilen; i++) {
if (items[i].id === "current-item") {
if (i + 1 < ilen) {
items[i].id = "item-" + items[i].getAttribute("data-item-id");
items[i + 1].id = "current-item";
scrollPageTo(items[i + 1]);
}
break;
}
}
}
}
function findPreviousItem()
{
var items = document.getElementsByTagName("article");
if (! document.getElementById("current-item")) {
items[items.length - 1].id = "current-item";
scrollPageTo(items[items.length - 1]);
}
else {
for (var i = items.length - 1; i >= 0; i--) {
if (items[i].id === "current-item") {
if (i - 1 >= 0) {
items[i].id = "item-" + items[i].getAttribute("data-item-id");
items[i - 1].id = "current-item";
scrollPageTo(items[i - 1]);
}
break;
}
}
}
}
function isListing()
{
return !!document.getElementById("listing");
}
return {
OpenNextPage: function() {
var link = document.getElementById("next-page");
if (link) link.click();
},
OpenPreviousPage: function() {
var link = document.getElementById("previous-page");
if (link) link.click();
},
SelectNextItem: function() {
var link = document.getElementById("next-item");
if (link) {
link.click();
}
else if (isListing()) {
findNextItem();
}
},
SelectPreviousItem: function() {
var link = document.getElementById("previous-item");
if (link) {
link.click();
}
else if (isListing()) {
findPreviousItem();
}
},
ShowHelp: function() {
var help_layer = document.getElementById("help-layer");
help_layer.removeAttribute("class");
},
CloseHelp: function() {
var help_layer = document.getElementById("help-layer");
help_layer.setAttribute("class", "hide");
},
ShowSearch: function() {
document.getElementById("search-opener").setAttribute("class", "hide");
document.getElementById("search-form").removeAttribute("class");
document.getElementById("form-text").focus();
},
ToggleMenuMore: function () {
var menu = document.getElementById("menu-more");
menu.hasAttribute("class")
? menu.removeAttribute("class")
: menu.setAttribute("class", "hide");
},
IsListing: isListing
};
})();
Miniflux.App.Run();