Seditio Source
Root |
./othercms/dotclear-2.22/plugins/widgets/class.widgets.php
<?php
/**
 * @brief widgets, a plugin for Dotclear 2
 *
 * @package Dotclear
 * @subpackage Plugins
 *
 * @copyright Olivier Meunier & Association Dotclear
 * @copyright GPL-2.0-only
 */
if (!defined('DC_RC_PATH')) {
    return;
}

class
dcWidgets
{
    private
$__widgets = [];

    public static function
load($s)
    {
       
$o = @unserialize(base64_decode($s));

        if (
$o instanceof self) {
            return
$o;
        }

        return
self::loadArray($o, $GLOBALS['__widgets']);
    }

    public function
store()
    {
       
$serialized = [];
        foreach (
$this->__widgets as $pos => $w) {
           
$serialized[] = ($w->serialize($pos));
        }

        return
base64_encode(serialize($serialized));
    }

    public function
create($id, $name, $callback, $append_callback = null, $desc = '')
    {
       
$this->__widgets[$id]                  = new dcWidgetExt($id, $name, $callback, $desc);
       
$this->__widgets[$id]->append_callback = $append_callback;

        return
$this->__widgets[$id];
    }

    public function
append($widget)
    {
        if (
$widget instanceof dcWidget) {
            if (
is_callable($widget->append_callback)) {
               
call_user_func($widget->append_callback, $widget);
            }
           
$this->__widgets[] = $widget;
        }
    }

    public function
isEmpty()
    {
        return
count($this->__widgets) == 0;
    }

    public function
elements($sorted = false)
    {
        if (
$sorted) {
           
uasort($this->__widgets, ['self', 'sort']);
        }

        return
$this->__widgets;
    }

    public function
__get($id)
    {
        if (!isset(
$this->__widgets[$id])) {
            return;
        }

        return
$this->__widgets[$id];
    }

    public function
__wakeup()
    {
        foreach (
$this->__widgets as $i => $w) {
            if (!(
$w instanceof dcWidget)) {
                unset(
$this->__widgets[$i]);
            }
        }
    }

    public static function
loadArray($A, $widgets)
    {
        if (!(
$widgets instanceof self)) {
            return
false;
        }

       
uasort($A, ['self', 'arraySort']);

       
$result = new self();
        foreach (
$A as $v) {
            if (
$widgets->{$v['id']} != null) {
               
$w = clone $widgets->{$v['id']};

               
# Settings
               
unset($v['id'], $v['order']);

                foreach (
$v as $sid => $s) {
                   
$w->{$sid} = $s;
                }

               
$result->append($w);
            }
        }

        return
$result;
    }

    private static function
arraySort($a, $b)
    {
        if (
$a['order'] == $b['order']) {
            return
0;
        }

        return
$a['order'] > $b['order'] ? 1 : -1;
    }

    private static function
sort($a, $b)
    {
       
$c = dcUtils::removeDiacritics(mb_strtolower($a->name()));
       
$d = dcUtils::removeDiacritics(mb_strtolower($b->name()));
        if (
$c == $d) {
            return
0;
        }

        return (
$c < $d) ? -1 : 1;
    }
}

