Refactoring of bookmarks

This commit is contained in:
Frederic Guillot 2013-06-14 23:12:08 -04:00
commit 17fbb3de91
16 changed files with 212 additions and 219 deletions

View File

@ -449,11 +449,6 @@ nav .active a {
max-width: 100%; max-width: 100%;
} }
.infos {
padding-bottom: 20px;
color: #ccc;
}
.item h1 a { .item h1 a {
font-size: 2.1em; font-size: 2.1em;
text-decoration: none; text-decoration: none;
@ -495,6 +490,19 @@ nav .active a {
display: block; display: block;
} }
.infos {
padding-bottom: 20px;
color: #ddd;
}
.item .infos a {
color: #ddd;
}
.item-status-read {
opacity: 0.4;
}
/* other pages */ /* other pages */
section li { section li {
margin-left: 15px; margin-left: 15px;

View File

@ -45,12 +45,25 @@
function mark_as_unread(item_id) function mark_as_unread(item_id)
{ {
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open("POST", "?action=mark-item-unread&id=" + item_id, true); request.open("POST", "?action=mark-item-unread&id=" + item_id, true);
request.send(); request.send();
} }
function bookmark_item()
{
var item = document.getElementById("current-item");
if (item) {
var item_id = item.getAttribute("data-item-id");
var redirect = item.getAttribute("data-item-page");
window.location = "?action=bookmark&value=1&id=" + item_id + "&redirect=" + redirect;
}
}
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);
@ -171,6 +184,24 @@
{ {
var item = document.getElementById("item-" + item_id); var item = document.getElementById("item-" + item_id);
if (item) item.parentNode.removeChild(item); if (item) item.parentNode.removeChild(item);
var container = document.getElementById("page-counter");
if (container) {
counter = parseInt(container.textContent.trim(), 10) - 1;
if (counter == 0) {
window.location = "?action=feeds&nothing_to_read=1";
}
else {
container.textContent = counter + " ";
document.title = "miniflux (" + counter + ")";
document.getElementById("nav-counter").textContent = "(" + counter + ")";
}
}
} }
@ -230,6 +261,10 @@
function change_item_status() function change_item_status()
{ {
if (is_listing() && ! document.getElementById("current-item")) {
document.querySelector("article").id = "current-item";
}
var item = document.getElementById("current-item"); var item = document.getElementById("current-item");
if (item) switch_status(item.getAttribute("data-item-id")); if (item) switch_status(item.getAttribute("data-item-id"));
} }
@ -364,6 +399,9 @@
case 109: case 109:
change_item_status(); change_item_status();
break; break;
case 102:
bookmark_item();
break;
} }
}; };

View File

@ -10,7 +10,7 @@ require 'schema.php';
require 'model.php'; require 'model.php';
const DB_VERSION = 7; const DB_VERSION = 8;
const APP_VERSION = 'master'; const APP_VERSION = 'master';
const APP_USERAGENT = 'Miniflux - http://miniflux.net'; const APP_USERAGENT = 'Miniflux - http://miniflux.net';
const HTTP_TIMEOUT = 5; const HTTP_TIMEOUT = 5;

122
index.php
View File

