Current File : /home/pacjaorg/public_html/kmm/libraries/regularlabs/src/Form/FormField.php |
<?php
/**
* @package Regular Labs Library
* @version 23.9.3039
*
* @author Peter van Westen <info@regularlabs.com>
* @link https://regularlabs.com
* @copyright Copyright © 2023 Regular Labs All Rights Reserved
* @license GNU General Public License version 2 or later
*/
namespace RegularLabs\Library\Form;
defined('_JEXEC') or die;
use DateTimeZone;
use Joomla\CMS\Application\CMSApplicationInterface as JCMSApplicationInterface;
use Joomla\CMS\Factory as JFactory;
use Joomla\CMS\Form\Form as JForm;
use Joomla\CMS\Form\FormField as JFormField;
use Joomla\CMS\Form\FormHelper as JFormHelper;
use Joomla\CMS\HTML\HTMLHelper as JHtml;
use Joomla\CMS\Language\Text as JText;
use Joomla\Database\DatabaseDriver as JDatabaseDriver;
use Joomla\Registry\Registry as JRegistry;
use ReflectionClass;
use RegularLabs\Library\Document as RL_Document;
use RegularLabs\Library\Parameters as RL_Parameters;
use RegularLabs\Library\RegEx as RL_RegEx;
use RegularLabs\Library\StringHelper as RL_String;
use SimpleXMLElement;
class FormField extends JFormField
{
public JCMSApplicationInterface $app;
/* @var object|JRegistry $attributes */
public $attributes;
public bool $collapse_children = false;
public JDatabaseDriver $db;
public bool $is_select_list = false;
public int $max_list_count = 0;
public $params;
public array $parent_request = [];
public bool $use_ajax = false;
public bool $use_tree_select = false;
/**
* @param JForm $form
*/
public function __construct($form = null)
{
$this->type ??= $this->getShortFieldName();
parent::__construct($form);
$this->db = JFactory::getDbo();
$this->app = JFactory::getApplication();
$params = RL_Parameters::getPlugin('regularlabs');
$this->max_list_count = $params->max_list_count;
RL_Document::style('regularlabs.admin-form');
}
/**
* Get a value from the field params
*
* @param string $key
* @param string $default
*
* @return bool|string
*/
public function get($key, $default = '')
{
$value = $default;
if (isset($this->params[$key]) && (string) $this->params[$key] != '')
{
$value = (string) $this->params[$key];
}
return $this->sanitizeValue($value);
}
/**
* @return string
*/
public function getAjaxRaw(JRegistry $attributes)
{
return $this->selectListForAjax($attributes);
}
public function getControlGroupEnd()
{
return '</div></div>';
}
public function getControlGroupStart()
{
return '<div class="control-group"><div class="control-label">';
}
/**
* Return a list option using the custom prepare methods
*
* @param object $item
* @param array $extras
* @param int $levelOffset
*
* @return mixed
*/
public function getOptionByListItem($item, $extras = [], $levelOffset = 0, $key = 'id')
{
$name = Form::getNameWithExtras($item, $extras);
$option = JHtml::_('select.option', $item->{$key}, $name, 'value', 'text', 0);
if (isset($item->level))
{
$option->level = $item->level + $levelOffset;
}
return $option;
}
/**
* Return a array of options using the custom prepare methods
*
* @param array $list
* @param array $extras
* @param int $levelOffset
*
* @return array
*/
public function getOptionsByList($list, $extras = [], $levelOffset = 0, $key = 'id')
{
$options = [];
foreach ($list as $id => $item)
{
$options[$id] = $this->getOptionByListItem($item, $extras, $levelOffset, $key);
}
return $options;
}
/**
* Return a recursive options list using the custom prepare methods
*
* @param array $items
* @param int $root
*
* @return array
*/
public function getOptionsTreeByList($items = [], $root = 0)
{
// establish the hierarchy of the menu
// TODO: use node model
$children = [];
if ( ! empty($items))
{
// first pass - collect children
foreach ($items as $v)
{
$pt = $v->parent_id;
$list = @$children[$pt] ?: [];
array_push($list, $v);
$children[$pt] = $list;
}
}
// second pass - get an indent list of the items
$list = JHtml::_('menu.treerecurse', $root, '', [], $children, 9999, 0, 0);
$options = [];
foreach ($list as $item)
{
$item->treename = Form::prepareSelectItem($item->treename, 1);
$options[] = JHtml::_('select.option', $item->id, $item->treename, 'value', 'text', 0);
}
return $options;
}
/**
* Passes along to the JText method.
* This is used for the array_walk in the sprintf method above.
*
* @param $string
*/
public function jText(&$string)
{
$string = JText::_($string);
}
/**
* Prepare the option string, handling language strings
*
* @param string $string
*
* @return string
*/
public function prepareText($string = '')
{
$string = trim((string) $string);
if ($string == '')
{
return '';
}
$string = JText::_($string);
$string = $this->replaceDateTags($string);
$string = $this->fixLanguageStringSyntax($string);
return $string;
}
public function replaceDateTags($string)
{
if ( ! RL_RegEx::matchAll('\[date:(?<format>.*?)\]', $string, $matches))
{
return $string;
}
$date = JFactory::getDate();
$tz = new DateTimeZone(JFactory::getApplication()->getCfg('offset'));
$date->setTimeZone($tz);
foreach ($matches as $match)
{
$replace = $date->format($match['format'], true);
$string = str_replace($match[0], $replace, $string);
}
return $string;
}
/**
* @param string $value
*
* @return bool|string
*/
public function sanitizeValue($value)
{
if (is_bool($value) || is_array($value) || is_object($value))
{
return $value;
}
if ($value === 'true')
{
return true;
}
if ($value === 'false')
{
return false;
}
return (string) $value;
}
public function selectList()
{
return $this->selectListFromData($this);
}
public function selectListAjax()
{
$class = $this->get('class', '');
$multiple = $this->get('multiple', false);
if ($this->use_tree_select)
{
RL_Document::useScript('bootstrap.dropdown');
}
else
{
RL_Document::usePreset('choicesjs');
RL_Document::useScript('webcomponent.field-fancy-select');
}
$attributes = compact('class', 'multiple');
if ( ! empty($this->attributes))
{
foreach ($this->attributes as $key => $default)
{
$attributes[$key] = $this->get($key, $default);
}
}
if ( ! empty($this->params))
{
foreach ($this->params as $key => $value)
{
$attributes[$key] = (string) $value;
}
}
$tree_select = $this->use_tree_select && $multiple;
return Form::selectListAjax(
get_class($this),
$this->name,
$this->value,
$this->id,
$attributes,
$tree_select,
$tree_select && $this->collapse_children
);
}
public function selectListForAjax($data)
{
return $this->selectListFromData($data);
}
public function selectListFromData($data)
{
$data_attributes = $data->get('attributes', []);
$this->parent_request = (array) $data->get('parent_request', []);
$name = $this->name ?: $data->get('name', $this->type);
$id = $this->id ?: $data->get('id', strtolower($name));
$value = $this->value ?: $data->get('value', []);
$class = $data->get('class', $data_attributes->class ?? '');
$multiple = $data->get('multiple', $data_attributes->multiple ?? 0);
$tree_select = $data->get('treeselect', $this->use_tree_select);
$collapse_children = $data->get('collapse_children', $this->collapse_children);
$attributes = compact('class', 'multiple');
if ( ! empty($this->attributes))
{
foreach ($this->attributes as $key => $default)
{
$attributes[$key] = $data->get($key, $this->get($key, $default));
}
}
foreach ($data_attributes as $key => $val)
{
$this->params[$key] = $this->sanitizeValue($val);
$attributes[$key] = $this->sanitizeValue($val);
}
$attributes = array_diff_key($attributes, ['name' => '', 'type' => '']);
$options = $this->getListOptions($attributes);
if ($this->get('text_as_value'))
{
$this->setTextAsValue($options);
}
return Form::selectList(
$options,
$name,
$value,
$id,
$attributes,
$tree_select && $multiple,
$tree_select && $multiple && $collapse_children
);
}
public function setup(SimpleXMLElement $element, $value, $group = null)
{
$this->params = $element->attributes();
return parent::setup($element, $value, $group);
}
/**
* Return the field input markup
* Return empty by default
*
* @return string
*/
protected function getInput()
{
if ( ! $this->is_select_list)
{
return '';
}
if ( ! $this->use_ajax && ! $this->use_tree_select)
{
return $this->selectList();
}
return $this->selectListAjax();
}
protected function getLabel()
{
$this->element['label'] = $this->prepareText($this->element['label']);
return $this->element['label'] == '---' ? ' ' : parent::getLabel();
}
/**
* @param array $attributes
*
* @return array
*/
protected function getListOptions($attributes)
{
return $this->getOptions();
}
/**
* Return the field options (array)
* Overrules the Joomla core functionality
*
* @return array
*/
protected function getOptions()
{
if (empty($this->element->option))
{
return [];
}
$fieldname = RL_RegEx::replace('[^a-z0-9_\-]', '_', $this->fieldname);
$options = [];
foreach ($this->element->option as $option)
{
$value = (string) $option['value'];
$text = trim((string) $option) != '' ? trim((string) $option) : $value;
$disabled = (string) $option['disabled'];
$disabled = ($disabled === 'true' || $disabled === 'disabled' || $disabled === '1');
$disabled = $disabled || ($this->readonly && $value != $this->value);
$checked = (string) $option['checked'];
$checked = ($checked === 'true' || $checked === 'checked' || $checked === '1');
$selected = (string) $option['selected'];
$selected = ($selected === 'true' || $selected === 'selected' || $selected === '1');
$attributes = '';
if ((string) $option['showon'])
{
$encodedConditions = json_encode(
JFormHelper::parseShowOnConditions((string) $option['showon'], $this->formControl, $this->group)
);
$attributes .= ' data-showon="' . $encodedConditions . '"';
}
// Add the option object to the result set.
$options[] = [
'value' => $value,
'text' => '- ' . JText::alt($text, $fieldname) . ' -',
'disable' => $disabled,
'class' => (string) $option['class'],
'selected' => ($checked || $selected),
'checked' => ($checked || $selected),
'onclick' => (string) $option['onclick'],
'onchange' => (string) $option['onchange'],
'optionattr' => $attributes,
];
}
return $options;
}
/**
* Fix some syntax/encoding issues in option text strings
*
* @param string $string
*
* @return string
*/
private function fixLanguageStringSyntax($string = '')
{
$string = str_replace('[:COMMA:]', ',', $string);
$string = trim(RL_String::html_entity_decoder($string));
$string = str_replace('"', '"', $string);
$string = str_replace('span style="font-family:monospace;"', 'span class="rl_code"', $string);
return $string;
}
/**
* Get the short name of the field class
* FoobarField => Foobar
*
* @return string
*/
private function getShortFieldName()
{
return substr((new ReflectionClass($this))->getShortName(), 0, -strlen('Field'));
}
private function setTextAsValue(&$options)
{
if (empty($options))
{
return;
}
foreach ($options as &$option)
{
$option->value = $option->text;
}
}
/**
* Replace language strings in a string
*
* @param string $string
*
* @return string
*/
private function sprintf($string = '')
{
$string = trim($string);
if (strpos($string, ',') === false)
{
return $string;
}
$string_parts = explode(',', $string);
$first_part = array_shift($string_parts);
if ($first_part === strtoupper($first_part))
{
$first_part = JText::_($first_part);
}
$first_part = RL_RegEx::replace('\[\[%([0-9]+):[^\]]*\]\]', '%\1$s', $first_part);
array_walk($string_parts, '\RegularLabs\Library\Field::jText');
return vsprintf($first_part, $string_parts);
}
}