class
dcWidget
{
    private
$id;
    private
$name;
    private
$desc;
    private
$public_callback = null;
    public
$append_callback  = null;
    protected
$settings      = [];

    public function
serialize($order)
    {
       
$values = [];
        foreach (
$this->settings as $k => $v) {
           
$values[$k] = $v['value'];
        }

       
$values['id']    = $this->id;
       
$values['order'] = $order;

        return
$values;
    }

    public function
__construct($id, $name, $callback, $desc = '')
    {
       
$this->public_callback = $callback;
       
$this->id              = $id;
       
$this->name            = $name;
       
$this->desc            = $desc;
    }

    public function
id()
    {
        return
$this->id;
    }

    public function
name()
    {
        return
$this->name;
    }

    public function
desc()
    {
        return
$this->desc;
    }

    public function
getCallback()
    {
        return
$this->public_callback;
    }

    public function
call($i = 0)
    {
        if (
is_callable($this->public_callback)) {
            return
call_user_func($this->public_callback, $this, $i);
        }

        return
'<p>Callback not found for widget ' . $this->id . '</p>';
    }

   
/* Widget rendering tool
    --------------------------------------------------- */
   
public function renderDiv($content_only, $class, $attr, $content)
    {
        if (
$content_only) {
            return
$content;
        }
       
$ret = '<div class="widget' . ($class ? ' ' . html::escapeHTML($class) : '') . '"' . ($attr ? ' ' . $attr : '') . '>' . "\n";
       
$ret .= $content . "\n";
       
$ret .= '</div>' . "\n";

        return
$ret;
    }

    public function
renderTitle($title)
    {
        global
$core;

        if (!
$title) {
            return
'';
        }

       
$wtscheme = $core->themes->moduleInfo($core->blog->settings->system->theme, 'widgettitleformat');
        if (empty(
$wtscheme)) {
           
$tplset = $core->themes->moduleInfo($core->blog->settings->system->theme, 'tplset');
            if (empty(
$tplset) || $tplset == DC_DEFAULT_TPLSET) {
               
// Use H2 for mustek based themes
               
$wtscheme = '<h2>%s</h2>';
            } else {
               
// Use H3 for dotty based themes
               
$wtscheme = '<h3>%s</h3>';
            }
        }
       
$ret = sprintf($wtscheme, $title);

        return
$ret;
    }

    public function
renderSubtitle($title, $render = true)
    {
        global
$core;

        if (!
$title && $render) {
            return
'';
        }

       
$wtscheme = $core->themes->moduleInfo($core->blog->settings->system->theme, 'widgetsubtitleformat');
        if (empty(
$wtscheme)) {
           
$tplset = $core->themes->moduleInfo($core->blog->settings->system->theme, 'tplset');
            if (empty(
$tplset) || $tplset == DC_DEFAULT_TPLSET) {
               
// Use H2 for mustek based themes
               
$wtscheme = '<h3>%s</h3>';
            } else {
               
// Use H3 for dotty based themes
               
$wtscheme = '<h4>%s</h4>';
            }
        }
        if (!
$render) {
            return
$wtscheme;
        }

       
$ret = sprintf($wtscheme, $title);

        return
$ret;
    }

   
/* Widget settings
    --------------------------------------------------- */
   
public function __get($n)
    {
        if (isset(
$this->settings[$n])) {
            return
$this->settings[$n]['value'];
        }
    }

    public function
__set($n, $v)
    {
        if (isset(
$this->settings[$n])) {
           
$this->settings[$n]['value'] = $v;
        }
    }

    public function
setting($name, $title, $value, $type = 'text')
    {
       
$types = [
           
// type (string) => list of items may be provided (boolean)
           
'text'     => false,
           
'textarea' => false,
           
'check'    => false,
           
'radio'    => true,
           
'combo'    => true,
           
'color'    => false,
           
'email'    => false,
           
'number'   => false,
        ];

        if (!
array_key_exists($type, $types)) {
            return
false;
        }

       
$index = 4; // 1st optional argument (after type)

       
if ($types[$type] && func_num_args() > $index) {
           
$options = func_get_arg($index);
            if (!
is_array($options)) {
                return
false;
            }
           
$index++;
        }

       
// If any, the last argument should be an array (key → value) of opts
       
if (func_num_args() > $index) {
           
$opts = func_get_arg($index);
        }

       
$this->settings[$name] = [
           
'title' => $title,
           
'type'  => $type,
           
'value' => $value,
        ];

        if (isset(
$options)) {
           
$this->settings[$name]['options'] = $options;
        }
        if (isset(
$opts)) {
           
$this->settings[$name]['opts'] = $opts;
        }

        return
$this;
    }

    public function
settings()
    {
        return
$this->settings;
    }

    public function
formSettings($pr = '', &$i = 0)
    {
       
$res = '';
        foreach (
$this->settings as $id => $s) {
           
$res .= $this->formSetting($id, $s, $pr, $i);
           
$i++;
        }

        return
$res;
    }

    public function
formSetting($id, $s, $pr = '', &$i = 0)
    {
        global
$core;

       
$res   = '';
       
$wfid  = 'wf-' . $i;
       
$iname = $pr ? $pr . '[' . $id . ']' : $id;
       
$class = (isset($s['opts']) && isset($s['opts']['class']) ? ' ' . $s['opts']['class'] : '');
        switch (
$s['type']) {
            case
'text':
               
$res .= '<p><label for="' . $wfid . '">' . $s['title'] . '</label> ' .
               
form::field([$iname, $wfid], 20, 255, [
                   
'default'    => html::escapeHTML($s['value']),
                   
'class'      => 'maximal' . $class,
                   
'extra_html' => 'lang="' . $core->auth->getInfo('user_lang') . '" spellcheck="true"',
                ]) .
               
'</p>';

                break;
            case
'textarea':
               
$res .= '<p><label for="' . $wfid . '">' . $s['title'] . '</label> ' .
               
form::textarea([$iname, $wfid], 30, 8, [
                   
'default'    => html::escapeHTML($s['value']),
                   
'class'      => 'maximal' . $class,
                   
'extra_html' => 'lang="' . $core->auth->getInfo('user_lang') . '" spellcheck="true"',
                ]) .
               
'</p>';

                break;
            case
'check':
               
$res .= '<p>' . form::hidden([$iname], '0') .
               
'<label class="classic" for="' . $wfid . '">' .
               
form::checkbox([$iname, $wfid], '1', $s['value'], $class) . ' ' . $s['title'] .
               
'</label></p>';

                break;
            case
'radio':
               
$res .= '<p>' . ($s['title'] ? '<label class="classic">' . $s['title'] . '</label><br/>' : '');
                if (!empty(
$s['options'])) {
                    foreach (
$s['options'] as $k => $v) {
                       
$res .= $k > 0 ? '<br/>' : '';
                       
$res .= '<label class="classic" for="' . $wfid . '-' . $k . '">' .
                       
form::radio([$iname, $wfid . '-' . $k], $v[1], $s['value'] == $v[1], $class) . ' ' . $v[0] .
                           
'</label>';
                    }
                }
               
$res .= '</p>';

                break;
            case
'combo':
               
$res .= '<p><label for="' . $wfid . '">' . $s['title'] . '</label> ' .
               
form::combo([$iname, $wfid], $s['options'], $s['value'], $class) .
               
'</p>';

                break;
            case
'color':
               
$res .= '<p><label for="' . $wfid . '">' . $s['title'] . '</label> ' .
               
form::color([$iname, $wfid], [
                   
'default' => $s['value'],
                ]) .
               
'</p>';

                break;
            case
'email':
               
$res .= '<p><label for="' . $wfid . '">' . $s['title'] . '</label> ' .
               
form::email([$iname, $wfid], [
                   
'default'      => html::escapeHTML($s['value']),
                   
'autocomplete' => 'email',
                ]) .
               
'</p>';

                break;
            case
'number':
               
$res .= '<p><label for="' . $wfid . '">' . $s['title'] . '</label> ' .
               
form::number([$iname, $wfid], [
                   
'default' => $s['value'],
                ]) .
               
'</p>';

                break;
        }

        return
$res;
    }
}

