Add keyboard shortcuts
This commit is contained in:
parent
93ce3e170a
commit
94c1beb19e
@ -234,6 +234,12 @@ textarea.form-error {
|
||||
border-color: #bce8f1;
|
||||
}
|
||||
|
||||
.alert-normal {
|
||||
color: #333;
|
||||
background-color: #f0f0f0;
|
||||
border-color: #ddd;
|
||||
}
|
||||
|
||||
|
||||
/* buttons */
|
||||
.btn {
|
||||
@ -389,6 +395,11 @@ nav .active a {
|
||||
font-family: Georgia, serif;
|
||||
}
|
||||
|
||||
.items #current-item {
|
||||
border: 2px dashed #d14;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
|
||||
/* item */
|
||||
.item {
|
||||
|
@ -5,18 +5,36 @@
|
||||
var queue_length = 5;
|
||||
|
||||
|
||||
function switch_status(item_id)
|
||||
{
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
request.onreadystatechange = function() {
|
||||
|
||||
if (request.readyState === 4) {
|
||||
|
||||
var response = JSON.parse(request.responseText);
|
||||
|
||||
if (response.status == "read" || response.status == "unread") {
|
||||
|
||||
find_next_item();
|
||||
remove_item(response.item_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request.open("POST", "?action=status&id=" + item_id, true);
|
||||
request.send();
|
||||
}
|
||||
|
||||
|
||||
function mark_as_read(item_id)
|
||||
{
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
request.onload = function() {
|
||||
|
||||
var article = document.getElementById("item-" + item_id);
|
||||
|
||||
if (article) {
|
||||
|
||||
article.style.display = "none";
|
||||
}
|
||||
remove_item(item_id);
|
||||
};
|
||||
|
||||
request.open("POST", "?action=read&id=" + item_id, true);
|
||||
@ -24,6 +42,15 @@
|
||||
}
|
||||
|
||||
|
||||
function mark_as_unread(item_id)
|
||||
{
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
request.open("POST", "?action=unread&id=" + item_id, true);
|
||||
request.send();
|
||||
}
|
||||
|
||||
|
||||
function show_refresh_icon(feed_id)
|
||||
{
|
||||
var container = document.getElementById("loading-feed-" + feed_id);
|
||||
@ -137,6 +164,157 @@
|
||||
}
|
||||
|
||||
|
||||
function remove_item(item_id)
|
||||
{
|
||||
var item = document.getElementById("item-" + item_id);
|
||||
if (item) item.parentNode.removeChild(item);
|
||||
}
|
||||
|
||||
|
||||
function open_original_item()
|
||||
{
|
||||
var link = document.getElementById("original-item");
|
||||
|
||||
if (link) {
|
||||
|
||||
mark_as_read(link.getAttribute("data-item-id"));
|
||||
find_next_item();
|
||||
link.click();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function open_item()
|
||||
{
|
||||
var link = document.getElementById("open-item");
|
||||
if (link) link.click();
|
||||
}
|
||||
|
||||
|
||||
function open_next_item()
|
||||
{
|
||||
var link = document.getElementById("next-item");
|
||||
|
||||
if (link) {
|
||||
|
||||
link.click();
|
||||
}
|
||||
else if (is_listing()) {
|
||||
|
||||
find_next_item();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function open_previous_item()
|
||||
{
|
||||
var link = document.getElementById("previous-item");
|
||||
|
||||
if (link) {
|
||||
|
||||
link.click();
|
||||
}
|
||||
else if (is_listing()) {
|
||||
|
||||
find_previous_item();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function change_item_status()
|
||||
{
|
||||
var item = document.getElementById("current-item");
|
||||
if (item) switch_status(item.getAttribute("data-item-id"));
|
||||
}
|
||||
|
||||
|
||||
function set_links_item(item_id)
|
||||
{
|
||||
var link = document.getElementById("original-item");
|
||||
if (link) link.id = "original-" + link.getAttribute("data-item-id");
|
||||
|
||||
var link = document.getElementById("open-item");
|
||||
if (link) link.id = "open-" + link.getAttribute("data-item-id");
|
||||
|
||||
var link = document.getElementById("original-" + item_id);
|
||||
if (link) link.id = "original-item";
|
||||
|
||||
var link = document.getElementById("open-" + item_id);
|
||||
if (link) link.id = "open-item";
|
||||
}
|
||||
|
||||
|
||||
function find_next_item()
|
||||
{
|
||||
var items = document.getElementsByTagName("article");
|
||||
|
||||
if (! document.getElementById("current-item")) {
|
||||
|
||||
items[0].id = "current-item";
|
||||
set_links_item(items[0].getAttribute("data-item-id"));
|
||||
}
|
||||
else {
|
||||
|
||||
for (var i = 0, ilen = items.length; i < ilen; i++) {
|
||||
|
||||
if (items[i].id == "current-item") {
|
||||
|
||||
items[i].id = "item-" + items[i].getAttribute("data-item-id");
|
||||
|
||||
if (i + 1 < ilen) {
|
||||
|
||||
items[i + 1].id = "current-item";
|
||||
set_links_item(items[i + 1].getAttribute("data-item-id"));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function find_previous_item()
|
||||
{
|
||||
var items = document.getElementsByTagName("article");
|
||||
|
||||
if (! document.getElementById("current-item")) {
|
||||
|
||||
items[items.length - 1].id = "current-item";
|
||||
set_links_item(items[items.length - 1].getAttribute("data-item-id"));
|
||||
}
|
||||
else {
|
||||
|
||||
for (var i = items.length - 1; i >= 0; i--) {
|
||||
|
||||
if (items[i].id == "current-item") {
|
||||
|
||||
items[i].id = "item-" + items[i].getAttribute("data-item-id");
|
||||
|
||||
if (i - 1 >= 0) {
|
||||
|
||||
items[i - 1].id = "current-item";
|
||||
set_links_item(items[i - 1].getAttribute("data-item-id"));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function is_listing()
|
||||
{
|
||||
if (document.getElementById("listing")) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
document.onclick = function(e) {
|
||||
|
||||
var action = e.target.getAttribute("data-action");
|
||||
@ -161,4 +339,25 @@
|
||||
}
|
||||
};
|
||||
|
||||
document.onkeypress = function(e) {
|
||||
|
||||
switch (e.keyCode || e.which) {
|
||||
case 112:
|
||||
open_previous_item();
|
||||
break;
|
||||
case 110:
|
||||
open_next_item();
|
||||
break;
|
||||
case 118:
|
||||
open_original_item();
|
||||
break;
|
||||
case 111:
|
||||
open_item();
|
||||
break;
|
||||
case 109:
|
||||
change_item_status();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
@ -9,6 +9,11 @@ require 'schema.php';
|
||||
require 'model.php';
|
||||
|
||||
|
||||
const DB_VERSION = 1;
|
||||
const APP_VERSION = 'master';
|
||||
|
||||
|
||||
// For future use...
|
||||
function get_db_filename()
|
||||
{
|
||||
return 'data/db.sqlite';
|
||||
@ -22,7 +27,7 @@ PicoTools\container('db', function() {
|
||||
'filename' => get_db_filename()
|
||||
));
|
||||
|
||||
if ($db->schema()->check(1)) {
|
||||
if ($db->schema()->check(DB_VERSION)) {
|
||||
|
||||
return $db;
|
||||
}
|
||||
|
@ -108,6 +108,27 @@ Router\post_action('read', function() {
|
||||
});
|
||||
|
||||
|
||||
Router\post_action('unread', function() {
|
||||
|
||||
$id = Request\param('id');
|
||||
|
||||
Model\set_item_unread($id);
|
||||
|
||||
Response\json(array('Ok'));
|
||||
});
|
||||
|
||||
|
||||
Router\post_action('status', function() {
|
||||
|
||||
$id = Request\param('id');
|
||||
|
||||
Response\json(array(
|
||||
'item_id' => urlencode($id),
|
||||
'status' => Model\switch_item_status($id)
|
||||
));
|
||||
});
|
||||
|
||||
|
||||
Router\get_action('history', function() {
|
||||
|
||||
Response\html(Template\layout('read_items', array(
|
||||
@ -171,9 +192,9 @@ Router\get_action('ajax-refresh-feed', function() {
|
||||
});
|
||||
|
||||
|
||||
Router\get_action('flush-unread', function() {
|
||||
Router\get_action('mark-as-read', function() {
|
||||
|
||||
Model\flush_unread();
|
||||
Model\mark_as_read();
|
||||
Response\redirect('?action=unread');
|
||||
});
|
||||
|
||||
|
@ -191,6 +191,55 @@ function set_item_read($id)
|
||||
}
|
||||
|
||||
|
||||
function set_item_unread($id)
|
||||
{
|
||||
\PicoTools\singleton('db')
|
||||
->table('items')
|
||||
->eq('id', $id)
|
||||
->save(array('status' => 'unread'));
|
||||
}
|
||||
|
||||
|
||||
function switch_item_status($id)
|
||||
{
|
||||
$item = \PicoTools\singleton('db')
|
||||
->table('items')
|
||||
->columns('status')
|
||||
->eq('id', $id)
|
||||
->findOne();
|
||||
|
||||
if ($item['status'] == 'unread') {
|
||||
|
||||
\PicoTools\singleton('db')
|
||||
->table('items')
|
||||
->eq('id', $id)
|
||||
->save(array('status' => 'read'));
|
||||
|
||||
return 'read';
|
||||
}
|
||||
else {
|
||||
|
||||
\PicoTools\singleton('db')
|
||||
->table('items')
|
||||
->eq('id', $id)
|
||||
->save(array('status' => 'unread'));
|
||||
|
||||
return 'unread';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
function mark_as_read()
|
||||
{
|
||||
\PicoTools\singleton('db')
|
||||
->table('items')
|
||||
->eq('status', 'unread')
|
||||
->save(array('status' => 'read'));
|
||||
}
|
||||
|
||||
|
||||
function flush_unread()
|
||||
{
|
||||
\PicoTools\singleton('db')
|
||||
|
@ -30,3 +30,25 @@
|
||||
<li><a href="?action=download-db">Download the entire database</a> (Gzip compressed Sqlite file).</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<div class="page-section">
|
||||
<h2>Help</h2>
|
||||
</div>
|
||||
<section>
|
||||
<div class="alert">
|
||||
<h3>Keyboard shortcuts</h3>
|
||||
<ul>
|
||||
<li>Previous item = <strong>p</strong></li>
|
||||
<li>Next item = <strong>n</strong></li>
|
||||
<li>Mark as read or unread = <strong>m</strong></li>
|
||||
<li>Open original link = <strong>v</strong></li>
|
||||
<li>Open item = <strong>o</strong></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="alert alert-normal">
|
||||
<h3>About</h3>
|
||||
<ul>
|
||||
<li>Miniflux version: <strong><?= APP_VERSION ?></strong></li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
@ -4,9 +4,9 @@
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
<article class="item">
|
||||
<article class="item" id="current-item" data-item-id="<?= urlencode($item['id']) ?>">
|
||||
<h1>
|
||||
<a href="<?= $item['url'] ?>" rel="noreferrer" target="_blank"><?= Helper\escape($item['title']) ?></a>
|
||||
<a href="<?= $item['url'] ?>" rel="noreferrer" target="_blank" id="original-item"><?= Helper\escape($item['title']) ?></a>
|
||||
</h1>
|
||||
|
||||
<p class="infos">
|
||||
@ -20,7 +20,7 @@
|
||||
<nav>
|
||||
<span class="nav-left">
|
||||
<?php if ($item_nav['previous']): ?>
|
||||
<a href="?action=read&id=<?= urlencode($item_nav['previous']['id']) ?>">« Previous</a>
|
||||
<a href="?action=read&id=<?= urlencode($item_nav['previous']['id']) ?>" id="previous-item">« Previous</a>
|
||||
<?php else: ?>
|
||||
« Previous
|
||||
<?php endif ?>
|
||||
@ -40,7 +40,7 @@
|
||||
|
||||
<span class="nav-right">
|
||||
<?php if ($item_nav['next']): ?>
|
||||
<a href="?action=read&id=<?= urlencode($item_nav['next']['id']) ?>">Next »</a>
|
||||
<a href="?action=read&id=<?= urlencode($item_nav['next']['id']) ?>" id="next-item">Next »</a>
|
||||
<?php else: ?>
|
||||
Next »
|
||||
<?php endif ?>
|
||||
|
@ -11,14 +11,30 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<section class="items">
|
||||
<section class="items" id="listing">
|
||||
<?php foreach ($items as $item): ?>
|
||||
<article>
|
||||
<h2><a href="?action=show&id=<?= urlencode($item['id']) ?>"><?= Helper\escape($item['title']) ?></a></h2>
|
||||
<article id="item-<?= urlencode($item['id']) ?>" data-item-id="<?= urlencode($item['id']) ?>">
|
||||
<h2>
|
||||
<a
|
||||
href="?action=show&id=<?= urlencode($item['id']) ?>"
|
||||
id="open-<?= urlencode($item['id']) ?>"
|
||||
>
|
||||
<?= Helper\escape($item['title']) ?>
|
||||
</a>
|
||||
</h2>
|
||||
<p>
|
||||
<?= Helper\get_host_from_url($item['url']) ?> |
|
||||
<?= date('l, j F Y H:i', $item['updated']) ?> |
|
||||
<a href="<?= $item['url'] ?>" rel="noreferrer" target="_blank">direct link</a>
|
||||
<a
|
||||
href="<?= $item['url'] ?>"
|
||||
id="original-<?= urlencode($item['id']) ?>"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
data-item-id="<?= urlencode($item['id']) ?>"
|
||||
data-action="mark-read"
|
||||
>
|
||||
direct link
|
||||
</a>
|
||||
</p>
|
||||
</article>
|
||||
<?php endforeach ?>
|
||||
|
@ -7,20 +7,36 @@
|
||||
<div class="page-header">
|
||||
<h2>Unread items</h2>
|
||||
<ul>
|
||||
<li><a href="?action=flush-unread">flush</a></li>
|
||||
<li><a href="?action=mark-as-read">mark all as read</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<section class="items">
|
||||
<section class="items" id="listing">
|
||||
<?php foreach ($items as $item): ?>
|
||||
<article id="item-<?= urlencode($item['id']) ?>">
|
||||
<h2><a href="?action=read&id=<?= urlencode($item['id']) ?>"><?= Helper\escape($item['title']) ?></a></h2>
|
||||
<article id="item-<?= urlencode($item['id']) ?>" data-item-id="<?= urlencode($item['id']) ?>">
|
||||
<h2>
|
||||
<a
|
||||
href="?action=read&id=<?= urlencode($item['id']) ?>"
|
||||
id="open-<?= urlencode($item['id']) ?>"
|
||||
>
|
||||
<?= Helper\escape($item['title']) ?>
|
||||
</a>
|
||||
</h2>
|
||||
<p class="preview">
|
||||
<?= Helper\escape(Helper\summary(strip_tags($item['content']), 50, 300)) ?>
|
||||
</p>
|
||||
<p>
|
||||
<?= Helper\get_host_from_url($item['url']) ?> |
|
||||
<a href="<?= $item['url'] ?>" rel="noreferrer" target="_blank" data-item-id="<?= urlencode($item['id']) ?>" data-action="mark-read">direct link</a>
|
||||
<a
|
||||
href="<?= $item['url'] ?>"
|
||||
id="original-<?= urlencode($item['id']) ?>"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
data-item-id="<?= urlencode($item['id']) ?>"
|
||||
data-action="mark-read"
|
||||
>
|
||||
direct link
|
||||
</a>
|
||||
</p>
|
||||
</article>
|
||||
<?php endforeach ?>
|
||||
|
Loading…
Reference in New Issue
Block a user