@ -57,7 +57,6 @@ Router\before(function($action) {
Router\get_action('logout', function() { Router\get_action('logout', function() {
Session\close(); Session\close();
Response\redirect('?action=login'); Response\redirect('?action=login');
}); });
@ -97,22 +96,15 @@ Router\get_action('show', function() {
$id = Model\decode_item_id(Request\param('id')); $id = Model\decode_item_id(Request\param('id'));
Response\html(Template\layout('read_item', array( Model\set_item_read($id);
'item' => Model\get_item($id)
Response\html(Template\layout('show_item', array(
'item' => Model\get_item($id),
'menu' => 'show'
))); )));
}); });
Router\get_action('show_starred_item', function() {
$id = Model\decode_item_id(Request\param('id'));
Response\html(Template\layout('starred_item', array(
'item' => Model\get_item($id)
)));
});
Router\get_action('read', function() { Router\get_action('read', function() {
$id = Model\decode_item_id(Request\param('id')); $id = Model\decode_item_id(Request\param('id'));
@ -121,24 +113,10 @@ Router\get_action('read', function() {
Model\set_item_read($id); Model\set_item_read($id);
Response\html(Template\layout('read_item', array( Response\html(Template\layout('show_item', array(
'item' => $item, 'item' => $item,
'item_nav' => $nav 'item_nav' => $nav,
))); 'menu' => 'read'
});
Router\get_action('read_starred', function() {
$id = Model\decode_item_id(Request\param('id'));
$item = Model\get_item($id);
$nav = Model\get_nav_starred_item($item); // must be placed before set_item_read()
Model\set_item_read($id);
Response\html(Template\layout('starred_item', array(
'item' => $item,
'item_nav' => $nav
))); )));
}); });
@ -147,7 +125,7 @@ Router\get_action('mark-item-read', function() {
$id = Model\decode_item_id(Request\param('id')); $id = Model\decode_item_id(Request\param('id'));
Model\set_item_read($id); Model\set_item_read($id);
Response\Redirect('?action='.$_SESSION['MODE']); Response\Redirect('?action='.Request\param('redirect', 'default'));
}); });
@ -155,7 +133,7 @@ Router\get_action('mark-item-unread', function() {
$id = Model\decode_item_id(Request\param('id')); $id = Model\decode_item_id(Request\param('id'));
Model\set_item_unread($id); Model\set_item_unread($id);
Response\Redirect('?action='.$_SESSION['MODE']); Response\Redirect('?action='.Request\param('redirect', 'history'));
}); });
@ -163,7 +141,7 @@ Router\get_action('mark-item-removed', function() {
$id = Model\decode_item_id(Request\param('id')); $id = Model\decode_item_id(Request\param('id'));
Model\set_item_removed($id); Model\set_item_removed($id);
Response\Redirect('?action='.$_SESSION['MODE']); Response\Redirect('?action='.Request\param('redirect', 'history'));
}); });
@ -183,19 +161,32 @@ Router\post_action('mark-item-unread', function() {
}); });
Router\get_action('mark-item-starred', function() { Router\post_action('bookmark-item', function() {
$id = Model\decode_item_id(Request\param('id')); $id = Model\decode_item_id(Request\param('id'));
Model\set_item_starred($id); Model\bookmark_item($id);
Response\Redirect('?action='.$_SESSION['MODE']); Response\json(array('Ok'));
}); });
Router\get_action('mark-item-unstarred', function() { Router\get_action('bookmark', function() {
$id = Model\decode_item_id(Request\param('id')); $param_id = Request\param('id');
Model\set_item_unstarred($id); $id = Model\decode_item_id($param_id);
Response\Redirect('?action='.$_SESSION['MODE']); $redirect = Request\param('redirect', 'unread');
Model\set_bookmark_value($id, Request\int_param('value'));
if ($redirect === 'show') {
Response\Redirect('?action=show&id='.$param_id);
}
else if ($redirect === 'read') {
Response\Redirect('?action=read&id='.$param_id);
}
Response\Redirect('?action='.$redirect);
}); });
@ -204,38 +195,40 @@ Router\post_action('change-item-status', function() {
$id = Model\decode_item_id(Request\param('id')); $id = Model\decode_item_id(Request\param('id'));
Response\json(array( Response\json(array(
'item_id' => urlencode($id), 'item_id' => Model\encode_item_id($id),
'status' => Model\switch_item_status($id) 'status' => Model\switch_item_status($id)
)); ));
}); });
Router\get_action('history', function() { Router\get_action('history', function() {
$_SESSION['MODE']='history';
Response\html(Template\layout('history', array( Response\html(Template\layout('history', array(
'items' => Model\get_read_items(), 'items' => Model\get_read_items(),
'menu' => 'history' 'menu' => 'history',
'title' => t('History')
))); )));
}); });
Router\get_action('starred', function() { Router\get_action('bookmarks', function() {
$_SESSION['MODE']='starred';
Response\html(Template\layout('starred', array( Response\html(Template\layout('bookmarks', array(
'items' => Model\get_starred_items(), 'items' => Model\get_bookmarks(),
'menu' => 'starred' 'menu' => 'bookmarks',
'title' => t('Bookmarks')
))); )));
}); });
Router\get_action('confirm-remove', function() { Router\get_action('confirm-remove', function() {
$id = Request\int_param('feed_id'); $id = Request\int_param('feed_id');
Response\html(Template\layout('confirm_remove_feed', array( Response\html(Template\layout('confirm_remove_feed', array(
'feed' => Model\get_feed($id), 'feed' => Model\get_feed($id),
'menu' => 'feeds' 'menu' => 'feeds',
'title' => t('Confirmation')
))); )));
}); });
@ -293,7 +286,8 @@ Router\get_action('mark-as-read', function() {
Router\get_action('confirm-flush-history', function() { Router\get_action('confirm-flush-history', function() {
Response\html(Template\layout('confirm_flush_items', array( Response\html(Template\layout('confirm_flush_items', array(
'menu' => 'history' 'menu' => 'history',
'title' => t('Confirmation')
))); )));
}); });
@ -318,7 +312,8 @@ Router\get_action('feeds', function() {
Response\html(Template\layout('feeds', array( Response\html(Template\layout('feeds', array(
'feeds' => Model\get_feeds(), 'feeds' => Model\get_feeds(),
'nothing_to_read' => Request\int_param('nothing_to_read'), 'nothing_to_read' => Request\int_param('nothing_to_read'),
'menu' => 'feeds' 'menu' => 'feeds',
'title' => t('Subscriptions')
))); )));
}); });
@ -328,7 +323,8 @@ Router\get_action('add', function() {
Response\html(Template\layout('add', array( Response\html(Template\layout('add', array(
'values' => array(), 'values' => array(),
'errors' => array(), 'errors' => array(),
'menu' => 'feeds' 'menu' => 'feeds',
'title' => t('New subscription')
))); )));
}); });
@ -347,7 +343,8 @@ Router\post_action('add', function() {
Response\html(Template\layout('add', array( Response\html(Template\layout('add', array(
'values' => array('url' => $_POST['url']), 'values' => array('url' => $_POST['url']),
'menu' => 'feeds' 'menu' => 'feeds',
'title' => t('Subscriptions')
))); )));
}); });
@ -377,7 +374,8 @@ Router\get_action('import', function() {
Response\html(Template\layout('import', array( Response\html(Template\layout('import', array(
'errors' => array(), 'errors' => array(),
'menu' => 'feeds' 'menu' => 'feeds',
'title' => t('OPML Import')
))); )));
}); });
@ -405,14 +403,15 @@ Router\get_action('config', function() {
'db_size' => filesize(get_db_filename()), 'db_size' => filesize(get_db_filename()),
'languages' => Model\get_languages(), 'languages' => Model\get_languages(),
'autoflush_options' => Model\get_autoflush_options(), 'autoflush_options' => Model\get_autoflush_options(),
'menu' => 'config' 'menu' => 'config',
'title' => t('Preferences')
))); )));
}); });
Router\post_action('config', function() { Router\post_action('config', function() {
$values = Request\values() + array('nocontent' => 0); $values = Request\values();
list($valid, $errors) = Model\validate_config_update($values); list($valid, $errors) = Model\validate_config_update($values);
if ($valid) { if ($valid) {
@ -435,25 +434,28 @@ Router\post_action('config', function() {
'db_size' => filesize(get_db_filename()), 'db_size' => filesize(get_db_filename()),
'languages' => Model\get_languages(), 'languages' => Model\get_languages(),
'autoflush_options' => Model\get_autoflush_options(), 'autoflush_options' => Model\get_autoflush_options(),
'menu' => 'config' 'menu' => 'config',
'title' => t('Preferences')
))); )));
}); });
Router\notfound(function() { Router\notfound(function() {
$_SESSION['MODE']='default';
Model\autoflush(); Model\autoflush();
$items = Model\get_unread_items(); $items = Model\get_unread_items();
$nb_items = count($items);
if (empty($items)) { if ($nb_items === 0) {
Response\redirect('?action=feeds&nothing_to_read=1'); Response\redirect('?action=feeds&nothing_to_read=1');
} }
Response\html(Template\layout('unread_items', array( Response\html(Template\layout('unread_items', array(
'items' => $items, 'items' => $items,
'nb_items' => $nb_items,
'title' => 'miniflux ('.$nb_items.')',
'menu' => 'unread' 'menu' => 'unread'
))); )));
}); });

