Add feed group feature

- each feed can have multiple groups assigned
- group assignments are done on the add or edit feed page
- groups are only visible on the unread page
- groups are exported via the fever api
- it's not possible do delete a group manually from the database (the group will be removed automatically, as soon as the last association of a group to a feed is removed)
- if you try to create an already existing group, the existing group is used to prevent duplicates
This commit is contained in:
Kordian Bruck 2015-08-05 01:01:21 +02:00 committed by Mathias Kresin
parent e214785be7
commit dd47b3f82e
27 changed files with 491 additions and 50 deletions

View File

@ -247,6 +247,38 @@ textarea.form-error {
display: none;
}
/* Feed group buttons */
#grouplist span {
float: left;
opacity: 0.4;
min-width: 4em;
margin-right: 6px;
overflow: auto;
text-align: center;
}
#grouplist input[type="text"] {
width: 150px;
}
#grouplist input[type="checkbox"] + span, #grouplist input[type="text"] {
padding: 4px;
margin-top: 6px;
margin-bottom: 0px;
}
#grouplist input[type="checkbox"]:checked + span {
opacity: 1;
}
ul#grouplist {
float: left;
}
ul#grouplist li {
margin-left: 0px;
}
/* alerts */
.alert, .panel {
padding: 8px 35px 8px 14px;
@ -287,7 +319,7 @@ textarea.form-error {
}
/* buttons */
.btn {
.btn, #grouplist span {
-webkit-appearance: none;
appearance: none;
display: inline-block;

View File

@ -22,7 +22,8 @@
"models/schema.php",
"models/auto_update.php",
"models/database.php",
"models/remember_me.php"
"models/remember_me.php",
"models/group.php"
],
"classmap": [
"vendor/fguillot/json-rpc/src/",

View File

@ -19,10 +19,16 @@ Router\get_action('edit-feed', function() {
$id = Request\int_param('feed_id');
$values = Model\Feed\get($id);
$values += array(
'feed_group_ids' => Model\Group\get_feed_group_ids($id)
);
Response\html(Template\layout('edit_feed', array(
'values' => Model\Feed\get($id),
'values' => $values,
'errors' => array(),
'nb_unread_items' => Model\Item\count_by_status('unread'),
'groups' => Model\Group\get_all(),
'menu' => 'feeds',
'title' => t('Edit subscription')
)));
@ -32,7 +38,14 @@ Router\get_action('edit-feed', function() {
Router\post_action('edit-feed', function() {
$values = Request\values();
$values += array('enabled' => 0, 'download_content' => 0, 'rtl' => 0, 'cloak_referrer' => 0);
$values += array(
'enabled' => 0,
'download_content' => 0,
'rtl' => 0,
'cloak_referrer' => 0,
'feed_group_ids' => array(),
'create_group' => ''
);
list($valid, $errors) = Model\Feed\validate_modification($values);
@ -50,6 +63,7 @@ Router\post_action('edit-feed', function() {
'values' => $values,
'errors' => $errors,
'nb_unread_items' => Model\Item\count_by_status('unread'),
'groups' => Model\Group\get_all(),
'menu' => 'feeds',
'title' => t('Edit subscription')
)));
@ -129,12 +143,19 @@ Router\get_action('feeds', function() {
// Display form to add one feed
Router\get_action('add', function() {
$values = array('download_content' => 0, 'rtl' => 0, 'cloak_referrer' => 0);
$values = array(
'download_content' => 0,
'rtl' => 0,
'cloak_referrer' => 0,
'create_group' => '',
'feed_group_ids' => array()
);
Response\html(Template\layout('add', array(
'values' => $values + array('csrf' => Model\Config\generate_csrf()),
'errors' => array(),
'nb_unread_items' => Model\Item\count_by_status('unread'),
'groups' => Model\Group\get_all(),
'menu' => 'feeds',
'title' => t('New subscription')
)));
@ -158,10 +179,24 @@ Router\action('subscribe', function() {
}
}
$values += array('url' => trim($url), 'download_content' => 0, 'rtl' => 0, 'cloak_referrer' => 0);
$values += array(
'url' => trim($url),
'download_content' => 0,
'rtl' => 0,
'cloak_referrer' => 0,
'create_group' => '',
'feed_group_ids' => array()
);
try {
$feed_id = Model\Feed\create($values['url'], $values['download_content'], $values['rtl'], $values['cloak_referrer']);
$feed_id = Model\Feed\create(
$values['url'],
$values['download_content'],
$values['rtl'],
$values['cloak_referrer'],
$values['feed_group_ids'],
$values['create_group']
);
}
catch (UnexpectedValueException $e) {
$error_message = t('This subscription already exists.');
@ -210,6 +245,7 @@ Router\action('subscribe', function() {
Response\html(Template\layout('add', array(
'values' => $values + array('csrf' => Model\Config\generate_csrf()),
'nb_unread_items' => Model\Item\count_by_status('unread'),
'groups' => Model\Group\get_all(),
'menu' => 'feeds',
'title' => t('Subscriptions')
)));

View File

@ -12,6 +12,7 @@ Router\get_action('history', function() {
$nb_items = Model\Item\count_by_status('read');
$items = Model\Item\get_all_by_status(
'read',
null,
$offset,
Model\Config\get('items_per_page'),
'updated',

View File

@ -14,11 +14,26 @@ Router\get_action('unread', function() {
$order = Request\param('order', 'updated');
$direction = Request\param('direction', Model\Config\get('items_sorting_direction'));
$offset = Request\int_param('offset', 0);
$items = Model\Item\get_all_by_status('unread', $offset, Model\Config\get('items_per_page'), $order, $direction);
$nb_items = Model\Item\count_by_status('unread');
$group_id = Request\int_param('group_id', null);
$feed_ids = null;
if ($nb_items === 0) {
if (!is_null($group_id)) {
$feed_ids = Model\Group\get_feeds_by_group($group_id);
}
$items = Model\Item\get_all_by_status(
'unread',
$feed_ids,
$offset,
Model\Config\get('items_per_page'),
$order,
$direction
);
$nb_items = Model\Item\count_by_status('unread', $feed_ids);
$nb_unread_items = Model\Item\count_by_status('unread');
if ($nb_unread_items === 0) {
$action = Model\Config\get('redirect_nothing_to_read');
Response\redirect('?action='.$action.'&nothing_to_read=1');
}
@ -29,13 +44,15 @@ Router\get_action('unread', function() {
'order' => $order,
'direction' => $direction,
'display_mode' => Model\Config\get('items_display_mode'),
'group_id' => $group_id,
'items' => $items,
'nb_items' => $nb_items,
'nb_unread_items' => $nb_items,
'nb_unread_items' => $nb_unread_items,
'offset' => $offset,
'items_per_page' => Model\Config\get('items_per_page'),
'title' => 'Miniflux ('.$nb_items.')',
'menu' => 'unread'
'menu' => 'unread',
'groups' => Model\Group\get_all()
)));
});
@ -146,10 +163,18 @@ Router\post_action('mark-item-unread', function() {
Response\json(array('Ok'));
});
// Mark all unread items as read
// Mark unread items as read
Router\get_action('mark-all-read', function() {
Model\Item\mark_all_as_read();
$group_id = Request\int_param('group_id', null);
if (!is_null($group_id)) {
Model\Item\mark_group_as_read($group_id);
}
else {
Model\Item\mark_all_as_read();
}
Response\redirect('?action=unread');
});

View File

@ -3,6 +3,7 @@
require '../common.php';
use Model\Feed;
use Model\Group;
use Model\Service;
use PicoDb\Database;
@ -59,8 +60,16 @@ route('groups', function() {
if ($response['auth']) {
$response['groups'] = array();
$response['groups'] = Group\get_all();
$response['feeds_groups'] = array();
$group_map = Group\get_map();
foreach ($group_map as $group_id => $feed_ids) {
$response['feeds_groups'][] = array(
'group_id' => $group_id,
'feed_ids' => implode(',', $feed_ids)
);
}
}
response($response);
@ -89,6 +98,14 @@ route('feeds', function() {
'last_updated_on_time' => $feed['last_checked'] ?: time(),
);
}
$group_map = Group\get_map();
foreach ($group_map as $group_id => $feed_ids) {
$response['feeds_groups'][] = array(
'group_id' => $group_id,
'feed_ids' => implode(',', $feed_ids)
);
}
}
response($response);
@ -286,11 +303,15 @@ route('write_groups', function() {
$response = auth();
if ($response['auth']) {
$db = Database::get('db')
->table('items')
->lte('updated', $_POST['before']);
Database::get('db')
->table('items')
->lte('updated', $_POST['before'])
->update(array('status' => 'read'));
if ($_POST['id'] > 0) {
$db->in('feed_id', Model\Group\get_feeds_by_group($_POST['id']));
}
$db->update(array('status' => 'read'));
}
response($response);

View File

@ -115,7 +115,7 @@ $server->register('item.bookmark.delete', function ($item_id) {
// Get all unread items
$server->register('item.list_unread', function ($offset = null, $limit = null) {
return Model\Item\get_all_by_status('unread', $offset, $limit);
return Model\Item\get_all_by_status('unread', null, $offset, $limit);
});
// Count all unread items
@ -127,7 +127,7 @@ $server->register('item.count_unread', function () {
// Get all read items
$server->register('item.list_read', function ($offset = null, $limit = null) {
return Model\Item\get_all_by_status('read', $offset, $limit);
return Model\Item\get_all_by_status('read', null, $offset, $limit);
});
// Count all read items

View File

@ -238,4 +238,6 @@ return array(
// 'Maximum number of HTTP redirections exceeded.' => '',
// 'The content size exceeds to maximum allowed size.' => '',
// 'Unable to detect the feed format.' => '',
// 'add a new group' => '',
// 'Groups' => '',
);

View File

@ -238,4 +238,6 @@ return array(
// 'Maximum number of HTTP redirections exceeded.' => '',
// 'The content size exceeds to maximum allowed size.' => '',
// 'Unable to detect the feed format.' => '',
// 'add a new group' => '',
// 'Groups' => '',
);

View File

@ -238,4 +238,6 @@ return array(
// 'Maximum number of HTTP redirections exceeded.' => '',
// 'The content size exceeds to maximum allowed size.' => '',
// 'Unable to detect the feed format.' => '',
// 'add a new group' => '',
// 'Groups' => '',
);

View File

@ -238,4 +238,6 @@ return array(
// 'Maximum number of HTTP redirections exceeded.' => '',
// 'The content size exceeds to maximum allowed size.' => '',
// 'Unable to detect the feed format.' => '',
// 'add a new group' => '',
// 'Groups' => '',
);

View File

@ -238,4 +238,6 @@ return array(
'Maximum number of HTTP redirections exceeded.' => 'Nombre maximal de redirections HTTP dépassé.',
'The content size exceeds to maximum allowed size.' => 'La taille du contenu dépasse la taille maximale autorisée.',
'Unable to detect the feed format.' => 'Impossible de détecter le format du flux.',
'add a new group' => 'add a new group',
'Groups' => 'Groups',
);

View File

@ -238,4 +238,6 @@ return array(
// 'Maximum number of HTTP redirections exceeded.' => '',
// 'The content size exceeds to maximum allowed size.' => '',
// 'Unable to detect the feed format.' => '',
// 'add a new group' => '',
// 'Groups' => '',
);

View File

@ -238,4 +238,6 @@ return array(
// 'Maximum number of HTTP redirections exceeded.' => '',
// 'The content size exceeds to maximum allowed size.' => '',
// 'Unable to detect the feed format.' => '',
// 'add a new group' => '',
// 'Groups' => '',
);

View File

@ -238,4 +238,6 @@ return array(
// 'Maximum number of HTTP redirections exceeded.' => '',
// 'The content size exceeds to maximum allowed size.' => '',
// 'Unable to detect the feed format.' => '',
// 'add a new group' => '',
// 'Groups' => '',
);

View File

@ -238,4 +238,6 @@ return array(
// 'Maximum number of HTTP redirections exceeded.' => '',
// 'The content size exceeds to maximum allowed size.' => '',
// 'Unable to detect the feed format.' => '',
// 'add a new group' => '',
// 'Groups' => '',
);

View File

@ -238,4 +238,6 @@ return array(
// 'Maximum number of HTTP redirections exceeded.' => '',
// 'The content size exceeds to maximum allowed size.' => '',
// 'Unable to detect the feed format.' => '',
// 'add a new group' => '',
// 'Groups' => '',
);

View File

@ -238,4 +238,6 @@ return array(
// 'Maximum number of HTTP redirections exceeded.' => '',
// 'The content size exceeds to maximum allowed size.' => '',
// 'Unable to detect the feed format.' => '',
// 'add a new group' => '',
// 'Groups' => '',
);

View File

@ -5,6 +5,7 @@ namespace Model\Feed;
use UnexpectedValueException;
use Model\Config;
use Model\Item;
use Model\Group;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
use PicoDb\Database;
@ -93,7 +94,9 @@ function get_all_favicons()
// Update feed information
function update(array $values)
{
return Database::get('db')
Database::get('db')->startTransaction();
$result = Database::get('db')
->table('feeds')
->eq('id', $values['id'])
->save(array(
@ -105,6 +108,17 @@ function update(array $values)
'download_content' => $values['download_content'],
'cloak_referrer' => $values['cloak_referrer'],
));
if ($result) {
if (! Group\update_feed_groups($values['id'], $values['feed_group_ids'], $values['create_group'])) {
Database::get('db')->cancelTransaction();
$result = false;
}
}
Database::get('db')->closeTransaction();
return $result;
}
// Export all feeds
@ -150,7 +164,7 @@ function import_opml($content)
}
// Add a new feed from an URL
function create($url, $enable_grabber = false, $force_rtl = false, $cloak_referrer = false)
function create($url, $enable_grabber = false, $force_rtl = false, $cloak_referrer = false, $group_ids = array(), $create_group = '')
{
$feed_id = false;
@ -194,6 +208,7 @@ function create($url, $enable_grabber = false, $force_rtl = false, $cloak_referr
if ($result) {
$feed_id = $db->getConnection()->getLastId();
Group\update_feed_groups($feed_id, $group_ids, $create_group);
Item\update_all($feed_id, $feed->getItems());
fetch_favicon($feed_id, $feed->getSiteUrl(), $feed->getIcon());
}

220
models/group.php Normal file
View File

@ -0,0 +1,220 @@
<?php
namespace Model\Group;
use PicoDb\Database;
/**
* Get all groups
*
* @return array
*/
function get_all()
{
return Database::get('db')
->table('groups')
->orderBy('title')
->findAll();
}
/**
* Get assoc array of group ids with assigned feeds ids
*
* @return array
*/
function get_map()
{
$result = Database::get('db')
->table('feeds_groups')
->findAll();
// TODO: add PDO::FETCH_COLUMN|PDO::FETCH_GROUP to picodb and use it instead
// of the following lines
$map = array();
foreach ($result as $row) {
$group_id = $row['group_id'];
$feed_id = $row['feed_id'];
if (isset($map[$group_id])) {
$map[$group_id][] = $feed_id;
}
else {
$map[$group_id] = array($feed_id);
}
}
return $map;
}
/**
* Get all groups assigned to feed
*
* @param integer $feed_id id of the feed
* @return array
*/
function get_feed_group_ids($feed_id)
{
return Database::get('db')
->table('groups')
->join('feeds_groups', 'group_id', 'id')
->eq('feed_id', $feed_id)
->findAllByColumn('id');
}
/**
* Get the id of a group
*
* @param string $title group name
* @return mixed group id or false if not found
*/
function get_group_id($title)
{
return Database::get('db')
->table('groups')
->eq('title', $title)
->findOneColumn('id');
}
/**
* Get all feed ids assigned to a group
*
* @param array $group_id
* @return array
*/
function get_feeds_by_group($group_id)
{
return Database::get('db')
->table('feeds_groups')
->eq('group_id', $group_id)
->findAllByColumn('feed_id');
}
/**
* Add a group to the Database
*
* Returns either the id of the new group or the id of an existing group with
* the same name
*
* @param string $title group name
* @return mixed id of the created group or false on error
*/
function create($title)
{
$data = array('title' => $title);
// check if the group already exists
$group_id = get_group_id($title);
// create group if missing
if ($group_id === false) {
Database::get('db')
->table('groups')
->insert($data);
$group_id = get_group_id($title);
}
return $group_id;
}
/**
* Add groups to feed
*
* @param integer $feed_id feed id
* @param array $group_ids array of group ids
* @return boolean true on success, false on error
*/
function add($feed_id, $group_ids)
{
foreach ($group_ids as $group_id){
$data = array('feed_id' => $feed_id, 'group_id' => $group_id);
$result = Database::get('db')
->table('feeds_groups')
->insert($data);
if ($result === false) {
return false;
}
}
return true;
}
/**
* Remove groups from feed
*
* @param integer $feed_id id of the feed
* @param array $group_ids array of group ids
* @return boolean true on success, false on error
*/
function remove($feed_id, $group_ids)
{
return Database::get('db')
->table('feeds_groups')
->eq('feed_id', $feed_id)
->in('group_id', $group_ids)
->remove();
}
/**
* Purge orphaned groups from database
*/
function purge_groups()
{
$groups = Database::get('db')
->table('groups')
->join('feeds_groups', 'group_id', 'id')
->isnull('feed_id')
->findAllByColumn('id');
if (! empty($groups)) {
Database::get('db')
->table('groups')
->in('id', $groups)
->remove();
}
}
/**
* Update feed group associations
*
* @param integer $feed_id id of the feed to update
* @param array $group_ids valid groups ids for feed
* @param string $create_group group to create and assign to feed
* @return boolean
*/
function update_feed_groups($feed_id, $group_ids, $create_group = '')
{
if ($create_group !== '') {
$id = create($create_group);
if ($id === false) {
return false;
}
if (! in_array($id, $group_ids)) {
$group_ids[] = $id;
}
}
$assigned = get_feed_group_ids($feed_id);
$superfluous = array_diff($assigned, $group_ids);
$missing = array_diff($group_ids, $assigned);
// remove no longer assigned groups from feed
if (! empty($superfluous) && ! remove($feed_id, $superfluous)) {
return false;
}
// add requested groups to feed
if (! empty($missing) && ! add($feed_id, $missing)) {
return false;
}
// cleanup
purge_groups();
return true;
}

View File

@ -4,6 +4,7 @@ namespace Model\Item;
use Model\Service;
use Model\Config;
use Model\Group;
use PicoDb\Database;
use PicoFeed\Logging\Logger;
use PicoFeed\Scraper\Scraper;
@ -89,7 +90,7 @@ function get_all_status()
}
// Get all items by status
function get_all_by_status($status, $offset = null, $limit = null, $order_column = 'updated', $order_direction = 'desc')
function get_all_by_status($status, $feed_ids = null, $offset = null, $limit = null, $order_column = 'updated', $order_direction = 'desc')
{
return Database::get('db')
->table('items')
@ -111,6 +112,7 @@ function get_all_by_status($status, $offset = null, $limit = null, $order_column
)
->join('feeds', 'id', 'feed_id')
->eq('status', $status)
->in('feed_id', $feed_ids)
->orderBy($order_column, $order_direction)
->offset($offset)
->limit($limit)
@ -118,11 +120,12 @@ function get_all_by_status($status, $offset = null, $limit = null, $order_column
}
// Get the number of items per status
function count_by_status($status)
function count_by_status($status, $feed_ids = null)
{
return Database::get('db')
->table('items')
->eq('status', $status)
->in('feed_id', $feed_ids)
->count();
}
@ -355,6 +358,19 @@ function mark_feed_as_read($feed_id)
->update(array('status' => 'read'));
}
// Mark all items of a group as read
function mark_group_as_read($group_id)
{
// workaround for missing update with join
$feed_ids = Group\get_feeds_by_group($group_id);
return Database::get('db')
->table('items')
->eq('status', 'unread')
->in('feed_id', $feed_ids)
->update(array('status' => 'read'));
}
// Mark all read items to removed after X days
function autoflush_read()
{

View File

@ -5,7 +5,27 @@ namespace Schema;
use PDO;
use Model\Config;
const VERSION = 40;
const VERSION = 41;
function version_41($pdo)
{
$pdo->exec('
CREATE TABLE "groups" (
id INTEGER PRIMARY KEY,
title TEXT
)
');
$pdo->exec('
CREATE TABLE "feeds_groups" (
feed_id INTEGER NOT NULL,
group_id INTEGER NOT NULL,
PRIMARY KEY(feed_id, group_id)
FOREIGN KEY(group_id) REFERENCES groups(id) ON DELETE CASCADE
FOREIGN KEY(feed_id) REFERENCES feeds(id) ON DELETE CASCADE
)
');
}
function version_40($pdo)
{

View File

@ -22,6 +22,16 @@
<?= Helper\form_checkbox('cloak_referrer', t('Cloak the image referrer'), 1, $values['cloak_referrer']) ?><br />
<p class="form-help"><?= t('Downloading full content is slower because Miniflux grab the content from the original website. You should use that for subscriptions that display only a summary. This feature doesn\'t work with all websites.') ?></p>
<?= Helper\form_label(t('Groups'), 'groups'); ?>
<div id="grouplist">
<?php foreach ($groups as $group): ?>
<?= Helper\form_checkbox('feed_group_ids[]', $group['title'], $group['id'], in_array($group['id'], $values['feed_group_ids']), 'hide') ?>
<?php endforeach ?>
<?= Helper\form_text('create_group', $values, array(), array('placeholder="'.t('add a new group').'"')) ?>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Add') ?></button>
<?= t('or') ?> <a href="?action=feeds"><?= t('cancel') ?></a>

View File

@ -27,7 +27,16 @@
<?= Helper\form_checkbox('cloak_referrer', t('Cloak the image referrer'), 1, $values['cloak_referrer']) ?><br />
<?= Helper\form_checkbox('enabled', t('Activated'), 1, $values['enabled']) ?>
<?= Helper\form_checkbox('enabled', t('Activated'), 1, $values['enabled']) ?><br />
<?= Helper\form_label(t('Groups'), 'groups'); ?>
<div id="grouplist">
<?php foreach ($groups as $group): ?>
<?= Helper\form_checkbox('feed_group_ids[]', $group['title'], $group['id'], in_array($group['id'], $values['feed_group_ids']), 'hide') ?>
<?php endforeach ?>
<?= Helper\form_text('create_group', $values, array(), array('placeholder="'.t('add a new group').'"')) ?>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>

View File

@ -4,6 +4,6 @@
<?php endif ?>
&nbsp;
<?php if (($nb_items - $offset) > $items_per_page): ?>
<a id="next-page" href="?action=<?= $menu ?>&amp;offset=<?= ($offset + $items_per_page) ?>&amp;order=<?= $order ?>&amp;direction=<?= $direction ?><?= isset($feed_id) ? '&amp;feed_id='.$feed_id : '' ?>"><?= t('Next page') ?> »</a>
<a id="next-page" href="?action=<?= $menu ?>&amp;offset=<?= ($offset + $items_per_page) ?>&amp;order=<?= $order ?>&amp;direction=<?= $direction ?><?= isset($feed_id) ? '&amp;feed_id='.$feed_id : '' ?><?= isset($group_id) ? '&amp;group_id='.$group_id : '' ?>"><?= t('Next page') ?> »</a>
<?php endif ?>
</div>

View File

@ -1,37 +1,49 @@
<?php if (empty($items)): ?>
<p class="alert alert-info"><?= t('Nothing to read') ?></p>
<?php else: ?>
<div class="page-header">
<h2><?= t('Unread') ?><span id="page-counter"><?= isset($nb_items) ? $nb_items : '' ?></span></h2>
<?php if (!empty($groups)): ?>
<nav>
<ul id="grouplist">
<?php foreach ($groups as $group): ?>
<li <?= $group['id'] == $group_id ? 'class="active"' : '' ?>>
<a href="?action=unread&group_id=<?=$group['id']?>"><?=$group['title']?></a>
</li>
<?php endforeach ?>
</ul>
</nav>
<?php endif ?>
<ul>
<li>
<a href="?action=unread&amp;order=updated&amp;direction=<?= $direction == 'asc' ? 'desc' : 'asc' ?>"><?= tne('sort by date %s(%s)%s', '<span class="hide-mobile">',$direction == 'desc' ? t('older first') : t('most recent first'), '</span>') ?></a>
<a href="?action=unread<?= is_null($group_id) ? '' : '&amp;group_id='.$group_id ?>&amp;order=updated&amp;direction=<?= $direction == 'asc' ? 'desc' : 'asc' ?>"><?= tne('sort by date %s(%s)%s', '<span class="hide-mobile">',$direction == 'desc' ? t('older first') : t('most recent first'), '</span>') ?></a>
</li>
<li>
<a href="?action=mark-all-read"><?= t('mark all as read') ?></a>
<a href="?action=mark-all-read<?= is_null($group_id) ? '' : '&amp;group_id='.$group_id ?>"><?= t('mark all as read') ?></a>
</li>
</ul>
</div>
<section class="items" id="listing">
<?php foreach ($items as $item): ?>
<?= \PicoFarad\Template\load('item', array(
'item' => $item,
'menu' => $menu,
'offset' => $offset,
'hide' => true,
'display_mode' => $display_mode,
'favicons' => $favicons,
'original_marks_read' => $original_marks_read,
)) ?>
<?php endforeach ?>
<?php if (empty($items)): ?>
<p class="alert alert-info"><?= t('Nothing to read') ?></p>
<?php else: ?>
<?php foreach ($items as $item): ?>
<?= \PicoFarad\Template\load('item', array(
'item' => $item,
'menu' => $menu,
'offset' => $offset,
'hide' => true,
'display_mode' => $display_mode,
'favicons' => $favicons,
'original_marks_read' => $original_marks_read,
)) ?>
<?php endforeach ?>
<div id="bottom-menu">
<a href="?action=mark-all-read"><?= t('mark all as read') ?></a>
</div>
<div id="bottom-menu">
<a href="?action=mark-all-read<?= is_null($group_id) ? '' : '&amp;group_id='.$group_id ?>"><?= t('mark all as read') ?></a>
</div>
<?= \PicoFarad\Template\load('paging', array('menu' => $menu, 'nb_items' => $nb_items, 'items_per_page' => $items_per_page, 'offset' => $offset, 'order' => $order, 'direction' => $direction)) ?>
<?= \PicoFarad\Template\load('paging', array('menu' => $menu, 'nb_items' => $nb_items, 'items_per_page' => $items_per_page, 'offset' => $offset, 'order' => $order, 'direction' => $direction, 'group_id' => $group_id)) ?>
<?php endif ?>
</section>
<?php endif ?>

View File

@ -18,4 +18,5 @@ return array(
$baseDir . '/models/auto_update.php',
$baseDir . '/models/database.php',
$baseDir . '/models/remember_me.php',
$baseDir . '/models/group.php',
);