class
dcWidgetExt extends dcWidget
{
    public const
ALL_PAGES   = 0; // Widget displayed on every page
   
public const HOME_ONLY   = 1; // Widget displayed on home page only
   
public const EXCEPT_HOME = 2; // Widget displayed on every page but home page

   
public function addTitle($title = '')
    {
        return
$this->setting('title', __('Title (optional)') . ' :', $title);
    }

    public function
addHomeOnly()
    {
        return
$this->setting(
           
'homeonly',
           
__('Display on:'),
           
self::ALL_PAGES,
           
'combo',
            [
__('All pages') => self::ALL_PAGES, __('Home page only') => self::HOME_ONLY, __('Except on home page') => self::EXCEPT_HOME]
        );
    }

    public function
checkHomeOnly($type, $alt_not_home = 1, $alt_home = 0)
    {
        global
$core;

       
/* @phpstan-ignore-next-line */
       
if (($this->homeonly == self::HOME_ONLY && !$core->url->isHome($type) && $alt_not_home) || ($this->homeonly == self::EXCEPT_HOME && ($core->url->isHome($type) || $alt_home))) {
            return
false;
        }

        return
true;
    }

    public function
addContentOnly($content_only = 0)
    {
        return
$this->setting('content_only', __('Content only'), $content_only, 'check');
    }

    public function
addClass($class = '')
    {
        return
$this->setting('class', __('CSS class:'), $class);
    }

    public function
addOffline($offline = 0)
    {
        return
$this->setting('offline', __('Offline'), $offline, 'check');
    }

    public function
isOffline()
    {
        return
$this->settings['offline']['value'] ?? false;
    }
}