View File

@ -9,11 +9,13 @@ return array(
'French' => 'Français', 'French' => 'Français',
'English' => 'Anglais', 'English' => 'Anglais',
'unread' => 'non lus', 'unread' => 'non lus',
'mark as starred' => 'ajouter aux favoris', 'bookmarks' => 'favoris',
'mark as unstarred' => 'supprimer des favoris', 'bookmark' => 'ajouter aux favoris',
'starred' => 'favoris', 'remove bookmark' => 'supprimer des favoris',
'No starred items' => 'Pas de favoris', 'bookmarks' => 'favoris',
'Starred' => 'Favoris', 'Bookmarks' => 'Favoris',
'Bookmark item' => 'Ajouter l\'élément séléctionné aux favoris',
'No bookmark' => 'Pas de favoris',
'history' => 'historique', 'history' => 'historique',
'subscriptions' => 'abonnements', 'subscriptions' => 'abonnements',
'Subscriptions' => 'Abonnements', 'Subscriptions' => 'Abonnements',
@ -24,7 +26,7 @@ return array(
'Password' => 'Mot de passe', 'Password' => 'Mot de passe',
'Confirmation' => 'Confirmation', 'Confirmation' => 'Confirmation',
'Language' => 'Langue', 'Language' => 'Langue',
'Update' => 'Mettre à jour', 'Save' => 'Sauvegarder',
'More informations' => 'Plus d\'informations', 'More informations' => 'Plus d\'informations',
'Database' => 'Base de données', 'Database' => 'Base de données',
'Database size:' => 'Taille de la base de données :', 'Database size:' => 'Taille de la base de données :',
@ -41,7 +43,7 @@ return array(
'About' => 'A propos', 'About' => 'A propos',
'Miniflux version:' => 'Version de Miniflux :', 'Miniflux version:' => 'Version de Miniflux :',
'Nothing to read' => 'Rien à lire', 'Nothing to read' => 'Rien à lire',
'Unread items' => léments non lus', 'unread items' => léments non lus',
'mark all as read' => 'tout marquer comme lu', 'mark all as read' => 'tout marquer comme lu',
'original link' => 'lien original', 'original link' => 'lien original',
'mark as read' => 'marquer comme lu', 'mark as read' => 'marquer comme lu',
@ -69,7 +71,7 @@ return array(
'New subscription' => 'Nouvel abonnement', 'New subscription' => 'Nouvel abonnement',
'Website or Feed URL' => 'URL du site ou du flux', 'Website or Feed URL' => 'URL du site ou du flux',
'Add' => 'Ajouter', 'Add' => 'Ajouter',
'http://website/' => 'http://siteweb/', 'http://website/' => 'http://site-web/',
'Yes' => 'Oui', 'Yes' => 'Oui',
'cancel' => 'annuler', 'cancel' => 'annuler',
'or' => 'ou', 'or' => 'ou',
@ -94,4 +96,4 @@ return array(
'Do you really want to remove this subscription: "%s"?' => 'Voulez-vous vraiment supprimer cet abonnement : "%s" ?', 'Do you really want to remove this subscription: "%s"?' => 'Voulez-vous vraiment supprimer cet abonnement : "%s" ?',
'Nothing to read, do you want to <a href="?action=refresh-all" data-action="refresh-all">update your subscriptions?</a>' => 'Nothing to read, do you want to <a href="?action=refresh-all" data-action="refresh-all">update your subscriptions?</a>' =>
'Il n\'y a rien à lire, voulez-vous <a href="?action=refresh-all" data-action="refresh-all">mettre à jour vos abonnements ?</a>' 'Il n\'y a rien à lire, voulez-vous <a href="?action=refresh-all" data-action="refresh-all">mettre à jour vos abonnements ?</a>'
); );

View File

@ -192,7 +192,6 @@ function get_feeds_id($limit = LIMIT_ALL)
->asc('last_checked'); ->asc('last_checked');
if ($limit !== LIMIT_ALL) { if ($limit !== LIMIT_ALL) {
$table_feeds->limit((int)$limit); $table_feeds->limit((int)$limit);
} }
@ -254,7 +253,7 @@ function get_unread_items()
{ {
return \PicoTools\singleton('db') return \PicoTools\singleton('db')
->table('items') ->table('items')
->columns('items.id', 'items.title', 'items.updated', 'items.url', 'feeds.site_url', 'items.content','starred') ->columns('items.id', 'items.title', 'items.updated', 'items.url', 'items.content', 'items.bookmark', 'items.status', 'feeds.site_url')
->join('feeds', 'id', 'feed_id') ->join('feeds', 'id', 'feed_id')
->eq('status', 'unread') ->eq('status', 'unread')
->desc('updated') ->desc('updated')
@ -266,23 +265,22 @@ function get_read_items()
{ {
return \PicoTools\singleton('db') return \PicoTools\singleton('db')
->table('items') ->table('items')
->columns('items.id', 'items.title', 'items.updated', 'items.url', 'feeds.site_url','starred') ->columns('items.id', 'items.title', 'items.updated', 'items.url', 'items.bookmark', 'feeds.site_url')
->join('feeds', 'id', 'feed_id') ->join('feeds', 'id', 'feed_id')
->eq('status', 'read') ->eq('status', 'read')
->desc('updated') ->desc('updated')
->findAll(); ->findAll();
} }
function get_starred_items() function get_bookmarks()
{ {
return \PicoTools\singleton('db') return \PicoTools\singleton('db')
->table('items') ->table('items')
->columns('items.id', 'items.title', 'items.updated', 'items.url', 'feeds.site_url') ->columns('items.id', 'items.title', 'items.updated', 'items.url', 'items.status', 'feeds.site_url')
->join('feeds', 'id', 'feed_id') ->join('feeds', 'id', 'feed_id')
->eq('starred', 'starred') ->in('status', array('read', 'unread'))
->eq('bookmark', 1)
->desc('updated') ->desc('updated')
->findAll(); ->findAll();
} }
@ -326,41 +324,12 @@ function get_nav_item($item)
} }
function get_nav_starred_item($item)
{
$starred_items = \PicoTools\singleton('db')
->table('items')
->columns('items.id')
->eq('starred', 'starred')
->desc('updated')
->findAll();
$next_item = null;
$previous_item = null;
for ($i = 0, $ilen = count($starred_items); $i < $ilen; $i++) {
if ($starred_items[$i]['id'] == $item['id']) {
if ($i > 0) $previous_item = $starred_items[$i - 1];
if ($i < ($ilen - 1)) $next_item = $starred_items[$i + 1];
break;
}
}
return array(
'next' => $next_item,
'previous' => $previous_item
);
}
function set_item_removed($id) function set_item_removed($id)
{ {
\PicoTools\singleton('db') \PicoTools\singleton('db')
->table('items') ->table('items')
->eq('id', $id) ->eq('id', $id)
->save(array('status' => 'removed','starred' => 'unstarred')); ->save(array('status' => 'removed', 'content' => ''));
} }
@ -382,22 +351,12 @@ function set_item_unread($id)
} }
function set_bookmark_value($id, $value)
function set_item_starred($id)
{ {
\PicoTools\singleton('db') \PicoTools\singleton('db')
->table('items') ->table('items')
->eq('id', $id) ->eq('id', $id)
->save(array('starred' => 'starred')); ->save(array('bookmark' => $value));
}
function set_item_unstarred($id)
{
\PicoTools\singleton('db')
->table('items')
->eq('id', $id)
->save(array('starred' => 'unstarred'));
} }
@ -446,7 +405,7 @@ function mark_as_removed()
\PicoTools\singleton('db') \PicoTools\singleton('db')
->table('items') ->table('items')
->eq('status', 'read') ->eq('status', 'read')
->save(array('status' => 'removed')); ->save(array('status' => 'removed', 'content' => ''));
} }
@ -459,9 +418,8 @@ function autoflush()
\PicoTools\singleton('db') \PicoTools\singleton('db')
->table('items') ->table('items')
->eq('status', 'read') ->eq('status', 'read')
->eq('starred', 'starred')
->lt('updated', strtotime('-'.$autoflush.'day')) ->lt('updated', strtotime('-'.$autoflush.'day'))
->save(array('status' => 'removed')); ->save(array('status' => 'removed', 'content' => ''));
} }
} }

