76a2202a20
search field in web apps, e. g. DuckDuckGo or Google Plus. Some editors and pagers use the same shortcut (Vim, less, ...). This commit adds an event handler for the pressed / key which calls the `ShowSearch()` function.
353 lines
14 KiB
JavaScript
353 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 '/':
|
|
case 47:
|
|
Miniflux.Nav.ShowSearch();
|
|
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;
|
|
}
|
|
};
|
|
},
|
|
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);
|
|
}
|
|
};
|
|
})();
|