Files
FreshRSS/app/views/helpers/feed/update.phtml
PeterVavercak ee7eb67f3c Implement sort order per feed (#8234)
* added local feed sorting

Addresses https://github.com/FreshRSS/FreshRSS/issues/4761

- Added number of sorted feeds and associative array for feed sorting option in Context.
- Number of sorted feeds and local sorting option by its index saved into Minz Request Parameters.
- Number of sorted feeds and local sorting options deleted when choosing another Option Of Global Sorting.
- Added option of allowing sorting by feed in configuration.
- Added variable for allowing local sorting in userConf.
- Added function to get feeds by current get in context.
- Added menu button for all individual feed sorting.
- New database options for individual feed sorting in EntryDAO.
- Considered choosing new entries based on chosen load limit.
- Local sorting parameter saved into continuation value in Index Controller.

How to test the feature manually:

1. At the bottom of Reading Configuration menu turn on individual sorting option menu 
2. Choose Sorting by feed option
3. Choose feed at next sorting menu and choose sorting option for that feed

* added feed sorting option

* added sort feeds display

* added template for sort feed name

* added title to feed sorting button

* added comments

* added local sorting option

* Added Docs

* css reset

* added getter and seter for local sort

* added getter and seter for local sort

* allowed sorting per feed

* allowed sorting per feed

* added sorting option for category

* deleted changes from NetryDAO

* add setting up sorting for category

* docs reset

* i18 reset

* updated i18 for category

* added i18 for categories

* added i18 for category

* added setting sorting for feeds and category

* removing userConf.allow-local-sort

* removing userConf.allow-local-sort

* removing white space

* added credits

* removed feeds_by_get

* removed whitespace

* changed escaping for values

* added escaping to user set values

* added in_array

* added secondary sort and order

* added secondary sort and order

* fixed readme

* removed whitespace change

* reseted i18n

* added translations

* added feed setting translations

* fixed i18n

* fixed i18n

* changes in sort order per feed

* changes in sort order per feed

* added secondary sort order

* primary sort

* changed to preferred sort order

* i18n

* Revert wrong whitespace changes

* Re-order new options

* added blank option

* fixed escaping

* fixed default sort in feed

* fixed default sort recovery

* siplyfied option

* added rand option

* Revert unrelated change

* Minor plaintext

* Whitespace and formatting fixes

* Avoid unneeded SQL requests and processing

* Improve syntax

* Improve logic

* Reuse existing translations as much as possible

* i18n

* Remove some options that make little sense

* Separators

* Fix old transation key

* Add help messages

* Progress on secondary sort

* raw name

* Pass parameters. Add TODO

* Progress

* Minor ordering

* Fix parenthesis

---------

Co-authored-by: root <root@LAPTOP-C8TCHHPN.localdomain>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-02-01 13:12:47 +01:00

951 lines
52 KiB
PHTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
/** @var FreshRSS_View $this */
if ($this->feed === null) {
return;
}
?>
<div class="post" id="feed_update" data-feed-id="<?= $this->feed->id() ?>">
<h1><?= $this->feed->name() ?></h1>
<div>
<a href="<?= _url('index', 'index', 'get', 'f_' . $this->feed->id()) ?>"><?= _i('link') ?> <?= _t('gen.action.filter') ?></a>
<?= _t('gen.short.or') ?>
<a href="<?= _url('stats', 'repartition', 'id', $this->feed->id()) ?>"><?= _i('stats') ?> <?= _t('sub.feed.stats') ?></a>
</div>
<?php $nbEntries = $this->feed->nbEntries(); ?>
<?php if ($this->feed->inError()) { ?>
<p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('sub.feed.error') ?></p>
<?php } elseif ($nbEntries === 0) { ?>
<p class="alert alert-warn"><?= _t('sub.feed.empty') ?></p>
<?php } ?>
<?php
$from = Minz_Request::paramString('from');
if ($from === '') {
$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');
} else {
$url = _url('subscription', 'feed', 'id', $this->feed->id(), 'from', $from, 'get', $get, '#', 'slider');
}
}
?>
<form method="post" action="<?= $url ?>" autocomplete="off" enctype="multipart/form-data" data-auto-leave-validation="1">
<input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<fieldset>
<legend><?= _t('sub.feed.information') ?></legend>
<div class="form-group">
<?php
$currentIconUrl = $this->feed->favicon();
$originalIconUrl = '';
if ($this->feed->customFavicon()) {
$this->feed->_attribute('customFavicon', false);
$this->feed->resetFaviconHash();
}
$originalIconUrl = $this->feed->favicon();
$this->feed->_attribute('customFavicon', $currentIconUrl !== $originalIconUrl);
$this->feed->resetFaviconHash();
$ext_url = Minz_ExtensionManager::callHook(Minz_HookType::CustomFaviconBtnUrl, $this->feed);
?>
<div class="group-name"><?= _t('sub.feed.icon') ?></div>
<div class="group-controls">
<img class="favicon upload" src="<?= $currentIconUrl ?>" data-initial-src="<?= $currentIconUrl ?>" data-original-icon="<?= $originalIconUrl ?>" alt="✇" loading="lazy" />
<div class="favicon-controls">
<input id="favicon-upload" name="newFavicon" type="file" accept="image/*" />
<label for="favicon-upload" class="btn"><?= _t('sub.feed.change_favicon') ?></label>
<button id="reset-favicon" class="btn"<?= $this->feed->customFavicon() ? '' : ' disabled="disabled"'?>><?= _t('sub.feed.reset_favicon') ?></button>
<?php if (is_string($ext_url)) { ?>
<button id="favicon-ext-btn" class="btn" data-extension-url="<?= htmlspecialchars(html_entity_decode($ext_url), ENT_COMPAT, 'UTF-8') ?>"><?= _t('sub.feed.ext_favicon') ?></button>
<?php } ?>
</div>
<p id="favicon-ext" class="<?= $this->feed->customFaviconExt() !== null ? '' : 'hidden' ?>"><?= _t('sub.feed.favicon_changed_by_ext', htmlspecialchars($this->feed->customFaviconExt() ?? '', ENT_NOQUOTES, 'UTF-8')) ?></p>
<p id="favicon-error" class="error"></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="name"><?= _t('sub.feed.title') ?></label>
<div class="group-controls">
<input type="text" name="name" id="name" class="w100" value="<?= $this->feed->name(true) ?>" required="required" />
</div>
</div>
<div class="form-group">
<label class="group-name" for="description"><?= _t('sub.feed.description') ?></label>
<div class="group-controls">
<textarea name="description" id="description" class="w100"><?= htmlspecialchars($this->feed->description(), ENT_NOQUOTES, 'UTF-8') ?></textarea>
</div>
</div>
<div class="form-group">
<label class="group-name" for="website"><?= _t('sub.feed.website') ?></label>
<div class="group-controls">
<div class="stick w100">
<input type="url" name="website" id="website" value="<?= $this->feed->website() ?>" />
<a class="btn open-url" target="_blank" rel="noreferrer" href="<?= $this->feed->website() ?>" data-input="website" title="<?= _t('gen.action.open_url') ?>"><?= _i('link') ?></a>
</div>
</div>
</div>
<div class="form-group">
<label class="group-name" for="url"><?= _t('sub.feed.url') ?></label>
<div class="group-controls">
<div class="stick w100">
<input type="url" name="url" id="url" value="<?= $this->feed->url() ?>" required="required" />
<a class="btn open-url" target="_blank" rel="noreferrer" href="<?= $this->feed->url() ?>" data-input="url" title="<?= _t('gen.action.open_url') ?>"><?= _i('link') ?></a>
</div>
<a class="btn open-url" target="_blank" rel="noreferrer" data-input="url" data-prefix="https://validator.w3.org/feed/check.cgi?url=" data-encode="1" href="https://validator.w3.org/feed/check.cgi?url=<?=
rawurlencode(htmlspecialchars_decode($this->feed->url(), ENT_QUOTES)) ?>"><?= _t('sub.feed.validator') ?></a>
</div>
</div>
<div class="form-group">
<label class="group-name" for="category"><?= _t('sub.category') ?></label>
<div class="group-controls">
<select name="category" id="category" class="w100">
<?php foreach ($this->categories as $cat) { ?>
<option value="<?= $cat->id() ?>"<?= $cat->id() == $this->feed->categoryId() ? ' selected="selected"' : '' ?>>
<?= $cat->name() ?>
</option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group">
<label class="group-name" for="priority"><?= _t('sub.feed.priority') ?></label>
<div class="group-controls">
<select name="priority" id="priority" class="w50">
<option value="<?= FreshRSS_Feed::PRIORITY_IMPORTANT ?>" <?=
FreshRSS_Feed::PRIORITY_IMPORTANT === $this->feed->priority() ? 'selected="selected"' : '' ?>><?= _t('sub.feed.priority.important') ?></option>
<option value="<?= FreshRSS_Feed::PRIORITY_MAIN_STREAM ?>" <?=
FreshRSS_Feed::PRIORITY_MAIN_STREAM === $this->feed->priority() ? 'selected="selected"' : '' ?>><?= _t('sub.feed.priority.main_stream') ?></option>
<option value="<?= FreshRSS_Feed::PRIORITY_CATEGORY ?>" <?=
FreshRSS_Feed::PRIORITY_CATEGORY === $this->feed->priority() ? 'selected="selected"' : '' ?>><?= _t('sub.feed.priority.category') ?></option>
<option value="<?= FreshRSS_Feed::PRIORITY_FEED ?>" <?=
FreshRSS_Feed::PRIORITY_FEED === $this->feed->priority() ? 'selected="selected"' : '' ?>><?= _t('sub.feed.priority.feed') ?></option>
<option value="<?= FreshRSS_Feed::PRIORITY_HIDDEN ?>" <?=
FreshRSS_Feed::PRIORITY_HIDDEN === $this->feed->priority() ? 'selected="selected"' : '' ?>><?= _t('sub.feed.priority.hidden') ?></option>
</select>
<?= _i('important') ?>
</div>
</div>
<?php
$feedDefaultSort = $this->feed->defaultSort();
$feedDefaultOrder = $this->feed->defaultOrder();
$feedDefaultSortOrder = $feedDefaultSort !== null
? ($feedDefaultSort === 'rand' ? 'rand' : $feedDefaultSort . '_' . strtolower($feedDefaultOrder ?? 'desc'))
: '';
?>
<div class="form-group">
<label class="group-name" for="defaultSortOrder"><?= _t('index.menu.sort.primary') ?></label>
<div class="group-controls">
<select name="defaultSortOrder" id="defaultSortOrderFeed" class="w50">
<option value=""></option>
<option value="id_desc" <?= $feedDefaultSortOrder === 'id_desc' ? 'selected="selected"' : '' ?>><?= _t('index.menu.sort.id_desc') ?></option>
<option value="date_desc" <?= $feedDefaultSortOrder === 'date_desc' ? 'selected="selected"' : '' ?>><?= _t('index.menu.sort.date_desc') ?></option>
<option value="length_desc" <?= $feedDefaultSortOrder === 'length_desc' ? 'selected="selected"' : '' ?>><?= _t('index.menu.sort.length_desc') ?></option>
<option value="link_desc" <?= $feedDefaultSortOrder === 'link_desc' ? 'selected="selected"' : '' ?>><?= _t('index.menu.sort.link_desc') ?></option>
<option value="title_desc" <?= $feedDefaultSortOrder === 'title_desc' ? 'selected="selected"' : '' ?>><?= _t('index.menu.sort.title_desc') ?></option>
<option disabled="disabled">────────────────</option>
<option value="rand" <?= $feedDefaultSortOrder === 'rand' ? 'selected="selected"' : '' ?>><?= _t('index.menu.sort.rand') ?></option>
<option disabled="disabled">────────────────</option>
<option value="id_asc" <?= $feedDefaultSortOrder === 'id_asc' ? 'selected="selected"' : '' ?>><?= _t('index.menu.sort.id_asc') ?></option>
<option value="date_asc" <?= $feedDefaultSortOrder === 'date_asc' ? 'selected="selected"' : '' ?>><?= _t('index.menu.sort.date_asc') ?></option>
<option value="length_asc" <?= $feedDefaultSortOrder === 'length_asc' ? 'selected="selected"' : '' ?>><?= _t('index.menu.sort.length_asc') ?></option>
<option value="link_asc" <?= $feedDefaultSortOrder === 'link_asc' ? 'selected="selected"' : '' ?>><?= _t('index.menu.sort.link_asc') ?></option>
<option value="title_asc" <?= $feedDefaultSortOrder === 'title_asc' ? 'selected="selected"' : '' ?>><?= _t('index.menu.sort.title_asc') ?></option>
</select>
</div>
</div>
<div class="form-group">
<label class="group-name" for="unicityCriteria"><?= _t('sub.feed.unicityCriteria') ?></label>
<?php
$unicityCriteria = $this->feed->attributeString('unicityCriteria');
if ($this->feed->attributeBoolean('hasBadGuids')) { // Legacy
$unicityCriteria = 'link';
}
?>
<div class="group-controls">
<select class="w50" name="unicityCriteria" id="unicityCriteria" required="required">
<option value="id" <?= $unicityCriteria == null ? 'selected="selected"' : '' ?>><?= _t('sub.feed.unicityCriteria.id') ?></option>
<option value="link" <?= $unicityCriteria === 'link' ? 'selected="selected"' : '' ?>><?= _t('sub.feed.unicityCriteria.link') ?></option>
<option value="sha1:link_published" <?= $unicityCriteria === 'sha1:link_published' ? 'selected="selected"' : '' ?>><?= _t('sub.feed.unicityCriteria.sha1:link_published') ?></option>
<option value="sha1:link_published_title" <?= $unicityCriteria === 'sha1:link_published_title' ? 'selected="selected"' : '' ?>><?= _t('sub.feed.unicityCriteria.sha1:link_published_title') ?></option>
<option value="sha1:link_published_title_content" <?= $unicityCriteria === 'sha1:link_published_title_content' ? 'selected="selected"' : '' ?>><?= _t('sub.feed.unicityCriteria.sha1:link_published_title_content') ?></option>
<option value="sha1:title" <?= $unicityCriteria === 'sha1:title' ? 'selected="selected"' : '' ?>><?= _t('sub.feed.unicityCriteria.sha1:title') ?></option>
<option value="sha1:title_published" <?= $unicityCriteria === 'sha1:title_published' ? 'selected="selected"' : '' ?>><?= _t('sub.feed.unicityCriteria.sha1:title_published') ?></option>
<option value="sha1:title_published_content" <?= $unicityCriteria === 'sha1:title_published_content' ? 'selected="selected"' : '' ?>><?= _t('sub.feed.unicityCriteria.sha1:title_published_content') ?></option>
<option value="sha1:content" <?= $unicityCriteria === 'sha1:content' ? 'selected="selected"' : '' ?>><?= _t('sub.feed.unicityCriteria.sha1:content') ?></option>
<option value="sha1:content_published" <?= $unicityCriteria === 'sha1:content_published' ? 'selected="selected"' : '' ?>><?= _t('sub.feed.unicityCriteria.sha1:content_published') ?></option>
<option value="sha1:published" <?= $unicityCriteria === 'sha1:published' ? 'selected="selected"' : '' ?>><?= _t('sub.feed.unicityCriteria.sha1:published') ?></option>
</select>
<label for="unicityCriteriaForced" class="inline">
<input type="checkbox" name="unicityCriteriaForced" id="unicityCriteriaForced" value="1"<?= $this->feed->attributeBoolean('unicityCriteriaForced') ? ' checked="checked"' : '' ?> />
<?= _t('sub.feed.unicityCriteria.forced') ?>
</label>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.unicityCriteria.help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="ttl"><?= _t('sub.feed.ttl') ?></label>
<div class="group-controls">
<select class="w50" name="ttl" id="ttl" required="required"><?php
$found = false;
foreach ([FreshRSS_Feed::TTL_DEFAULT => _t('gen.short.by_default'), 900 => '15min', 1200 => '20min', 1500 => '25min', 1800 => '30min', 2700 => '45min',
3600 => '1h', 5400 => '1.5h', 7200 => '2h', 10800 => '3h', 14400 => '4h', 18800 => '5h', 21600 => '6h', 25200 => '7h', 28800 => '8h',
36000 => '10h', 43200 => '12h', 64800 => '18h',
86400 => '1d', 129600 => '1.5d', 172800 => '2d', 259200 => '3d', 345600 => '4d', 432000 => '5d', 518400 => '6d',
604800 => '1wk', 1209600 => '2wk', 1814400 => '3wk', 2419200 => '4wk', 2629744 => '1mo'] as $v => $t) {
echo '<option value="' . $v . ($this->feed->ttl() === $v ? '" selected="selected' : '') . '">' . $t . '</option>';
if ($this->feed->ttl() == $v) {
$found = true;
}
}
if (!$found) {
echo '<option value="' . intval($this->feed->ttl()) . '" selected="selected">' . intval($this->feed->ttl()) . 's</option>';
}
?></select>
<label for="mute">
<input type="checkbox" name="mute" id="mute" value="1"<?= $this->feed->mute() ? ' checked="checked"' : '' ?> />
<?= _t('sub.feed.mute') ?>
</label>
</div>
</div>
<?php if ($this->feed->pubSubHubbubEnabled()) { ?>
<div class="form-group">
<div class="group-controls">
<label class="checkbox" for="pubsubhubbub">
<input type="checkbox" name="pubsubhubbub" id="pubsubhubbub" disabled="disabled" value="1" checked="checked" />
<?= _t('sub.feed.websub') ?>
</label>
</div>
</div>
<?php } ?>
<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>
<?php
if ($from === '') {
$url = _url('feed', 'delete', 'id', $this->feed->id());
} else {
$url = _url('feed', 'delete', 'id', $this->feed->id(), 'from', $from);
}
?>
<button type="submit" class="btn btn-attention confirm"
data-str-confirm="<?= _t('gen.js.confirm_action_feed_cat') ?>"
formaction="<?= $url ?>"
formmethod="post"><?= _t('gen.action.remove') ?></button>
</div>
</div>
</fieldset>
<fieldset>
<legend><?= _t('sub.feed.auth.configuration') ?></legend>
<?php $auth = $this->feed->httpAuth(false); ?>
<div class="form-group">
<label class="group-name" for="http_user_feed<?= $this->feed->id() ?>"><?= _t('sub.feed.auth.username') ?></label>
<div class="group-controls">
<input type="text" name="http_user_feed<?= $this->feed->id() ?>" id="http_user_feed<?= $this->feed->id() ?>" class="w50" value="<?=
empty($auth['username']) ? '' : $auth['username'] ?>" autocomplete="off" />
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.auth.help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="http_pass_feed<?= $this->feed->id() ?>"><?= _t('sub.feed.auth.password') ?></label>
<div class="group-controls">
<div class="stick w50">
<input type="password" name="http_pass_feed<?= $this->feed->id() ?>" id="http_pass_feed<?= $this->feed->id() ?>" value="<?=
$auth['password'] ?>" autocomplete="new-password" />
<button type="button" class="btn toggle-password"><?= _i('key') ?></button>
</div>
</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="mark_updated_article_unread"><?= _t('conf.reading.mark_updated_article_unread') ?></label>
<div class="group-controls">
<select name="mark_updated_article_unread" id="mark_updated_article_unread" class="w50">
<option value=""<?= $this->feed->attributeBoolean('mark_updated_article_unread') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
<option value="0"<?= $this->feed->attributeBoolean('mark_updated_article_unread') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
<option value="1"<?= $this->feed->attributeBoolean('mark_updated_article_unread') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option>
</select>
</div>
</div>
<div class="form-group">
<label class="group-name" for="read_when_same_title_in_feed"><?= _t('conf.reading.read.when') ?></label>
<div class="group-controls">
<select name="read_when_same_title_in_feed" id="read_when_same_title_in_feed" class="w50">
<option value=""<?= $this->feed->hasAttribute('read_when_same_title_in_feed') ? '' : ' selected="selected"' ?>><?= _t('gen.short.by_default') ?></option>
<option value="0"<?= $this->feed->attributeBoolean('read_when_same_title_in_feed') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
<option value="10"<?= $this->feed->attributeInt('read_when_same_title_in_feed') == 10 ? ' selected="selected"' : '' ?>>10</option>
<option value="25"<?= $this->feed->attributeInt('read_when_same_title_in_feed') == 25 ? ' selected="selected"' : '' ?>>25</option>
<option value="100"<?= $this->feed->attributeInt('read_when_same_title_in_feed') == 100 ? ' selected="selected"' : '' ?>>100</option>
<option value="1000"<?= $this->feed->attributeInt('read_when_same_title_in_feed') == 1000 ? ' selected="selected"' : '' ?>>1 000</option>
</select>
<?= _t('conf.reading.read.when_same_title_in_feed') ?>
</div>
</div>
<div class="form-group">
<label class="group-name" for="read_upon_reception"><?= _t('conf.reading.read.when') ?></label>
<div class="group-controls">
<select name="read_upon_reception" id="read_upon_reception" class="w50">
<option value=""<?= $this->feed->attributeBoolean('read_upon_reception') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
<option value="0"<?= $this->feed->attributeBoolean('read_upon_reception') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
<option value="1"<?= $this->feed->attributeBoolean('read_upon_reception') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option>
</select>
<?= _t('conf.reading.read.upon_reception') ?>
</div>
</div>
<div class="form-group">
<label class="group-name" for="read_upon_gone"><?= _t('conf.reading.read.when') ?></label>
<div class="group-controls">
<select name="read_upon_gone" id="read_upon_gone" class="w50">
<option value=""<?= $this->feed->attributeBoolean('read_upon_gone') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
<option value="0"<?= $this->feed->attributeBoolean('read_upon_gone') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
<option value="1"<?= $this->feed->attributeBoolean('read_upon_gone') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option>
</select>
<?= _t('conf.reading.read.upon_gone') ?>
</div>
</div>
<div class="form-group">
<label class="group-name" for="filteractions_read"><?= _t('conf.reading.read.when') ?></label>
<div class="group-controls">
<textarea name="filteractions_read" id="filteractions_read" class="w100"
placeholder="<?= _t('gen.short.blank_to_disable') ?>"><?php
foreach ($this->feed->filtersAction('read') 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>
<p>
<button class="btn" formaction="<?= _url('subscription', 'viewFilter', 'id', $this->feed->id()); ?>" formtarget="_blank">
<?= _t('sub.feed.filteractions.view_filter') ?>
</button>
</p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="keep_max_n_unread"><?= _t('conf.reading.read.keep_max_n_unread') ?></label>
<div class="group-controls">
<input type="number" name="keep_max_n_unread" id="keep_max_n_unread" class="w50" min="1" max="10000000"
value="<?= $this->feed->attributeInt('keep_max_n_unread') ?>"
placeholder="<?= _t('gen.short.by_default') ?>" />
</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.archiving') ?></legend>
<div class="form-group">
<div class="group-controls">
<?= _t('sub.feed.number_entries', $nbEntries) ?>
<a class="btn" href="<?= _url('feed', 'actualize', 'id', $this->feed->id(), '#', 'slider') ?>">
<?= _i('refresh') ?> <?= _t('gen.action.actualize') ?>
</a>
</div>
</div>
<?php
$archiving = $this->feed->attributeArray('archiving');
/** @var array{default?:bool,keep_period?:string,keep_max?:int,keep_min?:int,keep_favourites?:bool,keep_labels?:bool,keep_unreads?:bool}|null $archiving */
if (empty($archiving)) {
$archiving = [ 'default' => true ];
} else {
$archiving['default'] = false;
}
$volatile = [
'enable_keep_period' => false,
'keep_period_count' => '3',
'keep_period_unit' => 'P1M',
];
if (!empty($archiving['keep_period']) && is_string($archiving['keep_period'])) {
if (preg_match('/^PT?(?P<count>\d+)[YMWDH]$/', $archiving['keep_period'], $matches)) {
$volatile['enable_keep_period'] = true;
$volatile['keep_period_count'] = $matches['count'];
$volatile['keep_period_unit'] = str_replace($matches['count'], '1', $archiving['keep_period']);
}
}
//Defaults
if (!isset($archiving['keep_max']) || !is_int($archiving['keep_max'])) {
$archiving['keep_max'] = 0;
}
if (!isset($archiving['keep_min']) || !is_int($archiving['keep_min'])) {
$archiving['keep_min'] = 50;
}
if (!isset($archiving['keep_favourites']) || !is_bool($archiving['keep_favourites'])) {
$archiving['keep_favourites'] = true;
}
if (!isset($archiving['keep_labels']) || !is_bool($archiving['keep_labels'])) {
$archiving['keep_labels'] = true;
}
if (!isset($archiving['keep_unreads']) || !is_bool($archiving['keep_unreads'])) {
$archiving['keep_unreads'] = false;
}
?>
<p class="alert alert-warn">
<?= _t('conf.archiving.policy_warning') ?>
</p>
<div class="form-group">
<div class="group-name"><?= _t('conf.archiving.policy') ?></div>
<div class="group-controls">
<label class="checkbox">
<input type="checkbox" name="use_default_purge_options" id="use_default_purge_options" value="1"<?= $archiving['default'] ? ' checked="checked"' : '' ?> />
<?= _t('gen.short.by_default') ?>
</label>
</div>
</div>
<div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
<div class="group-controls">
<label class="checkbox" for="enable_keep_max">
<input type="checkbox" name="enable_keep_max" id="enable_keep_max" value="1"<?= empty($archiving['keep_max']) ? '' : ' checked="checked"' ?> />
<?= _t('conf.archiving.keep_max') ?>
<input type="number" id="keep_max" name="keep_max" min="0" value="<?= empty($archiving['keep_max']) ? 200 : $archiving['keep_max'] ?>" />
</label>
</div>
</div>
<div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
<div class="group-controls">
<label class="checkbox" for="enable_keep_period">
<input type="checkbox" name="enable_keep_period" id="enable_keep_period" value="1"<?= $volatile['enable_keep_period'] ? ' checked="checked"' : '' ?> />
<?= _t('conf.archiving.keep_period') ?>
<input type="number" id="keep_period_count" name="keep_period_count" min="0" value="<?= $volatile['keep_period_count'] ?>" />
<select class="number" name="keep_period_unit" id="keep_period_unit">
<option></option>
<option value="P1Y" <?= 'P1Y' === $volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.years') ?></option>
<option value="P1M" <?= 'P1M' === $volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.months') ?></option>
<option value="P1W" <?= 'P1W' === $volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.weeks') ?></option>
<option value="P1D" <?= 'P1D' === $volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.days') ?></option>
<option value="PT1H" <?= 'PT1H' === $volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.hours') ?></option>
</select>
</label>
</div>
</div>
<div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
<div class="group-name"><?= _t('conf.archiving.exception') ?></div>
<div class="group-controls">
<label class="checkbox" for="keep_favourites">
<input type="checkbox" name="keep_favourites" id="keep_favourites" value="1"<?= $archiving['keep_favourites'] ? ' checked="checked"' : '' ?> />
<?= _t('conf.archiving.keep_favourites') ?>
</label>
</div>
</div>
<div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
<div class="group-controls">
<label class="checkbox" for="keep_labels">
<input type="checkbox" name="keep_labels" id="keep_labels" value="1"<?= $archiving['keep_labels'] ? ' checked="checked"' : '' ?> />
<?= _t('conf.archiving.keep_labels') ?>
</label>
</div>
</div>
<div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
<div class="group-controls">
<label class="checkbox" for="keep_unreads">
<input type="checkbox" name="keep_unreads" id="keep_unreads" value="1"<?= $archiving['keep_unreads'] ? ' checked="checked"' : '' ?> />
<?= _t('conf.archiving.keep_unreads') ?>
</label>
</div>
</div>
<div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
<div class="group-controls">
<label for="keep_min"><?= _t('sub.feed.keep_min') ?>
<input type="number" id="keep_min" name="keep_min" min="0" value="<?= $archiving['keep_min'] ?>" />
</label>
</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>
<button type="submit" class="btn btn-attention confirm" formmethod="post" formaction="<?= _url('feed', 'truncate', 'id', $this->feed->id(), '#', 'slider') ?>"><?= _t('gen.action.truncate') ?></button>
</div>
</div>
</fieldset>
<fieldset>
<legend><?= _t('sub.feed.kind') ?></legend>
<div class="form-group">
<label class="group-name" for="feed_kind"><?= _t('sub.feed.kind') ?></label>
<div class="group-controls">
<select name="feed_kind" id="feed_kind" class="select-show w100">
<option value="<?= FreshRSS_Feed::KIND_RSS ?>" <?= $this->feed->kind() === FreshRSS_Feed::KIND_RSS ? 'selected="selected"' : '' ?>><?= _t('sub.feed.kind.rss') ?></option>
<option value="<?= FreshRSS_Feed::KIND_HTML_XPATH ?>" <?= $this->feed->kind() === FreshRSS_Feed::KIND_HTML_XPATH ? 'selected="selected"' : '' ?> data-show="html_xpath"><?= _t('sub.feed.kind.html_xpath') ?></option>
<option value="<?= FreshRSS_Feed::KIND_XML_XPATH ?>" <?= $this->feed->kind() === FreshRSS_Feed::KIND_XML_XPATH ? 'selected="selected"' : '' ?> data-show="html_xpath"><?= _t('sub.feed.kind.xml_xpath') ?></option>
<option value="<?= FreshRSS_Feed::KIND_JSONFEED ?>" <?= $this->feed->kind() === FreshRSS_Feed::KIND_JSONFEED ? 'selected="selected"' : '' ?>><?= _t('sub.feed.kind.jsonfeed') ?></option>
<option value="<?= FreshRSS_Feed::KIND_JSON_DOTNOTATION ?>" <?= $this->feed->kind() === FreshRSS_Feed::KIND_JSON_DOTNOTATION ? 'selected="selected"' : '' ?>
data-show="json_dotnotation"><?= _t('sub.feed.kind.json_dotnotation') ?></option>
<option value="<?= FreshRSS_Feed::KIND_HTML_XPATH_JSON_DOTNOTATION ?>" <?= $this->feed->kind() === FreshRSS_Feed::KIND_HTML_XPATH_JSON_DOTNOTATION ? 'selected="selected"' : '' ?>
data-show="json_dotnotation xPathToJsonGroup"><?= _t('sub.feed.kind.html_json') ?></option>
</select>
</div>
</div>
</fieldset>
<fieldset id="html_xpath">
<?php
/** @var array<string> $xpath */
$xpath = Minz_Helper::htmlspecialchars_utf8($this->feed->attributeArray('xpath') ?? []);
?>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.html_xpath.help') ?></p>
<div class="form-group">
<label class="group-name" for="xPathItem"><small><?= _t('sub.feed.kind.html_xpath.xpath') ?></small><br />
<?= _t('sub.feed.kind.html_xpath.item') ?></label>
<div class="group-controls">
<textarea class="valid-xpath w100" name="xPathItem" id="xPathItem" rows="2" cols="64" spellcheck="false"><?= $xpath['item'] ?? '' ?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.html_xpath.item.help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="xPathItemTitle"><small><?= _t('sub.feed.kind.html_xpath.relative') ?></small><br />
<?= _t('sub.feed.kind.html_xpath.item_title') ?></label>
<div class="group-controls">
<textarea class="valid-xpath w100" name="xPathItemTitle" id="xPathItemTitle" rows="2" cols="64" spellcheck="false"><?= $xpath['itemTitle'] ?? '' ?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.html_xpath.item_title.help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="xPathItemContent"><small><?= _t('sub.feed.kind.html_xpath.relative') ?></small><br />
<?= _t('sub.feed.kind.html_xpath.item_content') ?></label>
<div class="group-controls">
<textarea class="valid-xpath w100" name="xPathItemContent" id="xPathItemContent" rows="2" cols="64" spellcheck="false"><?= $xpath['itemContent'] ?? '' ?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.html_xpath.item_content.help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="xPathItemUri"><small><?= _t('sub.feed.kind.html_xpath.relative') ?></small><br />
<?= _t('sub.feed.kind.html_xpath.item_uri') ?></label>
<div class="group-controls">
<textarea class="valid-xpath w100" name="xPathItemUri" id="xPathItemUri" rows="2" cols="64" spellcheck="false"><?= $xpath['itemUri'] ?? '' ?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.html_xpath.item_uri.help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="xPathItemThumbnail"><small><?= _t('sub.feed.kind.html_xpath.relative') ?></small><br />
<?= _t('sub.feed.kind.html_xpath.item_thumbnail') ?></label>
<div class="group-controls">
<textarea class="valid-xpath w100" name="xPathItemThumbnail" id="xPathItemThumbnail" rows="2" cols="64" spellcheck="false"><?= $xpath['itemThumbnail'] ?? '' ?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.html_xpath.item_thumbnail.help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="xPathItemAuthor"><small><?= _t('sub.feed.kind.html_xpath.relative') ?></small><br />
<?= _t('sub.feed.kind.html_xpath.item_author') ?></label>
<div class="group-controls">
<textarea class="valid-xpath w100" name="xPathItemAuthor" id="xPathItemAuthor" rows="2" cols="64" spellcheck="false"><?= $xpath['itemAuthor'] ?? '' ?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.html_xpath.item_author.help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="xPathItemTimestamp"><small><?= _t('sub.feed.kind.html_xpath.relative') ?></small><br />
<?= _t('sub.feed.kind.html_xpath.item_timestamp') ?></label>
<div class="group-controls">
<textarea class="valid-xpath w100" name="xPathItemTimestamp" id="xPathItemTimestamp" rows="2" cols="64" spellcheck="false"><?= $xpath['itemTimestamp'] ?? '' ?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.html_xpath.item_timestamp.help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="xPathItemTimeFormat">
<?= _t('sub.feed.kind.html_xpath.item_timeFormat') ?></label>
<div class="group-controls">
<textarea class="w100" name="xPathItemTimeFormat" id="xPathItemTimeFormat" rows="2" cols="64" spellcheck="false"><?= $xpath['itemTimeFormat'] ?? '' ?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.html_xpath.item_timeFormat.help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="xPathItemCategories"><small><?= _t('sub.feed.kind.html_xpath.relative') ?></small><br />
<?= _t('sub.feed.kind.html_xpath.item_categories') ?></label>
<div class="group-controls">
<textarea class="valid-xpath w100" name="xPathItemCategories" id="xPathItemCategories" rows="2" cols="64" spellcheck="false"><?= $xpath['itemCategories'] ?? '' ?></textarea>
</div>
</div>
<div class="form-group">
<label class="group-name" for="xPathItemUid"><small><?= _t('sub.feed.kind.html_xpath.relative') ?></small><br />
<?= _t('sub.feed.kind.html_xpath.item_uid') ?></label>
<div class="group-controls">
<textarea class="valid-xpath w100" name="xPathItemUid" id="xPathItemUid" rows="2" cols="64" spellcheck="false"><?= $xpath['itemUid'] ?? '' ?></textarea>
</div>
</div>
</fieldset>
<fieldset id="json_dotnotation">
<?php
/** @var array<string,string> $jsonSettings */
$jsonSettings = Minz_Helper::htmlspecialchars_utf8($this->feed->attributeArray('json_dotnotation') ?? []);
$xPathToJson = Minz_Helper::htmlspecialchars_utf8($this->feed->attributeString('xPathToJson'));
?>
<div class="form-group" id="xPathToJsonGroup">
<label class="group-name" for="xPathToJson"><?= _t('sub.feed.kind.html_json.xpath') ?></label>
<div class="group-controls">
<textarea class="valid-xpath w100" name="xPathToJson" id="xPathToJson" rows="2" cols="64" spellcheck="false"><?= $xPathToJson ?? '' ?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.html_json.xpath.help') ?></p>
</div>
</div>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.json_dotnotation.help') ?></p>
<div class="form-group">
<label class="group-name" for="jsonItem"><small><?= _t('sub.feed.kind.json_dotnotation.json') ?></small><br />
<?= _t('sub.feed.kind.json_dotnotation.item') ?></label>
<div class="group-controls">
<textarea class="valid-json w100" name="jsonItem" id="jsonItem" rows="2" cols="64" spellcheck="false"><?= $jsonSettings['item'] ?? '' ?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.json_dotnotation.item.help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="jsonItemTitle"><small><?= _t('sub.feed.kind.json_dotnotation.relative') ?></small><br />
<?= _t('sub.feed.kind.json_dotnotation.item_title') ?></label>
<div class="group-controls">
<textarea class="valid-json w100" name="jsonItemTitle" id="jsonItemTitle" rows="2" cols="64" spellcheck="false"><?= $jsonSettings['itemTitle'] ?? '' ?></textarea>
</div>
</div>
<div class="form-group">
<label class="group-name" for="jsonItemContent"><small><?= _t('sub.feed.kind.json_dotnotation.relative') ?></small><br />
<?= _t('sub.feed.kind.json_dotnotation.item_content') ?></label>
<div class="group-controls">
<textarea class="valid-json w100" name="jsonItemContent" id="jsonItemContent" rows="2" cols="64" spellcheck="false"><?= $jsonSettings['itemContent'] ?? '' ?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.json_dotnotation.item_content.help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="jsonItemUri"><small><?= _t('sub.feed.kind.json_dotnotation.relative') ?></small><br />
<?= _t('sub.feed.kind.json_dotnotation.item_uri') ?></label>
<div class="group-controls">
<textarea class="valid-json w100" name="jsonItemUri" id="jsonItemUri" rows="2" cols="64" spellcheck="false"><?= $jsonSettings['itemUri'] ?? '' ?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.json_dotnotation.item_uri.help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="jsonItemThumbnail"><small><?= _t('sub.feed.kind.json_dotnotation.relative') ?></small><br />
<?= _t('sub.feed.kind.json_dotnotation.item_thumbnail') ?></label>
<div class="group-controls">
<textarea class="valid-json w100" name="jsonItemThumbnail" id="jsonItemThumbnail" rows="2" cols="64" spellcheck="false"><?= $jsonSettings['itemThumbnail'] ?? '' ?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.json_dotnotation.item_thumbnail.help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="jsonItemAuthor"><small><?= _t('sub.feed.kind.json_dotnotation.relative') ?></small><br />
<?= _t('sub.feed.kind.json_dotnotation.item_author') ?></label>
<div class="group-controls">
<textarea class="valid-json w100" name="jsonItemAuthor" id="jsonItemAuthor" rows="2" cols="64" spellcheck="false"><?= $jsonSettings['itemAuthor'] ?? '' ?></textarea>
</div>
</div>
<div class="form-group">
<label class="group-name" for="jsonItemTimestamp"><small><?= _t('sub.feed.kind.json_dotnotation.relative') ?></small><br />
<?= _t('sub.feed.kind.json_dotnotation.item_timestamp') ?></label>
<div class="group-controls">
<textarea class="valid-json w100" name="jsonItemTimestamp" id="jsonItemTimestamp" rows="2" cols="64" spellcheck="false"><?= $jsonSettings['itemTimestamp'] ?? '' ?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.json_dotnotation.item_timestamp.help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="jsonItemTimeFormat">
<?= _t('sub.feed.kind.json_dotnotation.item_timeFormat') ?></label>
<div class="group-controls">
<textarea class="w100" name="jsonItemTimeFormat" id="jsonItemTimeFormat" rows="2" cols="64" spellcheck="false"><?= $jsonSettings['itemTimeFormat'] ?? '' ?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.json_dotnotation.item_timeFormat.help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="jsonItemCategories"><small><?= _t('sub.feed.kind.json_dotnotation.relative') ?></small><br />
<?= _t('sub.feed.kind.json_dotnotation.item_categories') ?></label>
<div class="group-controls">
<textarea class="valid-json w100" name="jsonItemCategories" id="jsonItemCategories" rows="2" cols="64" spellcheck="false"><?= $jsonSettings['itemCategories'] ?? '' ?></textarea>
</div>
</div>
<div class="form-group">
<label class="group-name" for="jsonItemUid"><small><?= _t('sub.feed.kind.json_dotnotation.relative') ?></small><br />
<?= _t('sub.feed.kind.json_dotnotation.item_uid') ?></label>
<div class="group-controls">
<textarea class="valid-json w100" name="jsonItemUid" id="jsonItemUid" rows="2" cols="64" spellcheck="false"><?= $jsonSettings['itemUid'] ?? '' ?></textarea>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
<button 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.content_retrieval') ?></legend>
<div class="form-group">
<label class="group-name" for="path_entries"><?= _t('sub.feed.css_path') ?></label>
<div class="group-controls">
<div class="stick w100">
<input type="text" name="path_entries" id="path_entries" class="w100" value="<?= $this->feed->pathEntries() ?>" placeholder="<?= _t('gen.short.blank_to_disable') ?>" />
<a id="popup-preview-selector" class="btn" href="<?=
_url('feed', 'contentSelectorPreview', 'id', $this->feed->id(), 'selector', 'selector-token', 'selector_filter', 'selector-filter-token', '#', 'slider') ?>"><?= _i('look') ?></a>
</div>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.css_help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="path_entries_conditions"><?= _t('sub.feed.path_entries_conditions') ?></label>
<div class="group-controls">
<textarea class="w100" id="path_entries_conditions" name="path_entries_conditions"
rows="3" cols="64" spellcheck="false" placeholder="<?= _t('gen.short.blank_to_disable') ?>"><?php
foreach ($this->feed->attributeArray('path_entries_conditions') ?? [] as $condition) {
if (is_string($condition)) {
echo htmlspecialchars($condition, ENT_NOQUOTES, 'UTF-8'), PHP_EOL;
}
}
?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.filteractions.help') ?></p>
</div>
</div>
</fieldset>
<fieldset>
<legend><?= _t('sub.feed.advanced') ?></legend>
<div class="form-group">
<?php
$path_entries_filter = Minz_Helper::htmlspecialchars_utf8($this->feed->attributeString('path_entries_filter') ?? '');
?>
<label class="group-name" for="path_entries_filter"><?= _t('sub.feed.css_path_filter') ?></label>
<div class="group-controls">
<div class="w100">
<input type="text" name="path_entries_filter" id="path_entries_filter" class="w100" value="<?= $path_entries_filter ?>" placeholder="<?= _t('gen.short.blank_to_disable') ?>" />
</div>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.css_path_filter.help') ?></p>
</div>
</div>
<div class="form-group">
<?php
/** @var array<int,int|string> $curlParams */
$curlParams = $this->feed->attributeArray('curl_params') ?? [];
?>
<label class="group-name" for="curl_params_cookie"><?= _t('sub.feed.css_cookie') ?></label>
<div class="group-controls">
<input type="text" name="curl_params_cookie" id="curl_params_cookie" class="w100" value="<?=
htmlspecialchars((string)($curlParams[CURLOPT_COOKIE] ?? ''), ENT_COMPAT, 'UTF-8')
?>" placeholder="<?= _t('gen.short.blank_to_disable') ?>" />
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.css_cookie_help') ?></p>
<label for="curl_params_cookiefile">
<input type="checkbox" name="curl_params_cookiefile" id="curl_params_cookiefile" value="1"<?=
isset($curlParams[CURLOPT_COOKIEFILE]) ? ' checked="checked"' : ''
?> />
<?= _t('sub.feed.accept_cookies') ?>
</label>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.accept_cookies_help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="curl_params_redirects"><?= _t('sub.feed.max_http_redir') ?></label>
<div class="group-controls">
<input type="number" name="curl_params_redirects" id="curl_params_redirects" class="w50" min="-1" value="<?=
!empty($curlParams[CURLOPT_MAXREDIRS]) ? $curlParams[CURLOPT_MAXREDIRS] : ''
?>" placeholder="<?= _t('gen.short.blank_to_disable') ?>" />
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.max_http_redir_help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="content_action"><?= _t('sub.feed.content_action') ?></label>
<div class="group-controls">
<select name="content_action" id="content_action" class="w50">
<option value="replace"<?= 'replace' === $this->feed->attributeString('content_action') ? ' selected="selected"' : '' ?>><?= _t('sub.feed.content_action.replace') ?></option>
<option value="prepend"<?= 'prepend' === $this->feed->attributeString('content_action') ? ' selected="selected"' : '' ?>><?= _t('sub.feed.content_action.prepend') ?></option>
<option value="append"<?= 'append' === $this->feed->attributeString('content_action') ? ' selected="selected"' : '' ?>><?= _t('sub.feed.content_action.append') ?></option>
</select>
</div>
</div>
<div class="form-group">
<label class="group-name" for="curl_params_useragent"><?= _t('sub.feed.useragent') ?></label>
<div class="group-controls">
<input type="text" name="curl_params_useragent" id="curl_params_useragent" class="w100" value="<?=
htmlspecialchars((string)($curlParams[CURLOPT_USERAGENT] ?? ''), ENT_COMPAT, 'UTF-8')
?>" placeholder="<?= _t('gen.short.by_default') ?>" />
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.useragent_help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="proxy_type"><?= _t('sub.feed.proxy') ?></label>
<div class="group-controls">
<select name="proxy_type" id="proxy_type"><?php
defined('CURLPROXY_HTTPS') or define('CURLPROXY_HTTPS', 2); // Compatibility cURL 7.51
$type = $curlParams[CURLOPT_PROXYTYPE] ?? '';
if ($type === 3) { // Legacy for NONE
$type = -1;
}
foreach (['' => '', -1 => 'NONE', CURLPROXY_HTTP => 'HTTP', CURLPROXY_HTTPS => 'HTTPS',
CURLPROXY_SOCKS4 => 'SOCKS4', CURLPROXY_SOCKS4A => 'SOCKS4A', CURLPROXY_SOCKS5 => 'SOCKS5',
CURLPROXY_SOCKS5_HOSTNAME => 'SOCKS5H'] as $k => $v) {
echo '<option value="' . $k . ($type === $k ? '" selected="selected' : '' ) . '">' . $v . '</option>';
}
?>
</select>
<input type="text" name="curl_params" id="curl_params" value="<?=
htmlspecialchars((string)($curlParams[CURLOPT_PROXY] ?? ''), ENT_COMPAT, 'UTF-8')
?>" placeholder="<?= _t('gen.short.by_default') ?>" />
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.proxy_help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="curl_method"><?= _t('sub.feed.method') ?></label>
<div class="group-controls">
<select class="number" name="curl_method" id="curl_method"><?php
$curl_method = 'GET';
if ($this->feed->attributeArray('curl_params') !== null && !empty($this->feed->attributeArray('curl_params')[CURLOPT_POST])) {
$curl_method = 'POST';
}
foreach (['GET' => 'GET', 'POST' => 'POST'] as $k => $v) {
echo '<option value="' . $k . ($curl_method === $k ? '" selected="selected' : '') . '">' . $v . '</option>';
}
?>
</select>
<div class="stick">
<?php
$postFields = $this->feed->attributeArray('curl_params')[CURLOPT_POSTFIELDS] ?? '';
if (!is_string($postFields)) {
$postFields = '';
}
?>
<input type="text" name="curl_fields" id="curl_fields" value="<?=
htmlspecialchars($postFields, ENT_COMPAT, 'UTF-8')
?>" placeholder="<?= _t('sub.feed.method_postparams') ?>" />
</div>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.method_help') ?></p>
</div>
</div>
<div class="form-group">
<label class="group-name" for="timeout"><?= _t('sub.feed.timeout') ?></label>
<div class="group-controls">
<input type="number" name="timeout" id="timeout" class="w50" min="3" max="900" value="<?= $this->feed->attributeInt('timeout') ?>" placeholder="<?= _t('gen.short.by_default') ?>" />
</div>
</div>
<div class="form-group">
<label class="group-name" for="ssl_verify"><?= _t('sub.feed.ssl_verify') ?></label>
<div class="group-controls">
<select name="ssl_verify" id="ssl_verify" class="w50">
<option value=""<?= $this->feed->attributeBoolean('ssl_verify') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
<option value="0"<?= $this->feed->attributeBoolean('ssl_verify') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
<option value="1"<?= $this->feed->attributeBoolean('ssl_verify') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option>
</select>
</div>
</div>
<div class="form-group">
<label class="group-name" for="http_headers"><?= _t('sub.feed.http_headers') ?></label>
<div class="group-controls">
<?php
$httpHeaders = $this->feed->attributeArray('curl_params')[CURLOPT_HTTPHEADER] ?? [];
if (!is_array($httpHeaders)) {
$httpHeaders = [];
}
$httpHeaders = array_filter($httpHeaders, 'is_string');
// Remove headers problematic for security
$httpHeaders = array_filter($httpHeaders,
fn(string $header) => !preg_match('/^(Remote-User|X-WebAuth-User)\\s*:/i', $header));
?>
<textarea class="w100" id="http_headers" name="http_headers" rows="3" spellcheck="false"><?php
foreach ($httpHeaders as $header) {
echo htmlspecialchars($header, ENT_NOQUOTES, 'UTF-8'), PHP_EOL;
}
?></textarea>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.http_headers_help') ?></p>
</div>
</div>
<div class="form-group">
<div class="group-controls">
<label class="checkbox" for="clear_cache">
<input type="checkbox" name="clear_cache" id="clear_cache" value="1"<?= $this->feed->attributeBoolean('clear_cache') ? ' checked="checked"' : '' ?> />
<?= _t('sub.feed.clear_cache') ?>
</label>
</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>
</form>
<h2><?= _t('sub.feed.maintenance.title') ?></h2>
<div class="form-group">
<div class="group-controls">
<button class="btn btn-important" form="post-csrf" formaction="<?= _url('feed', 'clearCache', 'id', $this->feed->id(), '#', 'slider') ?>">
<?= _t('sub.feed.maintenance.clear_cache') ?>
</button>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.maintenance.clear_cache_help') ?></p>
</div>
<div class="group-controls">
<form method="post" action="<?= _url('feed', 'reload', '#', 'slider') ?>">
<input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<input type="hidden" name="id" value="<?= $this->feed->id() ?>" />
<button type="submit" class="btn btn-important">
<?= _t('sub.feed.maintenance.reload_articles') ?>
</button>
<input type="number" name="reload_limit" min="1" value="10" />
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.maintenance.reload_articles_help') ?></p>
</form>
</div>
</div>
<h2><?= _t('sub.import_export.export') ?></h2>
<div class="form-group">
<div class="group-name"><?= _t('sub.feed.export-as-opml.label') ?></div>
<div class="group-controls">
<a class="btn btn-important" href="<?= _url('index', 'opml', 'get', 'f_' . $this->feed->id()) ?>" download="f_<?= $this->feed->id() ?> <?= $this->feed->name(true) ?>.opml.xml">
<?= _t('sub.feed.export-as-opml.download') ?>
</a>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.export-as-opml.help') ?></p>
</div>
</div>
</div>
<div id="popup">
<div id="popup-content">
<div id="popup-close" class="popup-row"><?= _i('close') ?></div>
<div id="popup-iframe-container" class="popup-row">
<div id="popup-iframe-sub">
<iframe id="popup-iframe" frameborder="0"></iframe>
</div>
</div>
</div>
</div>