View File

@ -2,9 +2,10 @@
namespace Schema; namespace Schema;
function version_7($pdo)
function version_8($pdo)
{ {
$pdo->exec('ALTER TABLE items ADD COLUMN starred TEXT'); $pdo->exec('ALTER TABLE items ADD COLUMN bookmark INTEGER DEFAULT 0');
} }
@ -28,7 +29,7 @@ function version_5($pdo)
function version_4($pdo) function version_4($pdo)
{ {
$pdo->exec("CREATE INDEX idx_status ON items(status)"); $pdo->exec('CREATE INDEX idx_status ON items(status)');
} }

View File

@ -10,7 +10,7 @@
<link rel="apple-touch-icon" sizes="72x72" href="./assets/img/touch-icon-ipad.png"> <link rel="apple-touch-icon" sizes="72x72" href="./assets/img/touch-icon-ipad.png">
<link rel="apple-touch-icon" sizes="114x114" href="./assets/img/touch-icon-iphone-retina.png"> <link rel="apple-touch-icon" sizes="114x114" href="./assets/img/touch-icon-iphone-retina.png">
<link rel="apple-touch-icon" sizes="144x144" href="./assets/img/touch-icon-ipad-retina.png"> <link rel="apple-touch-icon" sizes="144x144" href="./assets/img/touch-icon-ipad-retina.png">
<title>miniflux</title> <title><?= isset($title) ? $title : 'miniflux' ?></title>
<link href="./assets/css/app.css?v<?= filemtime('assets/css/app.css') ?>" rel="stylesheet" media="screen"> <link href="./assets/css/app.css?v<?= filemtime('assets/css/app.css') ?>" rel="stylesheet" media="screen">
<script type="text/javascript" src="./assets/js/app.js?v<?= filemtime('assets/js/app.js') ?>" defer></script> <script type="text/javascript" src="./assets/js/app.js?v<?= filemtime('assets/js/app.js') ?>" defer></script>
</head> </head>
@ -19,12 +19,24 @@
<nav> <nav>
<a class="logo" href="?">mini<span>flux</span></a> <a class="logo" href="?">mini<span>flux</span></a>
<ul> <ul>
<li <?= isset($menu) && $menu === 'unread' ? 'class="active"' : '' ?>><a href="?action=default"><?= t('unread') ?></a></li> <li <?= isset($menu) && $menu === 'unread' ? 'class="active"' : '' ?>>
<li <?= isset($menu) && $menu === 'starred' ? 'class="active"' : '' ?>><a href="?action=starred"><?= t('starred') ?></a></li> <a href="?action=default"><?= t('unread') ?> <span id="nav-counter"><?= isset($nb_items) ? '('.$nb_items.')' : '' ?></span></a>
<li <?= isset($menu) && $menu === 'history' ? 'class="active"' : '' ?>><a href="?action=history"><?= t('history') ?></a></li> </li>
<li <?= isset($menu) && $menu === 'feeds' ? 'class="active"' : '' ?>><a href="?action=feeds"><?= t('subscriptions') ?></a></li> <li <?= isset($menu) && $menu === 'bookmarks' ? 'class="active"' : '' ?>>
<li <?= isset($menu) && $menu === 'config' ? 'class="active"' : '' ?>><a href="?action=config"><?= t('preferences') ?></a></li> <a href="?action=bookmarks"><?= t('bookmarks') ?></a>
<li><a href="?action=logout"><?= t('logout') ?></a></li> </li>
<li <?= isset($menu) && $menu === 'history' ? 'class="active"' : '' ?>>
<a href="?action=history"><?= t('history') ?></a>
</li>
<li <?= isset($menu) && $menu === 'feeds' ? 'class="active"' : '' ?>>
<a href="?action=feeds"><?= t('subscriptions') ?></a>
</li>
<li <?= isset($menu) && $menu === 'config' ? 'class="active"' : '' ?>>
<a href="?action=config"><?= t('preferences') ?></a>
</li>
<li>
<a href="?action=logout"><?= t('logout') ?></a>
</li>
</ul> </ul>
</nav> </nav>
</header> </header>

