code review and doc

This commit is contained in:
Jean-Christian Paul Denis 2023-04-22 00:21:30 +02:00
parent dd0e90cd5e
commit 2948be39fd
Signed by: JcDenis
GPG Key ID: 1B5B8C5B90B6C951
20 changed files with 640 additions and 419 deletions

View File

@ -48,7 +48,7 @@ class Backend extends dcNsProcess
return false;
}
# Admin menu
// backend sidebar menu icon
dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem(
My::name(),
dcCore::app()->adminurl?->get('admin.plugin.' . My::id()),
@ -58,7 +58,7 @@ class Backend extends dcNsProcess
);
dcCore::app()->addBehaviors([
# Dashboard favorites
// backend user dashboard favorites icon
'adminDashboardFavoritesV2' => function (dcFavorites $favs): void {
$favs->register(My::id(), [
'title' => My::name(),
@ -68,11 +68,11 @@ class Backend extends dcNsProcess
'permissions' => dcCore::app()->auth?->makePermissions([dcCore::app()->auth::PERMISSION_CONTENT_ADMIN]),
]);
},
# Preference form
// backend user preference form
'adminBlogPreferencesFormV2' => function (dcSettings $blog_settings): void {
$active = (bool) $blog_settings->get(My::id())->get('active');
$allowedtplvalues = Epc::blogAllowedTplValues();
$allowedpubpages = Epc::blogAllowedPubPages();
$allowedtplvalues = Epc::blogAllowedTemplateValue();
$allowedpubpages = Epc::blogAllowedTemplatePage();
echo
'<div class="fieldset"><h4 id="epc_params">' . My::name() . '</h4>' .
@ -95,13 +95,13 @@ class Backend extends dcNsProcess
// allowedtplvalues
(new Para())->items([
(new Label(__('Allowed DC template values:'), Label::OUTSIDE_LABEL_BEFORE))->for('epc_allowedtplvalues'),
(new Input('epc_allowedtplvalues'))->size(100)->maxlenght(0)->value(Epc::implode($allowedtplvalues)),
(new Input('epc_allowedtplvalues'))->size(100)->maxlenght(0)->value(Epc::encodeMulti($allowedtplvalues)),
])->render() .
'<p class="form-note">' . __('Use "readable_name1:template_value1;readable_name2:template_value2;" like "entry content:EntryContent;entry excerpt:EntryExcerpt;".') . '</p>' .
// allowedpubpages
(new Para())->items([
(new Label(__('Allowed public pages:'), Label::OUTSIDE_LABEL_BEFORE))->for('epc_allowedpubpages'),
(new Input('epc_allowedpubpages'))->size(100)->maxlenght(0)->value(Epc::implode($allowedpubpages)),
(new Input('epc_allowedpubpages'))->size(100)->maxlenght(0)->value(Epc::encodeMulti($allowedpubpages)),
])->render() .
'<p class="form-note">' . __('Use "readable_name1:template_page1;readable_name2:template_page2;" like "post page:post.html;home page:home.html;".') . '</p>' .
'</div>' .
@ -109,17 +109,17 @@ class Backend extends dcNsProcess
'<br class="clear" />' .
'</div>';
},
# Save preference
// backend user preference save
'adminBeforeBlogSettingsUpdate' => function (dcSettings $blog_settings): void {
$active = !empty($_POST['epc_active']);
$allowedtplvalues = Epc::explode($_POST['epc_allowedtplvalues']);
$allowedpubpages = Epc::explode($_POST['epc_allowedpubpages']);
$allowedtplvalues = Epc::decodeMulti($_POST['epc_allowedtplvalues']);
$allowedpubpages = Epc::decodeMulti($_POST['epc_allowedpubpages']);
$blog_settings->get(My::id())->put('active', $active);
$blog_settings->get(My::id())->put('allowedtplvalues', json_encode($allowedtplvalues));
$blog_settings->get(My::id())->put('allowedpubpages', json_encode($allowedpubpages));
},
# List filter
// backend epc list filter
'adminFiltersListsV2' => function (ArrayObject $sorts): void {
$sorts['epc'] = [
My::name(),
@ -134,7 +134,7 @@ class Backend extends dcNsProcess
[__('records per page'), 20],
];
},
# Widgets
// widgets registration
'initWidgets' => [Widgets::class, 'initWidgets'],
]);

View File

@ -22,57 +22,65 @@ use Dotclear\Helper\Html\Form\Checkbox;
use Dotclear\Helper\Html\Html;
/**
* @ingroup DC_PLUGIN_PERIODICAL
* @brief Periodical - admin pager methods.
* @since 2.6
* Backend filters values list.
*/
class BackendList extends adminGenericListV2
{
public function display(adminGenericFilterV2 $filter, string $pager_url, string $enclose_block): void
/**
* Display list.
*
* @param adminGenericFilterV2 $filter The filter
* @param string $url The pager URL
* @param string $block The enclose bloc
*/
public function display(adminGenericFilterV2 $filter, string $url, string $block): void
{
if ($this->rs->isEmpty()) {
echo '<p><strong>' . ($filter->show() ? __('No record matches the filter') : __('No record')) . '</strong></p>';
} else {
$pager = new dcPager($filter->value('page'), $this->rs_count, $filter->value('nb'), 10);
$pager->base_url = $pager_url;
$epc_id = [];
if (isset($_REQUEST['epc_id'])) {
foreach ($_REQUEST['epc_id'] as $v) {
$epc_id[(int) $v] = true;
}
}
$cols = [
'key' => '<th colspan="2" class="first">' . __('Key') . '</th>',
'value' => '<th scope="col">' . __('Value') . '</th>',
'date' => '<th scope="col">' . __('Date') . '</th>',
];
$html_block = '<div class="table-outer"><table><caption>' .
(
$filter->show() ?
sprintf(__('List of %s records matching the filter.'), $this->rs_count) :
sprintf(__('List of %s records.'), $this->rs_count)
) . '</caption>' .
'<tr>' . implode($cols) . '</tr>%s</table>%s</div>';
if ($enclose_block) {
$html_block = sprintf($enclose_block, $html_block);
}
$blocks = explode('%s', $html_block);
echo $pager->getLinks() . $blocks[0];
while ($this->rs->fetch()) {
echo $this->line(isset($epc_id[$this->rs->epc_id]));
}
echo $blocks[1] . $blocks[2] . $pager->getLinks();
return;
}
$pager = new dcPager($filter->value('page'), $this->rs_count, $filter->value('nb'), 10);
$pager->base_url = $url;
$epc_id = [];
if (isset($_REQUEST['epc_id'])) {
foreach ($_REQUEST['epc_id'] as $v) {
$epc_id[(int) $v] = true;
}
}
$cols = [
'key' => '<th colspan="2" class="first">' . __('Key') . '</th>',
'value' => '<th scope="col">' . __('Value') . '</th>',
'date' => '<th scope="col">' . __('Date') . '</th>',
];
$content = '<div class="table-outer"><table><caption>' . (
$filter->show() ?
sprintf(__('List of %s records matching the filter.'), $this->rs_count) :
sprintf(__('List of %s records.'), $this->rs_count)
) . '</caption>' .
'<tr>' . implode($cols) . '</tr>%s</table>%s</div>';
$blocks = explode('%s', sprintf($block, $content));
echo $pager->getLinks() . $blocks[0];
while ($this->rs->fetch()) {
$this->line(isset($epc_id[$this->rs->epc_id]));
}
echo $blocks[1] . $blocks[2] . $pager->getLinks();
}
private function line(bool $checked): string
/**
* Dispay a list line.
*
* @param bool $checked Checkbox checked
*/
private function line(bool $checked): void
{
$cols = [
'check' => '<td class="nowrap">' . (new Checkbox(['epc_id[]'], $checked))->value($this->rs->epc_id)->render() . '</td>',
@ -81,9 +89,9 @@ class BackendList extends adminGenericListV2
'date' => '<td class="nowrap count">' . Date::dt2str(__('%Y-%m-%d %H:%M'), $this->rs->epc_upddt) . '</td>',
];
return
'<tr class="line" id="p' . $this->rs->epc_id . '">' .
implode($cols) .
'</tr>';
echo
'<tr class="line" id="p' . $this->rs->epc_id . '">' .
implode($cols) .
'</tr>';
}
}

