97cdc67c1a
The `/` character is entered into the search field after activating it via the `keypress` event. That's unexpected behaviour. This commit fixes that by attaching the keyboard event handler to the `keyup` event.
365 lines
14 KiB
JavaScript
365 lines
14 KiB
JavaScript
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);
|
|
}
|
|
};
|
|
})();
|