View File

@ -5,16 +5,16 @@
<?php else: ?> <?php else: ?>
<div class="page-header"> <div class="page-header">
<h2><?= t('Starred') ?></h2> <h2><?= t('Bookmarks') ?></h2>
</div> </div>
<section class="items" id="listing"> <section class="items">
<?php foreach ($items as $item): ?> <?php foreach ($items as $item): ?>
<?php $item_id = Model\encode_item_id($item['id']) ?> <?php $item_id = Model\encode_item_id($item['id']) ?>
<article id="item-<?= $item_id ?>" data-item-id="<?= $item_id ?>"> <article id="item-<?= $item_id ?>" data-item-id="<?= $item_id ?>" class="<?= $item['status'] == 'read' ? 'item-status-read' : '' ?>">
<h2> <h2>
<a <a
href="?action=read_starred&amp;id=<?= $item_id ?>" href="?action=show&amp;id=<?= $item_id ?>"
id="open-<?= $item_id ?>" id="open-<?= $item_id ?>"
> >
<?= Helper\escape($item['title']) ?> <?= Helper\escape($item['title']) ?>
@ -22,9 +22,8 @@
</h2> </h2>
<p> <p>
<?= Helper\get_host_from_url($item['url']) ?> | <?= Helper\get_host_from_url($item['url']) ?> |
<?= dt('%A %e %B %Y %k:%M', $item['updated']) ?> | <?= dt('%e %B %Y %k:%M', $item['updated']) ?> |
<a href="?action=mark-item-unstarred&amp;id=<?= $item_id ?>"><?= t('mark as unstarred') ?></a> | <a href="?action=bookmark&amp;value=0&amp;id=<?= $item_id ?>&amp;redirect=bookmarks"><?= t('remove bookmark') ?></a> |
<a href="?action=mark-item-removed&amp;id=<?= $item_id ?>"><?= t('remove') ?></a> |
<a <a
href="<?= $item['url'] ?>" href="<?= $item['url'] ?>"
id="original-<?= $item_id ?>" id="original-<?= $item_id ?>"

