Improve consistency of slider behavior after submitting form (#8612)

Closes https://github.com/FreshRSS/FreshRSS/issues/8529

* Preserve `error` parameter after submitting form in subscription management
This commit is contained in:
Inverle
2026-03-18 00:10:53 +01:00
committed by GitHub
parent aeb55693e4
commit 815b97017b
18 changed files with 169 additions and 88 deletions

View File

@@ -174,7 +174,9 @@ class FreshRSS_category_Controller extends FreshRSS_ActionController {
invalidateHttpCache();
$url_redirect = ['c' => 'subscription', 'params' => ['id' => $id, 'type' => 'category']];
$from = Minz_Request::paramString('from');
$prev_controller = $from === 'update' ? 'category' : 'subscription';
$url_redirect = ['c' => $prev_controller, 'a' => $from, 'params' => ['id' => $id, 'type' => 'category']];
if (false !== $categoryDAO->updateCategory($id, $values)) {
Minz_Request::good(
_t('feedback.sub.category.updated'),

View File

@@ -542,7 +542,7 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
Minz_Request::good(
_t('feedback.conf.updated'),
[ 'c' => 'configure', 'a' => 'queries', 'params' => ['id' => (string)$id] ],
[ 'c' => 'configure', 'a' => Minz_Request::paramStringNull('from') ?? 'queries', 'params' => ['id' => (string)$id] ],
showNotification: FreshRSS_Context::userConf()->good_notification_timeout > 0);
}

View File

@@ -111,10 +111,17 @@ class FreshRSS_index_Controller extends FreshRSS_ActionController {
$id = Minz_Request::paramInt('id');
if ($id !== 0) {
$view = Minz_Request::paramString('a');
$url_redirect = ['c' => 'subscription', 'a' => 'feed', 'params' => ['id' => (string)$id, 'from' => $view]];
Minz_Request::forward($url_redirect, true);
return;
if (Minz_Request::paramString('type') === 'tag') {
$tagDAO = FreshRSS_Factory::createTagDao();
$tag = $tagDAO->searchById($id);
$this->view->tag = $tag;
} else {
$feedDAO = FreshRSS_Factory::createFeedDao();
$feed = $feedDAO->searchById($id);
$this->view->feed = $feed;
}
$this->view->displaySlider = true;
$this->view->cfrom = Minz_Request::actionName();
}
try {

View File

@@ -375,13 +375,16 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController {
case 'reader':
$get = Minz_Request::paramString('get');
if ($get !== '') {
$url_redirect = ['c' => 'index', 'a' => $from, 'params' => ['get' => $get]];
$url_redirect = ['c' => 'index', 'a' => $from, 'params' => ['id' => $id, 'get' => $get]];
} else {
$url_redirect = ['c' => 'index', 'a' => $from];
$url_redirect = ['c' => 'index', 'a' => $from, 'params' => ['id' => $id]];
}
break;
case 'index':
$url_redirect = ['c' => 'subscription', 'params' => ['id' => $id, 'error' => Minz_Request::paramBoolean('error') ? 1 : 0]];
break;
default:
$url_redirect = ['c' => 'subscription', 'params' => ['id' => $id]];
$url_redirect = ['c' => 'subscription', 'a' => 'feed', 'params' => ['id' => $id]];
}
if ($favicon_uploaded && !$resetFavicon) {

View File

@@ -124,7 +124,14 @@ class FreshRSS_tag_Controller extends FreshRSS_ActionController {
invalidateHttpCache();
$url_redirect = ['c' => 'tag', 'a' => 'update', 'params' => ['id' => $id]];
$prev_controller = 'tag';
$from = Minz_Request::paramStringNull('from') ?? 'update';
$params = ['id' => $id];
if ($from === 'normal' || $from === 'reader') {
$prev_controller = 'index';
$params['type'] = 'tag';
}
$url_redirect = ['c' => $prev_controller, 'a' => $from, 'params' => $params];
if ($ok) {
Minz_Request::good(
_t('feedback.tag.updated'),
@@ -225,6 +232,11 @@ class FreshRSS_tag_Controller extends FreshRSS_ActionController {
}
$tagDAO = FreshRSS_Factory::createTagDao();
$this->view->tags = $tagDAO->listTags(precounts: true);
$id = Minz_Request::paramInt('id');
if ($id !== 0) {
$this->view->displaySlider = true;
$this->view->tag = $tagDAO->searchById($id);
}
}
public static function escapeForSearch(string $tag): string {

View File

@@ -38,6 +38,7 @@ class FreshRSS_View extends Minz_View {
public array $labels;
// Subscriptions
public string $cfrom = '';
public bool $displaySlider = false;
public bool $load_ok;
public bool $onlyFeedsWithError;

View File

@@ -173,7 +173,7 @@
<template id="tag_config_template">
<ul class="dropdown-menu">
<li class="item">
<a class="configure open-slider" href="<?= _url('tag', 'update', 'id', '------') ?>"><?= _t('gen.action.manage') ?></a>
<a class="configure open-slider" href="<?= _url('tag', 'update', 'id', '------', 'from', Minz_Request::actionName()) ?>"><?= _t('gen.action.manage') ?></a>
</li>
</ul>
<a class="dropdown-close" href="#close"></a>

View File

@@ -15,7 +15,19 @@
<a href="<?= _url('index', 'index', 'get', 'c_' . $this->category->id()) ?>"><?= _i('link') ?> <?= _t('gen.action.filter') ?></a>
</div>
<form method="post" action="<?= _url('category', 'update', 'id', $this->category->id(), '#', 'slider') ?>" autocomplete="off" data-auto-leave-validation="1">
<?php
$from = Minz_Request::paramString('from');
$slider = ['#', 'slider'];
$ajax = Minz_Request::paramBoolean('ajax') || $this->displaySlider;
if (!$ajax) {
$from = 'update';
$slider = [];
} elseif ($from === '') {
$from = 'index';
}
?>
<form method="post" action="<?= _url('category', 'update', 'id', $this->category->id(), 'from', $from, ...$slider) ?>" autocomplete="off" data-auto-leave-validation="1">
<input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<fieldset>
<legend><?= _t('sub.category.information') ?></legend>

View File

@@ -4,6 +4,8 @@
if ($this->query === null) {
throw new FreshRSS_Context_Exception('Query not initialised!');
}
$ajax = Minz_Request::paramBoolean('ajax') || $this->displaySlider;
?>
<div class="post">
<h2><?= $this->query->getName() ?></h2>
@@ -11,7 +13,7 @@
<a href="<?= $this->query->getUrl() ?>"><?= _i('link') ?> <?= _t('gen.action.filter') ?></a>
</div>
<form method="post" action="<?= _url('configure', 'query', 'id', $this->queryId, '#', 'slider') ?>" autocomplete="off" data-auto-leave-validation="1">
<form method="post" action="<?= _url('configure', 'query', 'id', $this->queryId, 'from', $ajax ? 'queries' : 'query', ...($ajax ? ['#', 'slider'] : [])) ?>" autocomplete="off" data-auto-leave-validation="1">
<input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<div class="form-group">

View File

@@ -24,14 +24,22 @@
<?php
$from = Minz_Request::paramString('from');
$slider = ['#', 'slider'];
$ajax = Minz_Request::paramBoolean('ajax') || $this->displaySlider;
if (!$ajax) {
$from = 'feed';
$slider = [];
} elseif ($from === '') {
$from = $this->cfrom ?: 'index';
}
if ($from === '') {
$url = _url('subscription', 'feed', 'id', $this->feed->id(), '#', 'slider');
$url = _url('subscription', 'feed', 'id', $this->feed->id(), ...$slider);
} else {
$get = Minz_Request::paramString('get');
if ($get === '') {
$url = _url('subscription', 'feed', 'id', $this->feed->id(), 'from', $from, '#', 'slider');
$url = _url('subscription', 'feed', 'id', $this->feed->id(), 'from', $from, 'error', Minz_Request::paramBoolean('error') ? 1 : 0, ...$slider);
} else {
$url = _url('subscription', 'feed', 'id', $this->feed->id(), 'from', $from, 'get', $get, '#', 'slider');
$url = _url('subscription', 'feed', 'id', $this->feed->id(), 'from', $from, 'get', $get, ...$slider);
}
}
?>

View File

@@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
/** @var FreshRSS_View $this */
if ($this->tag === null) {
throw new FreshRSS_Context_Exception('Tag not initialised!');
}
$ajax = Minz_Request::paramBoolean('ajax') || $this->displaySlider;
$from = $ajax ? ($this->cfrom ?: Minz_Request::paramString('from')) : 'update';
?>
<div class="post">
<h2>
<?= $this->tag->name() ?>
</h2>
<div>
<a href="<?= _url('index', 'index', 'get', 't_' . $this->tag->id()) ?>"><?= _i('link') ?> <?= _t('gen.action.filter') ?></a>
</div>
<form method="post" action="<?= _url('tag', 'update', 'id', $this->tag->id(), 'from', $from, ...($ajax ? ['#', 'slider'] : [])) ?>" autocomplete="off" data-auto-leave-validation="1">
<input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<fieldset>
<legend><?= _t('sub.category.information') ?></legend>
<div class="form-group">
<label class="group-name" for="name"><?= _t('sub.tag.name') ?></label>
<div class="group-controls">
<input type="text" name="name" id="name" value="<?= $this->tag->name() ?>" />
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
<button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
<button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
</fieldset>
<fieldset>
<legend><?= _t('sub.feed.filteractions') ?></legend>
<div class="form-group">
<label class="group-name" for="filteractions_label"><?= _t('sub.tag.auto_label') ?></label>
<div class="group-controls">
<textarea name="filteractions_label" id="filteractions_label" class="w100"><?php
foreach ($this->tag->filtersAction('label') as $filterRead) {
echo htmlspecialchars($filterRead->toString(expandUserQueries: false), ENT_NOQUOTES, 'UTF-8') . PHP_EOL;
}
?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.filteractions.help') ?></p>
</div>
</div>
</fieldset>
<div class="form-group form-actions">
<div class="group-controls">
<button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
<button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
</form>
<h3><?= _t('sub.title.delete_label') ?></h3>
<form id="delete_tag" method="post" action="<?= _url('tag', 'delete', 'id_tag', $this->tag->id()) ?>">
<input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<div class="form-group form-actions">
<div class="group-controls">
<button type="submit" class="btn btn-attention confirm"><?= _t('gen.action.remove') ?></button>
</div>
</div>
</form>
</div>

View File

@@ -6,6 +6,8 @@ if (!Minz_Request::paramBoolean('ajax')) {
$this->partial('nav_menu');
}
$slider_feed = $this->feed;
call_user_func($this->callbackBeforeEntries, $this);
$last_transition = '';
@@ -192,6 +194,14 @@ $today = @strtotime('today');
<aside id="slider" class="<?= $class ?>">
<a class="toggle_aside" href="#close"><?= _i('close') ?></a>
<div id="slider-content">
<?php
if (isset($this->tag)) {
$this->renderHelper('tag/update');
} elseif (isset($slider_feed)) {
$this->feed = $slider_feed;
$this->renderHelper('feed/update');
}
?>
</div>
</aside>
<a href="#close" id="close-slider" class="<?= $class ?>">

View File

@@ -6,6 +6,8 @@ if (!Minz_Request::paramBoolean('ajax')) {
$this->partial('nav_menu');
}
$slider_feed = $this->feed;
call_user_func($this->callbackBeforeEntries, $this);
$lazyload = FreshRSS_Context::userConf()->lazyload;
@@ -66,6 +68,14 @@ $useKeepUnreadImportant = !FreshRSS_Context::isImportant() && !FreshRSS_Context:
<aside id="slider" class="<?= $class ?>">
<a class="toggle_aside" href="#close"><?= _i('close') ?></a>
<div id="slider-content">
<?php
if (isset($this->tag)) {
$this->renderHelper('tag/update');
} elseif (isset($slider_feed)) {
$this->feed = $slider_feed;
$this->renderHelper('feed/update');
}
?>
</div>
</aside>
<a href="#close" id="close-slider" class="<?= $class ?>">

View File

@@ -62,7 +62,7 @@
?>
<li class="item feed<?= $error_class, $empty_class, $mute_class ?>" title="<?= $title ?>"
draggable="true" data-feed-id="<?= $feed->id() ?>" data-priority="<?= $feed->priority() ?>">
<a class="configure open-slider" href="<?= _url('subscription', 'feed', 'id', $feed->id()) ?>" title="<?= _t('gen.action.manage') ?>"><?= _i('configure') ?></a><?php
<a class="configure open-slider" href="<?= _url('subscription', 'feed', 'id', $feed->id(), 'error', $feed->inError() ? 1 : 0) ?>" title="<?= _t('gen.action.manage') ?>"><?= _i('configure') ?></a><?php
if (FreshRSS_Context::userConf()->show_favicons): ?><img class="favicon" src="<?= $feed->favicon() ?>" alt="✇" loading="lazy" /><?php
endif; ?><span class="item-title"><?= $feed->name() ?></span>
</li>

View File

@@ -28,7 +28,7 @@
<ul id="tagsList" <?= (count($this->tags) > 11) ? 'class="listInColumns"' : '' ?>>
<?php foreach ($this->tags as $tag): ?>
<li>
<a href="<?= _url('tag', 'update', 'id', $tag->id()) ?>" class="configure open-slider" title="<?= _t('gen.action.manage') ?>"><?= _i('configure') ?></a>
<a href="<?= _url('tag', 'update', 'id', $tag->id(), 'from', 'index') ?>" class="configure open-slider" title="<?= _t('gen.action.manage') ?>"><?= _i('configure') ?></a>
<span class="item-name"><?= $tag->name() ?></span>
</li>
<?php endforeach; ?>

View File

@@ -1,73 +1,12 @@
<?php
declare(strict_types=1);
/** @var FreshRSS_View $this */
declare(strict_types=1);
/** @var FreshRSS_View $this */
if (!Minz_Request::paramBoolean('ajax')) {
$this->partial('aside_subscription');
}
if ($this->tag === null) {
throw new FreshRSS_Context_Exception('Tag not initialised!');
}
?>
<div class="post">
<h2>
<?= $this->tag->name() ?>
</h2>
if (!Minz_Request::paramBoolean('ajax')) {
$this->partial('aside_subscription');
}
if ($this->tag === null) {
throw new FreshRSS_Context_Exception('Tag not initialised!');
}
<div>
<a href="<?= _url('index', 'index', 'get', 't_' . $this->tag->id()) ?>"><?= _i('link') ?> <?= _t('gen.action.filter') ?></a>
</div>
<form method="post" action="<?= _url('tag', 'update', 'id', $this->tag->id(), '#', 'slider') ?>" autocomplete="off" data-auto-leave-validation="1">
<input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<fieldset>
<legend><?= _t('sub.category.information') ?></legend>
<div class="form-group">
<label class="group-name" for="name"><?= _t('sub.tag.name') ?></label>
<div class="group-controls">
<input type="text" name="name" id="name" value="<?= $this->tag->name() ?>" />
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
<button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
<button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
</fieldset>
<fieldset>
<legend><?= _t('sub.feed.filteractions') ?></legend>
<div class="form-group">
<label class="group-name" for="filteractions_label"><?= _t('sub.tag.auto_label') ?></label>
<div class="group-controls">
<textarea name="filteractions_label" id="filteractions_label" class="w100"><?php
foreach ($this->tag->filtersAction('label') as $filterRead) {
echo htmlspecialchars($filterRead->toString(expandUserQueries: false), ENT_NOQUOTES, 'UTF-8') . PHP_EOL;
}
?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.filteractions.help') ?></p>
</div>
</div>
</fieldset>
<div class="form-group form-actions">
<div class="group-controls">
<button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
<button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
</form>
<h3><?= _t('sub.title.delete_label') ?></h3>
<form id="delete_tag" method="post" action="<?= _url('tag', 'delete', 'id_tag', $this->tag->id()) ?>">
<input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<div class="form-group form-actions">
<div class="group-controls">
<button type="submit" class="btn btn-attention confirm"><?= _t('gen.action.remove') ?></button>
</div>
</div>
</form>
</div>
$this->renderHelper('tag/update');

View File

@@ -2069,6 +2069,7 @@ html.slider-active {
#slider.active:target {
width: 750px;
box-shadow: -3px 3px 5px var(--frss-box-shadow-color-transparent);
outline: none;
}
#slider.sliding {

View File

@@ -2069,6 +2069,7 @@ html.slider-active {
#slider.active:target {
width: 750px;
box-shadow: 3px 3px 5px var(--frss-box-shadow-color-transparent);
outline: none;
}
#slider.sliding {