Add keyboard shortcuts
This commit is contained in:
parent
93ce3e170a
commit
94c1beb19e
@ -234,6 +234,12 @@ textarea.form-error {
|
|||||||
border-color: #bce8f1;
|
border-color: #bce8f1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.alert-normal {
|
||||||
|
color: #333;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border-color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* buttons */
|
/* buttons */
|
||||||
.btn {
|
.btn {
|
||||||
@ -389,6 +395,11 @@ nav .active a {
|
|||||||
font-family: Georgia, serif;
|
font-family: Georgia, serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.items #current-item {
|
||||||
|
border: 2px dashed #d14;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* item */
|
/* item */
|
||||||
.item {
|
.item {
|
||||||
|
@ -5,18 +5,36 @@
|
|||||||
var queue_length = 5;
|
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)
|
function mark_as_read(item_id)
|
||||||
{
|
{
|
||||||
var request = new XMLHttpRequest();
|
var request = new XMLHttpRequest();
|
||||||
|
|
||||||
request.onload = function() {
|
request.onload = function() {
|
||||||
|
|
||||||
var article = document.getElementById("item-" + item_id);
|
remove_item(item_id);
|
||||||
|
|
||||||
if (article) {
|
|
||||||
|
|
||||||
article.style.display = "none";
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
request.open("POST", "?action=read&id=" + item_id, true);
|
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)
|
function show_refresh_icon(feed_id)
|
||||||
{
|
{
|
||||||
var container = document.getElementById("loading-feed-" + 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) {
|
document.onclick = function(e) {
|
||||||
|
|
||||||
var action = e.target.getAttribute("data-action");
|
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';
|
require 'model.php';
|
||||||
|
|
||||||
|
|
||||||
|
const DB_VERSION = 1;
|
||||||
|
const APP_VERSION = 'master';
|
||||||
|
|
||||||
|
|
||||||
|
// For future use...
|
||||||
function get_db_filename()
|
function get_db_filename()
|
||||||
{
|
{
|
||||||
return 'data/db.sqlite';
|
return 'data/db.sqlite';
|
||||||
@ -22,7 +27,7 @@ PicoTools\container('db', function() {
|
|||||||
'filename' => get_db_filename()
|
'filename' => get_db_filename()
|
||||||
));
|
));
|
||||||
|
|
||||||
if ($db->schema()->check(1)) {
|
if ($db->schema()->check(DB_VERSION)) {
|
||||||
|
|
||||||
return $db;
|
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() {
|
Router\get_action('history', function() {
|
||||||
|
|
||||||
Response\html(Template\layout('read_items', array(
|
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');
|
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()
|
function flush_unread()
|
||||||
{
|
{
|
||||||
\PicoTools\singleton('db')
|
\PicoTools\singleton('db')
|
||||||
|
@ -30,3 +30,25 @@
|
|||||||
<li><a href="?action=download-db">Download the entire database</a> (Gzip compressed Sqlite file).</li>
|
<li><a href="?action=download-db">Download the entire database</a> (Gzip compressed Sqlite file).</li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</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: ?>
|
<?php else: ?>
|
||||||
|
|
||||||
<article class="item">
|
<article class="item" id="current-item" data-item-id="<?= urlencode($item['id']) ?>">
|
||||||
<h1>
|
<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>
|
</h1>
|
||||||
|
|
||||||
<p class="infos">
|
<p class="infos">
|
||||||
@ -20,7 +20,7 @@
|
|||||||
<nav>
|
<nav>
|
||||||
<span class="nav-left">
|
<span class="nav-left">
|
||||||
<?php if ($item_nav['previous']): ?>
|
<?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: ?>
|
<?php else: ?>
|
||||||
« Previous
|
« Previous
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
<span class="nav-right">
|
<span class="nav-right">
|
||||||
<?php if ($item_nav['next']): ?>
|
<?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: ?>
|
<?php else: ?>
|
||||||
Next »
|
Next »
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
@ -11,14 +11,30 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section class="items">
|
<section class="items" id="listing">
|
||||||
<?php foreach ($items as $item): ?>
|
<?php foreach ($items as $item): ?>
|
||||||
<article>
|
<article id="item-<?= urlencode($item['id']) ?>" data-item-id="<?= urlencode($item['id']) ?>">
|
||||||
<h2><a href="?action=show&id=<?= urlencode($item['id']) ?>"><?= Helper\escape($item['title']) ?></a></h2>
|
<h2>
|
||||||
|
<a
|
||||||
|
href="?action=show&id=<?= urlencode($item['id']) ?>"
|
||||||
|
id="open-<?= urlencode($item['id']) ?>"
|
||||||
|
>
|
||||||
|
<?= Helper\escape($item['title']) ?>
|
||||||
|
</a>
|
||||||
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
<?= Helper\get_host_from_url($item['url']) ?> |
|
<?= Helper\get_host_from_url($item['url']) ?> |
|
||||||
<?= date('l, j F Y H:i', $item['updated']) ?> |
|
<?= 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>
|
</p>
|
||||||
</article>
|
</article>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
@ -7,20 +7,36 @@
|
|||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h2>Unread items</h2>
|
<h2>Unread items</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="?action=flush-unread">flush</a></li>
|
<li><a href="?action=mark-as-read">mark all as read</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section class="items">
|
<section class="items" id="listing">
|
||||||
<?php foreach ($items as $item): ?>
|
<?php foreach ($items as $item): ?>
|
||||||
<article id="item-<?= urlencode($item['id']) ?>">
|
<article id="item-<?= urlencode($item['id']) ?>" data-item-id="<?= urlencode($item['id']) ?>">
|
||||||
<h2><a href="?action=read&id=<?= urlencode($item['id']) ?>"><?= Helper\escape($item['title']) ?></a></h2>
|
<h2>
|
||||||
|
<a
|
||||||
|
href="?action=read&id=<?= urlencode($item['id']) ?>"
|
||||||
|
id="open-<?= urlencode($item['id']) ?>"
|
||||||
|
>
|
||||||
|
<?= Helper\escape($item['title']) ?>
|
||||||
|
</a>
|
||||||
|
</h2>
|
||||||
<p class="preview">
|
<p class="preview">
|
||||||
<?= Helper\escape(Helper\summary(strip_tags($item['content']), 50, 300)) ?>
|
<?= Helper\escape(Helper\summary(strip_tags($item['content']), 50, 300)) ?>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<?= Helper\get_host_from_url($item['url']) ?> |
|
<?= 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>
|
</p>
|
||||||
</article>
|
</article>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
Loading…
Reference in New Issue
Block a user