View File

@ -22,7 +22,7 @@
<?= Helper\form_checkbox('nocontent', t('Do not fetch the content of articles'), 1, $values['nocontent']) ?><br /> <?= Helper\form_checkbox('nocontent', t('Do not fetch the content of articles'), 1, $values['nocontent']) ?><br />
<div class="form-actions"> <div class="form-actions">
<input type="submit" value="<?= t('Update') ?>" class="btn btn-blue"/> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
</div> </div>
</form> </form>
</section> </section>
@ -47,6 +47,7 @@
<li><?= t('Mark as read or unread') ?> = <strong>m</strong></li> <li><?= t('Mark as read or unread') ?> = <strong>m</strong></li>
<li><?= t('Open original link') ?> = <strong>v</strong></li> <li><?= t('Open original link') ?> = <strong>v</strong></li>
<li><?= t('Open item') ?> = <strong>o</strong></li> <li><?= t('Open item') ?> = <strong>o</strong></li>
<li><?= t('Bookmark item') ?> = <strong>f</strong></li>
</ul> </ul>
</div> </div>
<div class="alert alert-normal"> <div class="alert alert-normal">

View File

@ -13,8 +13,9 @@
<section class="items" id="listing"> <section class="items" id="listing">
<?php foreach ($items as $item): ?> <?php foreach ($items as $item): ?>
<?php $item_id = Model\encode_item_id($item['id']) ?> <?php $item_id = Model\encode_item_id($item['id']) ?>
<article id="item-<?= $item_id ?>" data-item-id="<?= $item_id ?>"> <article id="item-<?= $item_id ?>" data-item-id="<?= $item_id ?>" data-item-page="<?= $menu ?>">
<h2> <h2>
<?= $item['bookmark'] ? '★ ' : '' ?>
<a <a
href="?action=show&amp;id=<?= $item_id ?>" href="?action=show&amp;id=<?= $item_id ?>"
id="open-<?= $item_id ?>" id="open-<?= $item_id ?>"
@ -23,19 +24,14 @@
</a> </a>
</h2> </h2>
<p> <p>
<?= Helper\get_host_from_url($item['url']) ?> | <?= Helper\get_host_from_url($item['url']) ?> |
<?= dt('%A %e %B %Y %k:%M', $item['updated']) ?> | <?= dt('%e %B %Y %k:%M', $item['updated']) ?> |
<a href="?action=mark-item-unread&amp;id=<?= $item_id ?>"><?= t('mark as unread') ?></a> |
<?php if (! $item['bookmark']): ?>
<?php if (isset($item['starred']) && $item['starred']=='starred'): ?> <a href="?action=bookmark&amp;value=1&amp;id=<?= $item_id ?>&amp;redirect=history"><?= t('bookmark') ?></a> |
<a href="?action=mark-item-unstarred&amp;id=<?= $item_id ?>"><?= t('mark as unstarred') ?></a> |
<?php else: ?>
<a href="?action=mark-item-starred&amp;id=<?= $item_id ?>"><?= t('mark as starred') ?></a> |
<?php endif ?> <?php endif ?>
<a href="?action=mark-item-unread&amp;id=<?= $item_id ?>"><?= t('mark as unread') ?></a> |
<a href="?action=mark-item-removed&amp;id=<?= $item_id ?>"><?= t('remove') ?></a> | <a href="?action=mark-item-removed&amp;id=<?= $item_id ?>"><?= t('remove') ?></a> |
<a <a
href="<?= $item['url'] ?>" href="<?= $item['url'] ?>"