View File

@ -33,39 +33,54 @@ __('RSS feeds');
class Epc
{
/** @var string The temporary pattern to tag words to replace */
public const FLAGGER = 'ççççç%sççççç';
/** @var EpcFilters $filters THe filters stack */
private static EpcFilters $filters;
public static array $epcFilterLimit = [];
#
# Default definition
#
/** @var array<string,int> $limits The replacment limit per filtre */
private static array $limits = [];
public static function defaultAllowedTplValues(): array
/**
* Get list of default allowed templates name->tag.
*
* @return array<string,string> The templates name->tag pairs
*/
public static function defaultAllowedTemplateValue(): array
{
$rs = new ArrayObject([
$list = new ArrayObject([
'entry excerpt' => 'EntryExcerpt',
'entry content' => 'EntryContent',
'comment content' => 'CommentContent',
]);
# --BEHAVIOR-- enhancePostContentAllowedTplValues : ArrayObject
dcCore::app()->callBehavior('enhancePostContentAllowedTplValues', $rs);
dcCore::app()->callBehavior('enhancePostContentAllowedTplValues', $list);
return iterator_to_array($rs, true);
return iterator_to_array($list, true);
}
public static function blogAllowedTplValues(): array
/**
* Get list of allowed templates name->tag set on current blog.
*
* @return array<string,string> The templates name->tag pairs
*/
public static function blogAllowedTemplateValue(): array
{
$rs = json_decode((string) dcCore::app()->blog?->settings->get(My::id())->get('allowedtplvalues'), true);
$list = json_decode((string) dcCore::app()->blog?->settings->get(My::id())->get('allowedtplvalues'), true);
return is_array($rs) ? $rs : self::defaultAllowedTplValues();
return is_array($list) ? $list : self::defaultAllowedTemplateValue();
}
public static function defaultAllowedWidgetValues(): array
/**
* Get list of allowed templates name->[tag,callback] to list on epc widgets.
*
* @return array The templates name->[id,cb] values
*/
public static function widgetAllowedTemplateValue(): array
{
$rs = new ArrayObject([
$list = new ArrayObject([
'entry excerpt' => [
'id' => 'entryexcerpt',
'cb' => [self::class, 'widgetContentEntryExcerpt'],
@ -81,14 +96,19 @@ class Epc
]);
# --BEHAVIOR-- enhancePostContentAllowedWidgetValues : ArrayObject
dcCore::app()->callBehavior('enhancePostContentAllowedWidgetValues', $rs);
dcCore::app()->callBehavior('enhancePostContentAllowedWidgetValues', $list);
return iterator_to_array($rs, true);
return iterator_to_array($list, true);
}
public static function defaultAllowedPubPages(): array
/**
* Get list of default allowed templates name->page to list on epc widgets.
*
* @return array<string,string> The templates name->page pairs
*/
public static function defaultAllowedTemplatePage(): array
{
$rs = new ArrayObject([
$list = new ArrayObject([
'home page' => 'home.html',
'post page' => 'post.html',
'category page' => 'category.html',
@ -98,16 +118,21 @@ class Epc
]);
# --BEHAVIOR-- enhancePostContentAllowedPubPages : ArrayObject
dcCore::app()->callBehavior('enhancePostContentAllowedPubPages', $rs);
dcCore::app()->callBehavior('enhancePostContentAllowedPubPages', $list);
return iterator_to_array($rs, true);
return iterator_to_array($list, true);
}
public static function blogAllowedPubPages(): array
/**
* Get list of allowed templates name->page set on blog to list on epc widgets.
*
* @return array<string,string> The templates name->page pairs
*/
public static function blogAllowedTemplatePage(): array
{
$rs = json_decode((string) dcCore::app()->blog?->settings->get(My::id())->get('allowedpubpages'), true);
$list = json_decode((string) dcCore::app()->blog?->settings->get(My::id())->get('allowedpubpages'), true);
return is_array($rs) ? $rs : self::defaultAllowedPubPages();
return is_array($list) ? $list : self::defaultAllowedTemplatePage();
}
/**
@ -135,153 +160,193 @@ class Epc
return self::$filters;
}
public static function testContext(string $tag, array $args, EpcFilter $filter): bool
{
return in_array((string) dcCore::app()->ctx?->__get('current_tpl'), $filter->pubPages)
&& in_array($tag, $filter->tplValues)
&& $args[0] != '' //content
&& empty($args['encode_xml'])
&& empty($args['encode_html'])
&& empty($args['remove_html'])
&& empty($args['strip_tags'])
;
}
public static function replaceString(string $p, string $r, string $s, EpcFilter $filter, string $before = '\b', string $after = '\b'): string
{
# Limit
/**
* Apply filter to content.
*
* @param string $search The search
* @param string $replacement The replacement
* @param string $content The content
* @param EpcFilter $filter The filter
* @param string $before The start limit pattern
* @param string $after The end limit pattern
*/
public static function replaceString(
string $search,
string $replacement,
string $content,
EpcFilter $filter,
string $before = '\b',
string $after = '\b'
): string {
// Limit
if ($filter->limit > 0) {
$limit = array_key_exists($filter->id() . '_' . $p, self::$epcFilterLimit) ? self::$epcFilterLimit[$filter->id() . '_' . $p] : $filter->limit;
// memorize limit between two template values
$limit = array_key_exists($filter->id() . '_' . $search, self::$limits) ? self::$limits[$filter->id() . '_' . $search] : $filter->limit;
if ($limit < 1) {
return $s;
return $content;
}
} else {
$limit = -1;
}
# Case sensitive
$i = $filter->nocase ? 'i' : '';
// Case sensitive
$caseless = $filter->nocase ? 'i' : '';
# Plural
$x = $filter->plural ? $p . 's|' . $p : $p;
$plural = $filter->plural ? 's?' : '';
# Mark words
$ret = preg_replace('#(' . $before . ')(' . $x . ')(' . $after . ')#su' . $i, '$1' . sprintf(self::FLAGGER, '$2') . '$3', $s, -1, $count);
// Mark words
$ret = preg_replace('#(' . $before . ')(' . $search . $plural . ')(' . $after . ')#su' . $caseless, '$1' . sprintf(self::FLAGGER, '$2') . '$3', $content, -1, $count);
if (is_string($ret)) {
$s = $ret;
$content = $ret;
}
# Nothing to parse
// Nothing to parse
if (!$count) {
return $s;
return $content;
}
# Remove words that are into unwanted html tags
$ignore_tags = array_merge(self::decodeTags($filter->htmltag), self::decodeTags($filter->notag));
if (!empty($ignore_tags)) {
$tags = implode('|', array_unique($ignore_tags));
$ret = preg_replace_callback('#(<(' . $tags . ')[^>]*?>)(.*?)(</\\2>)#s', [self::class, 'removeTags'], $s);
// Remove words that are into unwanted html tags
$ignore = array_merge(self::decodeSingle($filter->ignore), self::decodeSingle($filter->notag));
if (!empty($ignore)) {
$ret = preg_replace_callback('#(<(' . implode('|', array_unique($ignore)) . ')[^>]*?>)(.*?)(</\\2>)#s', function (array $m): string {
return $m[1] . preg_replace('#' . sprintf(self::FLAGGER, '(?!') . ')#s', '$1', $m[3]) . $m[4];
}, $content);
if (is_string($ret)) {
$s = $ret;
$content = $ret;
}
}
# Remove words inside html tag (class, title, alt, href, ...)
$ret = preg_replace('#(' . sprintf(self::FLAGGER, '(' . $x . '(s|))') . ')(?=[^<]*>)#s' . $i, '$2$4', $s);
// Remove words inside html tag (class, title, alt, href, ...)
$ret = preg_replace('#(' . sprintf(self::FLAGGER, '(' . $search . '(' . $plural . '))') . ')(?=[^<]*>)#s' . $caseless, '$2$4', $content);
if (is_string($ret)) {
$s = $ret;
$content = $ret;
}
# Replace words by what you want (with limit)
$ret = preg_replace('#' . sprintf(self::FLAGGER, '(' . $p . '(s|))') . '#s' . $i, $r, $s, $limit, $count);
// Replace words by what you want (with limit)
$ret = preg_replace('#' . sprintf(self::FLAGGER, '(' . $search . '(' . $plural . '))') . '#s' . $caseless, $replacement, $content, $limit, $count);
if (is_string($ret)) {
$s = $ret;
$content = $ret;
}
# update limit
self::$epcFilterLimit[$filter->id() . '_' . $p] = $limit - $count;
// update limit
self::$limits[$filter->id() . '_' . $search] = $limit - $count;
# Clean rest
$ret = preg_replace('#' . sprintf(self::FLAGGER, '(.*?)') . '#s', '$1', $s);
// Clean rest
$ret = preg_replace('#' . sprintf(self::FLAGGER, '(.*?)') . '#s', '$1', $content);
if (is_string($ret)) {
$s = $ret;
$content = $ret;
}
return $s;
return $content;
}
public static function matchString(string $p, string $r, string $s, EpcFilter $filter, string $before = '\b', string $after = '\b'): array
{
# Case sensitive
$i = $filter->nocase ? 'i' : '';
# Plural
$x = $filter->plural ? $p . 's|' . $p : $p;
# Mark words
$t = preg_match_all('#' . $before . '(' . $x . ')' . $after . '#su' . $i, $s, $matches);
# Nothing to parse
if (!$t) {
return ['total' => 0, 'matches' => []];
}
# Build array
$m = [];
$loop = 0;
foreach ($matches[1] as $match) {
$m[$loop]['key'] = $match;
$m[$loop]['match'] = preg_replace('#(' . $p . '(s|))#s' . $i, $r, $match, -1, $count);
$m[$loop]['num'] = $count;
$loop++;
}
return ['total' => $t, 'matches' => $m];
/**
* Find filter on content.
*
* @param string $search The search
* @param string $replacement The replacement
* @param string $content The content
* @param EpcFilter $filter The filter
* @param string $before The start limit pattern
* @param string $after The end limit pattern
*/
public static function matchString(
string $search,
string $replacement,
string $content,
EpcFilter $filter,
string $before = '\b',
string $after = '\b'
): array {
return [
'total' => (int) preg_match_all('#' . $before . '(' . $search . ($filter->plural ? 's?' : '') . ')' . $after . '#su' . ($filter->nocase ? 'i' : ''), $content),
'search' => $search,
'replacement' => preg_replace('#(' . $search . ')#', $replacement, $search),
];
}
public static function quote(string $s): string
/**
* Quote regular expression according to epc parser.
*
* @param string $string The string
*
* @return string The quoted string
*/
public static function quote(string $string): string
{
return preg_quote($s, '#');
return preg_quote($string, '#');
}
public static function removeTags(array $m): string
/**
* Implode simple array into string a,b,c.
*
* @param array|string $values The values
*
* @return string The value
*/
public static function encodeSingle(array|string $values): string
{
return $m[1] . preg_replace('#' . sprintf(self::FLAGGER, '(?!') . ')#s', '$1', $m[3]) . $m[4];
return implode(',', self::decodeSingle($values));
}
public static function decodeTags(string $t): array
/**
* Explode string into simple array [a,b,c].
*
* @param array|string $value The value
*
* @return array The values
*/
public static function decodeSingle(array|string $value): array
{
return preg_match_all('#([A-Za-z0-9]+)#', (string) $t, $m) ? $m[1] : [];
if (is_array($value)) {
$value = implode(',', $value);
}
return preg_match_all('#([A-Za-z0-9]+)#', (string) $value, $matches) ? $matches[1] : [];
}
public static function implode(array|string $a): string
/**
* Implode complexe array into string a:aa:b:bb;c:cc.
*
* @param array|string $values The values
*
* @return string The value
*/
public static function encodeMulti(array|string $values): string
{
if (is_string($a)) {
return $a;
}
if (!is_array($a)) {
return '';
if (is_string($values)) {
return $values;
}
$r = '';
foreach ($a as $k => $v) {
$r .= $k . ':' . $v . ';';
$string = '';
foreach ($values as $key => $value) {
$string .= $key . ':' . $value . ';';
}
return $r;
return $string;
}
public static function explode(array|string $s): array
/**
* Explode string into complexe array [a=>aa,b=>aa,c=>cc].
*
* @param array|string $value The value
*
* @return array The values
*/
public static function decodeMulti(array|string $value): array
{
if (is_array($s)) {
return $s;
if (is_array($value)) {
return $value;
}
if (!is_string($s)) {
$values = [];
$exp = explode(';', (string) $value);
if (!is_array($exp)) {
return [];
}
$r = [];
$s = explode(';', (string) $s);
if (!is_array($s)) {
return [];
}
foreach ($s as $cpl) {
foreach ($exp as $cpl) {
$cur = explode(':', $cpl);
if (!is_array($cur) || !isset($cur[1])) {
@ -295,59 +360,75 @@ class Epc
continue;
}
$r[$key] = $val;
$values[$key] = $val;
}
return $r;
return $values;
}
#
# Widgets
#
public static function widgetContentEntryExcerpt(?WidgetsElement $w = null): string
/**
* Send entries excerpts to widget.
*
* @param WidgetsElement|null $widget The widgets
*
* @return string The entries exceprts
*/
public static function widgetContentEntryExcerpt(?WidgetsElement $widget = null): string
{
if (is_null(dcCore::app()->ctx) || !dcCore::app()->ctx->exists('posts')) {
return '';
}
$res = '';
$content = '';
while (dcCore::app()->ctx->__get('posts')?->fetch()) {
$res .= dcCore::app()->ctx->__get('posts')->f('post_excerpt');
$content .= dcCore::app()->ctx->__get('posts')->f('post_excerpt');
}
return $res;
return $content;
}
public static function widgetContentEntryContent(): string
/**
* Send entries contents to widget.
*
* @param WidgetsElement|null $widget The widgets
*
* @return string The entries contents
*/
public static function widgetContentEntryContent(?WidgetsElement $widget = null): string
{
if (is_null(dcCore::app()->ctx) || !dcCore::app()->ctx->exists('posts')) {
return '';
}
$res = '';
$content = '';
while (dcCore::app()->ctx->__get('posts')?->fetch()) {
$res .= dcCore::app()->ctx->__get('posts')->f('post_content');
$content .= dcCore::app()->ctx->__get('posts')->f('post_content');
}
return $res;
return $content;
}
public static function widgetContentCommentContent(): string
/**
* Send entries comments to widget.
*
* @param WidgetsElement|null $widget The widgets
*
* @return string The entries comments
*/
public static function widgetContentCommentContent(?WidgetsElement $widget = null): string
{
if (is_null(dcCore::app()->ctx) || !dcCore::app()->ctx->exists('posts')) {
return '';
}
$res = '';
$post_ids = [];
$content = '';
while (dcCore::app()->ctx->__get('posts')?->fetch()) {
$comments = dcCore::app()->blog?->getComments(['post_id' => dcCore::app()->ctx->__get('posts')->f('post_id')]);
while ($comments?->fetch()) {
$res .= $comments->getContent();
$content .= $comments->getContent();
}
}
return $res;
return $content;
}
}

View File

@ -20,31 +20,67 @@ use dcRecord;
use Dotclear\Plugin\widgets\WidgetsElement;
use Exception;
/**
* Filter abstract class.
*
* All filter must extends this class.
*/
abstract class EpcFilter
{
/** @var string $id The filter id */
protected string $id = 'undefined';
/** @var dcRecord $records The filter record if any */
private ?dcRecord $records = null;
// properties
/** @var int $priority The filter priority (property) */
public readonly int $priority;
/** @var string $name The filter name (property) */
public readonly string $name;
public readonly string $help;
/** @var string $description The filter description (property) */
public readonly string $description;
/** @var bool $has_list Filter has list of records (property) */
public readonly bool $has_list;
public readonly string $htmltag;
/** @var array $ignore The filter disabled html tags (property) */
public readonly array $ignore;
/** @var array $class The css class that apply to filter (property) */
public readonly array $class;
/** @var string $replace The filter replacement bloc in content (property) */
public readonly string $replace;
/** @var string $widget The filter replacement bloc in widget (property) */
public readonly string $widget;
// settings
/** @var bool $nocase The filter caseless match (settings) */
public readonly bool $nocase;
public readonly bool $plural;
public readonly int $limit;
public readonly array $style;
public readonly string $notag;
public readonly array $tplValues;
public readonly array $pubPages;
/** @var bool $plural The filter caseless match (settings) */
public readonly bool $plural;
/** @var bool $plural The replacement limit per filter (settings) */
public readonly int $limit;
/** @var array $style The style applied to filter class (settings) */
public readonly array $style;
/** @var array $notag The filter disabled html tags (settings) */
public readonly array $notag;
/** @var array $template The extra template value to scan (settings) */
public readonly array $template;
/** @var array $page The extra frontend pages to scan (settings) */
public readonly array $page;
/**
* Constructor sets filter properties and settings.
*/
final public function __construct()
{
if ($this->id == 'undefined') {
@ -61,55 +97,66 @@ abstract class EpcFilter
$settings = $this->initSettings();
// from filter defautl properties
$this->priority = isset($properties['priority']) ? abs((int) $properties['priority']) : 500;
$this->name = isset($properties['name']) ? (string) $properties['name'] : 'undefined';
$this->help = isset($properties['help']) ? (string) $properties['help'] : 'undefined';
$this->has_list = isset($properties['has_list']) ? (bool) $properties['has_list'] : false;
$this->htmltag = isset($properties['htmltag']) ? (string) $properties['htmltag'] : '';
$this->class = isset($properties['class']) && is_array($properties['class']) ? $properties['class'] : [];
$this->replace = isset($properties['replace']) ? (string) $properties['replace'] : '';
$this->widget = isset($properties['widget']) ? (string) $properties['widget'] : '';
$this->priority = isset($properties['priority']) ? abs((int) $properties['priority']) : 500;
$this->name = isset($properties['name']) ? (string) $properties['name'] : 'undefined';
$this->description = isset($properties['description']) ? (string) $properties['description'] : 'undefined';
$this->has_list = isset($properties['has_list']) ? (bool) $properties['has_list'] : false;
$this->ignore = isset($properties['ignore']) && is_array($properties['ignore']) ? $properties['ignore'] : [];
$this->class = isset($properties['class']) && is_array($properties['class']) ? $properties['class'] : [];
$this->replace = isset($properties['replace']) ? (string) $properties['replace'] : '';
$this->widget = isset($properties['widget']) ? (string) $properties['widget'] : '';
// from filter defautl settings
$nocase = isset($settings['nocase']) ? (bool) $settings['nocase'] : false;
$plural = isset($settings['plural']) ? (bool) $settings['plural'] : false;
$limit = isset($settings['limit']) ? abs((int) $settings['limit']) : 0;
$style = isset($settings['style']) && is_array($settings['style']) ? $settings['style'] : [];
$notag = isset($settings['notag']) ? (string) $settings['notag'] : '';
$tplValues = isset($settings['tplValues']) && is_array($settings['tplValues']) ? $settings['tplValues'] : [];
$pubPages = isset($settings['pubPages']) && is_array($settings['pubPages']) ? $settings['pubPages'] : [];
$nocase = isset($settings['nocase']) ? (bool) $settings['nocase'] : false;
$plural = isset($settings['plural']) ? (bool) $settings['plural'] : false;
$limit = isset($settings['limit']) ? abs((int) $settings['limit']) : 0;
$style = isset($settings['style']) && is_array($settings['style']) ? $settings['style'] : [];
$notag = isset($settings['notag']) && is_array($settings['notag']) ? $settings['notag'] : [];
$template = isset($settings['template']) && is_array($settings['template']) ? $settings['template'] : [];
$page = isset($settings['page']) && is_array($settings['page']) ? $settings['page'] : [];
// from blog settings
$this->nocase = isset($s['nocase']) ? (bool) $s['nocase'] : $nocase;
$this->plural = isset($s['plural']) ? (bool) $s['plural'] : $plural;
$this->limit = isset($s['limit']) ? abs((int) $s['limit']) : $limit;
$this->style = isset($s['style']) && is_array($s['style']) ? $s['style'] : $style;
$this->notag = isset($s['notag']) ? (string) $s['notag'] : $notag;
$this->tplValues = isset($s['tplValues']) && is_array($s['tplValues']) ? $s['tplValues'] : $tplValues;
$this->pubPages = isset($s['pubPages']) && is_array($s['pubPages']) ? $s['pubPages'] : $pubPages;
$this->nocase = isset($s['nocase']) ? (bool) $s['nocase'] : $nocase;
$this->plural = isset($s['plural']) ? (bool) $s['plural'] : $plural;
$this->limit = isset($s['limit']) ? abs((int) $s['limit']) : $limit;
$this->style = isset($s['style']) && is_array($s['style']) ? $s['style'] : $style;
$this->notag = isset($s['notag']) && is_array($s['notag']) ? $s['notag'] : $notag;
$this->template = isset($s['template']) && is_array($s['template']) ? $s['template'] : $template;
$this->page = isset($s['page']) && is_array($s['page']) ? $s['page'] : $page;
}
protected function initProperties(): array
{
return [];
}
/**
* Return filter default properties.
*
* @return array The properties
*/
abstract protected function initProperties(): array;
protected function initSettings(): array
{
return [];
}
public static function create(ArrayObject $o): void
{
$c = static::class;
$o->append(new $c());
}
/**
* Return filter default settings.
*
* @return array The settings
*/
abstract protected function initSettings(): array;
/**
* Get fitler ID.
*
* @return string The filter ID
*/
final public function id(): string
{
return $this->id;
}
/**
* Get fitler record.
*
* Fitler records are usefull to store and retrieve
* list of keyword / replacement etc...
*
* @return dcRecord The filter record instance
*/
final public function records(): dcRecord
{
if ($this->records === null && $this->has_list) {
@ -119,11 +166,27 @@ abstract class EpcFilter
return $this->records ?? dcRecord::newFromArray([]);
}
/**
* Filter frontend contents in situ.
*
* @param string $tag The tempale block tag
* @param array $args The template block arguments
*/
public function publicContent(string $tag, array $args): void
{
}
public function widgetList(string $content, WidgetsElement $w, ArrayObject $list): void
/**
* Filter frontend contents for widgets.
*
* Filter the contents and return matching results infos
* into the list of current widget.
*
* @param string $content The contents
* @param WidgetsElement $widget The widget
* @param ArrayObject $list The list
*/
public function widgetList(string $content, WidgetsElement $widget, ArrayObject $list): void
{
}
}

View File

@ -67,7 +67,7 @@ class EpcFilters
{
$nid = [];
foreach ($this->stack as $filter) {
if ($filter->widget != '') {
if (!$exclude_widget || $filter->widget != '') {
$nid[$filter->name] = $filter->id();
}
}
@ -76,13 +76,17 @@ class EpcFilters
}
/**
* Sort filters stack by filter name.
* Sort filters stack by filter name or priority.
*
* @return EpcFilters The filters instance
*/
public function sort(): EpcFilters
public function sort(bool $by_name = false): EpcFilters
{
uasort($this->stack, fn ($a, $b) => $a->name <=> $b->name);
if ($by_name) {
uasort($this->stack, fn ($a, $b) => $a->name <=> $b->name);
} else {
uasort($this->stack, fn ($a, $b) => $a->priority <=> $b->priority);
}
return $this;
}

View File

@ -19,8 +19,19 @@ use dcCore;
use dcRecord;
use Exception;
/**
* Filter records.
*/
class EpcRecord
{
/**
* Get records.
*
* @param array $params The query params
* @param bool $count_only Count only
*
* @return dcRecord The records instance
*/
public static function getRecords(array $params, bool $count_only = false): dcRecord
{
if ($count_only) {
@ -99,6 +110,13 @@ class EpcRecord
return new dcRecord(dcCore::app()->con->select($strReq));
}
/**
* Add record.
*
* @param cursor $cur The cursor
*
* @return int The record ID
*/
public static function addRecord(cursor $cur): int
{
dcCore::app()->con->writeLock(dcCore::app()->prefix . My::TABLE_NAME);
@ -117,7 +135,7 @@ class EpcRecord
throw $e;
}
self::trigger();
dcCore::app()->blog?->triggerBlog();
# --BEHAVIOR-- enhancePostContentAfterAddRecord : cursor
dcCore::app()->callBehavior('enhancePostContentAfterAddRecord', $cur);
@ -125,6 +143,12 @@ class EpcRecord
return (int) $cur->getField('epc_id');
}
/**
* Update a record.
*
* @param int $id The record ID
* @param cursor $cur The cursor
*/
public static function updRecord(int $id, cursor $cur): void
{
if (empty($id)) {
@ -134,12 +158,21 @@ class EpcRecord
$cur->setField('epc_upddt', date('Y-m-d H:i:s'));
$cur->update('WHERE epc_id = ' . $id . " AND blog_id = '" . dcCore::app()->con->escapeStr((string) dcCore::app()->blog?->id) . "' ");
self::trigger();
dcCore::app()->blog?->triggerBlog();
# --BEHAVIOR-- enhancePostContentAfterUpdRecord : cursor, int
dcCore::app()->callBehavior('enhancePostContentAfterUpdRecord', $cur, $id);
}
/**
* Check if a record exists.
*
* @param null|string $filter The filter ID
* @param null|string $key The record key
* @param null|int $not_id Exclude an id
*
* @return bool True if it exists
*/
public static function isRecord(?string $filter, ?string $key, ?int $not_id = null): bool
{
return 0 < self::getRecords([
@ -149,6 +182,11 @@ class EpcRecord
], true)->f(0);
}
/**
* Delete a record.
*
* @param int $id The record ID
*/
public static function delRecord(int $id): void
{
if (empty($id)) {
@ -164,9 +202,14 @@ class EpcRecord
"AND blog_id = '" . dcCore::app()->con->escapeStr((string) dcCore::app()->blog?->id) . "' "
);
self::trigger();
dcCore::app()->blog?->triggerBlog();
}
/**
* Get next record ID.
*
* @return int The next record ID
*/
private static function getNextId(): int
{
return (int) dcCore::app()->con->select(
@ -174,11 +217,21 @@ class EpcRecord
)->f(0) + 1;
}
/**
* Open filter cursor.
*
* @return cursor The cursor
*/
public static function openCursor(): cursor
{
return dcCore::app()->con->openCursor(dcCore::app()->prefix . My::TABLE_NAME);
}
/**
* Clean up a cursor.
*
* @param cursor $cur The cursor
*/
private static function getCursor(cursor $cur): void
{
if ($cur->getField('epc_key') == '') {
@ -191,9 +244,4 @@ class EpcRecord
throw new Exception(__('No record filter'));
}
}
private static function trigger(): void
{
dcCore::app()->blog?->triggerBlog();
}
}

View File

@ -26,24 +26,24 @@ class EpcFilterAbbreviation extends EpcFilter
protected function initProperties(): array
{
return [
'priority' => 400,
'name' => __('Abbreviation'),
'help' => __('Explain some abbreviation. First term of the list is the abbreviation and second term the explanation.'),
'has_list' => true,
'htmltag' => 'pre,code,a',
'class' => ['abbr.epc-abbr'],
'replace' => '<abbr class="epc-abbr" title="%s">%s</abbr>',
'widget' => '<abbr title="%s">%s</abbr>',
'priority' => 400,
'name' => __('Abbreviation'),
'description' => __('Explain some abbreviation. First term of the list is the abbreviation and second term the explanation.'),
'has_list' => true,
'ignore' => ['pre','code','a'],
'class' => ['abbr.epc-abbr'],
'replace' => '<abbr class="epc-abbr" title="%s">%s</abbr>',
'widget' => '<abbr title="%s">%s</abbr>',
];
}
protected function initSettings(): array
{
return [
'style' => ['font-weight: bold;'],
'notag' => 'a,acronym,abbr,dfn,h1,h2,h3',
'tplValues' => ['EntryContent'],
'pubPages' => ['post.html'],
'style' => ['font-weight: bold;'],
'notag' => ['acronym','abbr','dfn','h1','h2','h3'],
'template' => ['EntryContent'],
'page' => ['post.html'],
];
}

View File

@ -26,24 +26,24 @@ class EpcFilterAcronym extends EpcFilter
protected function initProperties(): array
{
return [
'priority' => 700,
'name' => __('Acronym'),
'help' => __('Explain some acronyms. First term of the list is the acornym and second term the explanation.'),
'has_list' => true,
'htmltag' => 'pre,code,acronym',
'class' => ['acronym.epc-acronym'],
'replace' => '<acronym class="epc-acronym" title="%s">%s</acronym>',
'widget' => '<acronym title="%s">%s</acronym>',
'priority' => 700,
'name' => __('Acronym'),
'description' => __('Explain some acronyms. First term of the list is the acornym and second term the explanation.'),
'has_list' => true,
'ignore' => ['pre','code','acronym'],
'class' => ['acronym.epc-acronym'],
'replace' => '<acronym class="epc-acronym" title="%s">%s</acronym>',
'widget' => '<acronym title="%s">%s</acronym>',
];
}
protected function initSettings(): array
{
return [
'style' => ['font-weight: bold;'],
'notag' => 'a,acronym,abbr,dfn,h1,h2,h3',
'tplValues' => ['EntryContent'],
'pubPages' => ['post.html'],
'style' => ['font-weight: bold;'],
'notag' => ['a','acronym','abbr','dfn','h1','h2','h3'],
'template' => ['EntryContent'],
'page' => ['post.html'],
];
}

View File

@ -26,25 +26,25 @@ class EpcFilterCitation extends EpcFilter
protected function initProperties(): array
{
return [
'priority' => 600,
'name' => __('Citation'),
'help' => __('Highlight citation of people. First term of the list is the citation and second term the author.'),
'has_list' => true,
'htmltag' => 'pre,code,cite',
'class' => ['cite.epc-cite'],
'replace' => '<cite class="epc-cite" title="%s">%s</cite>',
'widget' => '<cite title="%s">%s</cite>',
'priority' => 600,
'name' => __('Citation'),
'description' => __('Highlight citation of people. First term of the list is the citation and second term the author.'),
'has_list' => true,
'ignore' => ['pre','code','cite'],
'class' => ['cite.epc-cite'],
'replace' => '<cite class="epc-cite" title="%s">%s</cite>',
'widget' => '<cite title="%s">%s</cite>',
];
}
protected function initSettings(): array
{
return [
'nocase' => true,
'style' => ['font-style: italic;'],
'notag' => 'a,h1,h2,h3',
'tplValues' => ['EntryContent'],
'pubPages' => ['post.html'],
'nocase' => true,
'style' => ['font-style: italic;'],
'notag' => ['a','h1','h2','h3'],
'template' => ['EntryContent'],
'page' => ['post.html'],
];
}

View File

@ -26,24 +26,24 @@ class EpcFilterDefinition extends EpcFilter
protected function initProperties(): array
{
return [
'priority' => 800,
'name' => __('Definition'),
'help' => __('Explain some definition. First term of the list is the sample to define and second term the explanation.'),
'has_list' => true,
'htmltag' => 'pre,code,dfn',
'class' => ['dfn.epc-dfn'],
'replace' => '<dfn class="epc-dfn" title="%s">%s</dfn>',
'widget' => '<dfn class="epc-dfn" title="%s">%s</dfn>',
'priority' => 800,
'name' => __('Definition'),
'description' => __('Explain some definition. First term of the list is the sample to define and second term the explanation.'),
'has_list' => true,
'ignore' => ['pre','code','dfn'],
'class' => ['dfn.epc-dfn'],
'replace' => '<dfn class="epc-dfn" title="%s">%s</dfn>',
'widget' => '<dfn class="epc-dfn" title="%s">%s</dfn>',
];
}
protected function initSettings(): array
{
return [
'style' => ['font-weight: bold;'],
'notag' => 'a,acronym,abbr,dfn,h1,h2,h3',
'tplValues' => ['EntryContent'],
'pubPages' => ['post.html'],
'style' => ['font-weight: bold;'],
'notag' => ['a','acronym','abbr','dfn','h1','h2','h3'],
'template' => ['EntryContent'],
'page' => ['post.html'],
];
}

View File

@ -26,24 +26,24 @@ class EpcFilterLink extends EpcFilter
protected function initProperties(): array
{
return [
'priority' => 500,
'name' => __('Link'),
'help' => __('Link some words. First term of the list is the term to link and second term the link.'),
'has_list' => true,
'htmltag' => 'pre,code,a',
'class' => ['a.epc-link'],
'replace' => '<a class="epc-link" title="%s" href="%s">%s</a>',
'widget' => '<a title="%s" href="%s">%s</a>',
'priority' => 500,
'name' => __('Link'),
'description' => __('Link some words. First term of the list is the term to link and second term the link.'),
'has_list' => true,
'ignore' => ['pre','code','a'],
'class' => ['a.epc-link'],
'replace' => '<a class="epc-link" title="%s" href="%s">%s</a>',
'widget' => '<a title="%s" href="%s">%s</a>',
];
}
protected function initSettings(): array
{
return [
'style' => ['text-decoration: none; font-style: italic; color: #0000FF;'],
'notag' => 'a,h1,h2,h3',
'tplValues' => ['EntryContent'],
'pubPages' => ['post.html'],
'style' => ['text-decoration: none; font-style: italic; color: #0000FF;'],
'notag' => ['h1','h2','h3'],
'template' => ['EntryContent'],
'page' => ['post.html'],
];
}

View File

@ -24,25 +24,25 @@ class EpcFilterReplace extends EpcFilter
protected function initProperties(): array
{
return [
'priority' => 200,
'name' => __('Replace'),
'help' => __('Replace some text. First term of the list is the text to replace and second term the replacement.'),
'has_list' => true,
'htmltag' => 'pre,code',
'class' => ['span.epc-replace'],
'replace' => '<span class="epc-replace">%s</span>',
'priority' => 200,
'name' => __('Replace'),
'description' => __('Replace some text. First term of the list is the text to replace and second term the replacement.'),
'has_list' => true,
'ignore' => ['pre','code'],
'class' => ['span.epc-replace'],
'replace' => '<span class="epc-replace">%s</span>',
];
}
protected function initSettings(): array
{
return [
'nocase' => true,
'plural' => true,
'style' => ['font-style: italic;'],
'notag' => 'h1,h2,h3',
'tplValues' => ['EntryContent'],
'pubPages' => ['post.html'],
'nocase' => true,
'plural' => true,
'style' => ['font-style: italic;'],
'notag' => ['h1','h2','h3'],
'template' => ['EntryContent'],
'page' => ['post.html'],
];
}

View File

@ -25,12 +25,12 @@ class EpcFilterSearch extends EpcFilter
protected function initProperties(): array
{
return [
'priority' => 100,
'name' => __('Search'),
'help' => __('Highlight searched words.'),
'htmltag' => '',
'class' => ['span.epc-search'],
'replace' => '<span class="epc-search" title="' . __('Search') . '">%s</span>',
'priority' => 100,
'name' => __('Search'),
'description' => __('Highlight searched words.'),
'ignore' => [],
'class' => ['span.epc-search'],
'replace' => '<span class="epc-search" title="' . __('Search') . '">%s</span>',
];
}
@ -40,9 +40,9 @@ class EpcFilterSearch extends EpcFilter
'nocase' => true,
'plural' => true,
'style' => ['color: #FFCC66;'],
'notag' => 'h1,h2,h3',
'notag' => ['h1','h2','h3'],
'tplValues' => ['EntryContent'],
'pubPages' => ['search.html'],
'page' => ['search.html'],
];
}

View File

@ -27,23 +27,23 @@ class EpcFilterTag extends EpcFilter
protected function initProperties(): array
{
return [
'priority' => 900,
'name' => __('Tag'),
'help' => __('Highlight tags of your blog.'),
'htmltag' => 'pre,code,a',
'class' => ['a.epc-tag'],
'replace' => '<a class="epc-tag" href="%s" title="' . __('Tag') . '">%s</a>',
'widget' => '<a href="%s" title="' . __('Tag') . '">%s</a>',
'priority' => 900,
'name' => __('Tag'),
'description' => __('Highlight tags of your blog.'),
'ignore' => ['pre','code','a'],
'class' => ['a.epc-tag'],
'replace' => '<a class="epc-tag" href="%s" title="' . __('Tag') . '">%s</a>',
'widget' => '<a href="%s" title="' . __('Tag') . '">%s</a>',
];
}
protected function initSettings(): array
{
return [
'style' => ['text-decoration: none; border-bottom: 3px double #CCCCCC;'],
'notag' => 'pre,code,a,h1,h2,h3',
'tplValues' => ['EntryContent'],
'pubPages' => ['post.html'],
'style' => ['text-decoration: none; border-bottom: 3px double #CCCCCC;'],
'notag' => ['h1','h2','h3'],
'template' => ['EntryContent'],
'page' => ['post.html'],
];
}

View File

@ -24,22 +24,22 @@ class EpcFilterTwitter extends EpcFilter
protected function initProperties(): array
{
return [
'priority' => 1000,
'name' => __('Twitter'),
'help' => __('Add link to twitter user page. Every word started with "@" will be considered as twitter user.'),
'htmltag' => 'pre,code,a',
'class' => ['a.epc-twitter'],
'replace' => '<a class="epc-twitter" title="' . __("View this user's twitter page") . '" href="%s">%s</a>',
'priority' => 1000,
'name' => __('Twitter'),
'description' => __('Add link to twitter user page. Every word started with "@" will be considered as twitter user.'),
'ingore' => ['pre','code','a'],
'class' => ['a.epc-twitter'],
'replace' => '<a class="epc-twitter" title="' . __("View this user's twitter page") . '" href="%s">%s</a>',
];
}
protected function initSettings(): array
{
return [
'style' => ['text-decoration: none; font-weight: bold; font-style: italic; color: #0000FF;'],
'notag' => 'a,h1,h2,h3',
'tplValues' => ['EntryContent'],
'pubPages' => ['post.html'],
'style' => ['text-decoration: none; font-weight: bold; font-style: italic; color: #0000FF;'],
'notag' => ['h1','h2','h3'],
'template' => ['EntryContent'],
'page' => ['post.html'],
];
}

View File

@ -24,25 +24,25 @@ class EpcFilterUpdate extends EpcFilter
protected function initProperties(): array
{
return [
'priority' => 300,
'name' => __('Update'),
'help' => __('Update and show terms. First term of the list is the term to update and second term the new term.'),
'has_list' => true,
'htmltag' => 'pre,code,del,ins',
'class' => ['del.epc-update', 'ins.epc-update'],
'replace' => '<del class="epc-update">%s</del> <ins class="epc-update">%s</ins>',
'priority' => 300,
'name' => __('Update'),
'description' => __('Update and show terms. First term of the list is the term to update and second term the new term.'),
'has_list' => true,
'ignore' => ['pre','code','del','ins'],
'class' => ['del.epc-update', 'ins.epc-update'],
'replace' => '<del class="epc-update">%s</del> <ins class="epc-update">%s</ins>',
];
}
protected function initSettings(): array
{
return [
'nocase' => true,
'plural' => true,
'style' => ['text-decoration: line-through;', 'font-style: italic;'],
'notag' => 'h1,h2,h3',
'tplValues' => ['EntryContent'],
'pubPages' => ['post.html'],
'nocase' => true,
'plural' => true,
'style' => ['text-decoration: line-through;', 'font-style: italic;'],
'notag' => ['h1','h2','h3'],
'template' => ['EntryContent'],
'page' => ['post.html'],
];
}

View File

@ -38,17 +38,24 @@ class Frontend extends dcNsProcess
}
dcCore::app()->addBehaviors([
// add CSS URL to header
// Add CSS URL to frontend header
'publicHeadContent' => function (): void {
echo dcUtils::cssLoad(dcCore::app()->blog?->url . dcCore::app()->url->getURLFor('epccss'));
},
// Filter template blocks content
'publicBeforeContentFilterV2' => function (string $tag, array $args): void {
foreach (Epc::getFilters()->dump() as $filter) {
if (!Epc::testContext($tag, $args, $filter)) {
continue;
// test context
if (in_array((string) dcCore::app()->ctx?->__get('current_tpl'), $filter->page)
&& in_array($tag, $filter->template)
&& $args[0] != '' //content
&& empty($args['encode_xml'])
&& empty($args['encode_html'])
&& empty($args['remove_html'])
&& empty($args['strip_tags'])
) {
$filter->publicContent($tag, $args);
}
$filter->publicContent($tag, $args);
}
},
// Widgets

View File

@ -71,19 +71,19 @@ class Install extends dcNsProcess
$s->put('list_sortby', 'epc_key', 'string', 'Admin records list field order', false, true);
$s->put('list_order', 'desc', 'string', 'Admin records list order', false, true);
$s->put('list_nb', 20, 'integer', 'Admin records list nb per page', false, true);
$s->put('allowedtplvalues', json_encode(Epc::defaultAllowedTplValues()), 'string', 'List of allowed template values', false, true);
$s->put('allowedpubpages', json_encode(Epc::defaultAllowedPubPages()), 'string', 'List of allowed template pages', false, true);
$s->put('allowedtplvalues', json_encode(Epc::defaultAllowedTemplateValue()), 'string', 'List of allowed template values', false, true);
$s->put('allowedpubpages', json_encode(Epc::defaultAllowedTemplatePage()), 'string', 'List of allowed template pages', false, true);
// Filters settings
foreach (Epc::getFilters()->dump() as $filter) {
// Only editable options
$opt = [
'nocase' => $filter->nocase,
'plural' => $filter->plural,
'style' => $filter->style,
'notag' => $filter->notag,
'tplValues' => $filter->tplValues,
'pubPages' => $filter->pubPages,
'nocase' => $filter->nocase,
'plural' => $filter->plural,
'style' => $filter->style,
'notag' => $filter->notag,
'template' => $filter->template,
'page' => $filter->page,
];
$s->put($filter->id(), json_encode($opt), 'string', 'Settings for ' . $filter->id(), false, true);
}
@ -114,10 +114,12 @@ class Install extends dcNsProcess
if ($current && version_compare($current, '2022.11.20', '<=')) {
self::upTo20221120();
}
// 2023.04.22: not replaced: tplValues->template and pubPages->page
}
/**
* 0.6.6
* Upgrade from 0.6.6
*
* - filters move from settings to dedicated table
*/
@ -150,7 +152,7 @@ class Install extends dcNsProcess
}
/**
* 2021.10.06
* Upgrade from 2021.10.06
*
* - filters change name to id
*/
@ -169,7 +171,7 @@ class Install extends dcNsProcess
}
/**
* 2022.11.20
* Upgrade from 2022.11.20
*
* - setting id changes to shorter one,
* - setting ns changes to abstract one (no real changes),

View File

@ -57,37 +57,41 @@ class Manage extends dcNsProcess
return false;
}
// nullsafe check
if (is_null(dcCore::app()->blog) || is_null(dcCore::app()->adminurl)) {
return false;
}
// get filter and post values
$action = $_POST['action'] ?? '';
$filter = Epc::getFilters()->get($_REQUEST['part'] ?? '');
if (is_null($filter)) {
return true;
}
// check errors
if (dcCore::app()->error->flag()) {
return true;
}
// open save to other plugins
if (!empty($action)) {
# --BEHAVIOR-- enhancePostContentAdminSave
dcCore::app()->callBehavior('enhancePostContentAdminSave');
}
try {
# Update filter settings
// Update filter settings
if ($action == 'savefiltersetting') {
# Parse filters options
$f = [
'nocase' => !empty($_POST['filter_nocase']),
'plural' => !empty($_POST['filter_plural']),
'limit' => abs((int) $_POST['filter_limit']),
'style' => (array) $_POST['filter_style'],
'notag' => (string) $_POST['filter_notag'],
'tplValues' => (array) $_POST['filter_tplValues'],
'pubPages' => (array) $_POST['filter_pubPages'],
'nocase' => !empty($_POST['filter_nocase']),
'plural' => !empty($_POST['filter_plural']),
'limit' => abs((int) $_POST['filter_limit']),
'style' => (array) $_POST['filter_style'],
'notag' => Epc::decodeSingle($_POST['filter_notag']),
'template' => (array) $_POST['filter_template'],
'page' => (array) $_POST['filter_page'],
];
dcCore::app()->blog->settings->get(My::id())->put($filter->id(), json_encode($f));
@ -105,7 +109,7 @@ class Manage extends dcNsProcess
);
}
# Add new filter record
// Add new filter record
if ($action == 'savenewrecord'
&& !empty($_POST['new_key'])
&& !empty($_POST['new_value'])
@ -133,7 +137,7 @@ class Manage extends dcNsProcess
);
}
# Update filter records
// Update filter records
if ($action == 'deleterecords'
&& $filter->has_list
&& !empty($_POST['epc_id'])
@ -172,17 +176,22 @@ class Manage extends dcNsProcess
return;
}
// nullsafe check
if (is_null(dcCore::app()->blog) || is_null(dcCore::app()->adminurl)) {
return;
}
// get filters
$filters = Epc::getFilters();
$filter = $filters->get($_REQUEST['part'] ?? 'link');
if (is_null($filter)) {
return;
}
# -- Prepare page --
// sort filters by name on backend
Epc::getFilters()->sort(true);
// Prepare tabs and lists
$header = '';
if ($filter->has_list) {
$sorts = new adminGenericFilterV2('epc');
@ -203,7 +212,7 @@ class Manage extends dcNsProcess
$header = $sorts->js(dcCore::app()->adminurl->get('admin.plugin.' . My::id(), ['part' => $filter->id()], '&') . '#record');
}
# Page headers
// display
dcPage::openModule(
My::name(),
dcPage::jsPageTabs() .
@ -214,7 +223,6 @@ class Manage extends dcNsProcess
dcCore::app()->callBehavior('enhancePostContentAdminHeader')
);
# Page title
echo
dcPage::breadcrumb([
__('Plugins') => '',
@ -223,7 +231,7 @@ class Manage extends dcNsProcess
]) .
dcPage::notices();
# Filters select menu list
// filters select menu
echo
(new Form('filters_menu'))->method('get')->action(dcCore::app()->adminurl->get('admin.plugin.' . My::id()))->fields([
(new Para())->class('anchor-nav')->items([
@ -233,25 +241,25 @@ class Manage extends dcNsProcess
]),
])->render();
# Filter title and description
// selected filter
echo
'<h3>' . $filter->name . '</h3>' .
'<p>' . $filter->help . '</p>';
'<p>' . $filter->description . '</p>';
# Filter settings
// Filter settings
$form_pages = [(new Text('h4', __('Pages to be filtered')))];
foreach (Epc::blogAllowedPubPages() as $k => $v) {
foreach (Epc::blogAllowedTemplatePage() as $k => $v) {
$form_pages[] = (new Para())->items([
(new Checkbox(['filter_pubPages[]', 'filter_pubPages' . $v], in_array($v, $filter->pubPages)))->value($v),
(new Label(__($k), Label::OUTSIDE_LABEL_AFTER))->for('filter_pubPages' . $v)->class('classic'),
(new Checkbox(['filter_page[]', 'filter_page' . $v], in_array($v, $filter->page)))->value($v),
(new Label(__($k), Label::OUTSIDE_LABEL_AFTER))->for('filter_page' . $v)->class('classic'),
]);
}
$form_values = [(new Text('h4', __('Contents to be filtered')))];
foreach (Epc::blogAllowedTplValues() as $k => $v) {
foreach (Epc::blogAllowedTemplateValue() as $k => $v) {
$form_values[] = (new Para())->items([
(new Checkbox(['filter_tplValues[]', 'filter_tplValues' . $v], in_array($v, $filter->tplValues)))->value($v),
(new Label(__($k), Label::OUTSIDE_LABEL_AFTER))->for('filter_tplValues' . $v)->class('classic'),
(new Checkbox(['filter_template[]', 'filter_template' . $v], in_array($v, $filter->template)))->value($v),
(new Label(__($k), Label::OUTSIDE_LABEL_AFTER))->for('filter_template' . $v)->class('classic'),
]);
}
@ -288,9 +296,9 @@ class Manage extends dcNsProcess
(new Note())->class('form-note')->text(sprintf(__('The inserted HTML tag looks like: %s'), Html::escapeHTML(str_replace('%s', '...', $filter->replace)))),
(new Para())->items([
(new Label(__('Ignore HTML tags:'), Label::OUTSIDE_LABEL_BEFORE))->for('filter_notag'),
(new Input('filter_notag'))->size(60)->maxlenght(255)->value(Html::escapeHTML($filter->notag)),
(new Input('filter_notag'))->size(60)->maxlenght(255)->value(Epc::encodeSingle($filter->notag)),
]),
(new Note())->class('form-note')->text(__('This is the list of HTML tags where content will be ignored.') . ' ' . ('' != $filter->htmltag ? '' : sprintf(__('Tag "%s" always be ignored.'), $filter->htmltag))),
(new Note())->class('form-note')->text(__('This is the list of HTML tags where content will be ignored.') . '<br />' . (empty($filter->ignore) ? '' : sprintf(__('Tags "%s" will allways be ignored.'), Epc::encodeSingle($filter->ignore)))),
])),
(new Div())->class('clear')->items([
@ -302,7 +310,7 @@ class Manage extends dcNsProcess
]),
])->render();
# Filter records list
// Filter records list (if any)
if ($filter->has_list && isset($pager)) {
$pager_url = dcCore::app()->adminurl->get('admin.plugin.' . My::id(), array_diff_key($sorts->values(true), ['page' => ''])) . '&page=%s#record';
@ -335,7 +343,7 @@ class Manage extends dcNsProcess
echo '</div>';
# New record
// New record
echo
(new Div('newrecord'))->class('multi-part')->title(__('New record'))->items([
(new Form('form-create'))->method('post')->action(dcCore::app()->adminurl->get('admin.plugin.' . My::id()) . '#record')->fields([

View File

@ -59,10 +59,10 @@ class Widgets
Epc::getFilters()->nid(true)
);
# Content
foreach (Epc::defaultAllowedWidgetValues() as $k => $v) {
foreach (Epc::widgetAllowedTemplateValue() as $name => $info) {
$w->epclist->setting(
'content' . $v['id'],
sprintf(__('Enable filter on %s'), __($k)),
'content' . $info['id'],
sprintf(__('Enable filter on %s'), __($name)),
1,
'check'
);
@ -101,11 +101,11 @@ class Widgets
# Content
$content = '';
foreach (Epc::defaultAllowedWidgetValues() as $k => $v) {
$ns = 'content' . $v['id'];
if ($w->$ns && is_callable($v['cb'])) {
foreach (Epc::widgetAllowedTemplateValue() as $info) {
$ns = 'content' . $info['id'];
if ($w->$ns && is_callable($info['cb'])) {
$content .= call_user_func(
$v['cb'],
$info['cb'],
$w
);
}
@ -130,11 +130,11 @@ class Widgets
# Parse result
$res = '';
foreach ($list as $line) {
if (empty($line['matches'][0]['match'])) {
if ((int) $line['total'] == 0) {
continue;
}
$res .= '<li>' . $line['matches'][0]['match'] .
$res .= '<li>' . $line['replacement'] .
($w->show_total ? ' (' . $line['total'] . ')' : '') .
'</li>';
}