View File

@ -4,20 +4,21 @@
<?php else: ?> <?php else: ?>
<?php $item_id = Model\encode_item_id($item['id']) ?> <?php $item_id = Model\encode_item_id($item['id']) ?>
<article class="item" id="current-item" data-item-id="<?= Model\encode_item_id($item['id']) ?>"> <article class="item" id="current-item" data-item-id="<?= Model\encode_item_id($item['id']) ?>" data-item-page="<?= $menu ?>">
<h1> <h1>
<a href="<?= $item['url'] ?>" rel="noreferrer" target="_blank" id="original-item"><?= 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">
<?= Helper\get_host_from_url($item['url']) ?> | <?= Helper\get_host_from_url($item['url']) ?> |
<?= dt('%A %e %B %Y %k:%M', $item['updated']) ?> | <?= dt('%A %e %B %Y %k:%M', $item['updated']) ?> |
<?php if (isset($item['starred']) && $item['starred']=='starred'): ?> <?php if ($item['bookmark']): ?>
<a href="?action=mark-item-unstarred&amp;id=<?= $item_id ?>"><?= t('mark as unstarred') ?></a> <a href="?action=bookmark&amp;value=0&amp;id=<?= $item_id ?>&amp;redirect=<?= $menu ?>"><?= t('remove bookmark') ?></a>
<?php else: ?> <?php else: ?>
<a href="?action=mark-item-starred&amp;id=<?= $item_id ?>"><?= t('mark as starred') ?></a> <a href="?action=bookmark&amp;value=1&amp;id=<?= $item_id ?>&amp;redirect=<?= $menu ?>"><?= t('bookmark') ?></a>
<?php endif ?> <?php endif ?>
</p> </p>
<?= $item['content'] ?> <?= $item['content'] ?>

View File

@ -1,44 +0,0 @@
<?php if (empty($item)): ?>
<p class="alert alert-info"><?= t('Item not found') ?></p>
<?php else: ?>
<article class="item" id="current-item" data-item-id="<?= Model\encode_item_id($item['id']) ?>">
<h1>
<a href="<?= $item['url'] ?>" rel="noreferrer" target="_blank" id="original-item"><?= Helper\escape($item['title']) ?></a>
</h1>
<p class="infos">
<?= Helper\get_host_from_url($item['url']) ?> |
<?= dt('%A %e %B %Y %k:%M', $item['updated']) ?> |
<a href="?action=mark-item-unstarred&amp;id=<?= $item_id ?>"><?= t('mark as unstarred') ?></a>
</p>
<?= $item['content'] ?>
<?php if (isset($item_nav)): ?>
<nav>
<span class="nav-left">
<?php if ($item_nav['previous']): ?>
<a href="?action=read_starred&amp;id=<?= Model\encode_item_id($item_nav['previous']['id']) ?>" id="previous-item">« <?= t('Previous') ?></a>
<?php else: ?>
« <?= t('Previous') ?>
<?php endif ?>
</span>
<span class="nav-middle">
<a href="?action=starred"><?= t('Starred') ?></a>
</span>
<span class="nav-right">
<?php if ($item_nav['next']): ?>
<a href="?action=read_starred&amp;id=<?= Model\encode_item_id($item_nav['next']['id']) ?>" id="next-item"><?= t('Next') ?> »</a>
<?php else: ?>
<?= t('Next') ?> »
<?php endif ?>
</span>
</nav>
<?php endif ?>
</article>
<?php endif ?>

View File

@ -5,7 +5,7 @@
<?php else: ?> <?php else: ?>
<div class="page-header"> <div class="page-header">
<h2><?= t('Unread items') ?></h2> <h2><span id="page-counter"><?= isset($nb_items) ? $nb_items.' ' : '' ?></span><?= t('unread items') ?></h2>
<ul> <ul>
<li><a href="?action=mark-as-read"><?= t('mark all as read') ?></a></li> <li><a href="?action=mark-as-read"><?= t('mark all as read') ?></a></li>
</ul> </ul>
@ -14,8 +14,9 @@
<section class="items" id="listing"> <section class="items" id="listing">
<?php foreach ($items as $item): ?> <?php foreach ($items as $item): ?>
<?php $item_id = Model\encode_item_id($item['id']) ?> <?php $item_id = Model\encode_item_id($item['id']) ?>
<article id="item-<?= $item_id ?>" data-item-id="<?= $item_id ?>"> <article id="item-<?= $item_id ?>" data-item-id="<?= $item_id ?>" data-item-page="<?= $menu ?>">
<h2> <h2>
<?= $item['bookmark'] ? '★ ' : '' ?>
<a <a
href="?action=read&amp;id=<?= $item_id ?>" href="?action=read&amp;id=<?= $item_id ?>"
id="open-<?= $item_id ?>" id="open-<?= $item_id ?>"
@ -28,12 +29,12 @@
</p> </p>
<p> <p>
<?= Helper\get_host_from_url($item['url']) ?> | <?= Helper\get_host_from_url($item['url']) ?> |
<?= dt('%e %B %Y %k:%M', $item['updated']) ?> |
<?php if ($item['bookmark']): ?>
<?php if (isset($item['starred']) && $item['starred']=='starred'): ?> <a href="?action=bookmark&amp;value=0&amp;id=<?= $item_id ?>&amp;redirect=unread"><?= t('remove bookmark') ?></a> |
<a href="?action=mark-item-unstarred&amp;id=<?= $item_id ?>"><?= t('mark as unstarred') ?></a> |
<?php else: ?> <?php else: ?>
<a href="?action=mark-item-starred&amp;id=<?= $item_id ?>"><?= t('mark as starred') ?></a> | <a href="?action=bookmark&amp;value=1&amp;id=<?= $item_id ?>&amp;redirect=unread"><?= t('bookmark') ?></a> |
<?php endif ?> <?php endif ?>
<a href="?action=mark-item-read&amp;id=<?= $item_id ?>"><?= t('mark as read') ?></a> | <a href="?action=mark-item-read&amp;id=<?= $item_id ?>"><?= t('mark as read') ?></a> |

View File

@ -3,15 +3,22 @@
namespace PicoFarad\Request; namespace PicoFarad\Request;
function param($name) function param($name, $default_value = null)
{ {
return isset($_GET[$name]) ? $_GET[$name] : null; return isset($_GET[$name]) ? $_GET[$name] : $default_value;
} }
function int_param($name) function int_param($name, $default_value = 0)
{ {
return isset($_GET[$name]) && ctype_digit($_GET[$name]) ? (int) $_GET[$name] : null; return isset($_GET[$name]) && ctype_digit($_GET[$name]) ? (int) $_GET[$name] : $default_value;
}
function value($name)
{
$values = values();
return isset($values[$name]) ? $values[$name] : null;
} }

View File

@ -73,6 +73,17 @@ function xml($data, $status_code = 200)
} }
function js($data, $status_code = 200)
{
status($status_code);
header('Content-Type: text/javascript; charset=utf-8');
echo $data;
exit;
}
function binary($data, $status_code = 200) function binary($data, $status_code = 200)
{ {
status($status_code); status($status_code);