primo commit
This commit is contained in:
2
libraries/regularlabs/autoload.php
Normal file
2
libraries/regularlabs/autoload.php
Normal file
@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// Only used for dealing with old Joomla 3 extensions (not reinstalled after upgrade to Joomla 3)
|
||||
43
libraries/regularlabs/layouts/regularlabs/buttons/button.php
Normal file
43
libraries/regularlabs/layouts/regularlabs/buttons/button.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Object\CMSObject as JCMSObject;
|
||||
|
||||
/**
|
||||
* @var JCMSObject $displayData
|
||||
*/
|
||||
|
||||
$button = $displayData;
|
||||
|
||||
if ( ! $button->get('name'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$is_modal = $button->get('modal');
|
||||
|
||||
$class = 'btn';
|
||||
$class .= $button->get('class') ? ' ' . $button->get('class') : ' btn-secondary';
|
||||
$class .= $is_modal ? ' modal-button' : null;
|
||||
$onclick = $button->get('onclick') ? ' onclick="' . str_replace('"', '"', $button->get('onclick')) . '"' : '';
|
||||
$title = $button->get('title') ? $button->get('title') : $button->get('text');
|
||||
$icon = $button->get('icon') ? $button->get('icon') : $button->get('name');
|
||||
|
||||
$href = $is_modal
|
||||
? 'data-bs-target="#' . strtolower($button->get('name')) . '_modal"'
|
||||
: 'href="' . $button->get('link', '#') . '"';
|
||||
?>
|
||||
<button type="button" <?php echo $href; ?> class="<?php echo $class; ?>" <?php echo $button->get('modal') ? 'data-bs-toggle="modal"' : '' ?> title="<?php echo $title; ?>" <?php echo $onclick; ?>>
|
||||
<span class="icon-<?php echo $icon; ?>" aria-hidden="true"></span>
|
||||
<?php echo $button->get('text'); ?>
|
||||
</button>
|
||||
85
libraries/regularlabs/layouts/regularlabs/buttons/modal.php
Normal file
85
libraries/regularlabs/layouts/regularlabs/buttons/modal.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper as JHtml;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use Joomla\CMS\Object\CMSObject as JCMSObject;
|
||||
use Joomla\CMS\Uri\Uri as JUri;
|
||||
|
||||
/**
|
||||
* @var JCMSObject $displayData
|
||||
*/
|
||||
|
||||
if ( ! function_exists('RegularLabsModalRenderButton'))
|
||||
{
|
||||
function RegularLabsModalRenderButton($options, $prefix = 'close', $default_text = 'JLIB_HTML_BEHAVIOR_CLOSE')
|
||||
{
|
||||
$class = $options[$prefix . 'Class'] ?? ($prefix == 'close' ? 'btn btn-secondary' : 'btn btn-success');
|
||||
$text = $options[$prefix . 'Text'] ?? JText::_($default_text);
|
||||
$onclick = $options[$prefix . 'Callback'] ?? '';
|
||||
$dismiss = $prefix == 'close' || ! empty($options[$prefix . 'Close']) ? 'data-bs-dismiss="modal"' : '';
|
||||
$icon = ! empty($options[$prefix . 'Icon']) ? '<span class="icon-' . $options[$prefix . 'Icon'] . '" aria-hidden="true"></span>' : '';
|
||||
|
||||
return '<button type="button" class="' . $class . '" ' . $dismiss . ' onclick="' . $onclick . '">'
|
||||
. $icon . $text . ' </button>';
|
||||
}
|
||||
}
|
||||
|
||||
$button = $displayData;
|
||||
|
||||
if ( ! $button->get('modal'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $button->get('name'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$link = ($button->get('link')) ? JUri::base() . $button->get('link') : null;
|
||||
$title = ($button->get('title')) ? $button->get('title') : $button->get('text');
|
||||
$options = is_array($button->get('options')) ? $button->get('options') : [];
|
||||
|
||||
$buttons = [];
|
||||
|
||||
if (isset($options['confirmCallback'])
|
||||
)
|
||||
{
|
||||
$buttons[] = RegularLabsModalRenderButton($options, 'confirm', 'JSAVE');
|
||||
}
|
||||
|
||||
if (isset($options['confirm2Callback'])
|
||||
)
|
||||
{
|
||||
$buttons[] = RegularLabsModalRenderButton($options, 'confirm2', 'JSAVE');
|
||||
}
|
||||
|
||||
$buttons[] = RegularLabsModalRenderButton($options, 'close', 'JLIB_HTML_BEHAVIOR_CLOSE');
|
||||
|
||||
$id = str_replace(' ', '', $button->get('id', strtolower($button->get('name')) . '_modal'));
|
||||
|
||||
echo JHtml::_(
|
||||
'bootstrap.renderModal',
|
||||
$id,
|
||||
[
|
||||
'url' => $link,
|
||||
'title' => $title,
|
||||
'height' => array_key_exists('height', $options) ? $options['height'] : '400px',
|
||||
'width' => array_key_exists('width', $options) ? $options['width'] : '800px',
|
||||
'bodyHeight' => array_key_exists('bodyHeight', $options) ? $options['bodyHeight'] : '70',
|
||||
'modalWidth' => array_key_exists('modalWidth', $options) ? $options['modalWidth'] : '80',
|
||||
'keyboard' => array_key_exists('keyboard', $options) ? $options['keyboard'] : true,
|
||||
'backdrop' => array_key_exists('backdrop', $options) ? $options['backdrop'] : true,
|
||||
'footer' => implode('', $buttons),
|
||||
]
|
||||
);
|
||||
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
extract($displayData);
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
* -----------------
|
||||
*
|
||||
* @var string $autocomplete Autocomplete attribute for the field.
|
||||
* @var boolean $autofocus Is autofocus enabled?
|
||||
* @var string $class Classes for the input.
|
||||
* @var string $description Description of the field.
|
||||
* @var boolean $disabled Is this field disabled?
|
||||
* @var string $group Group the field belongs to. <fields> section in form XML.
|
||||
* @var boolean $hidden Is this field hidden in the form?
|
||||
* @var string $hint Placeholder for the field.
|
||||
* @var string $id DOM id of the field.
|
||||
* @var string $label Label of the field.
|
||||
* @var string $labelclass Classes to apply to the label.
|
||||
* @var boolean $multiple Does this field support multiple values?
|
||||
* @var string $name Name of the input field.
|
||||
* @var string $onchange Onchange attribute for the field.
|
||||
* @var string $onclick Onclick attribute for the field.
|
||||
* @var string $pattern Pattern (Reg Ex) of value of the form field.
|
||||
* @var boolean $readonly Is this field read only?
|
||||
* @var boolean $repeat Allows extensions to duplicate elements.
|
||||
* @var boolean $required Is this field required?
|
||||
* @var integer $size Size attribute of the input.
|
||||
* @var boolean $spellcheck Spellcheck state for the form field.
|
||||
* @var string $validate Validation rules to apply.
|
||||
* @var string $value Value attribute of the field.
|
||||
* @var array $checkedOptions Options that will be set as checked.
|
||||
* @var boolean $hasValue Has this field a value assigned?
|
||||
* @var array $options Options available for this field.
|
||||
* @var string $dataAttribute Miscellaneous data attributes preprocessed for HTML output
|
||||
* @var array $dataAttributes Miscellaneous data attributes for eg, data-*.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The format of the input tag to be filled in using sprintf.
|
||||
* %1 - id
|
||||
* %2 - name
|
||||
* %3 - value
|
||||
* %4 = any other attributes
|
||||
*/
|
||||
$format = '<input type="checkbox" id="%1$s" name="%2$s" value="%3$s" %4$s>';
|
||||
|
||||
// The alt option for Text::alt
|
||||
$alt = preg_replace('/[^a-zA-Z0-9_\-]/', '_', $name);
|
||||
?>
|
||||
|
||||
<fieldset id="<?php echo $id; ?>" class="<?php echo trim($class . ' checkboxes'); ?>"
|
||||
<?php echo $required ? 'required' : ''; ?>
|
||||
<?php echo $autofocus ? 'autofocus' : ''; ?>
|
||||
<?php echo $dataAttribute; ?>>
|
||||
<legend class="visually-hidden"><?php echo $label; ?></legend>
|
||||
|
||||
<?php foreach ($options as $i => $option) : ?>
|
||||
<?php if (is_string($option)) : ?>
|
||||
<h4 class="mt-2 mb-0"><?php echo $option; ?></h4>
|
||||
<?php else: ?>
|
||||
<?php
|
||||
// Initialize some option attributes.
|
||||
$checked = in_array((string) $option->value, $checkedOptions, true) ? 'checked' : '';
|
||||
|
||||
// In case there is no stored value, use the option's default state.
|
||||
$checked = ( ! $hasValue && $option->checked) ? 'checked' : $checked;
|
||||
$optionClass = ! empty($option->class) ? 'class="form-check-input ' . $option->class . '"' : ' class="form-check-input"';
|
||||
$optionDisabled = ! empty($option->disable) || $disabled ? 'disabled' : '';
|
||||
|
||||
// Initialize some JavaScript option attributes.
|
||||
$onclick = ! empty($option->onclick) ? 'onclick="' . $option->onclick . '"' : '';
|
||||
$onchange = ! empty($option->onchange) ? 'onchange="' . $option->onchange . '"' : '';
|
||||
|
||||
$oid = $id . $i;
|
||||
$value = htmlspecialchars($option->value, ENT_COMPAT, 'UTF-8');
|
||||
$attributes = array_filter([$checked, $optionClass, $optionDisabled, $onchange, $onclick]);
|
||||
?>
|
||||
<div class="form-check form-check-inline">
|
||||
<?php echo sprintf($format, $oid, $name, $value, implode(' ', $attributes)); ?>
|
||||
<label for="<?php echo $oid; ?>" class="form-check-label">
|
||||
<?php echo $option->text; ?>
|
||||
</label>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</fieldset>
|
||||
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
extract($displayData);
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
* -----------------
|
||||
*
|
||||
* @var string $autocomplete Autocomplete attribute for the field.
|
||||
* @var boolean $autofocus Is autofocus enabled?
|
||||
* @var string $class Classes for the input.
|
||||
* @var string $description Description of the field.
|
||||
* @var boolean $disabled Is this field disabled?
|
||||
* @var string $group Group the field belongs to. <fields> section in form XML.
|
||||
* @var boolean $hidden Is this field hidden in the form?
|
||||
* @var string $hint Placeholder for the field.
|
||||
* @var string $id DOM id of the field.
|
||||
* @var string $label Label of the field.
|
||||
* @var string $labelclass Classes to apply to the label.
|
||||
* @var boolean $multiple Does this field support multiple values?
|
||||
* @var string $name Name of the input field.
|
||||
* @var string $onchange Onchange attribute for the field.
|
||||
* @var string $onclick Onclick attribute for the field.
|
||||
* @var string $pattern Pattern (Reg Ex) of value of the form field.
|
||||
* @var boolean $readonly Is this field read only?
|
||||
* @var boolean $repeat Allows extensions to duplicate elements.
|
||||
* @var boolean $required Is this field required?
|
||||
* @var integer $size Size attribute of the input.
|
||||
* @var boolean $spellcheck Spellcheck state for the form field.
|
||||
* @var string $validate Validation rules to apply.
|
||||
* @var string $value Value attribute of the field.
|
||||
* @var array $checkedOptions Options that will be set as checked.
|
||||
* @var boolean $hasValue Has this field a value assigned?
|
||||
* @var array $options Options available for this field.
|
||||
* @var array $inputType Options available for this field.
|
||||
* @var string $accept File types that are accepted.
|
||||
*/
|
||||
|
||||
$attributes = [
|
||||
'class="' . $class . '"',
|
||||
'allow-custom',
|
||||
'search-placeholder="' . $this->escape(Text::_('RL_ENTER_NEW_VALUES')) . '" ',
|
||||
];
|
||||
|
||||
$selectAttr = [
|
||||
$disabled ? 'disabled' : '',
|
||||
$readonly ? 'readonly' : '',
|
||||
strlen($hint) ? 'placeholder="' . $this->escape(Text::_('RL_ENTER_NEW_VALUES')) . '"' : '',
|
||||
$onchange ? 'onchange="' . $onchange . '"' : '',
|
||||
$autofocus ? 'autofocus' : '',
|
||||
'multiple',
|
||||
];
|
||||
|
||||
if ($required)
|
||||
{
|
||||
$selectAttr[] = 'required class="required"';
|
||||
$attributes[] = 'required';
|
||||
}
|
||||
|
||||
Text::script('JGLOBAL_SELECT_NO_RESULTS_MATCH');
|
||||
Text::script('JGLOBAL_SELECT_PRESS_TO_SELECT');
|
||||
|
||||
Factory::getDocument()->getWebAssetManager()
|
||||
->usePreset('choicesjs')
|
||||
->useScript('webcomponent.field-fancy-select');
|
||||
|
||||
?>
|
||||
<joomla-field-fancy-select <?php echo implode(' ', $attributes); ?>><?php
|
||||
echo HTMLHelper::_('select.genericlist', $options, $name,
|
||||
implode(' ', $selectAttr),
|
||||
'value', 'text', $value, $id
|
||||
);
|
||||
?></joomla-field-fancy-select>
|
||||
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use Joomla\CMS\Layout\FileLayout as JFileLayout;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
/**
|
||||
* @var array $displayData
|
||||
* @var int $id
|
||||
* @var string $extension
|
||||
* @var int $cloak_length
|
||||
* @var bool $use_modal
|
||||
* @var bool $show_label
|
||||
* @var bool $hidden
|
||||
* @var string $callback
|
||||
*/
|
||||
|
||||
extract($displayData);
|
||||
|
||||
$extension ??= 'all';
|
||||
$cloak_length ??= 4;
|
||||
$use_modal ??= false;
|
||||
$hidden ??= false;
|
||||
$show_label ??= false;
|
||||
$callback = htmlspecialchars($callback ?? '', ENT_QUOTES, 'UTF-8');
|
||||
?>
|
||||
<div id="downloadKeyWrapper_<?php echo $id; ?>" class="rl-download-key" data-callback="<?php echo $callback; ?>">
|
||||
<div class="rl-download-key-wrapper mb-4<?php echo $hidden ? ' hidden' : ''; ?>">
|
||||
<div class="<?php echo ! $show_label ? ' hidden' : ''; ?>">
|
||||
<label for="<?php echo $id; ?>">
|
||||
<span class="initialism text-muted">
|
||||
<?php echo JText::_('RL_DOWNLOAD_KEY'); ?>
|
||||
</span>
|
||||
<span class="rl-popover rl-popover-full">
|
||||
<small class="form-text">
|
||||
<?php echo JText::_('RL_DOWNLOAD_KEY_DESC'); ?>
|
||||
</small>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<span class="rl-spinner"></span>
|
||||
<div class="input-group">
|
||||
<input type="text" id="<?php echo $id; ?>" data-key-extension="<?php echo $extension; ?>" data-key-cloak-length="<?php echo $cloak_length; ?>"
|
||||
class="form-control rl-download-key-field form-control inactive rl-code-field hidden">
|
||||
<button type="button" class="btn btn-primary button-edit hidden">
|
||||
<span class="icon-edit" aria-hidden="true"></span><span class="visually-hidden"><?php echo JText::_('JEDIT'); ?></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-success button-apply hidden">
|
||||
<span class="icon-checkmark" aria-hidden="true"></span><span class="visually-hidden"><?php echo JText::_('JAPPLY'); ?></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger button-cancel hidden">
|
||||
<span class="icon-times" aria-hidden="true"></span><span class="visually-hidden"><?php echo JText::_('JCANCEL'); ?></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
echo (new JFileLayout(
|
||||
'regularlabs.form.field.downloadkey_errors',
|
||||
JPATH_SITE . '/libraries/regularlabs/layouts'
|
||||
))->render([
|
||||
'id' => $id,
|
||||
'extension' => $extension,
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
if ($use_modal)
|
||||
{
|
||||
echo (new JFileLayout(
|
||||
'regularlabs.form.field.downloadkey_modal',
|
||||
JPATH_SITE . '/libraries/regularlabs/layouts'
|
||||
))->render([
|
||||
'id' => $id,
|
||||
'extension' => $extension,
|
||||
]);
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
/**
|
||||
* @var array $displayData
|
||||
* @var int $id
|
||||
* @var string $extension
|
||||
*/
|
||||
|
||||
extract($displayData);
|
||||
|
||||
$extension = $extension ?: 'all';
|
||||
|
||||
$extension_name = $extension == 'all'
|
||||
? JText::_('RL_REGULAR_LABS_EXTENSIONS')
|
||||
: JText::_(strtoupper($extension));
|
||||
|
||||
?>
|
||||
|
||||
<div class="key-errors">
|
||||
<div class="key-error-empty alert alert-danger hidden">
|
||||
<?php echo JText::sprintf('RL_DOWNLOAD_KEY_ERROR_EMPTY', $extension_name, '<a href="https://regularlabs.com/download-keys" target="_blank">', '</a>'); ?>
|
||||
</div>
|
||||
<div class="key-error-invalid alert alert-danger hidden">
|
||||
<?php echo JText::sprintf('RL_DOWNLOAD_KEY_ERROR_INVALID', '<a href="https://regularlabs.com/download-keys" target="_blank">', '</a>'); ?>
|
||||
</div>
|
||||
<div class="key-error-expired alert alert-danger hidden">
|
||||
<?php echo JText::sprintf('RL_DOWNLOAD_KEY_ERROR_EXPIRED', '<a href="https://regularlabs.com/purchase" target="_blank">', '</a>'); ?>
|
||||
</div>
|
||||
<div class="key-error-local alert alert-danger hidden">
|
||||
<?php echo JText::_('RL_DOWNLOAD_KEY_ERROR_LOCAL'); ?>
|
||||
</div>
|
||||
<div class="key-error-external alert alert-danger hidden">
|
||||
<?php echo JText::sprintf('RL_DOWNLOAD_KEY_ERROR_EXTERNAL', '<a href="https://regularlabs.com/forum" target="_blank">', '</a>'); ?>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper as JHtml;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use Joomla\CMS\Layout\FileLayout as JFileLayout;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
/**
|
||||
* @var array $displayData
|
||||
* @var int $id
|
||||
* @var string $extension
|
||||
*/
|
||||
|
||||
extract($displayData);
|
||||
|
||||
$body = (new JFileLayout(
|
||||
'regularlabs.form.field.downloadkey_modal_body',
|
||||
JPATH_SITE . '/libraries/regularlabs/layouts'
|
||||
))->render([
|
||||
'id' => $id,
|
||||
'extension' => $extension,
|
||||
]);
|
||||
|
||||
$onclick = 'RegularLabs.DownloadKey.save(\'' . $extension . '\', document.querySelector(\'#' . $id . '_modal\').value, document.querySelector(\'#downloadKeyModal_' . $id . '\'));';
|
||||
|
||||
echo JHtml::_(
|
||||
'bootstrap.renderModal',
|
||||
'downloadKeyModal_' . $id,
|
||||
[
|
||||
'title' => JText::_('RL_REGULAR_LABS_DOWNLOAD_KEY'),
|
||||
'modalWidth' => '60',
|
||||
'footer' => '<button type="button" class="btn btn-success" onclick="' . $onclick . '">'
|
||||
. JText::_('JAPPLY')
|
||||
. '</button>'
|
||||
. '<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" aria-hidden="true">'
|
||||
. JText::_('JLIB_HTML_BEHAVIOR_CLOSE')
|
||||
. '</button>',
|
||||
],
|
||||
$body
|
||||
);
|
||||
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use Joomla\CMS\Layout\FileLayout as JFileLayout;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
/**
|
||||
* @var array $displayData
|
||||
* @var int $id
|
||||
* @var string $extension
|
||||
*/
|
||||
|
||||
extract($displayData);
|
||||
|
||||
$extension = $extension ?: 'all';
|
||||
|
||||
?>
|
||||
|
||||
<div class="content p-3">
|
||||
<?php
|
||||
echo (new JFileLayout(
|
||||
'regularlabs.form.field.downloadkey_errors',
|
||||
JPATH_SITE . '/libraries/regularlabs/layouts'
|
||||
))->render([
|
||||
'id' => $id,
|
||||
'extension' => $extension,
|
||||
]);
|
||||
?>
|
||||
<p>
|
||||
<?php echo html_entity_decode(JText::_('RL_DOWNLOAD_KEY_ENTER')); ?>:
|
||||
</p>
|
||||
<div class="input-group">
|
||||
<input type="text" id="<?php echo $id; ?>_modal" placeholder="ABC123..." class="rl-download-key-field form-control rl-code-field">
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use RegularLabs\Library\Document as RL_Document;
|
||||
|
||||
extract($displayData);
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
* -----------------
|
||||
*
|
||||
* @var string $id DOM id of the field.
|
||||
* @var string $icon1 Icon to show when the field is off.
|
||||
* @var string $icon2 Icon to show when the field is on.
|
||||
* @var string $text1 Text to show when the field is off.
|
||||
* @var string $text2 Text to show when the field is on.
|
||||
* @var string $class1 Class to add to the field when it is off.
|
||||
* @var string $class2 Class to add to the field when it is on.
|
||||
* @var string $name Name of the input field.
|
||||
*/
|
||||
|
||||
$text1 = JText::_($text1);
|
||||
$text2 = JText::_($text2);
|
||||
|
||||
RL_Document::useScript('showon');
|
||||
?>
|
||||
|
||||
<fieldset>
|
||||
<input type="hidden" name="<?php echo $name; ?>" id="<?php echo $id; ?>" value="0">
|
||||
<div data-showon='[{"field":"<?php echo $name; ?>","values":["0"],"sign":"=","op":""}]' class="hidden">
|
||||
<span class="<?php echo $class1; ?>" role="button" onclick="el=document.getElementById('<?php echo $id; ?>');el.value = 1;el.dispatchEvent(new Event('change'));">
|
||||
<span class="icon-<?php echo $icon1; ?>" aria-label="<?php echo $text1 ?: JText::_('JSHOW'); ?>"></span>
|
||||
<?php echo $text1; ?>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div data-showon='[{"field":"<?php echo $name; ?>","values":["1"],"sign":"=","op":""}]' class="hidden">
|
||||
<span class="<?php echo $class2; ?>" role="button" onclick="el=document.getElementById('<?php echo $id; ?>');el.value = 0;el.dispatchEvent(new Event('change'));">
|
||||
<span class="icon-<?php echo $icon2; ?>" aria-label="<?php echo $text2 ?: JText::_('JHIDE'); ?>"></span>
|
||||
<?php echo $text2; ?>
|
||||
</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
146
libraries/regularlabs/layouts/regularlabs/form/field/range.php
Normal file
146
libraries/regularlabs/layouts/regularlabs/form/field/range.php
Normal file
@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
/**
|
||||
* @var array $displayData
|
||||
* @var string $autocomplete Autocomplete attribute for the field.
|
||||
* @var boolean $autofocus Is autofocus enabled?
|
||||
* @var string $class Classes for the input.
|
||||
* @var string $description Description of the field.
|
||||
* @var boolean $disabled Is this field disabled?
|
||||
* @var string $group Group the field belongs to. <fields> section in form XML.
|
||||
* @var boolean $hidden Is this field hidden in the form?
|
||||
* @var string $hint Placeholder for the field.
|
||||
* @var string $id DOM id of the field.
|
||||
* @var string $label Label of the field.
|
||||
* @var string $labelclass Classes to apply to the label.
|
||||
* @var boolean $multiple Does this field support multiple values?
|
||||
* @var string $name Name of the input field.
|
||||
* @var string $onchange Onchange attribute for the field.
|
||||
* @var string $onclick Onclick attribute for the field.
|
||||
* @var string $pattern Pattern (Reg Ex) of value of the form field.
|
||||
* @var boolean $readonly Is this field read only?
|
||||
* @var boolean $repeat Allows extensions to duplicate elements.
|
||||
* @var boolean $required Is this field required?
|
||||
* @var integer $size Size attribute of the input.
|
||||
* @var boolean $spellcheck Spellcheck state for the form field.
|
||||
* @var string $validate Validation rules to apply.
|
||||
* @var string $value Value attribute of the field.
|
||||
* @var array $checkedOptions Options that will be set as checked.
|
||||
* @var boolean $hasValue Has this field a value assigned?
|
||||
* @var array $options Options available for this field.
|
||||
* @var array $inputType Options available for this field.
|
||||
* @var string $accept File types that are accepted.
|
||||
* @var string $dataAttribute Miscellaneous data attributes preprocessed for HTML output
|
||||
* @var array $dataAttributes Miscellaneous data attribute for eg, data-*.
|
||||
* @var int $min
|
||||
* @var int $max
|
||||
* @var string $prepend
|
||||
* @var string $append
|
||||
* @var string $class_range
|
||||
*/
|
||||
|
||||
extract($displayData);
|
||||
|
||||
$value = is_numeric($value) ? (float) $value : $min;
|
||||
|
||||
$class = $class ?: 'rl-w-6em font-monospace text-right';
|
||||
$class_range = $class_range ?: 'rl-w-16em';
|
||||
|
||||
// Initialize some field attributes.
|
||||
$attributes_range = [
|
||||
$class ? 'class="' . $class_range . '"' : '',
|
||||
$disabled ? 'disabled' : '',
|
||||
$readonly ? 'readonly' : '',
|
||||
! empty($onchange) ? 'onchange="' . $onchange . '"' : '',
|
||||
! empty($max) ? 'max="' . $max . '"' : '',
|
||||
! empty($step) ? 'step="' . $step . '"' : '',
|
||||
! empty($min) ? 'min="' . $min . '"' : '',
|
||||
$autofocus ? 'autofocus' : '',
|
||||
'oninput="document.querySelector(\'input[name=\\\'' . $name . '\\\']\').value=this.value;document.querySelector(\'input[name=\\\'' . $name . '\\\']\').dispatchEvent(new Event(\'change\'));"',
|
||||
];
|
||||
|
||||
$attributes_number = [
|
||||
$class ? 'class="form-control ' . $class . '"' : 'class="form-control"',
|
||||
! empty($description) ? 'aria-describedby="' . $name . '-desc"' : '',
|
||||
$disabled ? 'disabled' : '',
|
||||
$readonly ? 'readonly' : '',
|
||||
strlen($hint) ? 'placeholder="' . htmlspecialchars($hint, ENT_COMPAT, 'UTF-8') . '"' : '',
|
||||
! empty($onchange) ? 'onchange="' . $onchange . '"' : '',
|
||||
isset($max) ? 'max="' . $max . '"' : '',
|
||||
! empty($step) ? 'step="' . $step . '"' : '',
|
||||
isset($min) ? 'min="' . $min . '"' : '',
|
||||
$required ? 'required aria-required="true"' : '',
|
||||
$autocomplete,
|
||||
$autofocus ? 'autofocus' : '',
|
||||
$dataAttribute,
|
||||
'oninput="document.querySelector(\'input[data-for=\\\'' . $name . '\\\']\').value=this.value;"',
|
||||
];
|
||||
|
||||
$chars = (strlen($max) ?: $size) ?: 4;
|
||||
$width = $chars * 8;
|
||||
|
||||
$classes = [];
|
||||
|
||||
if ($prepend)
|
||||
{
|
||||
$classes[] = 'input-prepend';
|
||||
}
|
||||
|
||||
if ($append)
|
||||
{
|
||||
$classes[] = 'input-append';
|
||||
}
|
||||
|
||||
if (str_starts_with($prepend, 'icon-'))
|
||||
{
|
||||
$prepend = '<span class="' . $prepend . '"></span>';
|
||||
}
|
||||
|
||||
if (str_starts_with($append, 'icon-'))
|
||||
{
|
||||
$append = '<span class="' . $append . '"></span>';
|
||||
}
|
||||
|
||||
if ($prepend && preg_match('#^[A-Z][A-Z0-9_]+$#', $prepend))
|
||||
{
|
||||
$prepend = Text::_($prepend);
|
||||
}
|
||||
|
||||
if ($append && preg_match('#^[A-Z][A-Z0-9_]+$#', $append))
|
||||
{
|
||||
$append = Text::_($append);
|
||||
}
|
||||
?>
|
||||
<div class="rl-flex">
|
||||
|
||||
<span class="rl-mr-1 <?php echo implode(' ', $classes); ?>">
|
||||
<?php if ($prepend): ?>
|
||||
<span class="add-on"><?php echo $prepend; ?></span>
|
||||
<?php endif; ?>
|
||||
|
||||
<input type="number" inputmode="numeric" name="<?php echo $name; ?>" id="<?php echo $id; ?>"
|
||||
value="<?php echo htmlspecialchars($value, ENT_COMPAT, 'UTF-8'); ?>"
|
||||
<?php echo implode(' ', $attributes_number); ?>>
|
||||
|
||||
<?php if ($append): ?>
|
||||
<span class="add-on"><?php echo $append; ?></span>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
|
||||
<input type="range" data-for="<?php echo $name; ?>" value="<?php echo $value; ?>"
|
||||
<?php echo implode(' ', $attributes_range); ?> />
|
||||
|
||||
</div>
|
||||
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use RegularLabs\Library\Document as RL_Document;
|
||||
|
||||
extract($displayData);
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
* -----------------
|
||||
*
|
||||
* @var string $autocomplete Autocomplete attribute for the field.
|
||||
* @var boolean $autofocus Is autofocus enabled?
|
||||
* @var string $class Classes for the input.
|
||||
* @var string $description Description of the field.
|
||||
* @var boolean $disabled Is this field disabled?
|
||||
* @var string $group Group the field belongs to. <fields> section in form XML.
|
||||
* @var boolean $hidden Is this field hidden in the form?
|
||||
* @var string $hint Placeholder for the field.
|
||||
* @var string $id DOM id of the field.
|
||||
* @var string $label Label of the field.
|
||||
* @var string $labelclass Classes to apply to the label.
|
||||
* @var boolean $multiple Does this field support multiple values?
|
||||
* @var string $name Name of the input field.
|
||||
* @var string $onchange Onchange attribute for the field.
|
||||
* @var string $onclick Onclick attribute for the field.
|
||||
* @var string $pattern Pattern (Reg Ex) of value of the form field.
|
||||
* @var boolean $readonly Is this field read only?
|
||||
* @var boolean $repeat Allows extensions to duplicate elements.
|
||||
* @var boolean $required Is this field required?
|
||||
* @var integer $size Size attribute of the input.
|
||||
* @var boolean $spellcheck Spellcheck state for the form field.
|
||||
* @var string $validate Validation rules to apply.
|
||||
* @var string $value Value attribute of the field.
|
||||
* @var array $checkedOptions Options that will be set as checked.
|
||||
* @var boolean $hasValue Has this field a value assigned?
|
||||
* @var boolean $allowCustom Allow custom values.
|
||||
* @var array $options Options available for this field.
|
||||
* @var array $inputType Options available for this field.
|
||||
* @var string $accept File types that are accepted.
|
||||
*/
|
||||
|
||||
$attributes = [
|
||||
'class="' . $class . '"',
|
||||
'search-placeholder="' . $this->escape($hint) . '" ',
|
||||
];
|
||||
|
||||
if ($allowCustom)
|
||||
{
|
||||
$attributes[] = 'allow-custom';
|
||||
}
|
||||
|
||||
$selectAttr = [
|
||||
$disabled ? 'disabled' : '',
|
||||
$readonly ? 'readonly' : '',
|
||||
strlen($hint) ? 'placeholder="' . $this->escape($hint) . '"' : '',
|
||||
$onchange ? 'onchange="' . $onchange . '"' : '',
|
||||
$autofocus ? 'autofocus' : '',
|
||||
];
|
||||
|
||||
if ($required)
|
||||
{
|
||||
$selectAttr[] = 'required class="required"';
|
||||
$attributes[] = 'required';
|
||||
}
|
||||
|
||||
Text::script('JGLOBAL_SELECT_NO_RESULTS_MATCH');
|
||||
Text::script('JGLOBAL_SELECT_PRESS_TO_SELECT');
|
||||
|
||||
Factory::getDocument()->getWebAssetManager()
|
||||
->usePreset('choicesjs')
|
||||
->useScript('webcomponent.field-fancy-select');
|
||||
|
||||
RL_Document::script('regularlabs.simplecategory');
|
||||
?>
|
||||
<rl-field-simple-category>
|
||||
<joomla-field-fancy-select <?php echo implode(' ', $attributes); ?>><?php
|
||||
echo HTMLHelper::_('select.genericlist', $options, $name, [
|
||||
'id' => $id,
|
||||
'list.select' => $value,
|
||||
'list.attr' => implode(' ', $selectAttr),
|
||||
]
|
||||
);
|
||||
?></joomla-field-fancy-select>
|
||||
</rl-field-simple-category>
|
||||
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
extract($displayData);
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
* -----------------
|
||||
*
|
||||
* @var JForm $tmpl The Empty form for template
|
||||
* @var array $forms Array of JForm instances for render the rows
|
||||
* @var bool $multiple The multiple state for the form field
|
||||
* @var int $min Count of minimum repeating in multiple mode
|
||||
* @var int $max Count of maximum repeating in multiple mode
|
||||
* @var string $name Name of the input field.
|
||||
* @var string $field The field
|
||||
* @var string $fieldname The field name
|
||||
* @var string $fieldId The field ID
|
||||
* @var string $control The forms control
|
||||
* @var string $label The field label
|
||||
* @var string $description The field description
|
||||
* @var string $class Classes for the container
|
||||
* @var array $buttons Array of the buttons that will be rendered
|
||||
* @var bool $groupByFieldset Whether group the subform fields by it`s fieldset
|
||||
*/
|
||||
|
||||
// Add script
|
||||
if ($multiple)
|
||||
{
|
||||
Factory::getDocument()->getWebAssetManager()
|
||||
->useScript('webcomponent.field-subform');
|
||||
}
|
||||
|
||||
$class = $class ? ' ' . $class : '';
|
||||
$sublayout = (empty($groupByFieldset) ? 'section' : 'section-byfieldsets');
|
||||
$add_button_text = $field->getAttribute('add_button_text');
|
||||
?>
|
||||
|
||||
<div class="subform-repeatable-wrapper subform-layout">
|
||||
<joomla-field-subform class="subform-repeatable<?php echo $class; ?>" name="<?php echo $name; ?>"
|
||||
button-add=".group-add" button-remove=".group-remove" button-move="<?php echo empty($buttons['move']) ? '' : '.group-move' ?>"
|
||||
repeatable-element=".subform-repeatable-group" minimum="<?php echo $min; ?>" maximum="<?php echo $max; ?>">
|
||||
<?php if ( ! empty($buttons['add'])) : ?>
|
||||
<div class="btn-toolbar">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="group-add btn btn-sm button btn-success" aria-label="<?php echo Text::_($add_button_text ?: 'JGLOBAL_FIELD_ADD'); ?>">
|
||||
<span class="icon-plus icon-white" aria-hidden="true"></span>
|
||||
<?php echo Text::_($add_button_text ?: ''); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
foreach ($forms as $k => $form) :
|
||||
echo $this->sublayout($sublayout, [
|
||||
'form' => $form, 'basegroup' => $fieldname, 'group' => $fieldname . $k, 'buttons' => $buttons, 'field' => $field,
|
||||
]);
|
||||
endforeach;
|
||||
?>
|
||||
<?php if ($multiple) : ?>
|
||||
<template class="subform-repeatable-template-section hidden"><?php
|
||||
echo trim($this->sublayout($sublayout, [
|
||||
'form' => $tmpl, 'basegroup' => $fieldname, 'group' => $fieldname . 'X', 'buttons' => $buttons,
|
||||
'field' => $field,
|
||||
]));
|
||||
?></template>
|
||||
<?php endif; ?>
|
||||
</joomla-field-subform>
|
||||
</div>
|
||||
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
extract($displayData);
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
* -----------------
|
||||
*
|
||||
* @var JForm $form The form instance for render the section
|
||||
* @var JForm $field The field
|
||||
* @var string $basegroup The base group name
|
||||
* @var string $group Current group name
|
||||
* @var array $buttons Array of the buttons that will be rendered
|
||||
*/
|
||||
|
||||
$add_button_text = $field->getAttribute('add_button_text');
|
||||
?>
|
||||
|
||||
<div class="subform-repeatable-group" data-base-name="<?php echo $basegroup; ?>" data-group="<?php echo $group; ?>">
|
||||
<?php if ( ! empty($buttons)) : ?>
|
||||
<div class="btn-toolbar text-end">
|
||||
<div class="btn-group">
|
||||
<?php if ( ! empty($buttons['add'])): ?>
|
||||
<button type="button" class="group-add btn btn-sm btn-success" aria-label="<?php echo Text::_($add_button_text ?: 'JGLOBAL_FIELD_ADD'); ?>">
|
||||
<span class="icon-plus icon-white" aria-hidden="true"></span>
|
||||
<?php echo Text::_($add_button_text ?: ''); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty($buttons['remove'])): ?>
|
||||
<button type="button" class="group-remove btn btn-sm btn-danger" aria-label="<?php echo Text::_('JGLOBAL_FIELD_REMOVE'); ?>">
|
||||
<span class="icon-minus icon-white" aria-hidden="true"></span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty($buttons['move'])): ?>
|
||||
<button type="button" class="group-move btn btn-sm btn-primary" aria-label="<?php echo Text::_('JGLOBAL_FIELD_MOVE'); ?>">
|
||||
<span class="icon-arrows-alt icon-white" aria-hidden="true"></span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="row">
|
||||
<?php foreach ($form->getFieldsets() as $fieldset) : ?>
|
||||
<fieldset class="<?php if ( ! empty($fieldset->class))
|
||||
{
|
||||
echo $fieldset->class;
|
||||
} ?>">
|
||||
<?php if ( ! empty($fieldset->label)) : ?>
|
||||
<legend><?php echo Text::_($fieldset->label); ?></legend>
|
||||
<?php endif; ?>
|
||||
<?php foreach ($form->getFieldset($fieldset->name) as $field) : ?>
|
||||
<?php echo $field->renderField(); ?>
|
||||
<?php endforeach; ?>
|
||||
</fieldset>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
extract($displayData);
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
* -----------------
|
||||
*
|
||||
* @var JForm $form The form instance for render the section
|
||||
* @var JForm $field The field
|
||||
* @var string $basegroup The base group name
|
||||
* @var string $group Current group name
|
||||
* @var array $buttons Array of the buttons that will be rendered
|
||||
*/
|
||||
|
||||
$add_button_text = $field->getAttribute('add_button_text');
|
||||
?>
|
||||
|
||||
<div class="subform-repeatable-group" data-base-name="<?php echo $basegroup; ?>" data-group="<?php echo $group; ?>">
|
||||
<?php if ( ! empty($buttons)) : ?>
|
||||
<div class="btn-toolbar text-end">
|
||||
<div class="btn-group">
|
||||
<?php if ( ! empty($buttons['add'])): ?>
|
||||
<button type="button" class="group-add btn btn-sm btn-success" aria-label="<?php echo Text::_($add_button_text ?: 'JGLOBAL_FIELD_ADD'); ?>">
|
||||
<span class="icon-plus icon-white" aria-hidden="true"></span>
|
||||
<?php echo Text::_($add_button_text ?: ''); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty($buttons['remove'])): ?>
|
||||
<button type="button" class="group-remove btn btn-sm btn-danger" aria-label="<?php echo Text::_('JGLOBAL_FIELD_REMOVE'); ?>">
|
||||
<span class="icon-minus icon-white" aria-hidden="true"></span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty($buttons['move'])): ?>
|
||||
<button type="button" class="group-move btn btn-sm btn-primary" aria-label="<?php echo Text::_('JGLOBAL_FIELD_MOVE'); ?>">
|
||||
<span class="icon-arrows-alt icon-white" aria-hidden="true"></span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php foreach ($form->getGroup('') as $field) : ?>
|
||||
<?php echo $field->renderField(); ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Date\Date as JDate;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
|
||||
extract($displayData);
|
||||
|
||||
/**
|
||||
* Layout variables
|
||||
* -----------------
|
||||
*
|
||||
* @var object $field
|
||||
* @var string $autocomplete Autocomplete attribute for the field.
|
||||
* @var boolean $autofocus Is autofocus enabled?
|
||||
* @var string $class Classes for the input.
|
||||
* @var string $description Description of the field.
|
||||
* @var boolean $disabled Is this field disabled?
|
||||
* @var string $group Group the field belongs to. <fields> section in form XML.
|
||||
* @var boolean $hidden Is this field hidden in the form?
|
||||
* @var string $hint Placeholder for the field.
|
||||
* @var string $id DOM id of the field.
|
||||
* @var string $label Label of the field.
|
||||
* @var string $labelclass Classes to apply to the label.
|
||||
* @var boolean $multiple Does this field support multiple values?
|
||||
* @var string $name Name of the input field.
|
||||
* @var string $onchange Onchange attribute for the field.
|
||||
* @var string $onclick Onclick attribute for the field.
|
||||
* @var string $pattern Pattern (Reg Ex) of value of the form field.
|
||||
* @var boolean $readonly Is this field read only?
|
||||
* @var boolean $repeat Allows extensions to duplicate elements.
|
||||
* @var boolean $required Is this field required?
|
||||
* @var integer $size Size attribute of the input.
|
||||
* @var boolean $spellcheck Spellcheck state for the form field.
|
||||
* @var string $validate Validation rules to apply.
|
||||
* @var string $value Value attribute of the field.
|
||||
* @var array $checkedOptions Options that will be set as checked.
|
||||
* @var boolean $hasValue Has this field a value assigned?
|
||||
* @var array $options Options available for this field.
|
||||
* @var array $inputType Options available for this field.
|
||||
* @var string $accept File types that are accepted.
|
||||
* @var boolean $charcounter Does this field support a character counter?
|
||||
* @var string $dataAttribute Miscellaneous data attributes preprocessed for HTML output
|
||||
* @var array $dataAttributes Miscellaneous data attribute for eg, data-*.
|
||||
* @var string $columns
|
||||
* @var string $rows
|
||||
* @var string $maxlength
|
||||
* @var boolean $show_insert_date_name
|
||||
* @var boolean $add_separator
|
||||
*/
|
||||
|
||||
// Initialize some field attributes.
|
||||
if ($charcounter)
|
||||
{
|
||||
// Load the js file
|
||||
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
|
||||
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
|
||||
$wa->useScript('short-and-sweet');
|
||||
|
||||
// Set the css class to be used as the trigger
|
||||
$charcounter = ' charcount';
|
||||
// Set the text
|
||||
$counterlabel = 'data-counter-label="' . $this->escape(Text::_('JFIELD_META_DESCRIPTION_COUNTER')) . '"';
|
||||
}
|
||||
|
||||
$attributes = [
|
||||
$columns ?: '',
|
||||
$rows ?: '',
|
||||
! empty($class) ? 'class="form-control ' . $class . $charcounter . '"' : 'class="form-control' . $charcounter . '"',
|
||||
! empty($description) ? 'aria-describedby="' . $name . '-desc"' : '',
|
||||
strlen($hint) ? 'placeholder="' . htmlspecialchars($hint, ENT_COMPAT, 'UTF-8') . '"' : '',
|
||||
$disabled ? 'disabled' : '',
|
||||
$readonly ? 'readonly' : '',
|
||||
$onchange ? 'onchange="' . $onchange . '"' : '',
|
||||
$onclick ? 'onclick="' . $onclick . '"' : '',
|
||||
$required ? 'required' : '',
|
||||
! empty($autocomplete) ? 'autocomplete="' . $autocomplete . '"' : '',
|
||||
$autofocus ? 'autofocus' : '',
|
||||
$spellcheck ? '' : 'spellcheck="false"',
|
||||
$maxlength ?: '',
|
||||
! empty($counterlabel) ? $counterlabel : '',
|
||||
$dataAttribute,
|
||||
];
|
||||
|
||||
if ($show_insert_date_name)
|
||||
{
|
||||
$user = JFactory::getApplication()->getIdentity() ?: JFactory::getUser();
|
||||
|
||||
$date_name = JDate::getInstance()->format('[Y-m-d]') . ' ' . $user->name . ' : ';
|
||||
$separator = $add_separator ? '---' : 'none';
|
||||
$onclick = "RegularLabs.TextArea.prependTextarea('" . $id . "', '" . addslashes($date_name) . "', '" . $separator . "');";
|
||||
}
|
||||
?>
|
||||
<?php if ($show_insert_date_name) : ?>
|
||||
<span role="button" class="btn btn-sm btn-primary text-bg-primary" onclick="<?php echo $onclick; ?>">
|
||||
<span class="icon-pencil" aria-hidden="true"></span>
|
||||
<?php echo JText::_('RL_INSERT_DATE_NAME'); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
|
||||
<textarea name="<?php
|
||||
echo $name; ?>" id="<?php
|
||||
echo $id; ?>" <?php
|
||||
echo implode(' ', $attributes); ?> ><?php echo htmlspecialchars($value, ENT_COMPAT, 'UTF-8'); ?></textarea>
|
||||
@ -0,0 +1,168 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
use RegularLabs\Library\Document as RL_Document;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
/**
|
||||
* @var array $displayData
|
||||
* @var int $id
|
||||
* @var string $name
|
||||
* @var array $value
|
||||
* @var array $options
|
||||
* @var bool $collapse_children
|
||||
*/
|
||||
|
||||
extract($displayData);
|
||||
|
||||
if (empty($options))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RL_Document::script('regularlabs.treeselect');
|
||||
RL_Document::scriptDeclaration("
|
||||
document.addEventListener('DOMContentLoaded', () => {RegularLabs.TreeSelect.init('" . $id . "')});
|
||||
");
|
||||
|
||||
if ( ! is_array($value))
|
||||
{
|
||||
$value = [$value];
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="card rl-treeselect" id="rl-treeselect-<?php echo $id; ?>">
|
||||
<div class="card-header">
|
||||
<section class="d-flex align-items-center flex-wrap w-100">
|
||||
<div class="d-flex align-items-center flex-fill mb-1" role="group"
|
||||
aria-label="<?php echo Text::_('JSELECT'); ?>">
|
||||
<?php echo Text::_('JSELECT'); ?>
|
||||
<button data-action="checkAll" class="btn btn-secondary btn-sm mx-1" type="button">
|
||||
<?php echo Text::_('JALL'); ?>
|
||||
</button>
|
||||
<button data-action="uncheckAll" class="btn btn-secondary btn-sm mx-1" type="button">
|
||||
<?php echo Text::_('JNONE'); ?>
|
||||
</button>
|
||||
<button data-action="toggleAll" class="btn btn-secondary btn-sm mx-1" type="button">
|
||||
<?php echo Text::_('RL_TOGGLE'); ?>
|
||||
</button>
|
||||
</div>
|
||||
<div class="d-flex align-items-center mb-1 flex-fill" role="group"
|
||||
aria-label="<?php echo Text::_('RL_EXPAND'); ?>">
|
||||
<?php echo Text::_('RL_EXPAND'); ?>
|
||||
<button data-action="expandAll" class="btn btn-secondary btn-sm mx-1" type="button">
|
||||
<?php echo Text::_('JALL'); ?>
|
||||
</button>
|
||||
<button data-action="collapseAll" class="btn btn-secondary btn-sm mx-1" type="button">
|
||||
<?php echo Text::_('JNONE'); ?>
|
||||
</button>
|
||||
</div>
|
||||
<div class="d-flex align-items-center mb-1 flex-fill" role="group"
|
||||
aria-label="<?php echo Text::_('JSHOW'); ?>">
|
||||
<?php echo Text::_('JSHOW'); ?>
|
||||
<button data-action="showAll" class="btn btn-secondary btn-sm mx-1" type="button">
|
||||
<?php echo Text::_('JALL'); ?>
|
||||
</button>
|
||||
<button data-action="showSelected" class="btn btn-secondary btn-sm mx-1" type="button">
|
||||
<?php echo Text::_('RL_SELECTED'); ?>
|
||||
</button>
|
||||
</div>
|
||||
<div role="search" class="flex-grow-1">
|
||||
<label for="treeselectfilter" class="visually-hidden">
|
||||
<?php echo Text::_('JSEARCH_FILTER'); ?>
|
||||
</label>
|
||||
<input type="text" name="treeselectfilter" class="form-control search-query" autocomplete="off"
|
||||
placeholder="<?php echo Text::_('JSEARCH_FILTER'); ?>">
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="treeselect">
|
||||
<?php $previous_level = 0; ?>
|
||||
<?php foreach ($options
|
||||
|
||||
as $i => $option) : ?>
|
||||
<?php
|
||||
$option->level ??= 0;
|
||||
|
||||
if ($previous_level < $option->level)
|
||||
{
|
||||
echo '<ul class="treeselect-sub">';
|
||||
}
|
||||
|
||||
if ($previous_level > $option->level)
|
||||
{
|
||||
for ($i = 0; $i < $previous_level - $option->level; $i++)
|
||||
{
|
||||
echo '</ul></li>';
|
||||
}
|
||||
}
|
||||
|
||||
$selected = in_array($option->value, $value);
|
||||
?>
|
||||
<li>
|
||||
<div class="treeselect-item">
|
||||
<?php if (empty($option->no_checkbox)) : ?>
|
||||
<input type="checkbox" class="novalidate"
|
||||
name="<?php echo $name; ?>" id="<?php echo $id . $option->value; ?>" value="<?php echo $option->value; ?>"
|
||||
<?php echo $selected ? ' checked="checked"' : ''; ?>
|
||||
<?php echo ! empty($option->disable) ? ' disabled="disabled"' : ''; ?>
|
||||
<?php echo $collapse_children && ! $option->level ? ' data-rl-treeselect-collapse-children="true"' : ''; ?>>
|
||||
<?php endif; ?>
|
||||
<label for="<?php echo $id . $option->value; ?>" class="">
|
||||
<span class="<?php echo ! empty($option->disable) ? ' disabled' : ''; ?><?php echo ! empty($option->heading) ? ' text-uppercase fw-bold' : ''; ?>">
|
||||
<?php echo $option->text; ?>
|
||||
</span>
|
||||
<?php if (isset($option->published) && $option->published == 0) : ?>
|
||||
<?php echo ' <span class="badge bg-secondary">' . Text::_('JUNPUBLISHED') . '</span>'; ?>
|
||||
<?php endif; ?>
|
||||
</label>
|
||||
</div>
|
||||
<?php
|
||||
$previous_level = $option->level;
|
||||
?>
|
||||
<?php endforeach; ?>
|
||||
<?php
|
||||
for ($i = 0; $i < $previous_level; $i++)
|
||||
{
|
||||
echo '</ul></li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<joomla-alert type="warning" style="display:none"><?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?></joomla-alert>
|
||||
<div class="sub-tree-select hidden">
|
||||
<div class="nav-hover treeselect-menu">
|
||||
<div class="dropdown">
|
||||
<button type="button" data-bs-toggle="dropdown" class="dropdown-toggle btn btn-sm btn-light">
|
||||
<span class="visually-hidden"><?php echo Text::sprintf('JGLOBAL_TOGGLE_DROPDOWN'); ?></span>
|
||||
</button>
|
||||
<div class="dropdown-menu">
|
||||
<h1 class="dropdown-header"><?php echo Text::_('RL_SUBITEMS'); ?></h1>
|
||||
<button type="button" data-action="checkNested" class="dropdown-item">
|
||||
<span class="icon-check-square" aria-hidden="true"></span>
|
||||
<?php echo Text::_('RL_SELECT_ALL'); ?>
|
||||
</button>
|
||||
<button type="button" data-action="uncheckNested" class="dropdown-item">
|
||||
<span class="icon-square" aria-hidden="true"></span>
|
||||
<?php echo Text::_('RL_UNSELECT_ALL'); ?>
|
||||
</button>
|
||||
<button type="button" data-action="toggleNested" class="dropdown-item">
|
||||
<span class="icon-question-circle" aria-hidden="true"></span>
|
||||
<?php echo Text::_('RL_TOGGLE_SELECTION'); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
28
libraries/regularlabs/regularlabs.xml
Normal file
28
libraries/regularlabs/regularlabs.xml
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<extension version="4.0" type="library" method="upgrade">
|
||||
<name>Regular Labs Library</name>
|
||||
<description>Regular Labs Library - used by Regular Labs extensions</description>
|
||||
<version>24.11.1459</version>
|
||||
<creationDate>November 2024</creationDate>
|
||||
<author>Regular Labs (Peter van Westen)</author>
|
||||
<authorEmail>info@regularlabs.com</authorEmail>
|
||||
<authorUrl>https://regularlabs.com</authorUrl>
|
||||
<copyright>Copyright © 2024 Regular Labs - All Rights Reserved</copyright>
|
||||
<license>GNU General Public License version 2 or later</license>
|
||||
<libraryname>regularlabs</libraryname>
|
||||
<namespace path="src">RegularLabs\Library</namespace>
|
||||
<scriptfile>script.install.php</scriptfile>
|
||||
<files>
|
||||
<file>autoload.php</file>
|
||||
<file>regularlabs.xml</file>
|
||||
<folder>layouts</folder>
|
||||
<folder>src</folder>
|
||||
<folder>vendor</folder>
|
||||
</files>
|
||||
<media folder="media" destination="regularlabs">
|
||||
<folder>css</folder>
|
||||
<folder>images</folder>
|
||||
<folder>js</folder>
|
||||
<folder>scss</folder>
|
||||
</media>
|
||||
</extension>
|
||||
30
libraries/regularlabs/script.install.php
Normal file
30
libraries/regularlabs/script.install.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
|
||||
if ( ! class_exists('RegularLabsInstallerScript'))
|
||||
{
|
||||
class RegularLabsInstallerScript
|
||||
{
|
||||
public function postflight($install_type, $adapter)
|
||||
{
|
||||
if ( ! in_array($install_type, ['install', 'update']))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
JFactory::getCache()->clean('_system');
|
||||
}
|
||||
}
|
||||
}
|
||||
187
libraries/regularlabs/src/ActionLogPlugin.php
Normal file
187
libraries/regularlabs/src/ActionLogPlugin.php
Normal file
@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use Joomla\Component\Actionlogs\Administrator\Plugin\ActionLogPlugin as JActionLogPlugin;
|
||||
use Joomla\Event\DispatcherInterface as JDispatcherInterface;
|
||||
use RegularLabs\Library\Language as RL_Language;
|
||||
class ActionLogPlugin extends JActionLogPlugin
|
||||
{
|
||||
static $ids = [];
|
||||
static $item_titles = [];
|
||||
static $item_types = [];
|
||||
public $alias = '';
|
||||
public $events = [];
|
||||
public $lang_prefix_change_state = 'PLG_SYSTEM_ACTIONLOGS';
|
||||
public $lang_prefix_delete = 'PLG_SYSTEM_ACTIONLOGS';
|
||||
public $lang_prefix_install = 'PLG_ACTIONLOG_JOOMLA';
|
||||
public $lang_prefix_save = 'PLG_SYSTEM_ACTIONLOGS';
|
||||
public $lang_prefix_uninstall = 'PLG_ACTIONLOG_JOOMLA';
|
||||
public $name = '';
|
||||
public $option = '';
|
||||
public $table = null;
|
||||
public function __construct(JDispatcherInterface &$subject, array $config = [])
|
||||
{
|
||||
parent::__construct($subject, $config);
|
||||
\RegularLabs\Library\Language::load('plg_actionlog_joomla', JPATH_ADMINISTRATOR);
|
||||
\RegularLabs\Library\Language::load('plg_actionlog_' . $this->alias);
|
||||
$config = \RegularLabs\Library\Parameters::getComponent($this->alias);
|
||||
$enable_actionlog = $config->enable_actionlog ?? \true;
|
||||
$this->events = $enable_actionlog ? ['*'] : [];
|
||||
if ($enable_actionlog && !empty($config->actionlog_events)) {
|
||||
$this->events = \RegularLabs\Library\ArrayHelper::toArray($config->actionlog_events);
|
||||
}
|
||||
$this->name = JText::_($this->name);
|
||||
$this->option = $this->option ?: 'com_' . $this->alias;
|
||||
}
|
||||
public function addItem($extension, $type, $title)
|
||||
{
|
||||
self::$item_types[$extension] = $type;
|
||||
self::$item_titles[$extension] = $title;
|
||||
}
|
||||
public function getItem($context)
|
||||
{
|
||||
$item = $this->getItemData($context);
|
||||
if (!isset($item->file)) {
|
||||
$item->file = JPATH_ADMINISTRATOR . '/components/' . $item->option . '/models/' . $item->type . '.php';
|
||||
}
|
||||
if (!isset($item->model)) {
|
||||
$item->model = $this->alias . 'Model' . ucfirst($item->type);
|
||||
}
|
||||
if (!isset($item->url)) {
|
||||
$item->url = 'index.php?option=' . $item->option . '&view=' . $item->type . '&layout=edit&id={id}';
|
||||
}
|
||||
return $item;
|
||||
}
|
||||
public function onContentAfterDelete($context, $table)
|
||||
{
|
||||
if (!str_contains($context, $this->option)) {
|
||||
return;
|
||||
}
|
||||
if (!\RegularLabs\Library\ArrayHelper::find(['*', 'delete'], $this->events)) {
|
||||
return;
|
||||
}
|
||||
$item = $this->getItem($context);
|
||||
$title = $table->title ?? $table->name ?? $table->id;
|
||||
$message = ['action' => 'deleted', 'type' => $item->title, 'id' => $table->id, 'title' => $title];
|
||||
$this->addLog([$message], $this->lang_prefix_delete . '_CONTENT_DELETED', $context);
|
||||
}
|
||||
public function onContentAfterSave($context, $table, $isNew, $data = [])
|
||||
{
|
||||
$data = \RegularLabs\Library\ArrayHelper::toArray($data);
|
||||
if (isset($data['ignore_actionlog']) && $data['ignore_actionlog']) {
|
||||
return;
|
||||
}
|
||||
if (!str_contains($context, $this->option)) {
|
||||
return;
|
||||
}
|
||||
$event = $isNew ? 'create' : 'update';
|
||||
if (!\RegularLabs\Library\ArrayHelper::find(['*', $event], $this->events)) {
|
||||
return;
|
||||
}
|
||||
$item = $this->getItem($context);
|
||||
$title = $table->title ?? $table->name ?? $table->id;
|
||||
$item_url = str_replace('{id}', $table->id, $item->url);
|
||||
$message = ['action' => $isNew ? 'add' : 'update', 'type' => $item->title, 'id' => $table->id, 'title' => $title, 'itemlink' => $item_url];
|
||||
$languageKey = $isNew ? $this->lang_prefix_save . '_CONTENT_ADDED' : $this->lang_prefix_save . '_CONTENT_UPDATED';
|
||||
$this->addLog([$message], $languageKey, $context);
|
||||
}
|
||||
public function onContentChangeState($context, $ids, $value)
|
||||
{
|
||||
if (!str_contains($context, $this->option)) {
|
||||
return;
|
||||
}
|
||||
if (!\RegularLabs\Library\ArrayHelper::find(['*', 'change_state'], $this->events)) {
|
||||
return;
|
||||
}
|
||||
switch ($value) {
|
||||
case 0:
|
||||
$languageKey = $this->lang_prefix_change_state . '_CONTENT_UNPUBLISHED';
|
||||
$action = 'unpublish';
|
||||
break;
|
||||
case 1:
|
||||
$languageKey = $this->lang_prefix_change_state . '_CONTENT_PUBLISHED';
|
||||
$action = 'publish';
|
||||
break;
|
||||
case 2:
|
||||
$languageKey = $this->lang_prefix_change_state . '_CONTENT_ARCHIVED';
|
||||
$action = 'archive';
|
||||
break;
|
||||
case -2:
|
||||
$languageKey = $this->lang_prefix_change_state . '_CONTENT_TRASHED';
|
||||
$action = 'trash';
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
$item = $this->getItem($context);
|
||||
if (!$this->table) {
|
||||
if (!is_file($item->file)) {
|
||||
return;
|
||||
}
|
||||
require_once $item->file;
|
||||
$this->table = (new $item->model())->getTable();
|
||||
}
|
||||
foreach ($ids as $id) {
|
||||
$this->table->load($id);
|
||||
$title = $this->table->title ?? $this->table->name ?? $this->table->id;
|
||||
$itemlink = str_replace('{id}', $this->table->id, $item->url);
|
||||
$message = ['action' => $action, 'type' => $item->title, 'id' => $id, 'title' => $title, 'itemlink' => $itemlink];
|
||||
$this->addLog([$message], $languageKey, $context);
|
||||
}
|
||||
}
|
||||
public function onExtensionAfterDelete($context, $table)
|
||||
{
|
||||
self::onContentAfterDelete($context, $table);
|
||||
}
|
||||
public function onExtensionAfterSave($context, $table, $isNew)
|
||||
{
|
||||
self::onContentAfterSave($context, $table, $isNew);
|
||||
}
|
||||
public function onExtensionAfterUninstall($installer, $eid, $result)
|
||||
{
|
||||
// Prevent duplicate logs
|
||||
if (in_array('uninstall_' . $eid, self::$ids, \true)) {
|
||||
return;
|
||||
}
|
||||
$context = \RegularLabs\Library\Input::get('option', '');
|
||||
if (!str_contains($context, $this->option)) {
|
||||
return;
|
||||
}
|
||||
if (!\RegularLabs\Library\ArrayHelper::find(['*', 'uninstall'], $this->events)) {
|
||||
return;
|
||||
}
|
||||
if ($result === \false) {
|
||||
return;
|
||||
}
|
||||
$manifest = $installer->get('manifest');
|
||||
if ($manifest === null) {
|
||||
return;
|
||||
}
|
||||
self::$ids[] = 'uninstall_' . $eid;
|
||||
$message = ['action' => 'uninstall', 'type' => $this->lang_prefix_install . '_TYPE_' . strtoupper($manifest->attributes()->type), 'id' => $eid, 'extension_name' => JText::_($manifest->name)];
|
||||
$languageKey = $this->lang_prefix_uninstall . '_EXTENSION_UNINSTALLED';
|
||||
$this->addLog([$message], $languageKey, 'com_regularlabsmanager');
|
||||
}
|
||||
private function getItemData(string $extension): object
|
||||
{
|
||||
if (str_contains($extension, '.')) {
|
||||
[$extension, $type] = explode('.', $extension);
|
||||
}
|
||||
RL_Language::load($extension);
|
||||
$type ??= self::$item_types[$extension] ?? 'item';
|
||||
$title = self::$item_titles[$extension] ?? JText::_($extension) . ' ' . JText::_('RL_ITEM');
|
||||
return (object) ['context' => $extension . '.' . $type, 'option' => $extension, 'type' => $type, 'title' => $title];
|
||||
}
|
||||
}
|
||||
78
libraries/regularlabs/src/Alias.php
Normal file
78
libraries/regularlabs/src/Alias.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Application\ApplicationHelper as JApplicationHelper;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
class Alias
|
||||
{
|
||||
/**
|
||||
* Creates an alias from a string
|
||||
*/
|
||||
public static function get(string $string = '', bool $unicode = \false): string
|
||||
{
|
||||
if (empty($string)) {
|
||||
return '';
|
||||
}
|
||||
$string = \RegularLabs\Library\StringHelper::removeHtml($string);
|
||||
if ($unicode || JFactory::getApplication()->get('unicodeslugs') == 1) {
|
||||
return self::stringURLUnicodeSlug($string);
|
||||
}
|
||||
// Remove < > html entities
|
||||
$string = str_replace(['<', '>'], '', $string);
|
||||
// Convert html entities
|
||||
$string = \RegularLabs\Library\StringHelper::html_entity_decoder($string);
|
||||
return JApplicationHelper::stringURLSafe($string);
|
||||
}
|
||||
/**
|
||||
* Creates a unicode alias from a string
|
||||
* Based on stringURLUnicodeSlug method from the unicode slug plugin by infograf768
|
||||
*/
|
||||
private static function stringURLUnicodeSlug(string $string = ''): string
|
||||
{
|
||||
if (empty($string)) {
|
||||
return '';
|
||||
}
|
||||
// Remove < > html entities
|
||||
$string = str_replace(['<', '>'], '', $string);
|
||||
// Convert html entities
|
||||
$string = \RegularLabs\Library\StringHelper::html_entity_decoder($string);
|
||||
// Convert to lowercase
|
||||
$string = \RegularLabs\Library\StringHelper::strtolower($string);
|
||||
// remove html tags
|
||||
$string = \RegularLabs\Library\RegEx::replace('</?[a-z][^>]*>', '', $string);
|
||||
// remove comments tags
|
||||
$string = \RegularLabs\Library\RegEx::replace('<\!--.*?-->', '', $string);
|
||||
// Replace weird whitespace characters like (Â) with spaces
|
||||
//$string = str_replace(array(chr(160), chr(194)), ' ', $string);
|
||||
$string = str_replace(" ", ' ', $string);
|
||||
$string = str_replace("
", ' ', $string);
|
||||
// ascii only
|
||||
// Replace double byte whitespaces by single byte (East Asian languages)
|
||||
$string = str_replace(" ", ' ', $string);
|
||||
// Remove any '-' from the string as they will be used as concatenator.
|
||||
// Would be great to let the spaces in but only Firefox is friendly with this
|
||||
$string = str_replace('-', ' ', $string);
|
||||
// Replace forbidden characters by whitespaces
|
||||
$string = \RegularLabs\Library\RegEx::replace('[' . \RegularLabs\Library\RegEx::quote(',:#$*"@+=;&.%()[]{}/\'\|') . ']', " ", $string);
|
||||
// Delete all characters that should not take up any space, like: ?
|
||||
$string = \RegularLabs\Library\RegEx::replace('[' . \RegularLabs\Library\RegEx::quote('?!¿¡') . ']', '', $string);
|
||||
// Trim white spaces at beginning and end of alias and make lowercase
|
||||
$string = trim($string);
|
||||
// Remove any duplicate whitespace and replace whitespaces by hyphens
|
||||
$string = \RegularLabs\Library\RegEx::replace('\x20+', '-', $string);
|
||||
// Remove leading and trailing hyphens
|
||||
$string = trim($string, '-');
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
396
libraries/regularlabs/src/ArrayHelper.php
Normal file
396
libraries/regularlabs/src/ArrayHelper.php
Normal file
@ -0,0 +1,396 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
class ArrayHelper
|
||||
{
|
||||
/**
|
||||
* Add a postfix to all keys in an array
|
||||
*/
|
||||
public static function addPostfixToKeys(array|object $array, string $postfix): array|object
|
||||
{
|
||||
$pefixed = [];
|
||||
foreach ($array as $key => $value) {
|
||||
$pefixed[\RegularLabs\Library\StringHelper::addPostfix($key, $postfix)] = $value;
|
||||
}
|
||||
return $pefixed;
|
||||
}
|
||||
/**
|
||||
* Add a postfix to all string values in an array
|
||||
*/
|
||||
public static function addPostfixToValues(array|object $array, string $postfix): array|object
|
||||
{
|
||||
foreach ($array as &$value) {
|
||||
$value = \RegularLabs\Library\StringHelper::addPostfix($value, $postfix);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
/**
|
||||
* Add a prefix and postfix to all string values in an array
|
||||
*/
|
||||
public static function addPreAndPostfixToValues(array|object $array, string $prefix, string $postfix, bool $keep_leading_slash = \true): array|object
|
||||
{
|
||||
foreach ($array as &$value) {
|
||||
$value = \RegularLabs\Library\StringHelper::addPrefix($value, $prefix, $keep_leading_slash);
|
||||
$value = \RegularLabs\Library\StringHelper::addPostfix($value, $postfix, $keep_leading_slash);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
/**
|
||||
* Add a prefix to all keys in an array
|
||||
*/
|
||||
public static function addPrefixToKeys(array|object $array, string $prefix): array|object
|
||||
{
|
||||
$pefixed = [];
|
||||
foreach ($array as $key => $value) {
|
||||
$pefixed[\RegularLabs\Library\StringHelper::addPrefix($key, $prefix)] = $value;
|
||||
}
|
||||
return $pefixed;
|
||||
}
|
||||
/**
|
||||
* Add a prefix to all string values in an array
|
||||
*/
|
||||
public static function addPrefixToValues(array|object $array, string $prefix, bool $keep_leading_slash = \true): array|object
|
||||
{
|
||||
foreach ($array as &$value) {
|
||||
$value = \RegularLabs\Library\StringHelper::addPrefix($value, $prefix, $keep_leading_slash);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
/**
|
||||
* Run a method over all values inside the array or object
|
||||
*/
|
||||
public static function applyMethodToKeys(array $attributes, string $class = '', string $method = ''): array|object|null
|
||||
{
|
||||
if (!$class || !$method) {
|
||||
$caller = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1];
|
||||
$class = $caller['class'];
|
||||
$method = $caller['function'];
|
||||
}
|
||||
$array = array_shift($attributes);
|
||||
if (!is_array($array) && !is_object($array)) {
|
||||
return null;
|
||||
}
|
||||
if (empty($array)) {
|
||||
return $array;
|
||||
}
|
||||
$json = json_encode($array);
|
||||
foreach ($array as $key => $value) {
|
||||
$value_attributes = [$key, ...$attributes];
|
||||
$json = str_replace('"' . $key . '":', '"' . $class::$method(...$value_attributes) . '":', $json);
|
||||
}
|
||||
return json_decode($json, \true);
|
||||
}
|
||||
/**
|
||||
* Run a method over all values inside the array or object
|
||||
*/
|
||||
public static function applyMethodToValues(array $attributes, string $class = '', string $method = '', int $array_number_in_attributes = 0): array|object|null
|
||||
{
|
||||
if (!$class || !$method) {
|
||||
$caller = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1];
|
||||
$class = $caller['class'];
|
||||
$method = $caller['function'];
|
||||
}
|
||||
$array = $attributes[$array_number_in_attributes];
|
||||
if (!is_array($array) && !is_object($array)) {
|
||||
return null;
|
||||
}
|
||||
$as_object = is_object($array);
|
||||
foreach ($array as &$value) {
|
||||
if (!is_string($value) && !is_null($value)) {
|
||||
continue;
|
||||
}
|
||||
$value_attributes = array_values($attributes);
|
||||
$value_attributes[$array_number_in_attributes] = $value;
|
||||
$value = $class::$method(...$value_attributes);
|
||||
}
|
||||
return $as_object ? (object) $array : $array;
|
||||
}
|
||||
/**
|
||||
* Change the case of array keys
|
||||
*/
|
||||
public static function changeKeyCase(array|object|null $array, string $format, bool $to_lowercase = \true): array|object
|
||||
{
|
||||
if (is_null($array)) {
|
||||
return [];
|
||||
}
|
||||
return self::applyMethodToKeys([$array, $format, $to_lowercase], '\RegularLabs\Library\StringHelper', 'toCase');
|
||||
}
|
||||
/**
|
||||
* Clean array by trimming values and removing empty/false values
|
||||
*/
|
||||
public static function clean(?array $array): array
|
||||
{
|
||||
if (!is_array($array)) {
|
||||
return $array;
|
||||
}
|
||||
$array = self::trim($array);
|
||||
$array = self::unique($array);
|
||||
$array = self::removeEmpty($array);
|
||||
return $array;
|
||||
}
|
||||
/**
|
||||
* Create a tree from a flat array based on the parent_id value
|
||||
*/
|
||||
public static function createTreeArray(array $array, int $level = 0, int|string $parent = 0, string $id_name = 'id', string $parent_id_name = 'parent_id'): array
|
||||
{
|
||||
if (empty($array)) {
|
||||
return $array;
|
||||
}
|
||||
$tree = [];
|
||||
foreach ($array as $item) {
|
||||
$id = $item->{$id_name} ?? 0;
|
||||
$parent_id = $item->{$parent_id_name} ?? '';
|
||||
if ($parent_id !== $parent) {
|
||||
continue;
|
||||
}
|
||||
$item->level = $level;
|
||||
$tree[$id] = $item;
|
||||
$children = self::createTreeArray($array, $level + 1, $id, $id_name, $parent_id_name);
|
||||
if (empty($children)) {
|
||||
continue;
|
||||
}
|
||||
$tree[$id]->children = $children;
|
||||
}
|
||||
return $tree;
|
||||
}
|
||||
/**
|
||||
* Check if any of the given values is found in the array
|
||||
*/
|
||||
public static function find(array|string|null $needles, array|null $haystack, bool $strict = \true): bool
|
||||
{
|
||||
if (!is_array($haystack) || empty($haystack)) {
|
||||
return \false;
|
||||
}
|
||||
$needles = self::toArray($needles);
|
||||
foreach ($needles as $value) {
|
||||
if (in_array($value, $haystack, $strict)) {
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Flatten an array of nested arrays, keeping the order
|
||||
*/
|
||||
public static function flatten(array $array): array
|
||||
{
|
||||
$flattened = [];
|
||||
foreach ($array as $nested) {
|
||||
if (!is_array($nested)) {
|
||||
$flattened[] = $nested;
|
||||
continue;
|
||||
}
|
||||
$flattened = [...$flattened, ...self::flatten($nested)];
|
||||
}
|
||||
return $flattened;
|
||||
}
|
||||
/**
|
||||
* Flatten a tree array into a single dimension array
|
||||
*/
|
||||
public static function flattenTreeArray(array $array, string $children_name = 'children'): array
|
||||
{
|
||||
$flat = [];
|
||||
foreach ($array as $key => $item) {
|
||||
$flat[$key] = $item;
|
||||
if (!isset($item->{$children_name})) {
|
||||
continue;
|
||||
}
|
||||
$children = $item->{$children_name};
|
||||
unset($flat[$key]->{$children_name});
|
||||
$flat = [...$flat, ...self::flattenTreeArray($children, $children_name)];
|
||||
}
|
||||
foreach ($flat as $key => $item) {
|
||||
$check = (array) $item;
|
||||
unset($check['level']);
|
||||
if (empty($check)) {
|
||||
unset($flat[$key]);
|
||||
}
|
||||
}
|
||||
return $flat;
|
||||
}
|
||||
/**
|
||||
* Join array elements with a string
|
||||
*/
|
||||
public static function implode(array|object|string|null $pieces, string $glue = '', string $last_glue = null): string
|
||||
{
|
||||
if (!is_array($pieces)) {
|
||||
$pieces = self::toArray($pieces, $glue);
|
||||
}
|
||||
if (is_null($last_glue) || $last_glue == $glue || count($pieces) < 2) {
|
||||
return implode($glue ?? '', $pieces);
|
||||
}
|
||||
$last_item = array_pop($pieces);
|
||||
return implode($glue ?? '', $pieces) . $last_glue . $last_item;
|
||||
}
|
||||
/**
|
||||
* Removes empty values from the array
|
||||
*/
|
||||
public static function removeEmpty(array $array): array
|
||||
{
|
||||
if (!is_array($array)) {
|
||||
return $array;
|
||||
}
|
||||
foreach ($array as $key => &$value) {
|
||||
if ($key && !is_numeric($key)) {
|
||||
continue;
|
||||
}
|
||||
if ($value !== '') {
|
||||
continue;
|
||||
}
|
||||
unset($array[$key]);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
/**
|
||||
* Removes the trailing part of all keys in an array
|
||||
*/
|
||||
public static function removePostfixFromKeys(array $array, string $postfix): array
|
||||
{
|
||||
$pefixed = [];
|
||||
foreach ($array as $key => $value) {
|
||||
$pefixed[\RegularLabs\Library\StringHelper::removePostfix($key, $postfix)] = $value;
|
||||
}
|
||||
return $pefixed;
|
||||
}
|
||||
/**
|
||||
* Removes the trailing part of all string values in an array
|
||||
*/
|
||||
public static function removePostfixFromValues(array $array, string $postfix): array
|
||||
{
|
||||
foreach ($array as &$value) {
|
||||
$value = \RegularLabs\Library\StringHelper::removePostfix($value, $postfix);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
/**
|
||||
* Removes the first part of all keys in an array
|
||||
*/
|
||||
public static function removePrefixFromKeys(array $array, string $prefix): array
|
||||
{
|
||||
$pefixed = [];
|
||||
foreach ($array as $key => $value) {
|
||||
$pefixed[\RegularLabs\Library\StringHelper::removePrefix($key, $prefix)] = $value;
|
||||
}
|
||||
return $pefixed;
|
||||
}
|
||||
/**
|
||||
* Removes the first part of all string values in an array
|
||||
*/
|
||||
public static function removePrefixFromValues(array $array, string $prefix, bool $keep_leading_slash = \true): array
|
||||
{
|
||||
foreach ($array as &$value) {
|
||||
$value = \RegularLabs\Library\StringHelper::removePrefix($value, $prefix, $keep_leading_slash);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
/**
|
||||
* Set the level on each object based on the parent_id value
|
||||
*/
|
||||
public static function setLevelsByParentIds(array $array, int $starting_level = 0, int $parent = 0, string $id_name = 'id', string $parent_id_name = 'parent_id'): array
|
||||
{
|
||||
if (empty($array)) {
|
||||
return $array;
|
||||
}
|
||||
$tree = self::createTreeArray($array, $starting_level, $parent, $id_name, $parent_id_name);
|
||||
return self::flattenTreeArray($tree);
|
||||
}
|
||||
/**
|
||||
* Sorts the array by keys based on the values of another array
|
||||
*/
|
||||
public static function sortByOtherArray(array $array, array $order): array
|
||||
{
|
||||
if (empty($order)) {
|
||||
return $array;
|
||||
}
|
||||
uksort($array, function ($key1, $key2) use ($order) {
|
||||
return array_search($key1, $order) > array_search($key2, $order);
|
||||
});
|
||||
return $array;
|
||||
}
|
||||
/**
|
||||
* Convert data (string or object) to an array
|
||||
*/
|
||||
public static function toArray(mixed $data, string $separator = ',', bool $unique = \false, bool $trim = \true): array
|
||||
{
|
||||
if (is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
if (is_object($data)) {
|
||||
return (array) $data;
|
||||
}
|
||||
if ($data === '' || is_null($data)) {
|
||||
return [];
|
||||
}
|
||||
if ($separator === '') {
|
||||
return [$data];
|
||||
}
|
||||
// explode on separator, but keep escaped separators
|
||||
$splitter = uniqid('RL_SPLIT');
|
||||
$data = str_replace($separator, $splitter, $data);
|
||||
$data = str_replace('\\' . $splitter, $separator, $data);
|
||||
$array = explode($splitter, $data);
|
||||
if ($trim) {
|
||||
$array = self::trim($array);
|
||||
}
|
||||
if ($unique) {
|
||||
$array = array_unique($array);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
/**
|
||||
* Convert an associative array or object to a html style attribute list
|
||||
*/
|
||||
public static function toAttributeString(array $array, string $key_prefix = ''): string
|
||||
{
|
||||
$array = self::toArray($array);
|
||||
return implode(' ', array_map(fn($key, $value) => $key_prefix . $key . '="' . htmlspecialchars($value) . '"', array_keys($array), $array));
|
||||
}
|
||||
/**
|
||||
* Clean array by trimming values
|
||||
*/
|
||||
public static function trim(array $array): array
|
||||
{
|
||||
if (!is_array($array)) {
|
||||
return $array;
|
||||
}
|
||||
foreach ($array as &$value) {
|
||||
if (!is_string($value)) {
|
||||
continue;
|
||||
}
|
||||
$value = trim($value);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
/**
|
||||
* Removes duplicate values from the array
|
||||
*/
|
||||
public static function unique(?array $array): array
|
||||
{
|
||||
if (!is_array($array)) {
|
||||
return $array;
|
||||
}
|
||||
$values = [];
|
||||
foreach ($array as $key => $value) {
|
||||
if (!is_numeric($key)) {
|
||||
continue;
|
||||
}
|
||||
if (!in_array($value, $values, \true)) {
|
||||
$values[] = $value;
|
||||
continue;
|
||||
}
|
||||
unset($array[$key]);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
212
libraries/regularlabs/src/Article.php
Normal file
212
libraries/regularlabs/src/Article.php
Normal file
@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
use Joomla\Registry\Registry as JRegistry;
|
||||
class Article
|
||||
{
|
||||
static $articles = [];
|
||||
/**
|
||||
* Method to get article data.
|
||||
*/
|
||||
public static function get(int|string|null $id = null, bool $get_unpublished = \false, array $selects = []): object|null
|
||||
{
|
||||
$id = $id ?? null ?: (int) self::getId();
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
$db = \RegularLabs\Library\DB::get();
|
||||
$user = JFactory::getApplication()->getIdentity() ?: JFactory::getUser();
|
||||
$custom_selects = !empty($selects);
|
||||
$query = \RegularLabs\Library\DB::getQuery()->select($custom_selects ? $selects : [
|
||||
'a.id',
|
||||
'a.asset_id',
|
||||
'a.title',
|
||||
'a.alias',
|
||||
'a.introtext',
|
||||
'a.fulltext',
|
||||
'a.state',
|
||||
'a.catid',
|
||||
'a.created',
|
||||
'a.created_by',
|
||||
'a.created_by_alias',
|
||||
// Use created if modified is 0
|
||||
'CASE WHEN a.modified = ' . \RegularLabs\Library\DB::quote($db->getNullDate()) . ' THEN a.created ELSE a.modified END as modified',
|
||||
'a.modified_by',
|
||||
'a.checked_out',
|
||||
'a.checked_out_time',
|
||||
'a.publish_up',
|
||||
'a.publish_down',
|
||||
'a.images',
|
||||
'a.urls',
|
||||
'a.attribs',
|
||||
'a.version',
|
||||
'a.ordering',
|
||||
'a.metakey',
|
||||
'a.metadesc',
|
||||
'a.access',
|
||||
'a.hits',
|
||||
'a.metadata',
|
||||
'a.featured',
|
||||
'a.language',
|
||||
])->from(\RegularLabs\Library\DB::quoteName('#__content', 'a'));
|
||||
if (!is_numeric($id)) {
|
||||
$query->where('(' . \RegularLabs\Library\DB::is('a.title', $id) . ' OR ' . \RegularLabs\Library\DB::is('a.alias', $id) . ')');
|
||||
} else {
|
||||
$query->where(\RegularLabs\Library\DB::is('a.id', (int) $id));
|
||||
}
|
||||
// Join on category table.
|
||||
if (!$custom_selects) {
|
||||
$query->select([\RegularLabs\Library\DB::quoteName('c.title', 'category_title'), \RegularLabs\Library\DB::quoteName('c.alias', 'category_alias'), \RegularLabs\Library\DB::quoteName('c.access', 'category_access'), \RegularLabs\Library\DB::quoteName('c.lft', 'category_lft'), \RegularLabs\Library\DB::quoteName('c.lft', 'category_ordering')]);
|
||||
}
|
||||
$query->innerJoin(\RegularLabs\Library\DB::quoteName('#__categories', 'c') . ' ON ' . \RegularLabs\Library\DB::quoteName('c.id') . ' = ' . \RegularLabs\Library\DB::quoteName('a.catid'))->where(\RegularLabs\Library\DB::is('c.published', '>0'));
|
||||
// Join on user table.
|
||||
if (!$custom_selects) {
|
||||
$query->select(\RegularLabs\Library\DB::quoteName('u.name', 'author'));
|
||||
}
|
||||
$query->join('LEFT', \RegularLabs\Library\DB::quoteName('#__users', 'u') . ' ON ' . \RegularLabs\Library\DB::quoteName('u.id') . ' = ' . \RegularLabs\Library\DB::quoteName('a.created_by'));
|
||||
// Join over the categories to get parent category titles
|
||||
if (!$custom_selects) {
|
||||
$query->select([\RegularLabs\Library\DB::quoteName('parent.title', 'parent_title'), \RegularLabs\Library\DB::quoteName('parent.id', 'parent_id'), \RegularLabs\Library\DB::quoteName('parent.path', 'parent_route'), \RegularLabs\Library\DB::quoteName('parent.alias', 'parent_alias')]);
|
||||
}
|
||||
$query->join('LEFT', \RegularLabs\Library\DB::quoteName('#__categories', 'parent') . ' ON ' . \RegularLabs\Library\DB::quoteName('parent.id') . ' = ' . \RegularLabs\Library\DB::quoteName('c.parent_id'));
|
||||
// Join on voting table
|
||||
if (!$custom_selects) {
|
||||
$query->select(['ROUND(v.rating_sum / v.rating_count, 0) AS rating', \RegularLabs\Library\DB::quoteName('v.rating_count', 'rating_count')]);
|
||||
}
|
||||
$query->join('LEFT', \RegularLabs\Library\DB::quoteName('#__content_rating', 'v') . ' ON ' . \RegularLabs\Library\DB::quoteName('v.content_id') . ' = ' . \RegularLabs\Library\DB::quoteName('a.id'));
|
||||
if (!$get_unpublished && !$user->authorise('core.edit.state', 'com_content') && !$user->authorise('core.edit', 'com_content')) {
|
||||
\RegularLabs\Library\DB::addArticleIsPublishedFilters($query);
|
||||
}
|
||||
$db->setQuery($query);
|
||||
$data = $db->loadObject();
|
||||
if (empty($data)) {
|
||||
return null;
|
||||
}
|
||||
if (isset($data->attribs)) {
|
||||
// Convert parameter field to object.
|
||||
$data->params = new JRegistry($data->attribs);
|
||||
}
|
||||
if (isset($data->metadata)) {
|
||||
// Convert metadata field to object.
|
||||
$data->metadata = new JRegistry($data->metadata);
|
||||
}
|
||||
return $cache->set($data);
|
||||
}
|
||||
/**
|
||||
* Gets the current article id based on url data
|
||||
*/
|
||||
public static function getId(): int|false
|
||||
{
|
||||
$id = \RegularLabs\Library\Input::getInt('id');
|
||||
if (!$id || !(\RegularLabs\Library\Input::get('option', '') == 'com_content' && \RegularLabs\Library\Input::get('view', '') == 'article' || \RegularLabs\Library\Input::get('option', '') == 'com_flexicontent' && \RegularLabs\Library\Input::get('view', '') == 'item')) {
|
||||
return \false;
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
public static function getPageNumber(array|string &$all_pages, string $search_string): int
|
||||
{
|
||||
if (is_string($all_pages)) {
|
||||
$all_pages = self::getPages($all_pages);
|
||||
}
|
||||
if (count($all_pages) < 2) {
|
||||
return 0;
|
||||
}
|
||||
foreach ($all_pages as $i => $page_text) {
|
||||
if ($i % 2) {
|
||||
continue;
|
||||
}
|
||||
if (!str_contains($page_text, $search_string)) {
|
||||
continue;
|
||||
}
|
||||
$all_pages[$i] = \RegularLabs\Library\StringHelper::replaceOnce($search_string, '---', $page_text);
|
||||
return $i / 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
public static function getPages(string $string): array
|
||||
{
|
||||
if (empty($string)) {
|
||||
return [''];
|
||||
}
|
||||
return preg_split('#(<hr class="system-pagebreak" .*?>)#s', $string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
/**
|
||||
* Passes the different article parts through the given plugin method
|
||||
*/
|
||||
public static function process(?object &$article, string $context, object &$class, string $method, array $params = [], array $ignore_types = []): void
|
||||
{
|
||||
self::processText('title', $article, $class, $method, $params, $ignore_types);
|
||||
self::processText('created_by_alias', $article, $class, $method, $params, $ignore_types);
|
||||
$has_text = isset($article->text);
|
||||
$has_description = isset($article->description);
|
||||
$has_article_texts = isset($article->introtext) && isset($article->fulltext);
|
||||
$text_same_as_description = $has_text && $has_description && $article->text == $article->description;
|
||||
$text_same_as_article_text = \false;
|
||||
self::processText('description', $article, $class, $method, $params, $ignore_types);
|
||||
// This is a category page with a category description. So skip the text processing
|
||||
if ($text_same_as_description) {
|
||||
$article->text = $article->description;
|
||||
return;
|
||||
}
|
||||
// Don't replace in text fields in the category list view, as they won't get used anyway
|
||||
if (\RegularLabs\Library\Document::isCategoryList($context)) {
|
||||
return;
|
||||
}
|
||||
// prevent fulltext from being messed with, when it is a json encoded string (Yootheme Pro templates do this for some weird f-ing reason)
|
||||
if (!empty($article->fulltext) && str_starts_with($article->fulltext, '<!-- {')) {
|
||||
self::processText('text', $article, $class, $method, $params, $ignore_types);
|
||||
return;
|
||||
}
|
||||
if ($has_text && $has_article_texts) {
|
||||
$check_text = \RegularLabs\Library\RegEx::replace('\s', '', $article->text);
|
||||
$check_introtext_fulltext = \RegularLabs\Library\RegEx::replace('\s', '', $article->introtext . ' ' . $article->fulltext);
|
||||
$text_same_as_article_text = $check_text == $check_introtext_fulltext;
|
||||
}
|
||||
if ($has_article_texts && !$has_text) {
|
||||
self::processText('introtext', $article, $class, $method, $params, $ignore_types);
|
||||
self::processText('fulltext', $article, $class, $method, $params, $ignore_types);
|
||||
return;
|
||||
}
|
||||
if ($has_article_texts && $text_same_as_article_text) {
|
||||
$splitter = '͞';
|
||||
if (str_contains($article->introtext, $splitter) || str_contains($article->fulltext, $splitter)) {
|
||||
$splitter = 'Ͽ';
|
||||
}
|
||||
$article->text = $article->introtext . $splitter . $article->fulltext;
|
||||
self::processText('text', $article, $class, $method, $params, $ignore_types);
|
||||
[$article->introtext, $article->fulltext] = explode($splitter, $article->text, 2);
|
||||
$article->text = str_replace($splitter, ' ', $article->text);
|
||||
return;
|
||||
}
|
||||
self::processText('text', $article, $class, $method, $params, $ignore_types);
|
||||
self::processText('introtext', $article, $class, $method, $params, $ignore_types);
|
||||
// Don't handle fulltext on category blog views
|
||||
if ($context == 'com_content.category' && \RegularLabs\Library\Input::get('view', '') == 'category') {
|
||||
return;
|
||||
}
|
||||
self::processText('fulltext', $article, $class, $method, $params, $ignore_types);
|
||||
}
|
||||
public static function processText(string $type, ?object &$article, object &$class, string $method, array $params = [], array $ignore_types = []): void
|
||||
{
|
||||
if (empty($article->{$type})) {
|
||||
return;
|
||||
}
|
||||
if (in_array($type, $ignore_types, \true)) {
|
||||
return;
|
||||
}
|
||||
call_user_func_array([$class, $method], [&$article->{$type}, ...$params]);
|
||||
}
|
||||
}
|
||||
144
libraries/regularlabs/src/Cache.php
Normal file
144
libraries/regularlabs/src/Cache.php
Normal file
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Exception;
|
||||
use Joomla\CMS\Cache\CacheControllerFactoryInterface as JCacheControllerFactoryInterface;
|
||||
use Joomla\CMS\Cache\Controller\OutputController as JOutputController;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
class Cache
|
||||
{
|
||||
static array $cache = [];
|
||||
/**
|
||||
* @var [JOutputController]
|
||||
*/
|
||||
private array $file_cache_controllers = [];
|
||||
private bool $force_caching = \true;
|
||||
private string $group;
|
||||
private string $id;
|
||||
private int $time_to_life_in_seconds = 0;
|
||||
private bool $use_files = \false;
|
||||
public function __construct(mixed $id = null, string $group = 'regularlabs', int $class_offset = 1)
|
||||
{
|
||||
if (is_null($id)) {
|
||||
$caller = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 1 + $class_offset)[$class_offset];
|
||||
$id = [$caller['class'], $caller['function'], $caller['args']];
|
||||
}
|
||||
if (!is_string($id)) {
|
||||
$id = json_encode($id);
|
||||
}
|
||||
$this->id = md5($id);
|
||||
$this->group = $group;
|
||||
}
|
||||
public function exists(): bool
|
||||
{
|
||||
if (!$this->use_files) {
|
||||
return $this->existsMemory();
|
||||
}
|
||||
return $this->existsMemory() || $this->existsFile();
|
||||
}
|
||||
public function get(): mixed
|
||||
{
|
||||
return $this->use_files ? $this->getFile() : $this->getMemory();
|
||||
}
|
||||
public function reset(): void
|
||||
{
|
||||
unset(static::$cache[$this->id]);
|
||||
if ($this->use_files) {
|
||||
$this->getFileCache()->remove($this->id);
|
||||
}
|
||||
}
|
||||
public function resetAll(): void
|
||||
{
|
||||
static::$cache = [];
|
||||
if ($this->use_files) {
|
||||
$this->getFileCache()->clean($this->group);
|
||||
}
|
||||
}
|
||||
public function set(mixed $data): mixed
|
||||
{
|
||||
return $this->use_files ? $this->setFile($data) : $this->setMemory($data);
|
||||
}
|
||||
public function useFiles(int $time_to_life_in_minutes = 0, bool $force_caching = \true): self
|
||||
{
|
||||
$this->use_files = \true;
|
||||
// convert ttl to minutes
|
||||
$this->time_to_life_in_seconds = $time_to_life_in_minutes * 60;
|
||||
$this->force_caching = $force_caching;
|
||||
return $this;
|
||||
}
|
||||
private function existsFile(): bool
|
||||
{
|
||||
if (\RegularLabs\Library\Document::isDebug()) {
|
||||
return \false;
|
||||
}
|
||||
return $this->getFileCache()->contains($this->id);
|
||||
}
|
||||
private function existsMemory(): bool
|
||||
{
|
||||
return isset(static::$cache[$this->id]);
|
||||
}
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getFile(): mixed
|
||||
{
|
||||
if ($this->existsMemory()) {
|
||||
return $this->getMemory();
|
||||
}
|
||||
$data = $this->getFileCache()->get($this->id);
|
||||
$this->setMemory($data);
|
||||
return $data;
|
||||
}
|
||||
private function getFileCache(): JOutputController
|
||||
{
|
||||
$options = ['defaultgroup' => $this->group];
|
||||
if ($this->time_to_life_in_seconds) {
|
||||
$options['lifetime'] = $this->time_to_life_in_seconds;
|
||||
}
|
||||
if ($this->force_caching) {
|
||||
$options['caching'] = \true;
|
||||
}
|
||||
$id = json_encode($options);
|
||||
if (isset($this->file_cache_controllers[$id])) {
|
||||
return $this->file_cache_controllers[$id];
|
||||
}
|
||||
$this->file_cache_controllers[$id] = JFactory::getContainer()->get(JCacheControllerFactoryInterface::class)->createCacheController('output', $options);
|
||||
return $this->file_cache_controllers[$id];
|
||||
}
|
||||
private function getMemory(): mixed
|
||||
{
|
||||
if (!$this->existsMemory()) {
|
||||
return null;
|
||||
}
|
||||
$data = static::$cache[$this->id];
|
||||
return is_object($data) ? clone $data : $data;
|
||||
}
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
private function setFile(mixed $data): mixed
|
||||
{
|
||||
$this->setMemory($data);
|
||||
if (\RegularLabs\Library\Document::isDebug()) {
|
||||
return $data;
|
||||
}
|
||||
$this->getFileCache()->store($data, $this->id);
|
||||
return $data;
|
||||
}
|
||||
private function setMemory(mixed $data): mixed
|
||||
{
|
||||
static::$cache[$this->id] = $data;
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
43
libraries/regularlabs/src/Color.php
Normal file
43
libraries/regularlabs/src/Color.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
class Color
|
||||
{
|
||||
public static function save(string $table, int|string $item_id, ?string $color = null, string $id_column = 'id'): bool
|
||||
{
|
||||
if (empty($color)) {
|
||||
return \true;
|
||||
}
|
||||
if (in_array($color, ['none', 'transparent'])) {
|
||||
$color = '';
|
||||
}
|
||||
$db = \RegularLabs\Library\DB::get();
|
||||
$query = $db->getQuery(\true)->select(\RegularLabs\Library\DB::quoteName($id_column))->from(\RegularLabs\Library\DB::quoteName('#__' . $table))->where(\RegularLabs\Library\DB::quoteName($id_column) . ' = ' . $item_id);
|
||||
$item_exists = $db->setQuery($query)->loadResult();
|
||||
if ($item_exists) {
|
||||
$query = $db->getQuery(\true)->update(\RegularLabs\Library\DB::quoteName('#__' . $table))->set(\RegularLabs\Library\DB::quoteName('color') . ' = ' . \RegularLabs\Library\DB::quote($color))->where(\RegularLabs\Library\DB::quoteName($id_column) . ' = ' . $item_id);
|
||||
$db->setQuery($query)->execute();
|
||||
return \true;
|
||||
}
|
||||
$query = 'SHOW COLUMNS FROM `#__' . $table . '`';
|
||||
$db->setQuery($query);
|
||||
$columns = $db->loadColumn();
|
||||
$values = array_fill_keys($columns, '');
|
||||
$values[$id_column] = $item_id;
|
||||
$values['color'] = $color;
|
||||
$query = $db->getQuery(\true)->insert(\RegularLabs\Library\DB::quoteName('#__' . $table))->columns(\RegularLabs\Library\DB::quoteName($columns))->values(implode(',', \RegularLabs\Library\DB::quote($values)));
|
||||
$db->setQuery($query)->execute();
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
386
libraries/regularlabs/src/DB.php
Normal file
386
libraries/regularlabs/src/DB.php
Normal file
@ -0,0 +1,386 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
use Joomla\CMS\Uri\Uri as JUri;
|
||||
use Joomla\Database\DatabaseDriver as JDatabaseDriver;
|
||||
use Joomla\Database\DatabaseQuery as JDatabaseQuery;
|
||||
use Joomla\Database\QueryInterface as JQueryInterface;
|
||||
class DB
|
||||
{
|
||||
static $tables = [];
|
||||
public static function addArticleIsPublishedFilters(JQueryInterface &$query, string $prefix = 'a'): void
|
||||
{
|
||||
$filters = self::getArticleIsPublishedFilters($prefix);
|
||||
$query->where($filters);
|
||||
}
|
||||
public static function combine(array $conditions = [], string $glue = 'OR'): string
|
||||
{
|
||||
if (empty($conditions)) {
|
||||
return '';
|
||||
}
|
||||
if (!is_array($conditions)) {
|
||||
return (string) $conditions;
|
||||
}
|
||||
if (count($conditions) < 2) {
|
||||
return reset($conditions);
|
||||
}
|
||||
$glue = strtoupper($glue) == 'AND' ? 'AND' : 'OR';
|
||||
return '(' . implode(' ' . $glue . ' ', $conditions) . ')';
|
||||
}
|
||||
/**
|
||||
* Creat a query dump string
|
||||
*/
|
||||
public static function dump(string|JQueryInterface $query, string $class_prefix = '', int $caller_offset = 0): void
|
||||
{
|
||||
$string = "\n" . (string) $query;
|
||||
$string = str_replace('#__', JFactory::getDbo()->getPrefix(), $string);
|
||||
$bounded = $query->getBounded();
|
||||
foreach ($bounded as $key => $obj) {
|
||||
$string = str_replace($key, self::quote($obj->value, \false), $string);
|
||||
}
|
||||
\RegularLabs\Library\Protect::protectByRegex($string, ' IN \(.*?\)');
|
||||
\RegularLabs\Library\Protect::protectByRegex($string, ' FIELD\(.*?\)');
|
||||
$string = preg_replace('#(\n[A-Z][A-Z ]+) #', "\n\\1\n ", $string);
|
||||
$string = str_replace(' LIMIT ', "\n\nLIMIT ", $string);
|
||||
$string = str_replace(' ON ', "\n ON ", $string);
|
||||
$string = str_replace(' OR ', "\n OR ", $string);
|
||||
$string = str_replace(' AND ', "\n AND ", $string);
|
||||
$string = str_replace('`,', "`,\n ", $string);
|
||||
\RegularLabs\Library\Protect::unprotect($string);
|
||||
echo "\n<pre>==============================================================================\n";
|
||||
echo self::getQueryComment($class_prefix, $caller_offset) . "\n";
|
||||
echo "-----------------------------------------------------------------------------------\n";
|
||||
echo trim($string);
|
||||
echo "\n===================================================================================</pre>\n";
|
||||
}
|
||||
public static function escape(string $text, bool $extra = \false): string
|
||||
{
|
||||
return JFactory::getDbo()->escape($text, $extra);
|
||||
}
|
||||
public static function get(): JDatabaseDriver
|
||||
{
|
||||
return JFactory::getDbo();
|
||||
}
|
||||
public static function getArticleIsPublishedFilters(string $prefix = 'a'): string
|
||||
{
|
||||
$nowDate = self::getNowDate();
|
||||
$nullDate = self::getNullDate();
|
||||
$wheres = [];
|
||||
$wheres[] = self::is($prefix . '.state', 1);
|
||||
$wheres[] = self::combine([self::is($prefix . '.publish_up', 'NULL'), self::is($prefix . '.publish_up', '<=' . $nowDate)], 'OR');
|
||||
$wheres[] = self::combine([self::is($prefix . '.publish_down', 'NULL'), self::is($prefix . '.publish_down', $nullDate), self::is($prefix . '.publish_down', '>' . $nowDate)], 'OR');
|
||||
return self::combine($wheres, 'AND');
|
||||
}
|
||||
public static function getIncludesExcludes(array|string $values, bool $remove_exclude_operators = \true): array
|
||||
{
|
||||
$includes = [];
|
||||
$excludes = [];
|
||||
$values = \RegularLabs\Library\ArrayHelper::toArray($values);
|
||||
if (empty($values)) {
|
||||
return [$includes, $excludes];
|
||||
}
|
||||
foreach ($values as $value) {
|
||||
if ($value == '') {
|
||||
$value = '!*';
|
||||
}
|
||||
if ($value == '!') {
|
||||
$value = '+';
|
||||
}
|
||||
if (self::isExclude($value)) {
|
||||
$excludes[] = $remove_exclude_operators ? self::removeOperator($value) : $value;
|
||||
continue;
|
||||
}
|
||||
$includes[] = $value;
|
||||
}
|
||||
return [$includes, $excludes];
|
||||
}
|
||||
public static function getNowDate(): string
|
||||
{
|
||||
return JFactory::getDate()->toSql();
|
||||
}
|
||||
public static function getNullDate(): string
|
||||
{
|
||||
return JFactory::getDbo()->getNullDate();
|
||||
}
|
||||
public static function getOperator(array|string|null $value, string $default = '='): string
|
||||
{
|
||||
if (empty($value)) {
|
||||
return $default;
|
||||
}
|
||||
if (is_array($value)) {
|
||||
$value = array_values($value);
|
||||
return self::getOperator(reset($value), $default);
|
||||
}
|
||||
$regex = '^' . \RegularLabs\Library\RegEx::quote(self::getOperators(), 'operator');
|
||||
if (!\RegularLabs\Library\RegEx::match($regex, $value, $parts)) {
|
||||
return $default;
|
||||
}
|
||||
$operator = $parts['operator'];
|
||||
return match ($operator) {
|
||||
'!', '<>', '!NOT!' => '!=',
|
||||
'==' => '=',
|
||||
default => $operator,
|
||||
};
|
||||
}
|
||||
public static function getOperators(): array
|
||||
{
|
||||
return ['!NOT!', '!=', '!', '<>', '<=', '<', '>=', '>', '=', '=='];
|
||||
}
|
||||
public static function getQuery(): JDatabaseQuery
|
||||
{
|
||||
return JFactory::getDbo()->getQuery(\true);
|
||||
}
|
||||
public static function getQueryComment(string $class_prefix = '', int $caller_offset = 0): string
|
||||
{
|
||||
$callers = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, $caller_offset + 5);
|
||||
for ($i = 1; $i <= $caller_offset + 2; $i++) {
|
||||
array_shift($callers);
|
||||
}
|
||||
$callers = array_reverse($callers);
|
||||
$lines = [JUri::getInstance()->toString()];
|
||||
foreach ($callers as $caller) {
|
||||
$lines[] = '[' . str_pad($caller['line'] ?? '', 3, ' ', \STR_PAD_LEFT) . '] ' . str_replace('\\', '.', trim(substr($caller['class'] ?? '', strlen($class_prefix)), '\\')) . '.' . $caller['function'];
|
||||
}
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
public static function getTableColumns(string $table, bool $typeOnly = \true): array
|
||||
{
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
return $cache->set(JFactory::getDbo()->getTableColumns($table, $typeOnly));
|
||||
}
|
||||
public static function in(array|string $keys, array|string $values, array|object $options = [], bool $quote_key = \true): string
|
||||
{
|
||||
$options = (object) \RegularLabs\Library\ArrayHelper::toArray($options);
|
||||
$glue = $options->glue ?? 'OR';
|
||||
if (is_array($keys)) {
|
||||
$wheres = [];
|
||||
foreach ($keys as $single_key) {
|
||||
$wheres[] = self::in($single_key, $values, $options, $quote_key);
|
||||
}
|
||||
return self::combine($wheres, $glue);
|
||||
}
|
||||
if (empty($values)) {
|
||||
$values = [''];
|
||||
}
|
||||
$operator = self::getOperator($values);
|
||||
$db_key = $keys;
|
||||
if ($quote_key && !str_starts_with($db_key, '`')) {
|
||||
$db_key = self::quoteName($db_key);
|
||||
}
|
||||
if (!is_array($values) || count($values) == 1) {
|
||||
$values = self::removeOperator($values);
|
||||
$value = is_array($values) ? reset($values) : $values;
|
||||
$value = self::prepareValue($value, $options);
|
||||
if ($value === 'NULL') {
|
||||
$operator = $operator == '!=' ? 'IS NOT' : 'IS';
|
||||
}
|
||||
return $db_key . ' ' . $operator . ' ' . $value;
|
||||
}
|
||||
$values = \RegularLabs\Library\ArrayHelper::clean($values);
|
||||
$operator = $operator == '!=' ? 'NOT IN' : 'IN';
|
||||
if ($glue == 'OR') {
|
||||
$values = self::removeOperator($values);
|
||||
$values = self::prepareValue($values, $options);
|
||||
return $db_key . ' ' . $operator . ' (' . implode(',', $values) . ')';
|
||||
}
|
||||
$wheres = [];
|
||||
foreach ($values as $value) {
|
||||
$wheres[] = self::in($keys, $value, $options, $quote_key);
|
||||
}
|
||||
return self::combine($wheres, $glue);
|
||||
}
|
||||
public static function is(array|string $keys, array|string $values, array|object $options = [], bool $quote_key = \true): string
|
||||
{
|
||||
$options = (object) \RegularLabs\Library\ArrayHelper::toArray($options);
|
||||
$glue = $options->glue ?? 'OR';
|
||||
$handle_wildcards = $options->handle_wildcards ?? \true;
|
||||
if (is_array($keys) && $glue == 'OR') {
|
||||
$wheres = [];
|
||||
foreach ($keys as $single_key) {
|
||||
$wheres[] = self::is($single_key, $values, $options, $quote_key);
|
||||
}
|
||||
return self::combine($wheres, $glue);
|
||||
}
|
||||
if (is_array($keys) && $glue == 'AND') {
|
||||
$options->glue = 'OR';
|
||||
$wheres = [];
|
||||
foreach ($values as $single_values) {
|
||||
$wheres[] = self::is($keys, $single_values, $options, $quote_key);
|
||||
}
|
||||
return self::combine($wheres, $glue);
|
||||
}
|
||||
if (!is_array($values) && $handle_wildcards && str_contains($values, '*')) {
|
||||
return self::like($keys, $values, $options, $quote_key);
|
||||
}
|
||||
if (!is_array($values)) {
|
||||
return self::in($keys, $values, $options, $quote_key);
|
||||
}
|
||||
$includes = [];
|
||||
$excludes = [];
|
||||
$wheres = [];
|
||||
foreach ($values as $value) {
|
||||
if ($handle_wildcards && str_contains($value, '*')) {
|
||||
$wheres[] = self::is($keys, $value, $options, $quote_key);
|
||||
continue;
|
||||
}
|
||||
if (self::isExclude($value)) {
|
||||
$excludes[] = $value;
|
||||
continue;
|
||||
}
|
||||
$includes[] = $value;
|
||||
}
|
||||
if (!empty($includes)) {
|
||||
$wheres[] = self::in($keys, $includes, $options, $quote_key);
|
||||
}
|
||||
if (!empty($excludes)) {
|
||||
$wheres[] = self::in($keys, $excludes, $options, $quote_key);
|
||||
}
|
||||
if (empty($wheres)) {
|
||||
return '0';
|
||||
}
|
||||
if (count($wheres) == 1) {
|
||||
return reset($wheres);
|
||||
}
|
||||
return self::combine($wheres, $glue);
|
||||
}
|
||||
public static function isExclude(string $string): bool
|
||||
{
|
||||
return in_array(self::getOperator($string), ['!=', '<>'], \true);
|
||||
}
|
||||
public static function isNot(array|string $key, array|string $value, array|object $options = []): string
|
||||
{
|
||||
if (is_array($key)) {
|
||||
$wheres = [];
|
||||
foreach ($key as $single_key) {
|
||||
$wheres[] = self::isNot($single_key, $value, $options);
|
||||
}
|
||||
return self::combine($wheres, 'AND');
|
||||
}
|
||||
$values = $value;
|
||||
if (!is_array($values)) {
|
||||
$values = [$values];
|
||||
}
|
||||
foreach ($values as $i => $value) {
|
||||
$operator = self::isExclude($value) ? '=' : '!=';
|
||||
$values[$i] = $operator . self::removeOperator($value);
|
||||
}
|
||||
return self::is($key, $values, $options);
|
||||
}
|
||||
public static function like(string $key, array|string $value, array|object $options = [], $quote_key = \true): string
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$key, $value, $options, $quote_key], '', '', 1);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
$operator = self::getOperator($value);
|
||||
$db_key = $key;
|
||||
if ($quote_key && !str_starts_with($db_key, '`')) {
|
||||
$db_key = self::quoteName($db_key);
|
||||
}
|
||||
if ($value == '*') {
|
||||
return $db_key . ' ' . ($operator == '!=' ? 'IS NULL' : 'IS NOT NULL');
|
||||
}
|
||||
$db_key = 'LOWER(' . $db_key . ')';
|
||||
$operator = $operator == '!=' ? 'NOT LIKE' : 'LIKE';
|
||||
$options = (object) \RegularLabs\Library\ArrayHelper::toArray($options);
|
||||
$value = self::removeOperator($value);
|
||||
$value = self::prepareValue($value, $options);
|
||||
$value = str_replace(['*', '_'], ['%', '\_'], $value);
|
||||
if (!str_contains($value, '%')) {
|
||||
$value = 'LOWER(' . $value . ')';
|
||||
}
|
||||
return $db_key . ' ' . $operator . ' ' . $value;
|
||||
}
|
||||
/**
|
||||
* Create an NOT IN statement
|
||||
* Reverts to a simple equals statement if array just has 1 value
|
||||
*/
|
||||
public static function notIn(string|array $keys, string|array $values, array|object $options = [], bool $quote_key = \true): string
|
||||
{
|
||||
if (is_array($values) && count($values) > 0) {
|
||||
$values[0] = '!' . $values[0];
|
||||
}
|
||||
return self::in($keys, $values, $options, $quote_key);
|
||||
}
|
||||
public static function prepareValue(string|array|object $value, array|object $options = []): string|array
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$value, $options]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
if (!is_array($value) && $value === 'NULL') {
|
||||
return $value;
|
||||
}
|
||||
$options = (object) \RegularLabs\Library\ArrayHelper::toArray($options);
|
||||
$handle_now = $options->handle_now ?? \true;
|
||||
$dates = ['now', 'now()', 'date()', 'jfactory::getdate()'];
|
||||
if ($handle_now && !is_array($value) && in_array(strtolower($value), $dates, \true)) {
|
||||
return 'NOW()';
|
||||
}
|
||||
if ((empty($options->quote) || !$options->quote) && (is_int($value) || ctype_digit($value))) {
|
||||
return $value;
|
||||
}
|
||||
$value = self::quote($value);
|
||||
return $value;
|
||||
}
|
||||
public static function quote(array|string $text, bool $escape = \true): array|string
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$text, $escape]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
if (is_null($text)) {
|
||||
return 'NULL';
|
||||
}
|
||||
return JFactory::getDbo()->quote($text, $escape);
|
||||
}
|
||||
public static function quoteName(array|string $name, array|string|null $as = null): array|string
|
||||
{
|
||||
return JFactory::getDbo()->quoteName($name, $as);
|
||||
}
|
||||
public static function removeOperator(string|array|null $string)
|
||||
{
|
||||
if (empty($string)) {
|
||||
return $string;
|
||||
}
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
$regex = '^' . \RegularLabs\Library\RegEx::quote(self::getOperators(), 'operator');
|
||||
return \RegularLabs\Library\RegEx::replace($regex, '', $string);
|
||||
}
|
||||
public static function tableExists(string $table): bool
|
||||
{
|
||||
if (isset(self::$tables[$table])) {
|
||||
return self::$tables[$table];
|
||||
}
|
||||
$db = JFactory::getDbo();
|
||||
if (str_starts_with($table, '#__')) {
|
||||
$table = $db->getPrefix() . substr($table, 3);
|
||||
}
|
||||
if (!str_starts_with($table, $db->getPrefix())) {
|
||||
$table = $db->getPrefix() . $table;
|
||||
}
|
||||
$query = 'SHOW TABLES LIKE ' . $db->quote($table);
|
||||
$db->setQuery($query);
|
||||
$result = $db->loadResult();
|
||||
self::$tables[$table] = !empty($result);
|
||||
return self::$tables[$table];
|
||||
}
|
||||
}
|
||||
165
libraries/regularlabs/src/Date.php
Normal file
165
libraries/regularlabs/src/Date.php
Normal file
@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use DateTimeZone;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
class Date
|
||||
{
|
||||
/**
|
||||
* Applies offset to a date
|
||||
*/
|
||||
public static function applyTimezone(string &$date, string $timezone = ''): void
|
||||
{
|
||||
if ($date <= 0) {
|
||||
$date = 0;
|
||||
return;
|
||||
}
|
||||
$user = JFactory::getApplication()->getIdentity() ?: JFactory::getUser();
|
||||
$timezone = $timezone ?: $user->getParam('timezone', JFactory::getApplication()->get('offset'));
|
||||
$date = JFactory::getDate($date, $timezone);
|
||||
$date->setTimezone(new DateTimeZone('UTC'));
|
||||
$date = $date->format('Y-m-d H:i:s', \true, \false);
|
||||
}
|
||||
/**
|
||||
* Convert string with 'date' format to 'strftime' format
|
||||
*/
|
||||
public static function dateToStrftimeFormat(string $format): string
|
||||
{
|
||||
return strtr((string) $format, self::getDateToStrftimeFormats());
|
||||
}
|
||||
/**
|
||||
* Convert string to a correct date format ('00-00-00 00:00:00' or '00-00-00') or empty string
|
||||
*/
|
||||
public static function fix(string $date): string
|
||||
{
|
||||
if (!$date) {
|
||||
return '';
|
||||
}
|
||||
$date = trim($date);
|
||||
// Check if date has correct syntax: 00-00-00 00:00:00
|
||||
// If so, the date format is correct
|
||||
if (\RegularLabs\Library\RegEx::match('^[0-9]+-[0-9]+-[0-9]+( [0-9][0-9]:[0-9][0-9]:[0-9][0-9])?$', $date)) {
|
||||
return $date;
|
||||
}
|
||||
// Check if date has syntax: 00-00-00 00:00
|
||||
// If so, it is missing the seconds, so add :00 (seconds)
|
||||
if (\RegularLabs\Library\RegEx::match('^[0-9]+-[0-9]+-[0-9]+ [0-9][0-9]:[0-9][0-9]$', $date)) {
|
||||
return $date . ':00';
|
||||
}
|
||||
// Check if date has a prepending date syntax: 00-00-00
|
||||
// If so, it is missing a correct time time, so add 00:00:00 (hours, minutes, seconds)
|
||||
if (\RegularLabs\Library\RegEx::match('^([0-9]+-[0-9]+-[0-9]+)$', $date, $match)) {
|
||||
return $match[1] . ' 00:00:00';
|
||||
}
|
||||
// Date format is not correct, so return empty string
|
||||
return '';
|
||||
}
|
||||
/**
|
||||
* Convert string to a correct time format: 1:23 to 01:23
|
||||
*/
|
||||
public static function fixTime(string $time, bool $include_seconds = \true): string
|
||||
{
|
||||
[$hours, $minutes, $seconds] = explode(':', $time . '::');
|
||||
$hours = str_pad($hours, 2, '0', \STR_PAD_LEFT);
|
||||
$minutes = str_pad($minutes, 2, '0', \STR_PAD_LEFT);
|
||||
$seconds = str_pad($seconds, 2, '0', \STR_PAD_LEFT);
|
||||
if (!$include_seconds) {
|
||||
return $hours . ':' . $minutes;
|
||||
}
|
||||
return $hours . ':' . $minutes . ':' . $seconds;
|
||||
}
|
||||
/**
|
||||
* Convert string with 'date' format to 'strftime' format
|
||||
*/
|
||||
public static function strftimeToDateFormat(string $format): string
|
||||
{
|
||||
if (!str_contains($format, '%')) {
|
||||
return $format;
|
||||
}
|
||||
return strtr((string) $format, self::getStrftimeToDateFormats());
|
||||
}
|
||||
private static function getDateToStrftimeFormats(): array
|
||||
{
|
||||
return [
|
||||
// Day - no strf eq : S
|
||||
'd' => '%d',
|
||||
'D' => '%a',
|
||||
'jS' => '%#d[TH]',
|
||||
'j' => '%#d',
|
||||
'l' => '%A',
|
||||
'N' => '%u',
|
||||
'w' => '%w',
|
||||
'z' => '%j',
|
||||
// Week - no date eq : %U, %W
|
||||
'W' => '%V',
|
||||
// Month - no strf eq : n, t
|
||||
'F' => '%B',
|
||||
'm' => '%m',
|
||||
'M' => '%b',
|
||||
// Year - no strf eq : L; no date eq : %C, %g
|
||||
'o' => '%G',
|
||||
'Y' => '%Y',
|
||||
'y' => '%y',
|
||||
// Time - no strf eq : B, G, u; no date eq : %r, %R, %T, %X
|
||||
'a' => '%P',
|
||||
'A' => '%p',
|
||||
'g' => '%l',
|
||||
'h' => '%I',
|
||||
'H' => '%H',
|
||||
'i' => '%M',
|
||||
's' => '%S',
|
||||
// Timezone - no strf eq : e, I, P, Z
|
||||
'O' => '%z',
|
||||
'T' => '%Z',
|
||||
// Full Date / Time - no strf eq : c, r; no date eq : %c, %D, %F, %x
|
||||
'U' => '%s',
|
||||
];
|
||||
}
|
||||
private static function getStrftimeToDateFormats(): array
|
||||
{
|
||||
return [
|
||||
// Day
|
||||
'%d' => 'd',
|
||||
'%a' => 'D',
|
||||
'%#d' => 'j',
|
||||
'%A' => 'l',
|
||||
'%u' => 'N',
|
||||
'%w' => 'w',
|
||||
'%j' => 'z',
|
||||
// Week
|
||||
'%V' => 'W',
|
||||
// Month
|
||||
'%B' => 'F',
|
||||
'%m' => 'm',
|
||||
'%b' => 'M',
|
||||
// Year
|
||||
'%G' => 'o',
|
||||
'%Y' => 'Y',
|
||||
'%y' => 'y',
|
||||
// Time
|
||||
'%P' => 'a',
|
||||
'%p' => 'A',
|
||||
'%l' => 'g',
|
||||
'%I' => 'h',
|
||||
'%H' => 'H',
|
||||
'%M' => 'i',
|
||||
'%S' => 's',
|
||||
// Timezone
|
||||
'%z' => 'O',
|
||||
'%Z' => 'T',
|
||||
// Full Date / Time
|
||||
'%s' => 'U',
|
||||
];
|
||||
}
|
||||
}
|
||||
316
libraries/regularlabs/src/Document.php
Normal file
316
libraries/regularlabs/src/Document.php
Normal file
@ -0,0 +1,316 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Document\Document as JDocument;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
use Joomla\CMS\HTML\HTMLHelper as JHtml;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use Joomla\CMS\WebAsset\WebAssetManager as JWebAssetManager;
|
||||
class Document
|
||||
{
|
||||
public static function adminError(string $message): void
|
||||
{
|
||||
self::adminMessage($message, 'error');
|
||||
}
|
||||
public static function adminMessage(string $message, string $type = 'message'): void
|
||||
{
|
||||
if (!self::isAdmin()) {
|
||||
return;
|
||||
}
|
||||
self::message($message, $type);
|
||||
}
|
||||
public static function error(string $message): void
|
||||
{
|
||||
self::message($message, 'error');
|
||||
}
|
||||
public static function get(): ?JDocument
|
||||
{
|
||||
$app = JFactory::getApplication();
|
||||
if (!method_exists($app, 'getDocument')) {
|
||||
return null;
|
||||
}
|
||||
$document = JFactory::getApplication()->getDocument();
|
||||
if (!is_null($document)) {
|
||||
return $document;
|
||||
}
|
||||
JFactory::getApplication()->loadDocument();
|
||||
return JFactory::getApplication()->getDocument();
|
||||
}
|
||||
public static function getAssetManager(): ?JWebAssetManager
|
||||
{
|
||||
$document = self::get();
|
||||
if (is_null($document)) {
|
||||
return null;
|
||||
}
|
||||
return $document->getWebAssetManager();
|
||||
}
|
||||
public static function getComponentBuffer(): ?string
|
||||
{
|
||||
$buffer = self::get()->getBuffer('component') ?? null;
|
||||
if (empty($buffer) || !is_string($buffer)) {
|
||||
return null;
|
||||
}
|
||||
$buffer = trim($buffer);
|
||||
if (empty($buffer)) {
|
||||
return null;
|
||||
}
|
||||
return $buffer;
|
||||
}
|
||||
public static function isAdmin(bool $exclude_login = \false): bool
|
||||
{
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
$user = JFactory::getApplication()->getIdentity() ?: JFactory::getUser();
|
||||
$is_admin = self::isClient('administrator') && (!$exclude_login || !$user->get('guest')) && \RegularLabs\Library\Input::get('task', '') != 'preview' && !(\RegularLabs\Library\Input::get('option', '') == 'com_finder' && \RegularLabs\Library\Input::get('format', '') == 'json');
|
||||
return $cache->set($is_admin);
|
||||
}
|
||||
public static function isCategoryList(string $context): bool
|
||||
{
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
// Return false if it is not a category page
|
||||
if ($context != 'com_content.category' || \RegularLabs\Library\Input::get('view', '') != 'category') {
|
||||
return $cache->set(\false);
|
||||
}
|
||||
// Return false if layout is set and it is not a list layout
|
||||
if (\RegularLabs\Library\Input::get('layout', '') && \RegularLabs\Library\Input::get('layout', '') != 'list') {
|
||||
return $cache->set(\false);
|
||||
}
|
||||
// Return false if default layout is set to blog
|
||||
if (JFactory::getApplication()->getParams()->get('category_layout') == '_:blog') {
|
||||
return $cache->set(\false);
|
||||
}
|
||||
// Return true if it IS a list layout
|
||||
return $cache->set(\true);
|
||||
}
|
||||
public static function isCli(): bool
|
||||
{
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
$is_cli = (new \RegularLabs\Library\MobileDetect())->isCurl();
|
||||
return $cache->set($is_cli);
|
||||
}
|
||||
public static function isClient(string $identifier): bool
|
||||
{
|
||||
$identifier = $identifier == 'admin' ? 'administrator' : $identifier;
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
return $cache->set(JFactory::getApplication()->isClient($identifier));
|
||||
}
|
||||
public static function isDebug(): bool
|
||||
{
|
||||
return JFactory::getApplication()->get('debug') || \RegularLabs\Library\Input::get('debug');
|
||||
}
|
||||
public static function isEditPage(): bool
|
||||
{
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
$option = \RegularLabs\Library\Input::get('option', '');
|
||||
// always return false for these components
|
||||
if (in_array($option, ['com_rsevents', 'com_rseventspro'], \true)) {
|
||||
return $cache->set(\false);
|
||||
}
|
||||
$task = \RegularLabs\Library\Input::get('task', '');
|
||||
if (str_contains($task, '.')) {
|
||||
$task = explode('.', $task);
|
||||
$task = array_pop($task);
|
||||
}
|
||||
$view = \RegularLabs\Library\Input::get('view', '');
|
||||
if (str_contains($view, '.')) {
|
||||
$view = explode('.', $view);
|
||||
$view = array_pop($view);
|
||||
}
|
||||
$is_edit_page = in_array($option, ['com_config', 'com_contentsubmit', 'com_cckjseblod'], \true) || $option == 'com_comprofiler' && in_array($task, ['', 'userdetails'], \true) || in_array($task, ['edit', 'form', 'submission'], \true) || in_array($view, ['edit', 'form'], \true) || in_array(\RegularLabs\Library\Input::get('do', ''), ['edit', 'form'], \true) || in_array(\RegularLabs\Library\Input::get('layout', ''), ['edit', 'form', 'write'], \true) || self::isAdmin();
|
||||
return $cache->set($is_edit_page);
|
||||
}
|
||||
public static function isFeed(): bool
|
||||
{
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
$is_feed = self::get() && ((self::get()->getType() ?? null) == 'feed' || in_array(\RegularLabs\Library\Input::getWord('format'), ['feed', 'xml'], \true) || in_array(\RegularLabs\Library\Input::getWord('type'), ['rss', 'atom'], \true));
|
||||
return $cache->set($is_feed);
|
||||
}
|
||||
public static function isHtml(): bool
|
||||
{
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
$is_html = self::get() ? self::get()->getType() == 'html' : \false;
|
||||
return $cache->set($is_html);
|
||||
}
|
||||
public static function isHttps(): bool
|
||||
{
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
$is_https = !empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off' || isset($_SERVER['SSL_PROTOCOL']) || isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443 || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https';
|
||||
return $cache->set($is_https);
|
||||
}
|
||||
public static function isJSON(): bool
|
||||
{
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
$is_json = \RegularLabs\Library\Input::get('format', '') == 'json';
|
||||
return $cache->set($is_json);
|
||||
}
|
||||
/**
|
||||
* Check if the current setup matches the given main version number
|
||||
*/
|
||||
public static function isJoomlaVersion(int $version, string $title = ''): bool
|
||||
{
|
||||
$jversion = \RegularLabs\Library\Version::getMajorJoomlaVersion();
|
||||
if ($jversion == $version) {
|
||||
return \true;
|
||||
}
|
||||
if ($title && self::isAdmin()) {
|
||||
\RegularLabs\Library\Language::load('plg_system_regularlabs');
|
||||
JFactory::getApplication()->enqueueMessage(JText::sprintf('RL_NOT_COMPATIBLE_WITH_JOOMLA_VERSION', JText::_($title), $jversion), 'error');
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
public static function isPDF(): bool
|
||||
{
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
$is_pdf = self::get() && ((self::get()->getType() ?? null) == 'pdf' || \RegularLabs\Library\Input::getWord('format') == 'pdf' || \RegularLabs\Library\Input::getWord('cAction') == 'pdf');
|
||||
return $cache->set($is_pdf);
|
||||
}
|
||||
public static function message(string $message, string $type = 'message'): void
|
||||
{
|
||||
\RegularLabs\Library\Language::load('plg_system_regularlabs');
|
||||
JFactory::getApplication()->enqueueMessage($message, $type);
|
||||
}
|
||||
/**
|
||||
* @depecated Use RegularLabs\Library\StringHelper::minify()
|
||||
*/
|
||||
public static function minify(string $string): string
|
||||
{
|
||||
return \RegularLabs\Library\StringHelper::minify($string);
|
||||
}
|
||||
public static function removeScriptTag(string &$string, string $folder, string $name): void
|
||||
{
|
||||
$regex_name = \RegularLabs\Library\RegEx::quote($name);
|
||||
$regex_name = str_replace('\*', '[^"]*', $regex_name);
|
||||
$string = \RegularLabs\Library\RegEx::replace('\s*<script [^>]*href="[^"]*(' . $folder . '/js|js/' . $folder . ')/' . $regex_name . '\.[^>]*( /)?>', '', $string);
|
||||
}
|
||||
public static function removeScriptsOptions(string &$string, string $name, string $alias = ''): void
|
||||
{
|
||||
\RegularLabs\Library\RegEx::match('(<script type="application/json" class="joomla-script-options new">)(.*?)(</script>)', $string, $match);
|
||||
if (empty($match)) {
|
||||
return;
|
||||
}
|
||||
$alias = $alias ?: \RegularLabs\Library\Extension::getAliasByName($name);
|
||||
$scripts = json_decode($match[2]);
|
||||
if (!isset($scripts->{'rl_' . $alias})) {
|
||||
return;
|
||||
}
|
||||
unset($scripts->{'rl_' . $alias});
|
||||
$string = str_replace($match[0], $match[1] . json_encode($scripts) . $match[3], $string);
|
||||
}
|
||||
public static function removeScriptsStyles(string &$string, string $name, string $alias = ''): void
|
||||
{
|
||||
[$start, $end] = \RegularLabs\Library\Protect::getInlineCommentTags($name, null, \true);
|
||||
$alias = $alias ?: \RegularLabs\Library\Extension::getAliasByName($name);
|
||||
$string = \RegularLabs\Library\RegEx::replace('((?:;\s*)?)(;?)' . $start . '.*?' . $end . '\s*', '\1', $string);
|
||||
$string = \RegularLabs\Library\RegEx::replace('\s*<link [^>]*href="[^"]*/(' . $alias . '/css|css/' . $alias . ')/[^"]*\.css[^"]*"[^>]*( /)?>', '', $string);
|
||||
$string = \RegularLabs\Library\RegEx::replace('\s*<script [^>]*src="[^"]*/(' . $alias . '/js|js/' . $alias . ')/[^"]*\.js[^"]*"[^>]*></script>', '', $string);
|
||||
$string = \RegularLabs\Library\RegEx::replace('\s*<script></script>', '', $string);
|
||||
}
|
||||
public static function removeStyleTag(string &$string, string $folder, string $name): void
|
||||
{
|
||||
$name = \RegularLabs\Library\RegEx::quote($name);
|
||||
$name = str_replace('\*', '[^"]*', $name);
|
||||
$string = \RegularLabs\Library\RegEx::replace('\s*<link [^>]*href="[^"]*(' . $folder . '/css|css/' . $folder . ')/' . $name . '\.[^>]*( /)?>', '', $string);
|
||||
}
|
||||
public static function script(string $name, array $attributes = ['defer' => \true], array $dependencies = [], bool $convert_dots = \true): void
|
||||
{
|
||||
$file = $name;
|
||||
if ($convert_dots) {
|
||||
$file = str_replace('.', '/', $file) . '.min.js';
|
||||
}
|
||||
if ($name == 'regularlabs.regular') {
|
||||
$attributes['defer'] = \false;
|
||||
}
|
||||
self::getAssetManager()->registerAndUseScript($name, $file, [], $attributes, $dependencies);
|
||||
}
|
||||
public static function scriptDeclaration(string $content = '', string $name = '', bool $minify = \true, string $position = 'before'): void
|
||||
{
|
||||
if ($minify) {
|
||||
$content = \RegularLabs\Library\StringHelper::minify($content);
|
||||
}
|
||||
if (!empty($name)) {
|
||||
$content = \RegularLabs\Library\Protect::wrapScriptDeclaration($content, $name, $minify);
|
||||
}
|
||||
self::getAssetManager()->addInlineScript($content, ['position' => $position]);
|
||||
}
|
||||
public static function scriptOptions(array $options = [], string $name = ''): void
|
||||
{
|
||||
JHtml::_('behavior.core');
|
||||
$alias = \RegularLabs\Library\RegEx::replace('[^a-z0-9_-]', '', strtolower($name));
|
||||
$key = 'rl_' . $alias;
|
||||
self::get()->addScriptOptions($key, $options);
|
||||
}
|
||||
public static function setComponentBuffer(string $buffer = ''): void
|
||||
{
|
||||
self::get()->setBuffer($buffer, 'component');
|
||||
}
|
||||
public static function style(string $name, array $attributes = [], bool $convert_dots = \true): void
|
||||
{
|
||||
$file = $name;
|
||||
if ($convert_dots) {
|
||||
$file = str_replace('.', '/', $file) . '.min.css';
|
||||
}
|
||||
self::getAssetManager()->registerAndUseStyle($name, $file, [], $attributes);
|
||||
}
|
||||
public static function styleDeclaration(string $content = '', string $name = '', bool $minify = \true): void
|
||||
{
|
||||
if ($minify) {
|
||||
$content = \RegularLabs\Library\StringHelper::minify($content);
|
||||
}
|
||||
if (!empty($name)) {
|
||||
$content = \RegularLabs\Library\Protect::wrapStyleDeclaration($content, $name, $minify);
|
||||
}
|
||||
self::getAssetManager()->addInlineStyle($content);
|
||||
}
|
||||
public static function usePreset(string $name): void
|
||||
{
|
||||
self::getAssetManager()->usePreset($name);
|
||||
}
|
||||
public static function useScript(string $name): void
|
||||
{
|
||||
self::getAssetManager()->useScript($name);
|
||||
}
|
||||
public static function useStyle(string $name): void
|
||||
{
|
||||
self::getAssetManager()->useStyle($name);
|
||||
}
|
||||
}
|
||||
83
libraries/regularlabs/src/DownloadKey.php
Normal file
83
libraries/regularlabs/src/DownloadKey.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
use Joomla\CMS\Layout\FileLayout as JFileLayout;
|
||||
class DownloadKey
|
||||
{
|
||||
public static function get(bool $update = \true): string
|
||||
{
|
||||
$db = \RegularLabs\Library\DB::get();
|
||||
$query = \RegularLabs\Library\DB::getQuery()->select('extra_query')->from('#__update_sites')->where(\RegularLabs\Library\DB::like(\RegularLabs\Library\DB::quoteName('extra_query'), 'k=%'))->where(\RegularLabs\Library\DB::like(\RegularLabs\Library\DB::quoteName('location'), '%download.regularlabs.com%'));
|
||||
$db->setQuery($query);
|
||||
$key = $db->loadResult();
|
||||
if (!$key) {
|
||||
return '';
|
||||
}
|
||||
\RegularLabs\Library\RegEx::match('#k=([a-zA-Z0-9]{8}[A-Z0-9]{8})#', $key, $match);
|
||||
if (!$match[1]) {
|
||||
return '';
|
||||
}
|
||||
$key = $match[1];
|
||||
if ($update) {
|
||||
self::store($key);
|
||||
}
|
||||
return $key;
|
||||
}
|
||||
public static function getOutputForComponent(string $extension = 'all', bool $use_modal = \true, bool $hidden = \true, string $callback = ''): string
|
||||
{
|
||||
$id = 'downloadkey_' . strtolower($extension);
|
||||
\RegularLabs\Library\Document::script('regularlabs.script');
|
||||
\RegularLabs\Library\Document::script('regularlabs.downloadkey');
|
||||
return (new JFileLayout('regularlabs.form.field.downloadkey', JPATH_SITE . '/libraries/regularlabs/layouts'))->render(['id' => $id, 'extension' => strtolower($extension), 'use_modal' => $use_modal, 'hidden' => $hidden, 'callback' => $callback, 'show_label' => \true]);
|
||||
}
|
||||
public static function isValid(string $key, string $extension = 'all'): string
|
||||
{
|
||||
$key = trim($key);
|
||||
if (!self::isValidFormat($key)) {
|
||||
return json_encode(['valid' => \false, 'active' => \false]);
|
||||
}
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
$cache->useFiles(1);
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
$result = \RegularLabs\Library\Http::getFromUrl('https://download.regularlabs.com/check_key.php?k=' . $key . '&e=' . $extension);
|
||||
return $cache->set($result);
|
||||
}
|
||||
public static function isValidFormat(string $key): bool
|
||||
{
|
||||
$key = trim($key);
|
||||
if ($key === '') {
|
||||
return \true;
|
||||
}
|
||||
if (strlen($key) != 16) {
|
||||
return \false;
|
||||
}
|
||||
return \RegularLabs\Library\RegEx::match('^[a-zA-Z0-9]{8}[A-Z0-9]{8}$', $key, $match, 's');
|
||||
}
|
||||
public static function store(string $key): bool
|
||||
{
|
||||
if (!self::isValidFormat($key)) {
|
||||
return \false;
|
||||
}
|
||||
$query = \RegularLabs\Library\DB::getQuery()->update('#__update_sites')->set(\RegularLabs\Library\DB::is('extra_query', ''))->where(\RegularLabs\Library\DB::like(\RegularLabs\Library\DB::quoteName('location'), '%download.regularlabs.com%'));
|
||||
\RegularLabs\Library\DB::get()->setQuery($query)->execute();
|
||||
$extra_query = $key ? 'k=' . $key : '';
|
||||
$query = \RegularLabs\Library\DB::getQuery()->update('#__update_sites')->set(\RegularLabs\Library\DB::is('extra_query', $extra_query))->where(\RegularLabs\Library\DB::like(\RegularLabs\Library\DB::quoteName('location'), '%download.regularlabs.com%'))->where(\RegularLabs\Library\DB::combine([\RegularLabs\Library\DB::like(\RegularLabs\Library\DB::quoteName('location'), '%&pro=%'), \RegularLabs\Library\DB::like(\RegularLabs\Library\DB::quoteName('location'), '%e=extensionmanager%')], 'OR'));
|
||||
$result = \RegularLabs\Library\DB::get()->setQuery($query)->execute();
|
||||
JFactory::getCache()->clean('_system');
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
165
libraries/regularlabs/src/EditorButtonPlugin.php
Normal file
165
libraries/regularlabs/src/EditorButtonPlugin.php
Normal file
@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use Joomla\CMS\Object\CMSObject as JObject;
|
||||
use Joomla\CMS\Plugin\CMSPlugin as JCMSPlugin;
|
||||
use Joomla\CMS\Session\Session;
|
||||
use Joomla\Event\DispatcherInterface as JDispatcherInterface;
|
||||
use ReflectionClass;
|
||||
class EditorButtonPlugin extends JCMSPlugin
|
||||
{
|
||||
protected $asset;
|
||||
protected $author;
|
||||
protected $button_icon = '';
|
||||
protected $check_installed;
|
||||
protected $editor_name = '';
|
||||
protected $enable_on_acymailing = \false;
|
||||
protected $folder;
|
||||
protected $main_type = 'plugin';
|
||||
protected $popup_class = '';
|
||||
protected $require_core_auth = \true;
|
||||
private $_params;
|
||||
private $_pass;
|
||||
public function __construct(JDispatcherInterface &$subject, array $config = [])
|
||||
{
|
||||
parent::__construct($subject, $config);
|
||||
$this->popup_class = $this->popup_class ?: 'Plugin.EditorButton.' . $this->getShortName() . '.Popup';
|
||||
}
|
||||
public function extraChecks($params)
|
||||
{
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* Display the button
|
||||
*
|
||||
* @param string $name The name of the button to display.
|
||||
* @param string $asset The name of the asset being edited.
|
||||
* @param integer $author The id of the author owning the asset being edited.
|
||||
*
|
||||
* @return JObject|false
|
||||
*/
|
||||
public function onDisplay($editor_name, $asset, $author)
|
||||
{
|
||||
$this->editor_name = $editor_name;
|
||||
$this->asset = $asset;
|
||||
$this->author = $author;
|
||||
if (!$this->passChecks()) {
|
||||
return \false;
|
||||
}
|
||||
return $this->render();
|
||||
}
|
||||
protected function getButtonText()
|
||||
{
|
||||
$params = $this->getParams();
|
||||
$text_ini = strtoupper(str_replace(' ', '_', $params->button_text ?? $this->_name));
|
||||
$text = JText::_($text_ini);
|
||||
if ($text == $text_ini) {
|
||||
$text = JText::_($params->button_text ?? $this->_name);
|
||||
}
|
||||
return trim($text);
|
||||
}
|
||||
protected function getParams()
|
||||
{
|
||||
if (!is_null($this->_params)) {
|
||||
return $this->_params;
|
||||
}
|
||||
switch ($this->main_type) {
|
||||
case 'component':
|
||||
if (\RegularLabs\Library\Protect::isComponentInstalled($this->_name)) {
|
||||
// Load component parameters
|
||||
$this->_params = \RegularLabs\Library\Parameters::getComponent($this->_name);
|
||||
}
|
||||
break;
|
||||
case 'plugin':
|
||||
default:
|
||||
if (\RegularLabs\Library\Protect::isSystemPluginInstalled($this->_name)) {
|
||||
// Load plugin parameters
|
||||
$this->_params = \RegularLabs\Library\Parameters::getPlugin($this->_name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $this->_params;
|
||||
}
|
||||
protected function getPopupLink()
|
||||
{
|
||||
return 'index.php?rl_qp=1' . '&class=' . $this->popup_class . '&editor=' . $this->editor_name . '&tmpl=component' . '&' . Session::getFormToken() . '=1';
|
||||
}
|
||||
protected function getPopupOptions()
|
||||
{
|
||||
return ['popupType' => 'iframe', 'height' => '1600px', 'width' => '1200px', 'bodyHeight' => '70', 'modalWidth' => '80'];
|
||||
}
|
||||
protected function loadScripts()
|
||||
{
|
||||
}
|
||||
protected function loadStyles()
|
||||
{
|
||||
}
|
||||
protected function render()
|
||||
{
|
||||
$this->loadScripts();
|
||||
$this->loadStyles();
|
||||
return $this->renderPopupButton();
|
||||
}
|
||||
protected function renderPopupButton()
|
||||
{
|
||||
$button = new JObject();
|
||||
$button->setProperties(['modal' => \true, 'action' => 'modal', 'name' => $this->_name, 'text' => $this->getButtonText(), 'icon' => $this->_name . '" aria-hidden="true">' . $this->button_icon . '<span></span class="hidden', 'iconSVG' => $this->button_icon, 'link' => $this->getPopupLink(), 'options' => $this->getPopupOptions()]);
|
||||
return $button;
|
||||
}
|
||||
/**
|
||||
* Get the short name of the field class
|
||||
* PlgButtonFoobar => Foobar
|
||||
*/
|
||||
private function getShortName(): string
|
||||
{
|
||||
return substr((new ReflectionClass($this))->getShortName(), strlen('PlgButton'));
|
||||
}
|
||||
private function isInstalled(): bool
|
||||
{
|
||||
$extensions = !is_null($this->check_installed) ? $this->check_installed : [$this->main_type];
|
||||
return \RegularLabs\Library\Extension::areInstalled($this->_name, $extensions);
|
||||
}
|
||||
private function passChecks(): bool
|
||||
{
|
||||
if (!is_null($this->_pass)) {
|
||||
return $this->_pass;
|
||||
}
|
||||
$this->_pass = \false;
|
||||
if (!\RegularLabs\Library\Extension::isFrameworkEnabled()) {
|
||||
return \false;
|
||||
}
|
||||
if (!\RegularLabs\Library\Extension::isAuthorised($this->require_core_auth)) {
|
||||
return \false;
|
||||
}
|
||||
if (!$this->isInstalled()) {
|
||||
return \false;
|
||||
}
|
||||
if (!$this->enable_on_acymailing && \RegularLabs\Library\Input::get('option', '') == 'com_acymailing') {
|
||||
return \false;
|
||||
}
|
||||
$params = $this->getParams();
|
||||
if (!\RegularLabs\Library\Extension::isEnabledInComponent($params)) {
|
||||
return \false;
|
||||
}
|
||||
if (!\RegularLabs\Library\Extension::isEnabledInArea($params)) {
|
||||
return \false;
|
||||
}
|
||||
if (!$this->extraChecks($params)) {
|
||||
return \false;
|
||||
}
|
||||
$this->_pass = \true;
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
132
libraries/regularlabs/src/EditorButtonPopup.php
Normal file
132
libraries/regularlabs/src/EditorButtonPopup.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Exception;
|
||||
use Joomla\CMS\HTML\HTMLHelper as JHtml;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use Joomla\Registry\Registry as JRegistry;
|
||||
use ReflectionClass;
|
||||
class EditorButtonPopup
|
||||
{
|
||||
public $editor_name = '';
|
||||
public $form;
|
||||
public $params;
|
||||
protected $extension = '';
|
||||
protected $main_type = 'plugin';
|
||||
protected $require_core_auth = \true;
|
||||
private $_params;
|
||||
public function render()
|
||||
{
|
||||
if (!\RegularLabs\Library\Extension::isAuthorised($this->require_core_auth)) {
|
||||
throw new Exception(JText::_("ALERTNOTAUTH"));
|
||||
}
|
||||
$this->params = $this->getParams();
|
||||
if (!\RegularLabs\Library\Extension::isEnabledInArea($this->params)) {
|
||||
throw new Exception(JText::_("ALERTNOTAUTH"));
|
||||
}
|
||||
$this->loadLanguages();
|
||||
$doc = \RegularLabs\Library\Document::get();
|
||||
$asset_manager = \RegularLabs\Library\Document::getAssetManager();
|
||||
$direction = $doc->getDirection();
|
||||
$template_params = $this->getTemplateParams();
|
||||
// Get the hue value
|
||||
preg_match('#^hsla?\(([0-9]+)[\D]+([0-9]+)[\D]+([0-9]+)[\D]+([0-9](?:.\d+)?)?\)$#i', $template_params->get('hue', 'hsl(214, 63%, 20%)'), $matches);
|
||||
// Enable assets
|
||||
$asset_manager->getRegistry()->addTemplateRegistryFile('atum', 1);
|
||||
$asset_manager->usePreset('template.atum.' . ($direction === 'rtl' ? 'rtl' : 'ltr'))->addInlineStyle(':root {
|
||||
--hue: ' . $matches[1] . ';
|
||||
--template-bg-light: ' . $template_params->get('bg-light', '--template-bg-light') . ';
|
||||
--template-text-dark: ' . $template_params->get('text-dark', '--template-text-dark') . ';
|
||||
--template-text-light: ' . $template_params->get('text-light', '--template-text-light') . ';
|
||||
--template-link-color: ' . $template_params->get('link-color', '--template-link-color') . ';
|
||||
--template-special-color: ' . $template_params->get('special-color', '--template-special-color') . ';
|
||||
}');
|
||||
// No template.js for modals
|
||||
//$asset_manager->disableScript('template.atum');
|
||||
// Override 'template.active' asset to set correct ltr/rtl dependency
|
||||
$asset_manager->registerStyle('template.active', '', [], [], ['template.atum.' . ($direction === 'rtl' ? 'rtl' : 'ltr')]);
|
||||
// Browsers support SVG favicons
|
||||
$doc->addHeadLink(JHtml::_('image', 'joomla-favicon.svg', '', [], \true, 1), 'icon', 'rel', ['type' => 'image/svg+xml']);
|
||||
$doc->addHeadLink(JHtml::_('image', 'favicon.ico', '', [], \true, 1), 'alternate icon', 'rel', ['type' => 'image/vnd.microsoft.icon']);
|
||||
$doc->addHeadLink(JHtml::_('image', 'joomla-favicon-pinned.svg', '', [], \true, 1), 'mask-icon', 'rel', ['color' => '#000']);
|
||||
\RegularLabs\Library\Document::script('regularlabs.admin-form');
|
||||
\RegularLabs\Library\Document::style('regularlabs.admin-form');
|
||||
\RegularLabs\Library\Document::style('regularlabs.popup');
|
||||
$this->init();
|
||||
$this->loadScripts();
|
||||
$this->loadStyles();
|
||||
echo $this->renderTemplate();
|
||||
}
|
||||
protected function getParams()
|
||||
{
|
||||
if (!is_null($this->_params)) {
|
||||
return $this->_params;
|
||||
}
|
||||
switch ($this->main_type) {
|
||||
case 'component':
|
||||
if (\RegularLabs\Library\Protect::isComponentInstalled($this->extension)) {
|
||||
// Load component parameters
|
||||
$this->_params = \RegularLabs\Library\Parameters::getComponent($this->extension);
|
||||
}
|
||||
break;
|
||||
case 'plugin':
|
||||
default:
|
||||
if (\RegularLabs\Library\Protect::isSystemPluginInstalled($this->extension)) {
|
||||
// Load plugin parameters
|
||||
$this->_params = \RegularLabs\Library\Parameters::getPlugin($this->extension);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $this->_params;
|
||||
}
|
||||
protected function getTemplateParams()
|
||||
{
|
||||
$db = \RegularLabs\Library\DB::get();
|
||||
$query = \RegularLabs\Library\DB::getQuery()->select(\RegularLabs\Library\DB::quoteName('s.params'))->from(\RegularLabs\Library\DB::quoteName('#__template_styles', 's'))->where(\RegularLabs\Library\DB::is('s.template', 'atum'))->order(\RegularLabs\Library\DB::quoteName('s.home'));
|
||||
$db->setQuery($query, 0, 1);
|
||||
$template = $db->loadObject();
|
||||
return new JRegistry($template->params ?? null);
|
||||
}
|
||||
protected function init()
|
||||
{
|
||||
}
|
||||
protected function loadLanguages()
|
||||
{
|
||||
\RegularLabs\Library\Language::load('joomla', JPATH_ADMINISTRATOR);
|
||||
\RegularLabs\Library\Language::load('plg_system_regularlabs');
|
||||
\RegularLabs\Library\Language::load('plg_editors-xtd_' . $this->extension);
|
||||
\RegularLabs\Library\Language::load('plg_system_' . $this->extension);
|
||||
}
|
||||
protected function loadScripts()
|
||||
{
|
||||
}
|
||||
protected function loadStyles()
|
||||
{
|
||||
}
|
||||
private function getDir(): string
|
||||
{
|
||||
$rc = new ReflectionClass(static::class);
|
||||
return dirname($rc->getFileName());
|
||||
}
|
||||
private function renderTemplate(): string
|
||||
{
|
||||
$layout = \RegularLabs\Library\Input::getString('layout', '');
|
||||
$file = 'popup' . ($layout ? '.' . $layout : '') . '.php';
|
||||
ob_start();
|
||||
include dirname($this->getDir()) . '/tmpl/' . $file;
|
||||
$html = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
327
libraries/regularlabs/src/Extension.php
Normal file
327
libraries/regularlabs/src/Extension.php
Normal file
@ -0,0 +1,327 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Component\ComponentHelper as JComponentHelper;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
use Joomla\CMS\Filesystem\Folder as JFolder;
|
||||
use Joomla\CMS\Helper\ModuleHelper as JModuleHelper;
|
||||
use Joomla\CMS\Installer\Installer as JInstaller;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use Joomla\CMS\Plugin\PluginHelper as JPluginHelper;
|
||||
class Extension
|
||||
{
|
||||
/**
|
||||
* Check if all extension types of a given extension are installed
|
||||
*/
|
||||
public static function areInstalled(string $extension, array $types = ['plugin']): bool
|
||||
{
|
||||
foreach ($types as $type) {
|
||||
$folder = 'system';
|
||||
if (is_array($type)) {
|
||||
[$type, $folder] = $type;
|
||||
}
|
||||
if (!self::isInstalled($extension, $type, $folder)) {
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
return \true;
|
||||
}
|
||||
public static function disable(string $alias, string $type = 'plugin', string $folder = 'system'): void
|
||||
{
|
||||
$element = self::getElementByAlias($alias);
|
||||
$element = match ($element) {
|
||||
'module' => 'mod_' . $element,
|
||||
'component' => 'com_' . $element,
|
||||
default => $element,
|
||||
};
|
||||
$db = \RegularLabs\Library\DB::get();
|
||||
$query = \RegularLabs\Library\DB::getQuery()->update(\RegularLabs\Library\DB::quoteName('#__extensions'))->set(\RegularLabs\Library\DB::quoteName('enabled') . ' = 0')->where(\RegularLabs\Library\DB::is('element', $element))->where(\RegularLabs\Library\DB::is('type', $type));
|
||||
if ($type == 'plugin') {
|
||||
$query->where(\RegularLabs\Library\DB::is('folder', $folder));
|
||||
}
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
}
|
||||
/**
|
||||
* Return an alias and element name based on the given extension name
|
||||
*/
|
||||
public static function getAliasAndElement(string &$name): array
|
||||
{
|
||||
$name = self::getNameByAlias($name);
|
||||
$alias = self::getAliasByName($name);
|
||||
$element = self::getElementByAlias($alias);
|
||||
return [$alias, $element];
|
||||
}
|
||||
public static function getAliasByName(string $name): string
|
||||
{
|
||||
$alias = \RegularLabs\Library\RegEx::replace('[^a-z0-9]', '', strtolower($name));
|
||||
return match ($alias) {
|
||||
'advancedmodules' => 'advancedmodulemanager',
|
||||
'what-nothing' => 'whatnothing',
|
||||
default => $alias,
|
||||
};
|
||||
}
|
||||
public static function getById(int|string $id): ?object
|
||||
{
|
||||
$db = \RegularLabs\Library\DB::get();
|
||||
$query = \RegularLabs\Library\DB::getQuery()->select(\RegularLabs\Library\DB::quoteName(['extension_id', 'manifest_cache']))->from(\RegularLabs\Library\DB::quoteName('#__extensions'))->where(\RegularLabs\Library\DB::is('extension_id', (int) $id));
|
||||
$db->setQuery($query);
|
||||
return $db->loadObject();
|
||||
}
|
||||
/**
|
||||
* Return an element name based on the given extension alias
|
||||
*/
|
||||
public static function getElementByAlias(string $alias): string
|
||||
{
|
||||
$alias = self::getAliasByName($alias);
|
||||
return match ($alias) {
|
||||
'advancedmodulemanager' => 'advancedmodules',
|
||||
default => $alias,
|
||||
};
|
||||
}
|
||||
public static function getNameByAlias(string $alias): string
|
||||
{
|
||||
// Alias is a language string
|
||||
if (!str_contains($alias, ' ') && strtoupper($alias) == $alias) {
|
||||
return JText::_($alias);
|
||||
}
|
||||
// Alias has a space and/or capitals, so is already a name
|
||||
if (str_contains($alias, ' ') || $alias !== strtolower($alias)) {
|
||||
return $alias;
|
||||
}
|
||||
return JText::_(self::getXMLValue('name', $alias));
|
||||
}
|
||||
/**
|
||||
* Get the full path to the extension folder
|
||||
*/
|
||||
public static function getPath(string $extension = 'plg_system_regularlabs', string $basePath = JPATH_ADMINISTRATOR, string $check_folder = ''): string
|
||||
{
|
||||
$basePath = $basePath ?: JPATH_SITE;
|
||||
if (!in_array($basePath, [JPATH_ADMINISTRATOR, JPATH_SITE], \true)) {
|
||||
return $basePath;
|
||||
}
|
||||
$extension = str_replace('.sys', '', $extension);
|
||||
switch (\true) {
|
||||
case str_starts_with($extension, 'mod_'):
|
||||
$path = 'modules/' . $extension;
|
||||
break;
|
||||
case str_starts_with($extension, 'plg_'):
|
||||
[$prefix, $folder, $name] = explode('_', $extension, 3);
|
||||
$path = 'plugins/' . $folder . '/' . $name;
|
||||
break;
|
||||
case str_starts_with($extension, 'com_'):
|
||||
default:
|
||||
$path = 'components/' . $extension;
|
||||
break;
|
||||
}
|
||||
$check_folder = $check_folder ? '/' . $check_folder : '';
|
||||
if (is_dir($basePath . '/' . $path . $check_folder)) {
|
||||
return $basePath . '/' . $path;
|
||||
}
|
||||
if (is_dir(JPATH_ADMINISTRATOR . '/' . $path . $check_folder)) {
|
||||
return JPATH_ADMINISTRATOR . '/' . $path;
|
||||
}
|
||||
if (is_dir(JPATH_SITE . '/' . $path . $check_folder)) {
|
||||
return JPATH_SITE . '/' . $path;
|
||||
}
|
||||
return $basePath;
|
||||
}
|
||||
/**
|
||||
* Return an extensions main xml array
|
||||
*/
|
||||
public static function getXML(string $alias, string $type = '', string $folder = ''): array|false
|
||||
{
|
||||
$file = self::getXMLFile($alias, $type, $folder);
|
||||
if (!$file) {
|
||||
return \false;
|
||||
}
|
||||
return JInstaller::parseXMLInstallFile($file);
|
||||
}
|
||||
/**
|
||||
* Return an extensions main xml file name (including path)
|
||||
*/
|
||||
public static function getXMLFile(string $alias, string $type = '', string $folder = '', bool $get_params = \false): string
|
||||
{
|
||||
$element = self::getElementByAlias($alias);
|
||||
$files = [];
|
||||
// Components
|
||||
if (empty($type) || $type == 'component') {
|
||||
$file = $get_params ? 'config' : $element;
|
||||
$files[] = JPATH_ADMINISTRATOR . '/components/com_' . $element . '/' . $file . '.xml';
|
||||
$files[] = JPATH_SITE . '/components/com_' . $element . '/' . $file . '.xml';
|
||||
if (!$get_params) {
|
||||
$files[] = JPATH_ADMINISTRATOR . '/components/com_' . $element . '/com_' . $element . '.xml';
|
||||
$files[] = JPATH_SITE . '/components/com_' . $element . '/com_' . $element . '.xml';
|
||||
}
|
||||
}
|
||||
// Plugins
|
||||
if (empty($type) || $type == 'plugin') {
|
||||
if (!empty($folder)) {
|
||||
$files[] = JPATH_PLUGINS . '/' . $folder . '/' . $element . '/' . $element . '.xml';
|
||||
}
|
||||
// System Plugins
|
||||
$files[] = JPATH_PLUGINS . '/system/' . $element . '/' . $element . '.xml';
|
||||
// Editor Button Plugins
|
||||
$files[] = JPATH_PLUGINS . '/editors-xtd/' . $element . '/' . $element . '.xml';
|
||||
// Field Plugins
|
||||
$field_name = \RegularLabs\Library\RegEx::replace('field$', '', $element);
|
||||
$files[] = JPATH_PLUGINS . '/fields/' . $field_name . '/' . $field_name . '.xml';
|
||||
}
|
||||
// Modules
|
||||
if (empty($type) || $type == 'module') {
|
||||
$files[] = JPATH_ADMINISTRATOR . '/modules/mod_' . $element . '/' . $element . '.xml';
|
||||
$files[] = JPATH_SITE . '/modules/mod_' . $element . '/' . $element . '.xml';
|
||||
$files[] = JPATH_ADMINISTRATOR . '/modules/mod_' . $element . '/mod_' . $element . '.xml';
|
||||
$files[] = JPATH_SITE . '/modules/mod_' . $element . '/mod_' . $element . '.xml';
|
||||
}
|
||||
foreach ($files as $file) {
|
||||
if (!file_exists($file)) {
|
||||
continue;
|
||||
}
|
||||
return $file;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
/**
|
||||
* Return a value from an extensions main xml file based on the given key
|
||||
*/
|
||||
public static function getXMLValue(string $key, string $alias, string $type = '', string $folder = ''): string
|
||||
{
|
||||
$xml = self::getXML($alias, $type, $folder);
|
||||
if (!$xml) {
|
||||
return '';
|
||||
}
|
||||
if (!isset($xml[$key])) {
|
||||
return '';
|
||||
}
|
||||
return $xml[$key] ?? '';
|
||||
}
|
||||
public static function isAuthorised(bool $require_core_auth = \true): bool
|
||||
{
|
||||
$user = JFactory::getApplication()->getIdentity() ?: JFactory::getUser();
|
||||
if ($user->get('guest')) {
|
||||
return \false;
|
||||
}
|
||||
if (!$require_core_auth) {
|
||||
return \true;
|
||||
}
|
||||
if (!$user->authorise('core.edit', 'com_content') && !$user->authorise('core.edit.own', 'com_content') && !$user->authorise('core.create', 'com_content')) {
|
||||
return \false;
|
||||
}
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* Check if the Regular Labs Library is enabled
|
||||
*/
|
||||
public static function isEnabled(string $extension, string $type = 'component', string $folder = 'system'): bool
|
||||
{
|
||||
$extension = strtolower($extension);
|
||||
if (!self::isInstalled($extension, $type, $folder)) {
|
||||
return \false;
|
||||
}
|
||||
switch ($type) {
|
||||
case 'component':
|
||||
$extension = str_replace('com_', '', $extension);
|
||||
return JComponentHelper::isEnabled('com_' . $extension);
|
||||
case 'module':
|
||||
$extension = str_replace('mod_', '', $extension);
|
||||
return JModuleHelper::isEnabled('mod_' . $extension);
|
||||
case 'plugin':
|
||||
return JPluginHelper::isEnabled($folder, $extension);
|
||||
default:
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
public static function isEnabledInArea(object $params): bool
|
||||
{
|
||||
if (!isset($params->enable_frontend)) {
|
||||
return \true;
|
||||
}
|
||||
// Only allow in frontend
|
||||
if ($params->enable_frontend == 2 && \RegularLabs\Library\Document::isClient('administrator')) {
|
||||
return \false;
|
||||
}
|
||||
// Do not allow in frontend
|
||||
if (!$params->enable_frontend && \RegularLabs\Library\Document::isClient('site')) {
|
||||
return \false;
|
||||
}
|
||||
return \true;
|
||||
}
|
||||
public static function isEnabledInComponent(object $params): bool
|
||||
{
|
||||
if (!isset($params->disabled_components)) {
|
||||
return \true;
|
||||
}
|
||||
return !\RegularLabs\Library\Protect::isRestrictedComponent($params->disabled_components);
|
||||
}
|
||||
/**
|
||||
* Check if the Regular Labs Library is enabled
|
||||
*/
|
||||
public static function isFrameworkEnabled(): bool
|
||||
{
|
||||
return JPluginHelper::isEnabled('system', 'regularlabs');
|
||||
}
|
||||
public static function isInstalled(string $extension, string $type = 'component', string $folder = 'system'): bool
|
||||
{
|
||||
$extension = strtolower($extension);
|
||||
switch ($type) {
|
||||
case 'component':
|
||||
$extension = str_replace('com_', '', $extension);
|
||||
return file_exists(JPATH_ADMINISTRATOR . '/components/com_' . $extension . '/' . $extension . '.xml') || file_exists(JPATH_SITE . '/components/com_' . $extension . '/' . $extension . '.xml');
|
||||
case 'plugin':
|
||||
return file_exists(JPATH_PLUGINS . '/' . $folder . '/' . $extension . '/' . $extension . '.php');
|
||||
case 'module':
|
||||
$extension = str_replace('mod_', '', $extension);
|
||||
return file_exists(JPATH_ADMINISTRATOR . '/modules/mod_' . $extension . '/' . $extension . '.php') || file_exists(JPATH_ADMINISTRATOR . '/modules/mod_' . $extension . '/mod_' . $extension . '.php') || file_exists(JPATH_SITE . '/modules/mod_' . $extension . '/' . $extension . '.php') || file_exists(JPATH_SITE . '/modules/mod_' . $extension . '/mod_' . $extension . '.php');
|
||||
case 'library':
|
||||
$extension = str_replace('lib_', '', $extension);
|
||||
return JFolder::exists(JPATH_LIBRARIES . '/' . $extension);
|
||||
default:
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
public static function orderPluginFirst(string $name, string $folder = 'system'): void
|
||||
{
|
||||
$db = \RegularLabs\Library\DB::get();
|
||||
$query = \RegularLabs\Library\DB::getQuery()->select(['e.ordering'])->from(\RegularLabs\Library\DB::quoteName('#__extensions', 'e'))->where(\RegularLabs\Library\DB::is('e.type', 'plugin'))->where(\RegularLabs\Library\DB::is('e.folder', $folder))->where(\RegularLabs\Library\DB::is('e.element', $name));
|
||||
$db->setQuery($query);
|
||||
$current_ordering = $db->loadResult();
|
||||
if ($current_ordering == '') {
|
||||
return;
|
||||
}
|
||||
$query = \RegularLabs\Library\DB::getQuery()->select('e.ordering')->from(\RegularLabs\Library\DB::quoteName('#__extensions', 'e'))->where(\RegularLabs\Library\DB::is('e.type', 'plugin'))->where(\RegularLabs\Library\DB::is('e.folder', $folder))->where(\RegularLabs\Library\DB::like(\RegularLabs\Library\DB::quoteName('e.manifest_cache'), '%"author":"Regular Labs%'))->where(\RegularLabs\Library\DB::isNot('e.element', $name))->order('e.ordering ASC');
|
||||
$db->setQuery($query);
|
||||
$min_ordering = $db->loadResult();
|
||||
if ($min_ordering == '') {
|
||||
return;
|
||||
}
|
||||
if ($current_ordering < $min_ordering) {
|
||||
return;
|
||||
}
|
||||
if ($min_ordering < 1 || $current_ordering == $min_ordering) {
|
||||
$new_ordering = max($min_ordering, 1);
|
||||
$query = \RegularLabs\Library\DB::getQuery()->update(\RegularLabs\Library\DB::quoteName('#__extensions'))->set(\RegularLabs\Library\DB::quoteName('ordering') . ' = ' . $new_ordering)->where(\RegularLabs\Library\DB::is('ordering', $min_ordering))->where(\RegularLabs\Library\DB::is('type', 'plugin'))->where(\RegularLabs\Library\DB::is('folder', $folder))->where(\RegularLabs\Library\DB::isNot('element', $name))->where(\RegularLabs\Library\DB::like(\RegularLabs\Library\DB::quoteName('manifest_cache'), '%"author":"Regular Labs%'));
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
$min_ordering = $new_ordering;
|
||||
}
|
||||
if ($current_ordering == $min_ordering) {
|
||||
return;
|
||||
}
|
||||
$new_ordering = $min_ordering - 1;
|
||||
$query = $db->getQuery(\true)->update(\RegularLabs\Library\DB::quoteName('#__extensions'))->set(\RegularLabs\Library\DB::quoteName('ordering') . ' = ' . $new_ordering)->where(\RegularLabs\Library\DB::is('type', 'plugin'))->where(\RegularLabs\Library\DB::is('folder', $folder))->where(\RegularLabs\Library\DB::is('element', $name));
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
}
|
||||
}
|
||||
50
libraries/regularlabs/src/FieldHelper.php
Normal file
50
libraries/regularlabs/src/FieldHelper.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
class FieldHelper
|
||||
{
|
||||
private static $articles_field_names = null;
|
||||
public static function correctFieldValue(int|string $field_name, mixed &$field_value): void
|
||||
{
|
||||
if (is_array($field_value) && (count($field_value) > 1 || !isset($field_value[0]))) {
|
||||
foreach ($field_value as $key => &$value) {
|
||||
self::correctFieldValue($key, $value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!in_array($field_name, self::getArticlesFieldNames())) {
|
||||
return;
|
||||
}
|
||||
$field_value = (array) $field_value;
|
||||
if (count($field_value) == 1 && str_contains($field_value[0], ',')) {
|
||||
$field_value = explode(',', $field_value[0]);
|
||||
}
|
||||
}
|
||||
private static function getArticlesFieldNames(): array
|
||||
{
|
||||
if (!is_null(self::$articles_field_names)) {
|
||||
return self::$articles_field_names;
|
||||
}
|
||||
self::$articles_field_names = [];
|
||||
$db = \RegularLabs\Library\DB::get();
|
||||
$query = \RegularLabs\Library\DB::getQuery()->select([\RegularLabs\Library\DB::quoteName('f.name'), \RegularLabs\Library\DB::quoteName('f.id')])->from(\RegularLabs\Library\DB::quoteName('#__fields', 'f'))->where(\RegularLabs\Library\DB::quoteName('f.type') . ' = ' . $db->quote('articles'));
|
||||
$db->setQuery($query);
|
||||
$fields = $db->loadAssocList();
|
||||
foreach ($fields as $field) {
|
||||
self::$articles_field_names[] = 'field' . $field['id'];
|
||||
self::$articles_field_names[] = $field['name'];
|
||||
}
|
||||
return self::$articles_field_names;
|
||||
}
|
||||
}
|
||||
29
libraries/regularlabs/src/FieldsPlugin.php
Normal file
29
libraries/regularlabs/src/FieldsPlugin.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use JLoader;
|
||||
use Joomla\Component\Fields\Administrator\Plugin\FieldsPlugin as JFieldsPlugin;
|
||||
class FieldsPlugin extends JFieldsPlugin
|
||||
{
|
||||
public function __construct(&$subject, $config = [])
|
||||
{
|
||||
parent::__construct($subject, $config);
|
||||
$path = JPATH_PLUGINS . '/fields/' . $this->_name . '/src/Form/Field';
|
||||
if (!file_exists($path)) {
|
||||
return;
|
||||
}
|
||||
$name = str_replace('PlgFields', '', $this::class);
|
||||
JLoader::registerAlias('JFormField' . $name, '\RegularLabs\Plugin\Fields\\' . $name . '\Form\Field\\' . $name . 'Field');
|
||||
}
|
||||
}
|
||||
328
libraries/regularlabs/src/File.php
Normal file
328
libraries/regularlabs/src/File.php
Normal file
@ -0,0 +1,328 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Client\ClientHelper as JClientHelper;
|
||||
use Joomla\CMS\Client\FtpClient as JFtpClient;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
use Joomla\CMS\Filesystem\Folder as JFolder;
|
||||
use Joomla\CMS\Filesystem\Path as JPath;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use Joomla\CMS\Log\Log as JLog;
|
||||
use Joomla\CMS\Uri\Uri as JUri;
|
||||
class File
|
||||
{
|
||||
static $is_external = [];
|
||||
/**
|
||||
* some/url/to/a/file.ext
|
||||
* > some/url/to/a/file_suffix.ext
|
||||
*/
|
||||
public static function addSuffix(string $url, string $suffix): string
|
||||
{
|
||||
$url = \RegularLabs\Library\StringHelper::normalize($url);
|
||||
$info = pathinfo($url);
|
||||
return ($info['dirname'] ?? '') . '/' . ($info['filename'] ?? '') . $suffix . '.' . ($info['extension'] ?? '');
|
||||
}
|
||||
/**
|
||||
* Delete a file or array of files
|
||||
*/
|
||||
public static function delete(string|array $file, bool $show_messages = \false, int $min_age_in_minutes = 0): bool
|
||||
{
|
||||
$FTPOptions = JClientHelper::getCredentials('ftp');
|
||||
$pathObject = new JPath();
|
||||
$files = is_array($file) ? $file : [$file];
|
||||
if ($FTPOptions['enabled'] == 1) {
|
||||
// Connect the FTP client
|
||||
$ftp = JFtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], [], $FTPOptions['user'], $FTPOptions['pass']);
|
||||
}
|
||||
foreach ($files as $file) {
|
||||
$file = $pathObject->clean($file);
|
||||
if (!is_file($file)) {
|
||||
continue;
|
||||
}
|
||||
if ($min_age_in_minutes && floor((time() - filemtime($file)) / 60) < $min_age_in_minutes) {
|
||||
continue;
|
||||
}
|
||||
// Try making the file writable first. If it's read-only, it can't be deleted
|
||||
// on Windows, even if the parent folder is writable
|
||||
@chmod($file, 0777);
|
||||
if ($FTPOptions['enabled'] == 1) {
|
||||
$file = $pathObject->clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $file), '/');
|
||||
if (!$ftp->delete($file)) {
|
||||
// FTP connector throws an error
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
// Try the unlink twice in case something was blocking it on first try
|
||||
if (!@unlink($file) && !@unlink($file)) {
|
||||
$show_messages && JLog::add(JText::sprintf('JLIB_FILESYSTEM_DELETE_FAILED', basename($file)), JLog::WARNING, 'jerror');
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* Delete a folder.
|
||||
*/
|
||||
public static function deleteFolder(string $path, bool $show_messages = \false, int $min_age_in_minutes = 0): bool
|
||||
{
|
||||
@set_time_limit(ini_get('max_execution_time'));
|
||||
$pathObject = new JPath();
|
||||
if (!$path) {
|
||||
$show_messages && JLog::add(__METHOD__ . ': ' . JText::_('JLIB_FILESYSTEM_ERROR_DELETE_BASE_DIRECTORY'), JLog::WARNING, 'jerror');
|
||||
return \false;
|
||||
}
|
||||
// Check to make sure the path valid and clean
|
||||
$path = $pathObject->clean($path);
|
||||
if (!is_dir($path)) {
|
||||
$show_messages && JLog::add(JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER', $path), JLog::WARNING, 'jerror');
|
||||
return \false;
|
||||
}
|
||||
// Remove all the files in folder if they exist; disable all filtering
|
||||
$files = JFolder::files($path, '.', \false, \true, [], []);
|
||||
if (!empty($files)) {
|
||||
if (self::delete($files, $show_messages, $min_age_in_minutes) !== \true) {
|
||||
// JFile::delete throws an error
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
// Remove sub-folders of folder; disable all filtering
|
||||
$folders = JFolder::folders($path, '.', \false, \true, [], []);
|
||||
foreach ($folders as $folder) {
|
||||
if (is_link($folder)) {
|
||||
// Don't descend into linked directories, just delete the link.
|
||||
if (self::delete($folder, $show_messages, $min_age_in_minutes) !== \true) {
|
||||
return \false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!self::deleteFolder($folder, $show_messages, $min_age_in_minutes)) {
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
// Skip if folder is not empty yet
|
||||
if (!empty(JFolder::files($path, '.', \false, \true, [], [])) || !empty(JFolder::folders($path, '.', \false, \true, [], []))) {
|
||||
return \true;
|
||||
}
|
||||
if (@rmdir($path)) {
|
||||
return \true;
|
||||
}
|
||||
$FTPOptions = JClientHelper::getCredentials('ftp');
|
||||
if ($FTPOptions['enabled'] == 1) {
|
||||
// Connect the FTP client
|
||||
$ftp = JFtpClient::getInstance($FTPOptions['host'], $FTPOptions['port'], [], $FTPOptions['user'], $FTPOptions['pass']);
|
||||
// Translate path and delete
|
||||
$path = $pathObject->clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $path), '/');
|
||||
// FTP connector throws an error
|
||||
return $ftp->delete($path);
|
||||
}
|
||||
if (!@rmdir($path)) {
|
||||
$show_messages && JLog::add(JText::sprintf('JLIB_FILESYSTEM_ERROR_FOLDER_DELETE', $path), JLog::WARNING, 'jerror');
|
||||
return \false;
|
||||
}
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* some/url/to/a/file.ext
|
||||
* > file.ext
|
||||
*/
|
||||
public static function getBaseName(string $url, bool $lowercase = \false): string
|
||||
{
|
||||
$url = \RegularLabs\Library\StringHelper::normalize($url);
|
||||
$basename = ltrim(basename($url), '/');
|
||||
$parts = explode('?', $basename);
|
||||
$basename = $parts[0];
|
||||
if ($lowercase) {
|
||||
$basename = strtolower($basename);
|
||||
}
|
||||
return $basename;
|
||||
}
|
||||
/**
|
||||
* some/url/to/a/file.ext
|
||||
* > some/url/to/a
|
||||
*/
|
||||
public static function getDirName(string $url): string
|
||||
{
|
||||
$url = \RegularLabs\Library\StringHelper::normalize($url);
|
||||
$url = strtok($url, '?');
|
||||
$url = strtok($url, '#');
|
||||
return rtrim(dirname($url), '/');
|
||||
}
|
||||
/**
|
||||
* some/url/to/a/file.ext
|
||||
* > ext
|
||||
*/
|
||||
public static function getExtension(string $url): string
|
||||
{
|
||||
$info = pathinfo($url);
|
||||
if (!isset($info['extension'])) {
|
||||
return '';
|
||||
}
|
||||
$ext = explode('?', $info['extension']);
|
||||
return strtolower($ext[0]);
|
||||
}
|
||||
/**
|
||||
* some/url/to/a/file.ext
|
||||
* > file
|
||||
*/
|
||||
public static function getFileName(string $url, bool $lowercase = \false): string
|
||||
{
|
||||
$url = \RegularLabs\Library\StringHelper::normalize($url);
|
||||
$info = @pathinfo($url);
|
||||
$filename = $info['filename'] ?? $url;
|
||||
if ($lowercase) {
|
||||
$filename = strtolower($filename);
|
||||
}
|
||||
return $filename;
|
||||
}
|
||||
public static function getFileTypes(string $type = 'images'): array
|
||||
{
|
||||
return match ($type) {
|
||||
'image', 'images' => ['bmp', 'flif', 'gif', 'jpe', 'jpeg', 'jpg', 'png', 'tiff', 'eps', 'webp'],
|
||||
'audio' => ['aif', 'aiff', 'mp3', 'wav'],
|
||||
'video', 'videos' => ['3g2', '3gp', 'avi', 'divx', 'f4v', 'flv', 'm4v', 'mov', 'mp4', 'mpe', 'mpeg', 'mpg', 'ogv', 'swf', 'webm', 'wmv'],
|
||||
'document', 'documents' => ['doc', 'docm', 'docx', 'dotm', 'dotx', 'odb', 'odc', 'odf', 'odg', 'odi', 'odm', 'odp', 'ods', 'odt', 'onepkg', 'onetmp', 'onetoc', 'onetoc2', 'otg', 'oth', 'otp', 'ots', 'ott', 'oxt', 'pdf', 'potm', 'potx', 'ppam', 'pps', 'ppsm', 'ppsx', 'ppt', 'pptm', 'pptx', 'rtf', 'sldm', 'sldx', 'thmx', 'xla', 'xlam', 'xlc', 'xld', 'xll', 'xlm', 'xls', 'xlsb', 'xlsm', 'xlsx', 'xlt', 'xltm', 'xltx', 'xlw'],
|
||||
'other', 'others' => ['css', 'csv', 'js', 'json', 'tar', 'txt', 'xml', 'zip'],
|
||||
default => [...self::getFileTypes('images'), ...self::getFileTypes('audio'), ...self::getFileTypes('videos'), ...self::getFileTypes('documents'), ...self::getFileTypes('other')],
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Find a matching media file in the different possible extension media folders for given type
|
||||
*/
|
||||
public static function getMediaFile(string $type, string $file): bool|string
|
||||
{
|
||||
// If http is present in filename
|
||||
if (str_starts_with($file, 'http') || str_starts_with($file, '//')) {
|
||||
return $file;
|
||||
}
|
||||
$files = [];
|
||||
// Detect debug mode
|
||||
if (\RegularLabs\Library\Document::isDebug()) {
|
||||
$files[] = str_replace(['.min.', '-min.'], '.', $file);
|
||||
}
|
||||
$files[] = $file;
|
||||
/**
|
||||
* Loop on 1 or 2 files and break on first find.
|
||||
* Add the content of the MD5SUM file located in the same folder to url to ensure cache browser refresh
|
||||
* This MD5SUM file must represent the signature of the folder content
|
||||
*/
|
||||
foreach ($files as $check_file) {
|
||||
$file_found = self::findMediaFileByFile($check_file, $type);
|
||||
if (!$file_found) {
|
||||
continue;
|
||||
}
|
||||
return $file_found;
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
public static function isDocument(string $url): bool
|
||||
{
|
||||
return self::isMedia($url, self::getFileTypes('documents'));
|
||||
}
|
||||
public static function isExternal(string $url): bool
|
||||
{
|
||||
if (isset(static::$is_external[$url])) {
|
||||
return static::$is_external[$url];
|
||||
}
|
||||
$uri = parse_url($url);
|
||||
if (empty($uri['host'])) {
|
||||
static::$is_external[$url] = \false;
|
||||
return static::$is_external[$url];
|
||||
}
|
||||
// give preference to SERVER_NAME, because this includes subdomains
|
||||
$hostname = $_SERVER['SERVER_NAME'] ?: $_SERVER['HTTP_HOST'];
|
||||
static::$is_external[$url] = !(strcasecmp($hostname, $uri['host']) === 0);
|
||||
return static::$is_external[$url];
|
||||
}
|
||||
public static function isExternalVideo(string $url): bool
|
||||
{
|
||||
return str_contains($url, 'youtu.be') || str_contains($url, 'youtube.com') || str_contains($url, 'vimeo.com');
|
||||
}
|
||||
public static function isImage($url)
|
||||
{
|
||||
return self::isMedia($url, self::getFileTypes('images'));
|
||||
}
|
||||
public static function isInternal(string $url): bool
|
||||
{
|
||||
return !self::isExternal($url);
|
||||
}
|
||||
public static function isMedia(string $url, array|string $filetypes = []): bool
|
||||
{
|
||||
$filetype = self::getExtension($url);
|
||||
if (empty($filetype)) {
|
||||
return \false;
|
||||
}
|
||||
if (!is_array($filetypes)) {
|
||||
$filetypes = [$filetypes];
|
||||
}
|
||||
if (count($filetypes) == 1 && str_contains($filetypes[0], ',')) {
|
||||
$filetypes = \RegularLabs\Library\ArrayHelper::toArray($filetypes[0]);
|
||||
}
|
||||
$filetypes = $filetypes ?? null ?: self::getFileTypes();
|
||||
return in_array($filetype, $filetypes);
|
||||
}
|
||||
public static function isVideo(string $url): bool
|
||||
{
|
||||
return self::isMedia($url, self::getFileTypes('videos'));
|
||||
}
|
||||
public static function trimFolder(string $folder): string
|
||||
{
|
||||
return trim(str_replace(['\\', '//'], '/', $folder), '/');
|
||||
}
|
||||
/**
|
||||
* Find a matching media file in the different possible extension media folders for given type
|
||||
*/
|
||||
private static function findMediaFileByFile(string $file, string $type): string|false
|
||||
{
|
||||
$template = JFactory::getApplication()->getTemplate();
|
||||
// If the file is in the template folder
|
||||
$file_found = self::getFileUrl('/templates/' . $template . '/' . $type . '/' . $file);
|
||||
if ($file_found) {
|
||||
return $file_found;
|
||||
}
|
||||
// Try to deal with system files in the media folder
|
||||
if (!str_contains($file, '/')) {
|
||||
$file_found = self::getFileUrl('/media/system/' . $type . '/' . $file);
|
||||
if (!$file_found) {
|
||||
return \false;
|
||||
}
|
||||
return $file_found;
|
||||
}
|
||||
$paths = [];
|
||||
// If the file contains any /: it can be in a media extension subfolder
|
||||
// Divide the file extracting the extension as the first part before /
|
||||
[$extension, $file] = explode('/', $file, 2);
|
||||
$paths[] = '/media/' . $extension . '/' . $type;
|
||||
$paths[] = '/templates/' . $template . '/' . $type . '/system';
|
||||
$paths[] = '/media/system/' . $type;
|
||||
$paths[] = '';
|
||||
foreach ($paths as $path) {
|
||||
$file_found = self::getFileUrl($path . '/' . $file);
|
||||
if (!$file_found) {
|
||||
continue;
|
||||
}
|
||||
return $file_found;
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Get the url for the file
|
||||
*/
|
||||
private static function getFileUrl(string $path): string|false
|
||||
{
|
||||
if (!file_exists(JPATH_ROOT . $path)) {
|
||||
return \false;
|
||||
}
|
||||
return JUri::root(\true) . $path;
|
||||
}
|
||||
}
|
||||
37
libraries/regularlabs/src/Form/Field/AccessLevelsField.php
Normal file
37
libraries/regularlabs/src/Form/Field/AccessLevelsField.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use RegularLabs\Library\DB as RL_DB;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class AccessLevelsField extends RL_FormField
|
||||
{
|
||||
static $options;
|
||||
public bool $is_select_list = \true;
|
||||
public function getNamesByIds(array $values, array $attributes): array
|
||||
{
|
||||
$query = $this->db->getQuery(\true)->select('a.title')->from('#__viewlevels AS a')->where(RL_DB::is('a.id', $values))->order('a.ordering ASC');
|
||||
$this->db->setQuery($query);
|
||||
return $this->db->loadColumn();
|
||||
}
|
||||
protected function getOptions()
|
||||
{
|
||||
if (!is_null(self::$options)) {
|
||||
return self::$options;
|
||||
}
|
||||
$query = $this->db->getQuery(\true)->select('a.id as value, a.title as text')->from('#__viewlevels AS a')->order('a.ordering ASC');
|
||||
$this->db->setQuery($query);
|
||||
self::$options = $this->db->loadObjectList();
|
||||
return self::$options;
|
||||
}
|
||||
}
|
||||
91
libraries/regularlabs/src/Form/Field/AgentsField.php
Normal file
91
libraries/regularlabs/src/Form/Field/AgentsField.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\HTML\HTMLHelper as JHtml;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class AgentsField extends RL_FormField
|
||||
{
|
||||
public $attributes = ['group' => 'os'];
|
||||
public bool $is_select_list = \true;
|
||||
public function getNamesByIds(array $values, array $attributes): array
|
||||
{
|
||||
$agents = $this->getAgents($attributes);
|
||||
$names = [];
|
||||
foreach ($agents as $agent) {
|
||||
if (!in_array($agent[1], $values)) {
|
||||
continue;
|
||||
}
|
||||
$names[] = $agent[0];
|
||||
}
|
||||
return $names;
|
||||
}
|
||||
protected function getListOptions(array $attributes): array|int
|
||||
{
|
||||
$agents = $this->getAgents($attributes);
|
||||
$options = [];
|
||||
foreach ($agents as $agent) {
|
||||
$option = JHtml::_('select.option', $agent[1], $agent[0]);
|
||||
$options[] = $option;
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
private function getAgents(array $attributes): array
|
||||
{
|
||||
$agents = [];
|
||||
switch ($attributes['group']) {
|
||||
/* OS */
|
||||
case 'os':
|
||||
$agents[] = ['Windows', 'Windows'];
|
||||
$agents[] = ['Mac OS', '#(Mac OS|Mac_PowerPC|Macintosh)#'];
|
||||
$agents[] = ['Linux', '#(Linux|X11)#'];
|
||||
$agents[] = ['Open BSD', 'OpenBSD'];
|
||||
$agents[] = ['Sun OS', 'SunOS'];
|
||||
$agents[] = ['QNX', 'QNX'];
|
||||
$agents[] = ['BeOS', 'BeOS'];
|
||||
$agents[] = ['OS/2', 'OS/2'];
|
||||
break;
|
||||
/* Browsers */
|
||||
case 'browser':
|
||||
$agents[] = ['Chrome', 'Chrome'];
|
||||
$agents[] = ['Firefox', 'Firefox'];
|
||||
$agents[] = ['Microsoft Edge', 'MSIE Edge'];
|
||||
// missing MSIE is added to agent string in RegularLabs\Component\Conditions\Administrator\Condition\Agent\Agent
|
||||
$agents[] = ['Internet Explorer', 'MSIE [0-9]'];
|
||||
// missing MSIE is added to agent string in RegularLabs\Component\Conditions\Administrator\Condition\Agent\Agent
|
||||
$agents[] = ['Opera', 'Opera'];
|
||||
$agents[] = ['Safari', 'Safari'];
|
||||
break;
|
||||
/* Mobile browsers */
|
||||
case 'mobile':
|
||||
$agents[] = [JText::_('JALL'), 'mobile'];
|
||||
$agents[] = ['Android', 'Android'];
|
||||
$agents[] = ['Android Chrome', '#Android.*Chrome#'];
|
||||
$agents[] = ['Blackberry', 'Blackberry'];
|
||||
$agents[] = ['IE Mobile', 'IEMobile'];
|
||||
$agents[] = ['iPad', 'iPad'];
|
||||
$agents[] = ['iPhone', 'iPhone'];
|
||||
$agents[] = ['iPod Touch', 'iPod'];
|
||||
$agents[] = ['NetFront', 'NetFront'];
|
||||
$agents[] = ['Nokia', 'NokiaBrowser'];
|
||||
$agents[] = ['Opera Mini', 'Opera Mini'];
|
||||
$agents[] = ['Opera Mobile', 'Opera Mobi'];
|
||||
$agents[] = ['UC Browser', 'UC Browser'];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return $agents;
|
||||
}
|
||||
}
|
||||
54
libraries/regularlabs/src/Form/Field/AjaxField.php
Normal file
54
libraries/regularlabs/src/Form/Field/AjaxField.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use RegularLabs\Library\Document as RL_Document;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class AjaxField extends RL_FormField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
$class = $this->get('class', 'btn btn-success');
|
||||
if ($this->get('disabled')) {
|
||||
return $this->getButton($class . ' disabled', 'disabled');
|
||||
}
|
||||
RL_Document::script('regularlabs.admin-form');
|
||||
RL_Document::script('regularlabs.regular');
|
||||
RL_Document::script('regularlabs.script');
|
||||
$query = '';
|
||||
$url_query = $this->get('url-query');
|
||||
if ($url_query) {
|
||||
$name_prefix = $this->form->getFormControl() . '\\\\[' . $this->group . '\\\\]';
|
||||
$id_prefix = $this->form->getFormControl() . '_' . $this->group . '_';
|
||||
$query_parts = [];
|
||||
$url_query = explode(',', $url_query);
|
||||
foreach ($url_query as $url_query_part) {
|
||||
[$key, $id] = explode(':', $url_query_part);
|
||||
$el_name = 'document.querySelector(`input[name=' . $name_prefix . '\\\\[' . $id . '\\\\]]:checked`)';
|
||||
$el_id = 'document.querySelector(`#' . $id_prefix . $id . '`)';
|
||||
$query_parts[] = '`&' . $key . '=`' . ' + encodeURI(' . $el_name . ' ? ' . $el_name . '.value : (' . $el_id . ' ? ' . $el_id . '.value' . ' : ``))';
|
||||
}
|
||||
$query = '+' . implode('+', $query_parts);
|
||||
}
|
||||
$url = '`' . addslashes($this->get('url')) . '`' . $query;
|
||||
$attributes = 'onclick="RegularLabs.AdminForm.loadAjaxButton(`' . $this->id . '`, ' . $url . ')"';
|
||||
return $this->getButton($class, $attributes);
|
||||
}
|
||||
private function getButton(string $class = 'btn btn-success', string $attributes_string = ''): string
|
||||
{
|
||||
$icon = $this->get('icon', '') ? 'icon-' . $this->get('icon', '') : '';
|
||||
$attributes_string = $attributes_string ? ' ' . $attributes_string : '';
|
||||
return '<button type="button" id="' . $this->id . '" class="' . $class . '"' . ' title="' . JText::_($this->get('description')) . '"' . $attributes_string . '>' . '<span class="' . $icon . '"></span> ' . '<span>' . JText::_($this->get('text', $this->get('label'))) . '</span>' . '</button>' . '<div id="message_' . $this->id . '"></div>';
|
||||
}
|
||||
}
|
||||
48
libraries/regularlabs/src/Form/Field/BlockField.php
Normal file
48
libraries/regularlabs/src/Form/Field/BlockField.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Form\FormHelper as JFormHelper;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class BlockField extends RL_FormField
|
||||
{
|
||||
protected $hiddenDescription = \true;
|
||||
protected function getInput()
|
||||
{
|
||||
if ($this->get('end', 0)) {
|
||||
return $this->getControlGroupEnd() . '</fieldset>' . $this->getControlGroupStart();
|
||||
}
|
||||
$title = $this->get('label');
|
||||
$description = $this->get('description');
|
||||
$class = $this->get('class');
|
||||
$no_default_class = $this->get('no_default_class');
|
||||
$html = [];
|
||||
$attributes = 'class="' . ($no_default_class ? '' : 'options-form ') . $class . '"';
|
||||
if ($this->get('showon')) {
|
||||
$encodedConditions = json_encode(JFormHelper::parseShowOnConditions($this->get('showon'), $this->formControl, $this->group));
|
||||
$attributes .= " data-showon='" . $encodedConditions . "'";
|
||||
}
|
||||
$html[] = '<fieldset ' . $attributes . '>';
|
||||
if ($title) {
|
||||
$html[] = '<legend>' . $this->prepareText($title) . '</legend>';
|
||||
}
|
||||
if ($description) {
|
||||
$html[] = '<div class="form-text mb-3">' . $this->prepareText($description) . '</div>';
|
||||
}
|
||||
return $this->getControlGroupEnd() . implode('', $html) . $this->getControlGroupStart();
|
||||
}
|
||||
protected function getLabel()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
119
libraries/regularlabs/src/Form/Field/CheckboxesField.php
Normal file
119
libraries/regularlabs/src/Form/Field/CheckboxesField.php
Normal file
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Form\Field\CheckboxesField as JCheckboxesField;
|
||||
use Joomla\CMS\Form\FormHelper;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use SimpleXMLElement;
|
||||
use UnexpectedValueException;
|
||||
use function count;
|
||||
class CheckboxesField extends JCheckboxesField
|
||||
{
|
||||
/**
|
||||
* Name of the layout being used to render the field
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $layout = 'regularlabs.form.field.checkboxes';
|
||||
protected function getLayoutPaths()
|
||||
{
|
||||
$paths = parent::getLayoutPaths();
|
||||
$paths[] = JPATH_LIBRARIES . '/regularlabs/layouts';
|
||||
return $paths;
|
||||
}
|
||||
protected function getOptions()
|
||||
{
|
||||
$groups = $this->getGroups();
|
||||
return self::flattenGroups($groups);
|
||||
}
|
||||
private static function flattenGroups(array $groups): array
|
||||
{
|
||||
$options = [];
|
||||
foreach ($groups as $group_name => $group) {
|
||||
if ($group_name !== 0) {
|
||||
$options[] = $group_name;
|
||||
}
|
||||
foreach ($group as $option) {
|
||||
$options[] = $option;
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
private function getGroups(): array
|
||||
{
|
||||
$fieldname = preg_replace('/[^a-zA-Z0-9_\-]/', '_', $this->fieldname);
|
||||
$groups = [];
|
||||
$label = 0;
|
||||
foreach ($this->element->children() as $element) {
|
||||
switch ($element->getName()) {
|
||||
// The element is an <option />
|
||||
case 'option':
|
||||
if (!isset($groups[$label])) {
|
||||
$groups[$label] = [];
|
||||
}
|
||||
$groups[$label][] = $this->getOption($element, $fieldname);
|
||||
break;
|
||||
// The element is a <group />
|
||||
case 'group':
|
||||
// Get the group label.
|
||||
$groupLabel = (string) $element['label'];
|
||||
if ($groupLabel) {
|
||||
$label = JText::_($groupLabel);
|
||||
}
|
||||
// Initialize the group if necessary.
|
||||
if (!isset($groups[$label])) {
|
||||
$groups[$label] = [];
|
||||
}
|
||||
// Iterate through the children and build an array of options.
|
||||
foreach ($element->children() as $option) {
|
||||
// Only add <option /> elements.
|
||||
if ($option->getName() !== 'option') {
|
||||
continue;
|
||||
}
|
||||
$groups[$label][] = $this->getOption($option, $fieldname);
|
||||
}
|
||||
if ($groupLabel) {
|
||||
$label = count($groups);
|
||||
}
|
||||
break;
|
||||
// Unknown element type.
|
||||
default:
|
||||
throw new UnexpectedValueException(sprintf('Unsupported element %s in GroupedlistField', $element->getName()), 500);
|
||||
}
|
||||
}
|
||||
reset($groups);
|
||||
return $groups;
|
||||
}
|
||||
private function getOption(SimpleXMLElement $option, string $fieldname): object
|
||||
{
|
||||
$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';
|
||||
$tmp = ['value' => $value, 'text' => JText::alt($text, $fieldname), 'disable' => $disabled, 'class' => (string) $option['class'], 'selected' => $checked || $selected, 'checked' => $checked || $selected];
|
||||
// Set some event handler attributes. But really, should be using unobtrusive js.
|
||||
$tmp['onclick'] = (string) $option['onclick'];
|
||||
$tmp['onchange'] = (string) $option['onchange'];
|
||||
if ((string) $option['showon']) {
|
||||
$encodedConditions = json_encode(FormHelper::parseShowOnConditions((string) $option['showon'], $this->formControl, $this->group));
|
||||
$tmp['optionattr'] = " data-showon='" . $encodedConditions . "'";
|
||||
}
|
||||
return (object) $tmp;
|
||||
}
|
||||
}
|
||||
101
libraries/regularlabs/src/Form/Field/ComponentsField.php
Normal file
101
libraries/regularlabs/src/Form/Field/ComponentsField.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Filesystem\Folder as JFolder;
|
||||
use Joomla\CMS\HTML\HTMLHelper as JHtml;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use RegularLabs\Library\DB as RL_DB;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
use RegularLabs\Library\RegEx as RL_RegEx;
|
||||
class ComponentsField extends RL_FormField
|
||||
{
|
||||
static $components;
|
||||
public $attributes = ['frontend' => \true, 'admin' => \true];
|
||||
public bool $is_select_list = \true;
|
||||
public bool $use_ajax = \true;
|
||||
public function getNamesByIds(array $values, array $attributes): array
|
||||
{
|
||||
$query = $this->db->getQuery(\true)->select('e.name, e.element')->from('#__extensions AS e')->where('e.type = ' . $this->db->quote('component'))->where(RL_DB::is('e.element', $values))->order('e.name');
|
||||
$this->db->setQuery($query);
|
||||
$components = $this->db->loadObjectList();
|
||||
$lang = $this->app->getLanguage();
|
||||
$names = [];
|
||||
foreach ($components as $component) {
|
||||
$name = $component->name;
|
||||
if (!str_contains($component->name, ' ')) {
|
||||
// Load the core file then
|
||||
// Load extension-local file.
|
||||
$lang->load($component->element . '.sys', JPATH_BASE, null, \false, \false) || $lang->load($component->element . '.sys', JPATH_ADMINISTRATOR . '/components/' . $component->element, null, \false, \false) || $lang->load($component->element . '.sys', JPATH_BASE, $lang->getDefault(), \false, \false) || $lang->load($component->element . '.sys', JPATH_ADMINISTRATOR . '/components/' . $component->element, $lang->getDefault(), \false, \false);
|
||||
$name = JText::_(strtoupper($name));
|
||||
}
|
||||
$names[] = $name;
|
||||
}
|
||||
return $names;
|
||||
}
|
||||
protected function getListOptions(array $attributes): array|int
|
||||
{
|
||||
$frontend = $attributes['frontend'];
|
||||
$admin = $attributes['admin'];
|
||||
if (!$frontend && !$admin) {
|
||||
return [];
|
||||
}
|
||||
$components = $this->getComponents();
|
||||
$comps = [];
|
||||
$lang = $this->app->getLanguage();
|
||||
foreach ($components as $component) {
|
||||
if (empty($component->element)) {
|
||||
continue;
|
||||
}
|
||||
$component_folder = ($frontend ? JPATH_SITE : JPATH_ADMINISTRATOR) . '/components/' . $component->element;
|
||||
if (!JFolder::exists($component_folder) && $admin) {
|
||||
$component_folder = JPATH_ADMINISTRATOR . '/components/' . $component->element;
|
||||
}
|
||||
// return if there is no main component folder
|
||||
if (!JFolder::exists($component_folder)) {
|
||||
continue;
|
||||
}
|
||||
// return if there is no view(s) folder
|
||||
if ($component->element !== 'com_ajax' && !JFolder::exists($component_folder . '/src/View') && !JFolder::exists($component_folder . '/views') && !JFolder::exists($component_folder . '/view')) {
|
||||
continue;
|
||||
}
|
||||
if (!str_contains($component->name, ' ')) {
|
||||
// Load the core file then
|
||||
// Load extension-local file.
|
||||
$lang->load($component->element . '.sys', JPATH_BASE, null, \false, \false) || $lang->load($component->element . '.sys', JPATH_ADMINISTRATOR . '/components/' . $component->element, null, \false, \false) || $lang->load($component->element . '.sys', JPATH_BASE, $lang->getDefault(), \false, \false) || $lang->load($component->element . '.sys', JPATH_ADMINISTRATOR . '/components/' . $component->element, $lang->getDefault(), \false, \false);
|
||||
$component->name = JText::_(strtoupper($component->name));
|
||||
}
|
||||
$comps[RL_RegEx::replace('[^a-z0-9_]', '', $component->name . '_' . $component->element)] = $component;
|
||||
}
|
||||
ksort($comps);
|
||||
$options = [];
|
||||
foreach ($comps as $component) {
|
||||
$key = $component->element;
|
||||
if ($this->get('no_com_prefix')) {
|
||||
$key = RL_RegEx::replace('^com_', '', $key);
|
||||
}
|
||||
$options[] = JHtml::_('select.option', $key, $component->name);
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
private function getComponents(): array
|
||||
{
|
||||
if (!is_null(self::$components)) {
|
||||
return self::$components;
|
||||
}
|
||||
$query = $this->db->getQuery(\true)->select('e.name, e.element')->from('#__extensions AS e')->where('e.type = ' . $this->db->quote('component'))->where('e.name != ""')->where('e.element != ""')->group('e.element')->order('e.element, e.name');
|
||||
$this->db->setQuery($query);
|
||||
self::$components = $this->db->loadObjectList();
|
||||
return self::$components;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\HTML\HTMLHelper as JHtml;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use RegularLabs\Library\DB as RL_DB;
|
||||
use RegularLabs\Library\Form\Form;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class ContentArticlesField extends RL_FormField
|
||||
{
|
||||
public bool $is_select_list = \true;
|
||||
public bool $use_ajax = \true;
|
||||
public function getNamesByIds(array $values, array $attributes): array
|
||||
{
|
||||
$query = $this->db->getQuery(\true)->from('#__content AS i')->select('i.id, i.title as name, i.language, c.title as category, i.state as published')->join('LEFT', '#__categories AS c ON c.id = i.catid')->where(RL_DB::is('i.id', $values))->order('i.title, i.ordering, i.id');
|
||||
$this->db->setQuery($query);
|
||||
$articles = $this->db->loadObjectList();
|
||||
return Form::getNamesWithExtras($articles, ['language', 'category', 'id', 'unpublished']);
|
||||
}
|
||||
protected function getOptions()
|
||||
{
|
||||
if ($this->max_list_count) {
|
||||
$query = $this->db->getQuery(\true)->select('COUNT(*)')->from('#__content AS i')->where('i.access > -1')->where('i.state > -1');
|
||||
$this->db->setQuery($query);
|
||||
$total = $this->db->loadResult();
|
||||
if ($total > $this->max_list_count) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
$id = 'i.id';
|
||||
$extras = ['language', 'category', 'id', 'unpublished'];
|
||||
if ($this->get('id_alias_name_as_value', 0)) {
|
||||
$id = 'CONCAT(i.id, "::", i.alias, "::", i.title) AS id';
|
||||
$extras = ['language', 'category', 'id_number', 'unpublished'];
|
||||
}
|
||||
$query->clear('select')->select($id . ', i.id AS id_number, i.title AS name, i.language, c.title AS category, i.state AS published')->join('LEFT', '#__categories AS c ON c.id = i.catid')->order('i.title, i.ordering, i.id');
|
||||
$this->db->setQuery($query);
|
||||
$list = $this->db->loadObjectList();
|
||||
$options = $this->getOptionsByList($list, $extras);
|
||||
if ($this->get('showselect')) {
|
||||
array_unshift($options, JHtml::_('select.option', '-', ' ', 'value', 'text', \true));
|
||||
array_unshift($options, JHtml::_('select.option', '-', '- ' . JText::_('Select Item') . ' -'));
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use RegularLabs\Library\ArrayHelper as RL_Array;
|
||||
use RegularLabs\Library\DB as RL_DB;
|
||||
use RegularLabs\Library\Form\Form as RL_Form;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class ContentCategoriesField extends RL_FormField
|
||||
{
|
||||
public bool $is_select_list = \true;
|
||||
public bool $use_ajax = \true;
|
||||
public bool $use_tree_select = \true;
|
||||
public function getNamesByIds(array $values, array $attributes): array
|
||||
{
|
||||
$query = $this->db->getQuery(\true)->select('c.id, c.title as name, c.published, c.language')->from('#__categories AS c')->where('c.extension = ' . $this->db->quote('com_content'))->where(RL_DB::is('c.id', $values))->order('c.lft');
|
||||
$this->db->setQuery($query);
|
||||
$categories = $this->db->loadObjectList();
|
||||
return RL_Form::getNamesWithExtras($categories, ['language', 'unpublished']);
|
||||
}
|
||||
protected function getOptions()
|
||||
{
|
||||
if ($this->max_list_count) {
|
||||
$query = $this->db->getQuery(\true)->select('COUNT(*)')->from('#__categories as c')->where('c.extension = ' . $this->db->quote('com_content'))->where('c.parent_id > 0')->where('c.published > -1');
|
||||
$this->db->setQuery($query);
|
||||
$total = $this->db->loadResult();
|
||||
if ($total > $this->max_list_count) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
$this->value = RL_Array::toArray($this->value);
|
||||
$query->clear('select')->select('c.id, c.title as name, c.published, c.language, c.level')->order('c.lft');
|
||||
$this->db->setQuery($query);
|
||||
$list = $this->db->loadObjectList();
|
||||
return $this->getOptionsByList($list, ['language', 'unpublished'], -1);
|
||||
}
|
||||
}
|
||||
38
libraries/regularlabs/src/Form/Field/CustomOptionsField.php
Normal file
38
libraries/regularlabs/src/Form/Field/CustomOptionsField.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use Joomla\CMS\Layout\FileLayout as JFileLayout;
|
||||
use RegularLabs\Library\ArrayHelper as RL_Array;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class CustomOptionsField extends RL_FormField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
$data = $this->getLayoutData();
|
||||
$data['options'] = $this->getOptions();
|
||||
$data['value'] = RL_Array::toArray($this->value);
|
||||
$data['placeholder'] = JText::_('RL_ENTER_NEW_VALUES');
|
||||
return (new JFileLayout('regularlabs.form.field.customoptions', JPATH_SITE . '/libraries/regularlabs/layouts'))->render($data);
|
||||
}
|
||||
protected function getOptions()
|
||||
{
|
||||
$values = RL_Array::toArray($this->value);
|
||||
$options = [];
|
||||
foreach ($values as $value) {
|
||||
$options[] = (object) ['value' => $value, 'text' => $value];
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
29
libraries/regularlabs/src/Form/Field/DependencyField.php
Normal file
29
libraries/regularlabs/src/Form/Field/DependencyField.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class DependencyField extends RL_FormField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
$file = $this->get('file', '');
|
||||
$label = $this->get('label', 'the main extension');
|
||||
\RegularLabs\Library\Form\Field\DependencyFieldHelper::setMessage($file, $label);
|
||||
return '';
|
||||
}
|
||||
protected function getLabel()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
class DependencyFieldHelper
|
||||
{
|
||||
public static function setMessage(string $file, string $name): void
|
||||
{
|
||||
if (empty($file)) {
|
||||
return;
|
||||
}
|
||||
$file = JPATH_SITE . '/' . trim($file, '/');
|
||||
if (file_exists($file)) {
|
||||
return;
|
||||
}
|
||||
$msg = JText::sprintf('RL_THIS_EXTENSION_NEEDS_THE_MAIN_EXTENSION_TO_FUNCTION', JText::_($name));
|
||||
$messageQueue = JFactory::getApplication()->getMessageQueue();
|
||||
foreach ($messageQueue as $queue_message) {
|
||||
if ($queue_message['type'] == 'error' && $queue_message['message'] == $msg) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
JFactory::getApplication()->enqueueMessage($msg, 'error');
|
||||
}
|
||||
}
|
||||
26
libraries/regularlabs/src/Form/Field/DownloadKeyField.php
Normal file
26
libraries/regularlabs/src/Form/Field/DownloadKeyField.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Layout\FileLayout as JFileLayout;
|
||||
use RegularLabs\Library\Document as RL_Document;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class DownloadKeyField extends RL_FormField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
RL_Document::script('regularlabs.script');
|
||||
RL_Document::script('regularlabs.downloadkey');
|
||||
return (new JFileLayout('regularlabs.form.field.downloadkey', JPATH_SITE . '/libraries/regularlabs/layouts'))->render(['id' => $this->id, 'extension' => strtolower($this->get('extension', 'all')), 'use_modal' => $this->get('use-modal', \true)]);
|
||||
}
|
||||
}
|
||||
62
libraries/regularlabs/src/Form/Field/FieldField.php
Normal file
62
libraries/regularlabs/src/Form/Field/FieldField.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\HTML\HTMLHelper as JHtml;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use RegularLabs\Library\ArrayHelper as RL_Array;
|
||||
use RegularLabs\Library\DB as RL_DB;
|
||||
use RegularLabs\Library\Form\Form;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class FieldField extends RL_FormField
|
||||
{
|
||||
static $fields;
|
||||
public bool $is_select_list = \true;
|
||||
public function getNameById(string $value, array $attributes): string
|
||||
{
|
||||
return RL_Array::implode($this->getNamesByIds([$value], $attributes));
|
||||
}
|
||||
public function getNamesByIds(array $values, array $attributes): array
|
||||
{
|
||||
$db = RL_DB::get();
|
||||
$query = RL_DB::getQuery()->select('DISTINCT a.id, a.type, a.title as name')->from('#__fields AS a')->where('a.state = 1')->where(RL_DB::is('a.id', $values))->order('a.title');
|
||||
$db->setQuery($query);
|
||||
$fields = $db->loadObjectList();
|
||||
return Form::getNamesWithExtras($fields, ['type']);
|
||||
}
|
||||
protected function getOptions()
|
||||
{
|
||||
$fields = $this->getFields();
|
||||
$options = [];
|
||||
$options[] = JHtml::_('select.option', '', '- ' . JText::_('RL_SELECT_FIELD') . ' -');
|
||||
foreach ($fields as $field) {
|
||||
$key = $field->{$this->get('key', 'id')} ?? $field->id;
|
||||
$options[] = JHtml::_('select.option', $key, $field->title . ' [' . $field->type . ']');
|
||||
}
|
||||
if ($this->get('show_custom')) {
|
||||
$options[] = JHtml::_('select.option', 'custom', '- ' . JText::_('RL_CUSTOM') . ' -');
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
private function getFields(): array
|
||||
{
|
||||
if (!is_null(self::$fields)) {
|
||||
return self::$fields;
|
||||
}
|
||||
$db = RL_DB::get();
|
||||
$query = RL_DB::getQuery()->select('DISTINCT a.id, a.type, a.name, a.title')->from('#__fields AS a')->where('a.state = 1')->where('a.only_use_in_subform = 0')->where(RL_DB::isNot('a.type', ['subform', 'repeatable']))->order('a.title');
|
||||
$db->setQuery($query);
|
||||
self::$fields = $db->loadObjectList();
|
||||
return self::$fields;
|
||||
}
|
||||
}
|
||||
82
libraries/regularlabs/src/Form/Field/GeoField.php
Normal file
82
libraries/regularlabs/src/Form/Field/GeoField.php
Normal file
File diff suppressed because one or more lines are too long
42
libraries/regularlabs/src/Form/Field/GeoInformationField.php
Normal file
42
libraries/regularlabs/src/Form/Field/GeoInformationField.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
use RegularLabs\Library\GeoIp\GeoIp as RL_GeoIP;
|
||||
class GeoInformationField extends RL_FormField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
protected function getLabel()
|
||||
{
|
||||
if (!class_exists('RegularLabs\Library\GeoIp\GeoIp')) {
|
||||
return '';
|
||||
}
|
||||
$ip = '';
|
||||
$geo = new RL_GeoIP($ip);
|
||||
if (empty($geo)) {
|
||||
return \false;
|
||||
}
|
||||
$geo = $geo->get();
|
||||
if (empty($geo)) {
|
||||
return \false;
|
||||
}
|
||||
$details = [JText::_('CON_CONTINENT') . ': <strong>' . $geo->continent . '</strong>', JText::_('CON_COUNTRY') . ': <strong>' . $geo->country . '</strong>', JText::_('CON_REGION') . ': <strong>' . implode(', ', $geo->regions) . '</strong>', JText::_('CON_POSTAL_CODE') . ': <strong>' . $geo->postalCode . '</strong>'];
|
||||
$html = '<div class="rl-alert alert alert-info rl-alert-light">' . JText::_('CON_GEO_CURRENT_DETAILS') . '<ul><li>' . implode('</li><li>', $details) . '</li></ul>' . '</div>';
|
||||
return '</div><div>' . $html;
|
||||
}
|
||||
}
|
||||
100
libraries/regularlabs/src/Form/Field/HeaderField.php
Normal file
100
libraries/regularlabs/src/Form/Field/HeaderField.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
use Joomla\CMS\Installer\Installer as JInstaller;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
use RegularLabs\Library\RegEx as RL_RegEx;
|
||||
use RegularLabs\Library\StringHelper as RL_String;
|
||||
use RegularLabs\Library\Version;
|
||||
class HeaderField extends RL_FormField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
$title = $this->get('label');
|
||||
$jversion = Version::getMajorJoomlaVersion();
|
||||
if ($jversion != 4) {
|
||||
JFactory::getApplication()->enqueueMessage(JText::sprintf('RL_NOT_COMPATIBLE_WITH_JOOMLA_VERSION', JText::_($title), $jversion), 'error');
|
||||
return '';
|
||||
}
|
||||
$description = $this->get('description');
|
||||
$xml = $this->get('xml');
|
||||
$url = $this->get('url');
|
||||
$this->description = '';
|
||||
if ($description) {
|
||||
$description = RL_String::html_entity_decoder(trim(JText::_($description)));
|
||||
}
|
||||
if ($title) {
|
||||
$title = JText::_($title);
|
||||
}
|
||||
if ($description) {
|
||||
// Replace inline monospace style with rl_code classname
|
||||
$description = str_replace('span style="font-family:monospace;"', 'span class="rl_code"', $description);
|
||||
// 'Break' plugin style tags
|
||||
$description = str_replace(['{', '['], ['<span>{</span>', '<span>[</span>'], $description);
|
||||
// Wrap in paragraph (if not already starting with an html tag)
|
||||
if ($description[0] != '<') {
|
||||
$description = '<p>' . $description . '</p>';
|
||||
}
|
||||
}
|
||||
if (!$xml && $this->form->getValue('element')) {
|
||||
if ($this->form->getValue('folder')) {
|
||||
$xml = 'plugins/' . $this->form->getValue('folder') . '/' . $this->form->getValue('element') . '/' . $this->form->getValue('element') . '.xml';
|
||||
} else {
|
||||
$xml = 'administrator/modules/' . $this->form->getValue('element') . '/' . $this->form->getValue('element') . '.xml';
|
||||
}
|
||||
}
|
||||
if ($xml) {
|
||||
$xml = JInstaller::parseXMLInstallFile(JPATH_SITE . '/' . $xml);
|
||||
$version = 0;
|
||||
if ($xml && isset($xml['version'])) {
|
||||
$version = $xml['version'];
|
||||
}
|
||||
if ($version) {
|
||||
if (str_contains($version, 'PRO')) {
|
||||
$version = str_replace('PRO', '', $version);
|
||||
$version .= ' <small style="color:green">[PRO]</small>';
|
||||
} elseif (str_contains($version, 'FREE')) {
|
||||
$version = str_replace('FREE', '', $version);
|
||||
$version .= ' <small style="color:green">[FREE]</small>';
|
||||
}
|
||||
if ($title) {
|
||||
$title .= ' v';
|
||||
} else {
|
||||
$title = JText::_('Version') . ' ';
|
||||
}
|
||||
$title .= $version;
|
||||
}
|
||||
}
|
||||
$html = [];
|
||||
if ($title) {
|
||||
if ($url) {
|
||||
$title = '<a href="' . $url . '" target="_blank" title="' . RL_RegEx::replace('<[^>]*>', '', $title) . '">' . $title . '</a>';
|
||||
}
|
||||
$html[] = '<h4>' . RL_String::html_entity_decoder($title) . '</h4>';
|
||||
}
|
||||
if ($description) {
|
||||
$html[] = $description;
|
||||
}
|
||||
if ($url) {
|
||||
$html[] = '<p><a href="' . $url . '" class="btn btn-outline-info" target="_blank" title="' . JText::_('RL_MORE_INFO') . '">' . JText::_('RL_MORE_INFO') . ' >></a></p>';
|
||||
}
|
||||
return $this->getControlGroupEnd() . implode('', $html) . $this->getControlGroupStart();
|
||||
}
|
||||
protected function getLabel()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
53
libraries/regularlabs/src/Form/Field/HeaderLibraryField.php
Normal file
53
libraries/regularlabs/src/Form/Field/HeaderLibraryField.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
class HeaderLibraryField extends \RegularLabs\Library\Form\Field\HeaderField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
$extensions = [
|
||||
'Advanced Module Manager',
|
||||
'Articles Anywhere',
|
||||
'Articles Field',
|
||||
'Better Frontend Link',
|
||||
'Cache Cleaner',
|
||||
'CDN for Joomla!',
|
||||
'Conditional Content',
|
||||
// 'Content Templater',
|
||||
'DB Replacer',
|
||||
'GeoIP',
|
||||
'IP Login',
|
||||
// 'Keyboard Shortcuts',
|
||||
// 'Modals',
|
||||
'Modules Anywhere',
|
||||
'Quick Index',
|
||||
'Regular Labs Extension Manager',
|
||||
'ReReplacer',
|
||||
'Snippets',
|
||||
'Sourcerer',
|
||||
// 'Tabs & Accordions',
|
||||
// 'Tooltips',
|
||||
'What? Nothing!',
|
||||
];
|
||||
$list = '<ul><li>' . implode('</li><li>', $extensions) . '</li></ul>';
|
||||
$attributes = $this->element->attributes();
|
||||
$warning = '';
|
||||
if (isset($attributes['warning'])) {
|
||||
$warning = '<div class="alert alert-danger">' . JText::_($attributes['warning']) . '</div>';
|
||||
}
|
||||
$this->element->attributes()['description'] = JText::sprintf($attributes['description'], $warning, $list);
|
||||
return parent::getInput();
|
||||
}
|
||||
}
|
||||
23
libraries/regularlabs/src/Form/Field/IconToggleField.php
Normal file
23
libraries/regularlabs/src/Form/Field/IconToggleField.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Layout\FileLayout as JFileLayout;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class IconToggleField extends RL_FormField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
return (new JFileLayout('regularlabs.form.field.icontoggle', JPATH_SITE . '/libraries/regularlabs/layouts'))->render(['id' => $this->id, 'name' => $this->name, 'icon1' => strtolower($this->get('icon1', 'arrow-down')), 'icon2' => $this->get('icon2', 'arrow-up'), 'text1' => $this->get('text1', ''), 'text2' => $this->get('text2', ''), 'class1' => $this->get('class1', ''), 'class2' => $this->get('class2', '')]);
|
||||
}
|
||||
}
|
||||
43
libraries/regularlabs/src/Form/Field/IconsField.php
Normal file
43
libraries/regularlabs/src/Form/Field/IconsField.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class IconsField extends RL_FormField
|
||||
{
|
||||
protected $layout = 'joomla.form.field.radio.buttons';
|
||||
protected function getInput()
|
||||
{
|
||||
$data = $this->getLayoutData();
|
||||
return $this->getRenderer($this->layout)->render($data);
|
||||
}
|
||||
protected function getLayoutData()
|
||||
{
|
||||
$data = parent::getLayoutData();
|
||||
$extraData = ['options' => $this->getOptions(), 'value' => (string) $this->value, 'class' => 'btn-group rl-btn-group rl-btn-group-separate rl-btn-group-min-size'];
|
||||
return [...$data, ...$extraData];
|
||||
}
|
||||
protected function getOptions()
|
||||
{
|
||||
$classes = ['address-book', 'address-card', 'align-center', 'align-justify', 'align-left', 'align-right', 'angle-double-left', 'angle-double-right', 'angle-down', 'angle-left', 'angle-right', 'angle-up', 'archive', 'arrow-alt-circle-down', 'arrow-alt-circle-left', 'arrow-alt-circle-right', 'arrow-alt-circle-up', 'arrow-down', 'arrow-left', 'arrow-right', 'arrow-up', 'arrows-alt', 'bars', 'bell', 'bolt', 'bookmark', 'briefcase', 'bullhorn', 'calendar-alt', 'calendar-check', 'camera', 'caret-down', 'caret-left', 'caret-right', 'caret-up', 'chart-area', 'chart-bar', 'chart-pie', 'check-square', 'plus-square', 'minus-square', 'check-circle', 'plus-circle', 'minus-circle', 'times-circle', 'play-circle', 'pause-circle', 'stop-circle', 'chevron-circle-left', 'chevron-circle-right', 'backward', 'forward', 'step-backward', 'fast-backward', 'fast-forward', 'square', 'chevron-down', 'chevron-left', 'chevron-right', 'chevron-up', 'circle', 'clipboard', 'clock', 'cloud-download-alt', 'cloud-upload-alt', 'code-branch', 'cogs', 'comment-dots', 'comments', 'compress', 'copy', 'credit-card', 'crop', 'cubes', 'cut', 'database', 'desktop', 'tablet', 'mobile', 'dot-circle', 'download', 'upload', 'edit', 'pen-square', 'pencil-alt', 'ellipsis-h', 'ellipsis-v', 'envelope-open-text', 'exclamation-circle', 'exclamation-triangle', 'info-circle', 'question-circle', 'expand-arrows-alt', 'external-link-alt', 'external-link-square-alt', 'eye-slash', 'fax', 'file-alt', 'filter', 'flag', 'folder-open', 'handshake', 'home', 'image', 'key', 'lock-open', 'unlock-alt', 'language', 'life-ring', 'lightbulb', 'link', 'list-ol', 'list-ul', 'tasks', 'magic', 'compass', 'globe', 'map-marker-alt', 'thumbtack', 'map-signs', 'medkit', 'music', 'paint-brush', 'paperclip', 'phone-square', 'plug', 'power-off', 'print', 'project-diagram', 'puzzle-piece', 'quote-left', 'quote-right', 'random', 'rss-square', 'save', 'search-minus', 'search-plus', 'shield-alt', 'shopping-basket', 'shopping-cart', 'sign-in-alt', 'sign-out-alt', 'sitemap', 'sliders-h', 'smile', 'frown', 'thumbs-down', 'thumbs-up', 'heart', 'star', 'star-half', 'trophy', 'tachometer-alt', 'tags', 'text-width', 'th-large', 'toggle-off', 'toggle-on', 'trash', 'share', 'sync', 'undo', 'universal-access', 'user-circle', 'user-edit', 'user-lock', 'user-tag', 'users-cog', 'video', 'wifi', 'wrench'];
|
||||
$options = [];
|
||||
foreach ($classes as $class) {
|
||||
$options[] = (object) ['value' => $class, 'text' => '<i class="fa fa-' . $class . '"></i>'];
|
||||
}
|
||||
if ($this->get('show_none')) {
|
||||
$options[] = (object) ['value' => '0', 'text' => JText::_('JNONE')];
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
37
libraries/regularlabs/src/Form/Field/ImageField.php
Normal file
37
libraries/regularlabs/src/Form/Field/ImageField.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
use RegularLabs\Library\HtmlTag as RL_HtmlTag;
|
||||
class ImageField extends RL_FormField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
$attributes = ['src' => (string) (string) $this->element['src']];
|
||||
if ($this->element['alt']) {
|
||||
$attributes['alt'] = (string) $this->element['alt'];
|
||||
}
|
||||
if ($this->element['title']) {
|
||||
$attributes['title'] = (string) $this->element['title'];
|
||||
}
|
||||
if ($this->element['height']) {
|
||||
$attributes['height'] = (string) $this->element['height'];
|
||||
}
|
||||
if ($this->element['width']) {
|
||||
$attributes['width'] = (string) $this->element['width'];
|
||||
}
|
||||
$attributes = RL_HtmlTag::combineAttributes($attributes, (string) $this->element['attributes']);
|
||||
return '<img ' . $attributes . '>';
|
||||
}
|
||||
}
|
||||
25
libraries/regularlabs/src/Form/Field/IsInstalledField.php
Normal file
25
libraries/regularlabs/src/Form/Field/IsInstalledField.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use RegularLabs\Library\Extension as RL_Extension;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class IsInstalledField extends RL_FormField
|
||||
{
|
||||
protected $layout = 'joomla.form.field.hidden';
|
||||
protected function getLabel()
|
||||
{
|
||||
$this->value = (int) RL_Extension::isInstalled($this->get('extension'), $this->get('extension_type', 'component'), $this->get('folder', 'system'));
|
||||
return $this->getControlGroupEnd() . rtrim($this->getRenderer($this->layout)->render($this->getLayoutData()), \PHP_EOL) . $this->getControlGroupStart();
|
||||
}
|
||||
}
|
||||
39
libraries/regularlabs/src/Form/Field/JCompatibilityField.php
Normal file
39
libraries/regularlabs/src/Form/Field/JCompatibilityField.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use RegularLabs\Library\Document as RL_Document;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
use RegularLabs\Library\Version;
|
||||
class JCompatibilityField extends RL_FormField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
$extension = $this->get('extension');
|
||||
if (empty($extension)) {
|
||||
return '';
|
||||
}
|
||||
$jversion = Version::getMajorJoomlaVersion();
|
||||
if ($jversion == 4) {
|
||||
return '';
|
||||
}
|
||||
RL_Document::useStyle('webcomponent.joomla-alert');
|
||||
RL_Document::useScript('webcomponent.joomla-alert');
|
||||
return '<joomla-alert type="danger" dismiss="true" class="joomla-alert--show" role="alert">' . JText::sprintf('RL_NOT_COMPATIBLE_WITH_JOOMLA_VERSION', JText::_($extension), $jversion) . '</joomla-alert>';
|
||||
}
|
||||
protected function getLabel()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
51
libraries/regularlabs/src/Form/Field/LanguagesField.php
Normal file
51
libraries/regularlabs/src/Form/Field/LanguagesField.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\HTML\HTMLHelper as JHtml;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class LanguagesField extends RL_FormField
|
||||
{
|
||||
public bool $is_select_list = \true;
|
||||
public function getNamesByIds(array $values, array $attributes): array
|
||||
{
|
||||
$languages = JHtml::_('contentlanguage.existing');
|
||||
$names = [];
|
||||
foreach ($languages as $language) {
|
||||
if (empty($language->value)) {
|
||||
continue;
|
||||
}
|
||||
if (!in_array($language->value, $values)) {
|
||||
continue;
|
||||
}
|
||||
$names[] = $language->text . ' [' . $language->value . ']';
|
||||
}
|
||||
return $names;
|
||||
}
|
||||
protected function getOptions()
|
||||
{
|
||||
$languages = JHtml::_('contentlanguage.existing');
|
||||
$value = $this->get('value', []);
|
||||
if (!is_array($value)) {
|
||||
$value = [$value];
|
||||
}
|
||||
$options = [];
|
||||
foreach ($languages as $language) {
|
||||
if (empty($language->value)) {
|
||||
continue;
|
||||
}
|
||||
$options[] = (object) ['value' => $language->value, 'text' => $language->text . ' [' . $language->value . ']', 'selected' => in_array($language->value, $value, \true)];
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
31
libraries/regularlabs/src/Form/Field/LicenseField.php
Normal file
31
libraries/regularlabs/src/Form/Field/LicenseField.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
use RegularLabs\Library\License as RL_License;
|
||||
class LicenseField extends RL_FormField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
$extension = $this->get('extension');
|
||||
if (empty($extension)) {
|
||||
return '';
|
||||
}
|
||||
return RL_License::getMessage($extension, \true);
|
||||
}
|
||||
protected function getLabel()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
37
libraries/regularlabs/src/Form/Field/LoadLanguageField.php
Normal file
37
libraries/regularlabs/src/Form/Field/LoadLanguageField.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
use RegularLabs\Library\Language as RL_Language;
|
||||
class LoadLanguageField extends RL_FormField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
$extension = $this->get('extension');
|
||||
$admin = (bool) $this->get('admin', 1);
|
||||
self::loadLanguage($extension, $admin);
|
||||
return '';
|
||||
}
|
||||
protected function getLabel()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
private static function loadLanguage(string $extension, bool $admin = \true): void
|
||||
{
|
||||
if (!$extension) {
|
||||
return;
|
||||
}
|
||||
RL_Language::load($extension, $admin ? JPATH_ADMINISTRATOR : JPATH_SITE);
|
||||
}
|
||||
}
|
||||
39
libraries/regularlabs/src/Form/Field/LoadMediaField.php
Normal file
39
libraries/regularlabs/src/Form/Field/LoadMediaField.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use RegularLabs\Library\Document as RL_Document;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class LoadMediaField extends RL_FormField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
protected function getLabel()
|
||||
{
|
||||
$filetype = $this->get('filetype');
|
||||
$file = $this->get('file');
|
||||
switch ($filetype) {
|
||||
case 'style':
|
||||
RL_Document::style($file);
|
||||
break;
|
||||
case 'script':
|
||||
RL_Document::script($file);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
81
libraries/regularlabs/src/Form/Field/MenuItemsField.php
Normal file
81
libraries/regularlabs/src/Form/Field/MenuItemsField.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\HTML\HTMLHelper as JHtml;
|
||||
use Joomla\CMS\Language\Multilanguage as JMultilanguage;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use Joomla\Component\Menus\Administrator\Helper\MenusHelper as JMenusHelper;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
use RegularLabs\Library\Language as RL_Language;
|
||||
use RegularLabs\Library\RegEx as RL_RegEx;
|
||||
class MenuItemsField extends RL_FormField
|
||||
{
|
||||
public bool $collapse_children = \true;
|
||||
public bool $is_select_list = \true;
|
||||
public bool $use_ajax = \true;
|
||||
public bool $use_tree_select = \true;
|
||||
public function getNamesByIds(array $ids): array
|
||||
{
|
||||
if (empty($ids)) {
|
||||
return [];
|
||||
}
|
||||
RL_Language::load('com_modules', JPATH_ADMINISTRATOR);
|
||||
$menuTypes = JMenusHelper::getMenuLinks();
|
||||
$items = array_fill_keys($ids, '');
|
||||
foreach ($menuTypes as $type) {
|
||||
if (isset($items['type.' . $type->menutype])) {
|
||||
$items['type.' . $type->menutype] = $type->title . ' <span class="small">(' . JText::_('JALL') . ')</span>';
|
||||
}
|
||||
foreach ($type->links as $link) {
|
||||
if (!isset($items[$link->value])) {
|
||||
continue;
|
||||
}
|
||||
$text = [];
|
||||
$text[] = $link->text;
|
||||
$items[$link->value] = implode(' ', $text);
|
||||
}
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
protected function getOptions()
|
||||
{
|
||||
RL_Language::load('com_modules', JPATH_ADMINISTRATOR);
|
||||
$menuTypes = JMenusHelper::getMenuLinks();
|
||||
$options = [];
|
||||
foreach ($menuTypes as &$type) {
|
||||
$option = (object) ['value' => 'type.' . $type->menutype, 'text' => $type->title, 'level' => 0, 'class' => 'hidechildren', 'labelclass' => 'nav-header'];
|
||||
$options[] = $option;
|
||||
foreach ($type->links as $link) {
|
||||
$check1 = RL_RegEx::replace('[^a-z0-9]', '', strtolower($link->text));
|
||||
$check2 = RL_RegEx::replace('[^a-z0-9]', '', $link->alias);
|
||||
$text = [];
|
||||
$text[] = $link->text;
|
||||
if ($check1 !== $check2) {
|
||||
$text[] = '<small class="text-muted">[' . $link->alias . ']</small>';
|
||||
}
|
||||
if (in_array($link->type, ['separator', 'heading', 'alias', 'url'], \true)) {
|
||||
$text[] = '<span class="badge bg-secondary">' . JText::_('COM_MODULES_MENU_ITEM_' . strtoupper($link->type)) . '</span>';
|
||||
// Don't disable, as you need to be able to select the 'Also on Child Items' option
|
||||
// $link->disable = 1;
|
||||
}
|
||||
if (JMultilanguage::isEnabled() && $link->language != '' && $link->language != '*') {
|
||||
$text[] = $link->language_image ? JHtml::_('image', 'mod_languages/' . $link->language_image . '.gif', $link->language_title, ['title' => $link->language_title], \true) : '<span class="badge bg-secondary" title="' . $link->language_title . '">' . $link->language_sef . '</span>';
|
||||
}
|
||||
$link->text = implode(' ', $text);
|
||||
$options[] = $link;
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
35
libraries/regularlabs/src/Form/Field/MiniColorField.php
Normal file
35
libraries/regularlabs/src/Form/Field/MiniColorField.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use RegularLabs\Library\ArrayHelper as RL_Array;
|
||||
use RegularLabs\Library\Document as RL_Document;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class MiniColorField extends RL_FormField
|
||||
{
|
||||
public function getInput()
|
||||
{
|
||||
$class = trim('rl-mini-colors ' . $this->get('class'));
|
||||
$table = $this->get('table');
|
||||
$item_id = $this->get('item_id');
|
||||
$id_column = $this->get('id_column') ?: 'id';
|
||||
$disabled = $this->get('disabled') ? ' disabled="disabled"' : '';
|
||||
$colors = $this->get('colors', 'none,#c0c6cf,#000000,#dc2a28,#fb6b14,#ffa813,#eac90a,#18a047,#0f9aa4,#115dda,#761bda,#d319a4');
|
||||
$colors = str_replace('none', 'transparent', $colors);
|
||||
RL_Document::scriptOptions(['swatches' => RL_Array::toArray($colors)], 'minicolors');
|
||||
RL_Document::script('regularlabs.script');
|
||||
RL_Document::script('regularlabs.mini-colors');
|
||||
RL_Document::style('regularlabs.mini-colors');
|
||||
return '<div class="rl-mini-colors">' . '<input type="text" name="' . $this->name . '" id="' . $this->id . '"' . ' class="' . $class . '" value="' . $this->value . '"' . $disabled . ' data-rl-mini-colors data-table="' . $table . '" data-item_id="' . $item_id . '" data-id_column="' . $id_column . '"' . '>' . '</div>';
|
||||
}
|
||||
}
|
||||
50
libraries/regularlabs/src/Form/Field/NoteField.php
Normal file
50
libraries/regularlabs/src/Form/Field/NoteField.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class NoteField extends RL_FormField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
if (empty($this->element['label'])) {
|
||||
return '';
|
||||
}
|
||||
return $this->getNote();
|
||||
}
|
||||
protected function getLabel()
|
||||
{
|
||||
if (!empty($this->element['label'])) {
|
||||
return parent::getLabel();
|
||||
}
|
||||
$note = $this->getNote();
|
||||
if (empty($note)) {
|
||||
return '';
|
||||
}
|
||||
return '</div><div>' . $note;
|
||||
}
|
||||
protected function getNote()
|
||||
{
|
||||
if (empty($this->element['title']) && empty($this->element['text'])) {
|
||||
return '';
|
||||
}
|
||||
$title = $this->prepareText($this->element['title']);
|
||||
$text = $this->prepareText($this->element['text']);
|
||||
$heading = $this->element['heading'] ?: 'h4';
|
||||
$class = !empty($this->element['class']) ? ' class="' . $this->element['class'] . '"' : '';
|
||||
$html = [];
|
||||
$html[] = !empty($title) ? '<' . $heading . '>' . $title . '</' . $heading . '>' : '';
|
||||
$html[] = $text ?: '';
|
||||
return '<div ' . $class . '>' . implode('', $html) . '</div>';
|
||||
}
|
||||
}
|
||||
70
libraries/regularlabs/src/Form/Field/OnlyProField.php
Normal file
70
libraries/regularlabs/src/Form/Field/OnlyProField.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use RegularLabs\Library\Extension as RL_Extension;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class OnlyProField extends RL_FormField
|
||||
{
|
||||
protected function getExtensionName()
|
||||
{
|
||||
$element = $this->form->getValue('element');
|
||||
if ($element) {
|
||||
return $element;
|
||||
}
|
||||
$component = $this->app->input->get('component', '');
|
||||
if ($component) {
|
||||
return str_replace('com_', '', $component);
|
||||
}
|
||||
$folder = $this->app->input->get('folder', '');
|
||||
if ($folder) {
|
||||
$extension = explode('.', $folder);
|
||||
return array_pop($extension);
|
||||
}
|
||||
$option = $this->app->input->get('option', '');
|
||||
if ($option) {
|
||||
return str_replace('com_', '', $option);
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
protected function getInput()
|
||||
{
|
||||
$label = $this->prepareText($this->get('label'));
|
||||
$description = $this->prepareText($this->get('description'));
|
||||
if (!$label && !$description) {
|
||||
return '';
|
||||
}
|
||||
return $this->getText();
|
||||
}
|
||||
protected function getLabel()
|
||||
{
|
||||
$label = $this->prepareText($this->get('label'));
|
||||
$description = $this->prepareText($this->get('description'));
|
||||
if (!$label && !$description) {
|
||||
return '</div><div>' . $this->getText();
|
||||
}
|
||||
return parent::getLabel();
|
||||
}
|
||||
protected function getText()
|
||||
{
|
||||
$text = JText::_('RL_ONLY_AVAILABLE_IN_PRO');
|
||||
$text = '<em>' . $text . '</em>';
|
||||
$extension = $this->getExtensionName();
|
||||
$alias = RL_Extension::getAliasByName($extension);
|
||||
if (!$alias) {
|
||||
return $text;
|
||||
}
|
||||
return '<a href="https://regularlabs.com/' . $extension . '/features" target="_blank">' . $text . '</a>';
|
||||
}
|
||||
}
|
||||
51
libraries/regularlabs/src/Form/Field/RangeField.php
Normal file
51
libraries/regularlabs/src/Form/Field/RangeField.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
class RangeField extends \Joomla\CMS\Form\Field\RangeField
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $layout = 'regularlabs.form.field.range';
|
||||
/**
|
||||
* @return string The field input markup.
|
||||
*/
|
||||
protected function getInput()
|
||||
{
|
||||
$this->value = (float) ($this->value ?: $this->default);
|
||||
if (!empty($this->max)) {
|
||||
$this->value = min($this->value, $this->max);
|
||||
}
|
||||
if (!empty($this->min)) {
|
||||
$this->value = max($this->value, $this->min);
|
||||
}
|
||||
return $this->getRenderer($this->layout)->render($this->getLayoutData());
|
||||
}
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getLayoutData()
|
||||
{
|
||||
$data = parent::getLayoutData();
|
||||
// Initialize some field attributes.
|
||||
$extraData = ['prepend' => (string) ($this->element['prepend'] ?? ''), 'append' => (string) ($this->element['append'] ?? ''), 'class_range' => (string) ($this->element['class_range'] ?? '')];
|
||||
return [...$data, ...$extraData];
|
||||
}
|
||||
protected function getLayoutPaths()
|
||||
{
|
||||
$paths = parent::getLayoutPaths();
|
||||
$paths[] = JPATH_LIBRARIES . '/regularlabs/layouts';
|
||||
return $paths;
|
||||
}
|
||||
}
|
||||
41
libraries/regularlabs/src/Form/Field/ShowOnField.php
Normal file
41
libraries/regularlabs/src/Form/Field/ShowOnField.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
use RegularLabs\Library\RegEx as RL_RegEx;
|
||||
use RegularLabs\Library\ShowOn as RL_ShowOn;
|
||||
class ShowOnField extends RL_FormField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
$value = (string) $this->get('value');
|
||||
$class = $this->get('class', '');
|
||||
if (!$value) {
|
||||
return $this->getControlGroupEnd() . RL_ShowOn::close() . $this->getControlGroupStart();
|
||||
}
|
||||
$formControl = $this->get('form', $this->formControl);
|
||||
$formControl = $formControl == 'root' ? '' : $formControl;
|
||||
while (str_starts_with($value, '../')) {
|
||||
$value = substr($value, 3);
|
||||
if (str_contains($formControl, '[')) {
|
||||
$formControl = RL_RegEx::replace('^(.*)\[.*?\]$', '\1', $formControl);
|
||||
}
|
||||
}
|
||||
return $this->getControlGroupEnd() . RL_ShowOn::open($value, $formControl, $this->group, $class) . $this->getControlGroupStart();
|
||||
}
|
||||
protected function getLabel()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
60
libraries/regularlabs/src/Form/Field/SimpleCategoryField.php
Normal file
60
libraries/regularlabs/src/Form/Field/SimpleCategoryField.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\HTML\HTMLHelper as JHtml;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use Joomla\CMS\Layout\FileLayout as JFileLayout;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class SimpleCategoryField extends RL_FormField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
$categories = $this->getOptions();
|
||||
$options = parent::getOptions();
|
||||
$options = [...$options, ...$categories];
|
||||
if ($this->get('show_none', \true)) {
|
||||
$empty_option = JHtml::_('select.option', $this->get('none_value', ''), '- ' . JText::_('JNONE') . ' -');
|
||||
$empty_option->class = 'hidden';
|
||||
array_unshift($options, $empty_option);
|
||||
}
|
||||
if ($this->get('show_keep_original')) {
|
||||
$keep_original_option = JHtml::_('select.option', ' ', '- ' . JText::_('RL_KEEP_ORIGINAL_CATEGORY') . ' -');
|
||||
array_unshift($options, $keep_original_option);
|
||||
}
|
||||
$data = $this->getLayoutData();
|
||||
$data['options'] = $options;
|
||||
$data['placeholder'] = JText::_($this->get('hint', 'RL_SELECT_OR_CREATE_A_CATEGORY'));
|
||||
$data['allowCustom'] = $this->get('allow_custom', \true);
|
||||
return (new JFileLayout('regularlabs.form.field.simplecategory', JPATH_SITE . '/libraries/regularlabs/layouts'))->render($data);
|
||||
}
|
||||
protected function getOptions()
|
||||
{
|
||||
$table = $this->get('table');
|
||||
if (!$table) {
|
||||
return [];
|
||||
}
|
||||
// Get the user groups from the database.
|
||||
$query = $this->db->getQuery(\true)->select([$this->db->quoteName('category', 'value'), $this->db->quoteName('category', 'text')])->from($this->db->quoteName('#__' . $table))->where($this->db->quoteName('category') . ' != ' . $this->db->quote(''))->group($this->db->quoteName('category'))->order($this->db->quoteName('category') . ' ASC');
|
||||
$this->db->setQuery($query);
|
||||
$categories = $this->db->loadObjectList();
|
||||
foreach ($categories as &$category) {
|
||||
if (!str_contains($category->text, '::')) {
|
||||
continue;
|
||||
}
|
||||
[$text, $icon] = explode('::', $category->text, 2);
|
||||
$category->text = $text;
|
||||
}
|
||||
return $categories;
|
||||
}
|
||||
}
|
||||
113
libraries/regularlabs/src/Form/Field/SubformField.php
Normal file
113
libraries/regularlabs/src/Form/Field/SubformField.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Joomla\CMS\Form\Field\SubformField as JSubformField;
|
||||
use Joomla\CMS\Form\Form;
|
||||
use RuntimeException;
|
||||
use function count;
|
||||
defined('_JEXEC') or die;
|
||||
class SubformField extends JSubformField
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $layout = 'regularlabs.form.field.subform.repeatable';
|
||||
/**
|
||||
* @param string $name The property name for which to set the value.
|
||||
* @param mixed $value The value of the property.
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
switch ($name) {
|
||||
case 'layout':
|
||||
$this->layout = (string) $value;
|
||||
if (!$this->layout) {
|
||||
$this->layout = !$this->multiple ? 'joomla.form.field.subform.default' : 'regularlabs.form.field.subform.repeatable';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
parent::__set($name, $value);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Loads the form instance for the subform.
|
||||
*
|
||||
* @return Form The form instance.
|
||||
*
|
||||
* @throws InvalidArgumentException if no form provided.
|
||||
* @throws RuntimeException if the form could not be loaded.
|
||||
*/
|
||||
public function loadSubForm()
|
||||
{
|
||||
$control = $this->name;
|
||||
if ($this->multiple) {
|
||||
$control .= '[' . $this->fieldname . 'X]';
|
||||
}
|
||||
// Prepare the form template
|
||||
$formname = 'subform.' . str_replace(['jform[', '[', ']'], ['', '.', ''], $this->name);
|
||||
return $this->loadSubFormByName($formname, $control);
|
||||
}
|
||||
protected function getLayoutPaths()
|
||||
{
|
||||
$paths = parent::getLayoutPaths();
|
||||
$paths[] = JPATH_LIBRARIES . '/regularlabs/layouts';
|
||||
return $paths;
|
||||
}
|
||||
/**
|
||||
* Loads the form instance for the subform by given name and control.
|
||||
*
|
||||
* @param string $name The name of the form.
|
||||
* @param string $control The control name of the form.
|
||||
*
|
||||
* @return Form The form instance.
|
||||
*
|
||||
* @throws InvalidArgumentException if no form provided.
|
||||
* @throws RuntimeException if the form could not be loaded.
|
||||
*/
|
||||
protected function loadSubFormByName($name, $control)
|
||||
{
|
||||
// Prepare the form template
|
||||
return Form::getInstance($name, $this->formsource, ['control' => $control]);
|
||||
}
|
||||
/**
|
||||
* Binds given data to the subform and its elements.
|
||||
*
|
||||
* @param Form $subForm Form instance of the subform.
|
||||
*
|
||||
* @return Form[] Array of Form instances for the rows.
|
||||
*/
|
||||
protected function loadSubFormData(Form $subForm)
|
||||
{
|
||||
$value = $this->value ? (array) $this->value : [];
|
||||
// Simple form, just bind the data and return one row.
|
||||
if (!$this->multiple) {
|
||||
$subForm->bind($value);
|
||||
return [$subForm];
|
||||
}
|
||||
// Multiple rows possible: Construct array and bind values to their respective forms.
|
||||
$forms = [];
|
||||
$value = array_values($value);
|
||||
// Show as many rows as we have values, but at least min and at most max.
|
||||
$c = max($this->min, min(count($value), $this->max));
|
||||
for ($i = 0; $i < $c; $i++) {
|
||||
$control = $this->name . '[' . $this->fieldname . $i . ']';
|
||||
$itemForm = $this->loadSubFormByName($subForm->getName() . $i, $control);
|
||||
if (!empty($value[$i])) {
|
||||
$itemForm->bind($value[$i]);
|
||||
}
|
||||
$forms[] = $itemForm;
|
||||
}
|
||||
return $forms;
|
||||
}
|
||||
}
|
||||
39
libraries/regularlabs/src/Form/Field/TagsField.php
Normal file
39
libraries/regularlabs/src/Form/Field/TagsField.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use RegularLabs\Library\DB as RL_DB;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class TagsField extends RL_FormField
|
||||
{
|
||||
static $options;
|
||||
public bool $is_select_list = \true;
|
||||
public bool $use_ajax = \true;
|
||||
public bool $use_tree_select = \true;
|
||||
public function getNamesByIds(array $values, array $attributes): array
|
||||
{
|
||||
$query = $this->db->getQuery(\true)->select('a.title')->from('#__tags AS a')->where(RL_DB::is('a.id', $values))->order('a.title');
|
||||
$this->db->setQuery($query);
|
||||
return $this->db->loadColumn();
|
||||
}
|
||||
protected function getOptions()
|
||||
{
|
||||
if (!is_null(self::$options)) {
|
||||
return self::$options;
|
||||
}
|
||||
$query = $this->db->getQuery(\true)->select('a.id as value, a.title as text, a.parent_id AS parent')->from('#__tags AS a')->select('COUNT(DISTINCT b.id) - 1 AS level')->join('LEFT', '#__tags AS b ON a.lft > b.lft AND a.rgt < b.rgt')->where('a.alias <> ' . $this->db->quote('root'))->where('a.published IN (0,1)')->group('a.id')->order('a.lft ASC');
|
||||
$this->db->setQuery($query);
|
||||
self::$options = $this->db->loadObjectList();
|
||||
return self::$options;
|
||||
}
|
||||
}
|
||||
87
libraries/regularlabs/src/Form/Field/TemplatesField.php
Normal file
87
libraries/regularlabs/src/Form/Field/TemplatesField.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\HTML\HTMLHelper as JHtml;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use RegularLabs\Library\DB as RL_DB;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class TemplatesField extends RL_FormField
|
||||
{
|
||||
public bool $collapse_children = \true;
|
||||
public bool $is_select_list = \true;
|
||||
public bool $use_ajax = \true;
|
||||
public bool $use_tree_select = \true;
|
||||
public function getNamesByIds(array $values, array $attributes): array
|
||||
{
|
||||
if (empty($values)) {
|
||||
return [];
|
||||
}
|
||||
$query = $this->db->getQuery(\true)->select('e.name, e.element as template')->from('#__extensions as e')->where('e.enabled=1')->where($this->db->quoteName('e.type') . '=' . $this->db->quote('template'))->where(RL_DB::is('e.name', $values))->order('e.name');
|
||||
$this->db->setQuery($query);
|
||||
$templates = $this->db->loadObjectList();
|
||||
$query = $this->db->getQuery(\true)->select('s.title, e.name as template_name, s.template')->from('#__template_styles as s')->join('LEFT', '#__extensions as e on e.element = s.template')->where(RL_DB::is('s.client_id', 0))->where(RL_DB::is('e.enabled', 1))->where(RL_DB::is('e.type', 'template'))->where(RL_DB::in('CONCAT(e.name, "--", s.id)', $values, [], \false))->order('s.template')->order('s.title');
|
||||
$this->db->setQuery($query);
|
||||
$styles = $this->db->loadObjectList();
|
||||
$lang = $this->app->getLanguage();
|
||||
$names = [];
|
||||
foreach ($templates as $template) {
|
||||
$lang->load('tpl_' . $template->template . '.sys', JPATH_SITE) || $lang->load('tpl_' . $template->template . '.sys', JPATH_SITE . '/templates/' . $template->template);
|
||||
$names[] = JText::_($template->name);
|
||||
}
|
||||
foreach ($styles as $style) {
|
||||
$lang->load('tpl_' . $style->template . '.sys', JPATH_SITE) || $lang->load('tpl_' . $style->template . '.sys', JPATH_SITE . '/templates/' . $style->template);
|
||||
$names[] = '[' . JText::_($style->template_name) . '] ' . JText::_($style->title);
|
||||
}
|
||||
return $names;
|
||||
}
|
||||
protected function getOptions()
|
||||
{
|
||||
$options = [];
|
||||
$templates = $this->getTemplates();
|
||||
foreach ($templates as $styles) {
|
||||
$level = 0;
|
||||
foreach ($styles as $style) {
|
||||
$style->level = $level;
|
||||
$options[] = $style;
|
||||
if (count($styles) <= 2) {
|
||||
break;
|
||||
}
|
||||
$level = 1;
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
protected function getTemplates()
|
||||
{
|
||||
$query = $this->db->getQuery(\true)->select('s.id, s.title, e.name as name, s.template')->from('#__template_styles as s')->where('s.client_id = 0')->join('LEFT', '#__extensions as e on e.element=s.template')->where('e.enabled=1')->where($this->db->quoteName('e.type') . '=' . $this->db->quote('template'))->order('s.template')->order('s.title');
|
||||
$this->db->setQuery($query);
|
||||
$styles = $this->db->loadObjectList();
|
||||
if (empty($styles)) {
|
||||
return [];
|
||||
}
|
||||
$lang = $this->app->getLanguage();
|
||||
$groups = [];
|
||||
foreach ($styles as $style) {
|
||||
$template = $style->template;
|
||||
$lang->load('tpl_' . $template . '.sys', JPATH_SITE) || $lang->load('tpl_' . $template . '.sys', JPATH_SITE . '/templates/' . $template);
|
||||
$name = JText::_($style->name);
|
||||
if (!isset($groups[$template])) {
|
||||
$groups[$template] = [];
|
||||
$groups[$template][] = JHtml::_('select.option', $template, $name);
|
||||
}
|
||||
$groups[$template][] = JHtml::_('select.option', $template . '--' . $style->id, $style->title);
|
||||
}
|
||||
return $groups;
|
||||
}
|
||||
}
|
||||
33
libraries/regularlabs/src/Form/Field/TextAreaField.php
Normal file
33
libraries/regularlabs/src/Form/Field/TextAreaField.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Form\Field\TextareaField as JTextareaField;
|
||||
use RegularLabs\Library\Document as RL_Document;
|
||||
class TextAreaField extends JTextareaField
|
||||
{
|
||||
protected $layout = 'regularlabs.form.field.textarea';
|
||||
protected function getLayoutData()
|
||||
{
|
||||
RL_Document::script('regularlabs.textarea');
|
||||
$data = parent::getLayoutData();
|
||||
$extraData = ['show_insert_date_name' => (bool) $this->element['show_insert_date_name'] ?? \false, 'add_separator' => (bool) $this->element['add_separator'] ?? \true];
|
||||
return [...$data, ...$extraData];
|
||||
}
|
||||
protected function getLayoutPaths()
|
||||
{
|
||||
$paths = parent::getLayoutPaths();
|
||||
$paths[] = JPATH_LIBRARIES . '/regularlabs/layouts';
|
||||
return $paths;
|
||||
}
|
||||
}
|
||||
39
libraries/regularlabs/src/Form/Field/UserGroupsField.php
Normal file
39
libraries/regularlabs/src/Form/Field/UserGroupsField.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use RegularLabs\Library\DB as RL_DB;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class UserGroupsField extends RL_FormField
|
||||
{
|
||||
static $options;
|
||||
public bool $is_select_list = \true;
|
||||
public bool $use_tree_select = \true;
|
||||
// public bool $use_ajax = true;
|
||||
public function getNamesByIds(array $values, array $attributes): array
|
||||
{
|
||||
$query = $this->db->getQuery(\true)->select('a.title')->from('#__usergroups AS a')->where(RL_DB::is('a.id', $values))->order('a.lft ASC');
|
||||
$this->db->setQuery($query);
|
||||
return $this->db->loadColumn();
|
||||
}
|
||||
protected function getOptions()
|
||||
{
|
||||
if (!empty(self::$options)) {
|
||||
return self::$options;
|
||||
}
|
||||
$query = $this->db->getQuery(\true)->select('a.id as value, a.title as text, a.parent_id AS parent')->from('#__usergroups AS a')->select('COUNT(DISTINCT b.id) AS level')->join('LEFT', '#__usergroups AS b ON a.lft > b.lft AND a.rgt < b.rgt')->group('a.id')->order('a.lft ASC');
|
||||
$this->db->setQuery($query);
|
||||
self::$options = $this->db->loadObjectList();
|
||||
return self::$options;
|
||||
}
|
||||
}
|
||||
69
libraries/regularlabs/src/Form/Field/UsersField.php
Normal file
69
libraries/regularlabs/src/Form/Field/UsersField.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\HTML\HTMLHelper as JHtml;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use RegularLabs\Library\DB as RL_DB;
|
||||
use RegularLabs\Library\Form\Form;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
class UsersField extends RL_FormField
|
||||
{
|
||||
static $users;
|
||||
static $users_count;
|
||||
public $attributes = ['show_current' => \false];
|
||||
public bool $is_select_list = \true;
|
||||
public bool $use_ajax = \true;
|
||||
public function getNamesByIds(array $values, array $attributes): array
|
||||
{
|
||||
$query = $this->db->getQuery(\true)->select('u.name, u.username, u.id, u.block as disabled')->from('#__users AS u')->where(RL_DB::is('u.id', $values))->order('name');
|
||||
$this->db->setQuery($query);
|
||||
$users = $this->db->loadObjectList();
|
||||
if (in_array('current', $values)) {
|
||||
array_unshift($users, (object) ['id' => 'current', 'name' => JText::_('RL_CURRENT_USER'), 'add_id' => \false]);
|
||||
}
|
||||
return Form::getNamesWithExtras($users, ['username', 'id', 'disabled']);
|
||||
}
|
||||
protected function getListOptions(array $attributes): array|int
|
||||
{
|
||||
if ($this->max_list_count && $this->getUsersCount() > $this->max_list_count) {
|
||||
return -1;
|
||||
}
|
||||
$users = $this->getUsers();
|
||||
$options = $this->getOptionsByList($users, ['username', 'id', 'disabled'], 0, $this->get('username_as_value') ? 'username' : 'id');
|
||||
if (!empty($attributes['show_current'])) {
|
||||
array_unshift($options, JHtml::_('select.option', 'current', '- ' . JText::_('RL_CURRENT_USER') . ' -'));
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
private function getUsers(): array
|
||||
{
|
||||
if (!is_null(self::$users)) {
|
||||
return self::$users;
|
||||
}
|
||||
$query = $this->db->getQuery(\true)->select('u.name, u.username, u.id, u.block as disabled')->from('#__users AS u')->order('name');
|
||||
$this->db->setQuery($query);
|
||||
self::$users = $this->db->loadObjectList();
|
||||
return self::$users;
|
||||
}
|
||||
private function getUsersCount(): int
|
||||
{
|
||||
if (!is_null(self::$users_count)) {
|
||||
return self::$users_count;
|
||||
}
|
||||
$query = $this->db->getQuery(\true)->select('COUNT(*)')->from('#__users AS u');
|
||||
$this->db->setQuery($query);
|
||||
self::$users_count = $this->db->loadResult();
|
||||
return self::$users_count;
|
||||
}
|
||||
}
|
||||
48
libraries/regularlabs/src/Form/Field/VersionField.php
Normal file
48
libraries/regularlabs/src/Form/Field/VersionField.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form\Field;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
use RegularLabs\Library\Form\FormField as RL_FormField;
|
||||
use RegularLabs\Library\Version as RL_Version;
|
||||
class VersionField extends RL_FormField
|
||||
{
|
||||
protected function getInput()
|
||||
{
|
||||
$extension = $this->get('extension');
|
||||
$xml = $this->get('xml');
|
||||
if (!$xml && $this->form->getValue('element')) {
|
||||
if ($this->form->getValue('folder')) {
|
||||
$xml = 'plugins/' . $this->form->getValue('folder') . '/' . $this->form->getValue('element') . '/' . $this->form->getValue('element') . '.xml';
|
||||
} else {
|
||||
$xml = 'administrator/modules/' . $this->form->getValue('element') . '/' . $this->form->getValue('element') . '.xml';
|
||||
}
|
||||
if (!file_exists(JPATH_SITE . '/' . $xml)) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
if (empty($extension) || empty($xml)) {
|
||||
return '';
|
||||
}
|
||||
$user = JFactory::getApplication()->getIdentity() ?: JFactory::getUser();
|
||||
$authorise = $user->authorise('core.manage', 'com_installer');
|
||||
if (!$authorise) {
|
||||
return '';
|
||||
}
|
||||
return RL_Version::getMessage($extension);
|
||||
}
|
||||
protected function getLabel()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
169
libraries/regularlabs/src/Form/Form.php
Normal file
169
libraries/regularlabs/src/Form/Form.php
Normal file
@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use Joomla\CMS\Layout\FileLayout as JFileLayout;
|
||||
use Joomla\CMS\Plugin\PluginHelper as JPluginHelper;
|
||||
use RegularLabs\Library\Document as RL_Document;
|
||||
use RegularLabs\Library\Input as RL_Input;
|
||||
use RegularLabs\Library\Parameters as RL_Parameters;
|
||||
use RegularLabs\Library\RegEx as RL_RegEx;
|
||||
class Form
|
||||
{
|
||||
public static function getLayout(array $options, bool $treeselect = \false): string
|
||||
{
|
||||
if ($treeselect) {
|
||||
return 'regularlabs.form.field.treeselect';
|
||||
}
|
||||
if (is_array(reset($options))) {
|
||||
return 'joomla.form.field.groupedlist-fancy-select';
|
||||
}
|
||||
return 'joomla.form.field.list-fancy-select';
|
||||
}
|
||||
/**
|
||||
* Return a name with added extras and formatting
|
||||
*/
|
||||
public static function getNameWithExtras(object $item, array $extras = []): string
|
||||
{
|
||||
$name = trim($item->name);
|
||||
foreach ($extras as $extra) {
|
||||
if ($extra == 'language' && $item->{$extra} == '*') {
|
||||
continue;
|
||||
}
|
||||
if (in_array($extra, ['id', 'alias'], \true) && $item->{$extra} == $item->name) {
|
||||
continue;
|
||||
}
|
||||
if ($extra == 'unpublished') {
|
||||
$name .= isset($item->published) && !$item->published ? ' (' . JText::_('JUNPUBLISHED') . ')' : '';
|
||||
continue;
|
||||
}
|
||||
if ($extra == 'disabled') {
|
||||
$name .= isset($item->disabled) && $item->disabled ? ' (' . JText::_('JDISABLED') . ')' : '';
|
||||
continue;
|
||||
}
|
||||
if (empty($item->{$extra})) {
|
||||
continue;
|
||||
}
|
||||
if (isset($item->{'add_' . $extra}) && !$item->{'add_' . $extra}) {
|
||||
continue;
|
||||
}
|
||||
$name .= ' [' . $item->{$extra} . ']';
|
||||
}
|
||||
return self::prepareSelectItem($name);
|
||||
}
|
||||
/**
|
||||
* Return an array with names with added extras and formatting
|
||||
*/
|
||||
public static function getNamesWithExtras(array $items, array $extras = []): array
|
||||
{
|
||||
$names = [];
|
||||
foreach ($items as $item) {
|
||||
$names[] = self::getNameWithExtras($item, $extras);
|
||||
}
|
||||
return $names;
|
||||
}
|
||||
public static function prepareSelectItem(string $string, int $remove_first = 0): string
|
||||
{
|
||||
if (empty($string)) {
|
||||
return '';
|
||||
}
|
||||
$string = str_replace([' ', ' '], ' ', $string);
|
||||
$string = RL_RegEx::replace('^(- )+', ' ', $string);
|
||||
for ($i = 0; $remove_first > $i; $i++) {
|
||||
$string = RL_RegEx::replace('^ ', '', $string, '');
|
||||
}
|
||||
if (RL_RegEx::match('^( *)(.*)$', $string, $match, '')) {
|
||||
[$string, $pre, $name] = $match;
|
||||
$pre = str_replace(' ', ' · ', $pre);
|
||||
$pre = RL_RegEx::replace('(( · )*) · ', '\1 » ', $pre);
|
||||
$pre = str_replace(' ', ' ', $pre);
|
||||
$string = $pre . $name;
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
/**
|
||||
* Render a full select list
|
||||
*/
|
||||
public static function selectList(int|array $options, string $name, mixed $value, string $id, array $attributes = [], bool $treeselect = \false, bool $collapse_children = \false, null|int $max_list_count = null): string
|
||||
{
|
||||
if (empty($options)) {
|
||||
return '<fieldset class="radio">' . JText::_('RL_NO_ITEMS_FOUND') . '</fieldset>';
|
||||
}
|
||||
$params = RL_Parameters::getPlugin('regularlabs');
|
||||
$max_list_count = $max_list_count ?? $params->max_list_count;
|
||||
if (!is_array($value)) {
|
||||
$value = explode(',', $value);
|
||||
}
|
||||
if (count($value) === 1 && str_contains($value[0], ',')) {
|
||||
$value = explode(',', $value[0]);
|
||||
}
|
||||
$count = 0;
|
||||
if ($max_list_count && $options != -1) {
|
||||
foreach ($options as $option) {
|
||||
$count++;
|
||||
if (isset($option->links)) {
|
||||
$count += count($option->links);
|
||||
}
|
||||
if ($count > $params->max_list_count) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($options == -1 || $max_list_count && $count > $max_list_count) {
|
||||
if (is_array($value)) {
|
||||
$value = implode(',', $value);
|
||||
}
|
||||
if (!$value) {
|
||||
$input = '<textarea name="' . $name . '" id="' . $id . '" cols="40" rows="5">' . $value . '</textarea>';
|
||||
} else {
|
||||
$input = '<input type="text" name="' . $name . '" id="' . $id . '" value="' . $value . '" size="60">';
|
||||
}
|
||||
$plugin = JPluginHelper::getPlugin('system', 'regularlabs');
|
||||
$url = !empty($plugin->id) ? 'index.php?option=com_plugins&task=plugin.edit&extension_id=' . $plugin->id : 'index.php?option=com_plugins&&filter[folder]=&filter[search]=Regular%20Labs%20Library';
|
||||
$label = JText::_('RL_ITEM_IDS');
|
||||
$text = JText::_('RL_MAX_LIST_COUNT_INCREASE');
|
||||
$tooltip = JText::_('RL_MAX_LIST_COUNT_INCREASE_DESC,' . $max_list_count . ',RL_MAX_LIST_COUNT');
|
||||
$link = '<a href="' . $url . '" target="_blank" id="' . $id . '_msg"' . ' class="hasPopover" title="' . $text . '" data-content="' . htmlentities($tooltip) . '">' . '<span class="icon icon-cog"></span>' . $text . '</a>';
|
||||
$script = 'jQuery("#' . $id . '_msg").popover({"html": true,"trigger": "hover focus","container": "body"})';
|
||||
return '<fieldset class="radio">' . '<label for="' . $id . '">' . $label . ':</label>' . $input . '<br><small>' . $link . '</small>' . '</fieldset>' . '<script>' . $script . '</script>';
|
||||
}
|
||||
$layout = self::getLayout($options, $treeselect);
|
||||
$path = $treeselect ? JPATH_SITE . '/libraries/regularlabs/layouts' : null;
|
||||
$data = [...compact('id', 'name', 'value', 'options'), 'multiple' => \false, 'autofocus' => \false, 'onchange' => '', 'dataAttribute' => '', 'readonly' => \false, 'disabled' => '', 'hint' => \false, 'required' => \false, 'collapse_children' => $collapse_children, 'groups' => $options, ...$attributes];
|
||||
$renderer = new JFileLayout($layout, $path);
|
||||
return $renderer->render($data);
|
||||
}
|
||||
/**
|
||||
* Render a select list loaded via Ajax
|
||||
*/
|
||||
public static function selectListAjax(string $field_class, string $name, mixed $value, string $id, array $attributes = [], bool $treeselect = \false, bool $collapse_children = \false): string
|
||||
{
|
||||
RL_Document::style('regularlabs.admin-form');
|
||||
RL_Document::script('regularlabs.admin-form');
|
||||
RL_Document::script('regularlabs.regular');
|
||||
RL_Document::script('regularlabs.script');
|
||||
if ($treeselect) {
|
||||
RL_Document::script('regularlabs.treeselect');
|
||||
RL_Document::useScript('bootstrap.dropdown');
|
||||
} else {
|
||||
RL_Document::usePreset('choicesjs');
|
||||
RL_Document::useScript('webcomponent.field-fancy-select');
|
||||
}
|
||||
if (is_array($value)) {
|
||||
$value = implode(',', $value);
|
||||
}
|
||||
$ajax_data = ['parent_request' => ['option' => RL_Input::getCmd('option'), 'view' => RL_Input::getCmd('view'), 'id' => RL_Input::getInt('id')], 'field_class' => $field_class, 'value' => $value, 'attributes' => $attributes, 'treeselect' => $treeselect, 'collapse_children' => $collapse_children];
|
||||
return '<div class="rl-ajax-wrapper">' . '<textarea name="' . $name . '" id="' . $id . '" cols="40" rows="1" class="form-control rl-ajax-field"' . ' data-rl-ajax="' . htmlspecialchars(json_encode($ajax_data)) . '">' . $value . '</textarea>' . '<div class="rl-spinner"></div>' . '</div>';
|
||||
}
|
||||
}
|
||||
321
libraries/regularlabs/src/Form/FormField.php
Normal file
321
libraries/regularlabs/src/Form/FormField.php
Normal file
@ -0,0 +1,321 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 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;
|
||||
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;
|
||||
use function explode;
|
||||
use function is_array;
|
||||
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 null|int $max_list_count = null;
|
||||
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 = $this->max_list_count ?? $params->max_list_count;
|
||||
RL_Document::style('regularlabs.admin-form');
|
||||
}
|
||||
/**
|
||||
* Get a value from the field params
|
||||
*/
|
||||
public function get(string $key, mixed $default = ''): mixed
|
||||
{
|
||||
$value = $default;
|
||||
if (isset($this->params[$key]) && (string) $this->params[$key] != '') {
|
||||
$value = (string) $this->params[$key];
|
||||
}
|
||||
return $this->sanitizeValue($value);
|
||||
}
|
||||
public function getAjaxRaw(JRegistry|\RegularLabs\Library\Form\FormField $attributes): string
|
||||
{
|
||||
return $this->selectListForAjax($attributes);
|
||||
}
|
||||
public function getControlGroupEnd(): string
|
||||
{
|
||||
return '</div></div>';
|
||||
}
|
||||
public function getControlGroupStart(): string
|
||||
{
|
||||
return '<div class="control-group"><div class="control-label">';
|
||||
}
|
||||
/**
|
||||
* Return a list option using the custom prepare methods
|
||||
*/
|
||||
public function getOptionByListItem(object $item, array $extras = [], int $levelOffset = 0, string $key = 'id'): object
|
||||
{
|
||||
$name = \RegularLabs\Library\Form\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 an array of options using the custom prepare methods
|
||||
*/
|
||||
public function getOptionsByList(array $list, array $extras = [], int $levelOffset = 0, string $key = 'id'): array
|
||||
{
|
||||
$options = [];
|
||||
foreach ($list as $id => $item) {
|
||||
$options[$id] = $this->getOptionByListItem($item, $extras, $levelOffset, $key);
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
/**
|
||||
* Method to post-process a field value.
|
||||
*
|
||||
* @param mixed $value The optional value to use as the default for the field.
|
||||
* @param string $group The optional dot-separated form group path on which to find the field.
|
||||
* @param ?Registry $input An optional Registry object with the entire data set to filter
|
||||
* against the entire form.
|
||||
*
|
||||
* @return mixed The processed value.
|
||||
*/
|
||||
public function postProcess($value, $group = null, Registry $input = null)
|
||||
{
|
||||
if (!$this->multiple) {
|
||||
return $value;
|
||||
}
|
||||
if (!is_array($value)) {
|
||||
$value = [$value];
|
||||
}
|
||||
if (count($value) == 1) {
|
||||
$value = explode(',', $value[0]);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
/**
|
||||
* Prepare the option string, handling language strings
|
||||
*/
|
||||
public function prepareText(?string $string = ''): 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 $string): 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;
|
||||
}
|
||||
public function sanitizeValue(mixed $value): mixed
|
||||
{
|
||||
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(): string
|
||||
{
|
||||
return $this->selectListFromData($this);
|
||||
}
|
||||
public function selectListAjax(): string
|
||||
{
|
||||
$class = $this->get('class', '');
|
||||
$multiple = $this->get('multiple', \false);
|
||||
$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 \RegularLabs\Library\Form\Form::selectListAjax($this::class, $this->name, $this->value, $this->id, $attributes, $tree_select, $tree_select && $this->collapse_children);
|
||||
}
|
||||
public function selectListForAjax(JRegistry|\RegularLabs\Library\Form\FormField $data): string
|
||||
{
|
||||
return $this->selectListFromData($data);
|
||||
}
|
||||
public function selectListFromData(JRegistry|\RegularLabs\Library\Form\FormField $data): string
|
||||
{
|
||||
$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);
|
||||
if (!is_array($value)) {
|
||||
$value = explode(',', $value);
|
||||
}
|
||||
$this->value = $value;
|
||||
$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 \RegularLabs\Library\Form\Form::selectList($options, $name, $value, $id, $attributes, $tree_select && $multiple, $tree_select && $multiple && $collapse_children, $this->max_list_count);
|
||||
}
|
||||
/**
|
||||
* Method declaration must be compatible with JFormField::setup()
|
||||
*/
|
||||
public function setup(SimpleXMLElement $element, $value, $group = null)
|
||||
{
|
||||
$this->params = $element->attributes();
|
||||
return parent::setup($element, $value, $group);
|
||||
}
|
||||
/**
|
||||
* Method declaration must be compatible with JFormField::getInput()
|
||||
*/
|
||||
protected function getInput()
|
||||
{
|
||||
if (!$this->is_select_list) {
|
||||
return '';
|
||||
}
|
||||
if (!$this->use_ajax && !$this->use_tree_select) {
|
||||
return $this->selectList();
|
||||
}
|
||||
return $this->selectListAjax();
|
||||
}
|
||||
/**
|
||||
* Method declaration must be compatible with JFormField::getLabel()
|
||||
*/
|
||||
protected function getLabel()
|
||||
{
|
||||
$this->element['label'] = $this->prepareText($this->element['label']);
|
||||
return $this->element['label'] == '---' ? ' ' : parent::getLabel();
|
||||
}
|
||||
protected function getListOptions(array $attributes): array|int
|
||||
{
|
||||
return $this->getOptions();
|
||||
}
|
||||
/**
|
||||
* Return the field options (array)
|
||||
* Overrules the Joomla core functionality
|
||||
* Method declaration must be compatible with JFormField::getOptions()
|
||||
*/
|
||||
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
|
||||
*/
|
||||
private function fixLanguageStringSyntax(string $string = ''): 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
|
||||
*/
|
||||
private function getShortFieldName(): string
|
||||
{
|
||||
return substr((new ReflectionClass($this))->getShortName(), 0, -strlen('Field'));
|
||||
}
|
||||
private function setTextAsValue(array &$options): void
|
||||
{
|
||||
if (empty($options)) {
|
||||
return;
|
||||
}
|
||||
foreach ($options as &$option) {
|
||||
$option->value = $option->text;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
libraries/regularlabs/src/Form/FormFieldGroup.php
Normal file
22
libraries/regularlabs/src/Form/FormFieldGroup.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library\Form;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
/**
|
||||
* @depracated No longer used
|
||||
*/
|
||||
class FormFieldGroup extends \RegularLabs\Library\Form\FormField
|
||||
{
|
||||
public $default_group = 'Categories';
|
||||
public $type = 'Field';
|
||||
}
|
||||
508
libraries/regularlabs/src/Html.php
Normal file
508
libraries/regularlabs/src/Html.php
Normal file
@ -0,0 +1,508 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use DOMDocument;
|
||||
class Html
|
||||
{
|
||||
/**
|
||||
* Removes complete html tag pairs from the concatenated parts
|
||||
*/
|
||||
public static function cleanSurroundingTags(array $parts, array $elements = ['p', 'span', 'strong', 'b', 'em', 'i']): array
|
||||
{
|
||||
$breaks = '(?:(?:<br ?/?>|<\!--[^>]*-->|:\|:)\s*)*';
|
||||
$keys = array_keys($parts);
|
||||
$string = implode(':|:', $parts);
|
||||
\RegularLabs\Library\Protect::protectHtmlCommentTags($string);
|
||||
// Remove empty tags
|
||||
$regex = '<(?<tag>' . implode('|', $elements) . ')(?: [^>]*)?>\s*(?<breaks>' . $breaks . ')<\/\1>\s*';
|
||||
while (\RegularLabs\Library\RegEx::match($regex, $string, $match)) {
|
||||
$string = str_replace($match[0], $match['breaks'], $string);
|
||||
}
|
||||
// Remove paragraphs around block elements
|
||||
$block_elements = ['p', 'div', 'table', 'tr', 'td', 'thead', 'tfoot', 'h[1-6]'];
|
||||
$block_elements = '(?<element>' . implode('|', $block_elements) . ')';
|
||||
$regex = '(?<p_tag><p(?: [^>]*)?>)(?<breaks>\s*' . $breaks . ')(?<block_tag><' . $block_elements . '(?: [^>]*)?>)';
|
||||
while (\RegularLabs\Library\RegEx::match($regex, $string, $match)) {
|
||||
$tags = $match['block_tag'];
|
||||
if ($match['element'] == 'p') {
|
||||
$tags = $match['p_tag'] . $tags;
|
||||
self::combinePTags($tags);
|
||||
}
|
||||
$string = str_replace($match[0], $match['breaks'] . $tags, $string);
|
||||
}
|
||||
$regex = '(</' . $block_elements . '>\s*' . $breaks . ')</p>';
|
||||
while (\RegularLabs\Library\RegEx::match($regex, $string, $match)) {
|
||||
$string = str_replace($match[0], $match[1], $string);
|
||||
}
|
||||
\RegularLabs\Library\Protect::unprotect($string);
|
||||
$parts = explode(':|:', $string);
|
||||
$new_tags = [];
|
||||
foreach ($parts as $key => $val) {
|
||||
$key = $keys[$key] ?? $key;
|
||||
$new_tags[$key] = $val;
|
||||
}
|
||||
return $new_tags;
|
||||
}
|
||||
/**
|
||||
* Combine duplicate <p> tags
|
||||
* input: <p class="aaa" a="1"><!-- ... --><p class="bbb" b="2">
|
||||
* output: <p class="aaa bbb" a="1" b="2"><!-- ... -->
|
||||
*/
|
||||
public static function combinePTags(string &$string): void
|
||||
{
|
||||
if (empty($string)) {
|
||||
return;
|
||||
}
|
||||
$p_start_tag = '<p(?: [^>]*)?>';
|
||||
$optional_tags = '\s*(?:<\!--[^>]*-->| |&\#160;)*\s*';
|
||||
\RegularLabs\Library\Protect::protectHtmlCommentTags($string);
|
||||
\RegularLabs\Library\RegEx::matchAll('(' . $p_start_tag . ')(' . $optional_tags . ')(' . $p_start_tag . ')', $string, $tags);
|
||||
if (empty($tags)) {
|
||||
\RegularLabs\Library\Protect::unprotect($string);
|
||||
return;
|
||||
}
|
||||
foreach ($tags as $tag) {
|
||||
$string = str_replace($tag[0], $tag[2] . \RegularLabs\Library\HtmlTag::combine($tag[1], $tag[3]), $string);
|
||||
}
|
||||
\RegularLabs\Library\Protect::unprotect($string);
|
||||
}
|
||||
/**
|
||||
* Check if string contains block elements
|
||||
*/
|
||||
public static function containsBlockElements(string $string): string
|
||||
{
|
||||
return \RegularLabs\Library\RegEx::match('</?(' . implode('|', self::getBlockElements()) . ')(?: [^>]*)?>', $string);
|
||||
}
|
||||
/**
|
||||
* Convert content saved in a WYSIWYG editor to plain text (like removing html tags)
|
||||
*/
|
||||
public static function convertWysiwygToPlainText(string $string): string
|
||||
{
|
||||
// replace chr style enters with normal enters
|
||||
$string = str_replace([chr(194) . chr(160), ' ', ' '], ' ', $string);
|
||||
// replace linebreak tags with normal linebreaks (paragraphs, enters, etc).
|
||||
$enter_tags = ['p', 'br'];
|
||||
$regex = '</?((' . implode(')|(', $enter_tags) . '))+[^>]*?>\n?';
|
||||
$string = \RegularLabs\Library\RegEx::replace($regex, " \n", $string);
|
||||
// replace indent characters with spaces
|
||||
$string = \RegularLabs\Library\RegEx::replace('<img [^>]*/sourcerer/images/tab\.png[^>]*>', ' ', $string);
|
||||
// strip all other tags
|
||||
$regex = '<(/?\w+((\s+\w+(\s*=\s*(?:".*?"|\'.*?\'|[^\'">\s]+))?)+\s*|\s*)/?)>';
|
||||
$string = \RegularLabs\Library\RegEx::replace($regex, '', $string);
|
||||
// reset htmlentities
|
||||
$string = \RegularLabs\Library\StringHelper::html_entity_decoder($string);
|
||||
// convert protected html entities &_...; -> &...;
|
||||
$string = \RegularLabs\Library\RegEx::replace('&_([a-z0-9\#]+?);', '&\1;', $string);
|
||||
return $string;
|
||||
}
|
||||
/**
|
||||
* Fix broken/invalid html syntax in a string
|
||||
*/
|
||||
public static function fix(string $string): string
|
||||
{
|
||||
if (!self::containsBlockElements($string)) {
|
||||
return $string;
|
||||
}
|
||||
// Convert utf8 characters to html entities
|
||||
if (function_exists('mb_decode_numericentity')) {
|
||||
$string = mb_encode_numericentity($string, [0x80, 0xffff, 0, ~0], 'UTF-8');
|
||||
}
|
||||
$string = self::protectSpecialCode($string);
|
||||
$string = self::convertDivsInsideInlineElementsToSpans($string);
|
||||
$string = self::removeParagraphsAroundBlockElements($string);
|
||||
$string = self::removeInlineElementsAroundBlockElements($string);
|
||||
$string = self::fixParagraphsAroundParagraphElements($string);
|
||||
$string = class_exists('DOMDocument') ? self::fixUsingDOMDocument($string) : self::fixUsingCustomFixer($string);
|
||||
$string = self::unprotectSpecialCode($string);
|
||||
// Convert html entities back to utf8 characters
|
||||
if (function_exists('mb_decode_numericentity')) {
|
||||
$string = mb_decode_numericentity($string, [0x80, 0xffff, 0, ~0], 'UTF-8');
|
||||
}
|
||||
$string = self::removeParagraphsAroundComments($string);
|
||||
return $string;
|
||||
}
|
||||
/**
|
||||
* Fix broken/invalid html syntax in an array of strings
|
||||
*/
|
||||
public static function fixArray(array $array): array
|
||||
{
|
||||
$splitter = ':|:';
|
||||
$string = self::fix(implode($splitter, $array));
|
||||
$parts = self::removeEmptyTags(explode($splitter, $string));
|
||||
// use original keys but new values
|
||||
return array_combine(array_keys($array), $parts);
|
||||
}
|
||||
/**
|
||||
* Return an array of block element names, optionally without any of the names given $exclude
|
||||
*/
|
||||
public static function getBlockElements(array $exclude = []): array
|
||||
{
|
||||
if (!is_array($exclude)) {
|
||||
$exclude = [$exclude];
|
||||
}
|
||||
$elements = ['div', 'p', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
|
||||
$elements = array_diff($elements, $exclude);
|
||||
$elements = implode(',', $elements);
|
||||
$elements = str_replace('h1,h2,h3,h4,h5,h6', 'h[1-6]', $elements);
|
||||
$elements = explode(',', $elements);
|
||||
return $elements;
|
||||
}
|
||||
/**
|
||||
* Return an array of block element names, without divs and any of the names given $exclude
|
||||
*/
|
||||
public static function getBlockElementsNoDiv(array $exclude = []): array
|
||||
{
|
||||
return array_diff(self::getBlockElements($exclude), ['div']);
|
||||
}
|
||||
/**
|
||||
* Extract the <body>...</body> part from an entire html output string
|
||||
*/
|
||||
public static function getBody(string $html, bool $include_body_tag = \true): array
|
||||
{
|
||||
if (!str_contains($html, '<body') || !str_contains($html, '</body>')) {
|
||||
return ['', $html, ''];
|
||||
}
|
||||
// Force string to UTF-8
|
||||
$html = \RegularLabs\Library\StringHelper::convertToUtf8($html);
|
||||
$split = explode('<body', $html, 2);
|
||||
$pre = $split[0];
|
||||
$split = explode('>', $split[1], 2);
|
||||
$body_start = '<body' . $split[0] . '>';
|
||||
$body_end = '</body>';
|
||||
$split = explode('</body>', $split[1]);
|
||||
$post = array_pop($split);
|
||||
$body = implode('</body>', $split);
|
||||
if (!$include_body_tag) {
|
||||
return [$pre . $body_start, $body, $body_end . $post];
|
||||
}
|
||||
return [$pre, $body_start . $body . $body_end, $post];
|
||||
}
|
||||
/**
|
||||
* Search the string for the start and end searches and split the string in a pre, body and post part
|
||||
* This is used to be able to do replacements on the body part, which will be lighter than doing it on the entire string
|
||||
*/
|
||||
public static function getContentContainingSearches(string $string, array $start_searches = [], array $end_searches = [], int $start_offset = 1000, ?int $end_offset = null): array
|
||||
{
|
||||
// String is too short to split and search through
|
||||
if (strlen($string) < 2000) {
|
||||
return ['', $string, ''];
|
||||
}
|
||||
$end_offset = is_null($end_offset) ? $start_offset : $end_offset;
|
||||
$found = \false;
|
||||
$start_split = strlen($string);
|
||||
foreach ($start_searches as $search) {
|
||||
$pos = strpos($string, $search);
|
||||
if ($pos === \false) {
|
||||
continue;
|
||||
}
|
||||
$start_split = min($start_split, $pos);
|
||||
$found = \true;
|
||||
}
|
||||
// No searches are found
|
||||
if (!$found) {
|
||||
return [$string, '', ''];
|
||||
}
|
||||
// String is too short to split
|
||||
if (strlen($string) < $start_offset + $end_offset + 1000) {
|
||||
return ['', $string, ''];
|
||||
}
|
||||
$start_split = max($start_split - $start_offset, 0);
|
||||
$pre = substr($string, 0, $start_split);
|
||||
$string = substr($string, $start_split);
|
||||
self::fixBrokenTagsByPreString($pre, $string);
|
||||
if (empty($end_searches)) {
|
||||
$end_searches = $start_searches;
|
||||
}
|
||||
$end_split = 0;
|
||||
$found = \false;
|
||||
foreach ($end_searches as $search) {
|
||||
$pos = strrpos($string, $search);
|
||||
if ($pos === \false) {
|
||||
continue;
|
||||
}
|
||||
$end_split = max($end_split, $pos + strlen($search));
|
||||
$found = \true;
|
||||
}
|
||||
// No end split is found, so don't split remainder
|
||||
if (!$found) {
|
||||
return [$pre, $string, ''];
|
||||
}
|
||||
$end_split = min($end_split + $end_offset, strlen($string));
|
||||
$post = substr($string, $end_split);
|
||||
$string = substr($string, 0, $end_split);
|
||||
self::fixBrokenTagsByPostString($post, $string);
|
||||
return [$pre, $string, $post];
|
||||
}
|
||||
/**
|
||||
* Return an array of inline element names, optionally without any of the names given $exclude
|
||||
*/
|
||||
public static function getInlineElements(array $exclude = []): array
|
||||
{
|
||||
if (!is_array($exclude)) {
|
||||
$exclude = [$exclude];
|
||||
}
|
||||
$elements = ['span', 'code', 'a', 'strong', 'b', 'em', 'i', 'u', 'big', 'small', 'font', 'sup', 'sub'];
|
||||
return array_diff($elements, $exclude);
|
||||
}
|
||||
/**
|
||||
* Return an array of block element names, without anchors (a) and any of the names given $exclude
|
||||
*/
|
||||
public static function getInlineElementsNoAnchor(array $exclude = []): array
|
||||
{
|
||||
return array_diff(self::getInlineElements($exclude), ['a']);
|
||||
}
|
||||
/**
|
||||
* Remove empty tags
|
||||
*/
|
||||
public static function removeEmptyTagPairs(string $string, array $elements = ['p', 'span']): string
|
||||
{
|
||||
$breaks = '(?:(?:<br ?/?>|<\!--[^>]*-->)\s*)*';
|
||||
$regex = '<(' . implode('|', $elements) . ')(?: [^>]*)?>\s*(' . $breaks . ')<\/\1>\s*';
|
||||
\RegularLabs\Library\Protect::protectHtmlCommentTags($string);
|
||||
while (\RegularLabs\Library\RegEx::match($regex, $string, $match)) {
|
||||
$string = str_replace($match[0], $match[2], $string);
|
||||
}
|
||||
\RegularLabs\Library\Protect::unprotect($string);
|
||||
return $string;
|
||||
}
|
||||
/**
|
||||
* Removes empty tags which span concatenating parts in the array
|
||||
*/
|
||||
public static function removeEmptyTags(array $array): array
|
||||
{
|
||||
$splitter = ':|:';
|
||||
$comments = '(?:\s*<\!--[^>]*-->\s*)*';
|
||||
$string = implode($splitter, $array);
|
||||
\RegularLabs\Library\Protect::protectHtmlCommentTags($string);
|
||||
$string = \RegularLabs\Library\RegEx::replace('<([a-z][a-z0-9]*)(?: [^>]*)?>\s*(' . $comments . \RegularLabs\Library\RegEx::quote($splitter) . $comments . ')\s*</\1>', '\2', $string);
|
||||
\RegularLabs\Library\Protect::unprotect($string);
|
||||
return explode($splitter, $string);
|
||||
}
|
||||
/**
|
||||
* Removes html tags from string
|
||||
*/
|
||||
public static function removeHtmlTags(string $string, bool $remove_comments = \false): string
|
||||
{
|
||||
// remove pagenavcounter
|
||||
$string = \RegularLabs\Library\RegEx::replace('<div class="pagenavcounter">.*?</div>', ' ', $string);
|
||||
// remove pagenavbar
|
||||
$string = \RegularLabs\Library\RegEx::replace('<div class="pagenavbar">(<div>.*?</div>)*</div>', ' ', $string);
|
||||
// remove inline scripts
|
||||
$string = \RegularLabs\Library\RegEx::replace('<script[^a-z0-9].*?</script>', '', $string);
|
||||
$string = \RegularLabs\Library\RegEx::replace('<noscript[^a-z0-9].*?</noscript>', '', $string);
|
||||
// remove inline styles
|
||||
$string = \RegularLabs\Library\RegEx::replace('<style[^a-z0-9].*?</style>', '', $string);
|
||||
// remove inline html tags
|
||||
$string = \RegularLabs\Library\RegEx::replace('</?(' . implode('|', self::getInlineElements()) . ')( [^>]*)?>', '', $string);
|
||||
if ($remove_comments) {
|
||||
// remove html comments
|
||||
$string = \RegularLabs\Library\RegEx::replace('<!--.*?-->', ' ', $string);
|
||||
}
|
||||
// replace other tags with a space
|
||||
$string = \RegularLabs\Library\RegEx::replace('</?[a-z].*?>', ' ', $string);
|
||||
// remove double whitespace
|
||||
$string = trim(\RegularLabs\Library\RegEx::replace('(\s)[ ]+', '\1', $string));
|
||||
return $string;
|
||||
}
|
||||
/**
|
||||
* Remove inline elements around block elements
|
||||
*/
|
||||
public static function removeInlineElementsAroundBlockElements(string $string): string
|
||||
{
|
||||
$string = \RegularLabs\Library\RegEx::replace('(?:<(?:' . implode('|', self::getInlineElementsNoAnchor()) . ')(?: [^>]*)?>\s*)' . '(</?(?:' . implode('|', self::getBlockElements()) . ')(?: [^>]*)?>)', '\1', $string);
|
||||
$string = \RegularLabs\Library\RegEx::replace('(</?(?:' . implode('|', self::getBlockElements()) . ')(?: [^>]*)?>)' . '(?:\s*</(?:' . implode('|', self::getInlineElementsNoAnchor()) . ')>)', '\1', $string);
|
||||
return $string;
|
||||
}
|
||||
/**
|
||||
* Convert <div> tags inside inline elements to <span> tags
|
||||
*/
|
||||
private static function convertDivsInsideInlineElementsToSpans(string $string): string
|
||||
{
|
||||
if (!str_contains($string, '</div>')) {
|
||||
return $string;
|
||||
}
|
||||
// Ignore block elements inside anchors
|
||||
$regex = '<(' . implode('|', self::getInlineElementsNoAnchor()) . ')(?: [^>]*)?>.*?</\1>';
|
||||
\RegularLabs\Library\RegEx::matchAll($regex, $string, $matches, '', \PREG_PATTERN_ORDER);
|
||||
if (empty($matches)) {
|
||||
return $string;
|
||||
}
|
||||
$matches = array_unique($matches[0]);
|
||||
$searches = [];
|
||||
$replacements = [];
|
||||
foreach ($matches as $match) {
|
||||
if (!str_contains($match, '</div>')) {
|
||||
continue;
|
||||
}
|
||||
$searches[] = $match;
|
||||
$replacements[] = str_replace(['<div>', '<div ', '</div>'], ['<span>', '<span ', '</span>'], $match);
|
||||
}
|
||||
if (empty($searches)) {
|
||||
return $string;
|
||||
}
|
||||
return str_replace($searches, $replacements, $string);
|
||||
}
|
||||
/**
|
||||
* Prevents broken html tags at the beginning of $pre (other half at end of $string)
|
||||
* It will move the broken part to the end of $string to complete it
|
||||
*/
|
||||
private static function fixBrokenTagsByPostString(string &$post, string &$string): void
|
||||
{
|
||||
if (!\RegularLabs\Library\RegEx::match('<(\![^>]*|/?[a-z][^>]*(="[^"]*)?)$', $string, $match)) {
|
||||
return;
|
||||
}
|
||||
if (!\RegularLabs\Library\RegEx::match('^[^>]*>', $post, $match)) {
|
||||
return;
|
||||
}
|
||||
$post = substr($post, strlen($match[0]));
|
||||
$string .= $match[0];
|
||||
}
|
||||
/**
|
||||
* Prevents broken html tags at the end of $pre (other half at beginning of $string)
|
||||
* It will move the broken part to the beginning of $string to complete it
|
||||
*/
|
||||
private static function fixBrokenTagsByPreString(string &$pre, string &$string): void
|
||||
{
|
||||
if (!\RegularLabs\Library\RegEx::match('<(\![^>]*|/?[a-z][^>]*(="[^"]*)?)$', $pre, $match)) {
|
||||
return;
|
||||
}
|
||||
$pre = substr($pre, 0, strlen($pre) - strlen($match[0]));
|
||||
$string = $match[0] . $string;
|
||||
}
|
||||
/**
|
||||
* Fix <p> tags around other <p> elements
|
||||
*/
|
||||
private static function fixParagraphsAroundParagraphElements(string $string): string
|
||||
{
|
||||
if (!str_contains($string, '</p>')) {
|
||||
return $string;
|
||||
}
|
||||
$parts = explode('</p>', $string);
|
||||
$ending = '</p>' . array_pop($parts);
|
||||
foreach ($parts as &$part) {
|
||||
if (!str_contains($part, '<p>') && !str_contains($part, '<p ')) {
|
||||
$part = '<p>' . $part;
|
||||
continue;
|
||||
}
|
||||
$part = \RegularLabs\Library\RegEx::replace('(<p(?: [^>]*)?>.*?)(<p(?: [^>]*)?>)', '\1</p>\2', $part);
|
||||
}
|
||||
return implode('</p>', $parts) . $ending;
|
||||
}
|
||||
/**
|
||||
* Fix broken/invalid html syntax in a string using custom code as an alternative to php DOMDocument functionality
|
||||
*/
|
||||
private static function fixUsingCustomFixer(string $string): string
|
||||
{
|
||||
$block_regex = '<(' . implode('|', self::getBlockElementsNoDiv()) . ')[\s>]';
|
||||
$string = \RegularLabs\Library\RegEx::replace('(' . $block_regex . ')', '[:SPLIT-BLOCK:]\1', $string);
|
||||
$parts = explode('[:SPLIT-BLOCK:]', $string);
|
||||
foreach ($parts as $i => &$part) {
|
||||
if (!\RegularLabs\Library\RegEx::match('^' . $block_regex, $part, $type)) {
|
||||
continue;
|
||||
}
|
||||
$type = strtolower($type[1]);
|
||||
// remove endings of other block elements
|
||||
$part = \RegularLabs\Library\RegEx::replace('</(?:' . implode('|', self::getBlockElementsNoDiv($type)) . ')>', '', $part);
|
||||
if (str_contains($part, '</' . $type . '>')) {
|
||||
continue;
|
||||
}
|
||||
// Add ending tag once
|
||||
$part = \RegularLabs\Library\RegEx::replaceOnce('(\s*)$', '</' . $type . '>\1', $part);
|
||||
// Remove empty block tags
|
||||
$part = \RegularLabs\Library\RegEx::replace('^<' . $type . '(?: [^>]*)?>\s*</' . $type . '>', '', $part);
|
||||
}
|
||||
return implode('', $parts);
|
||||
}
|
||||
/**
|
||||
* Fix broken/invalid html syntax in a string using php DOMDocument functionality
|
||||
*/
|
||||
private static function fixUsingDOMDocument(string $string): string
|
||||
{
|
||||
$doc = new DOMDocument();
|
||||
$doc->substituteEntities = \false;
|
||||
[$pre, $body, $post] = \RegularLabs\Library\Html::getBody($string, \false);
|
||||
// Add temporary document structures
|
||||
$body = '<html><body><div>' . $body . '</div></body></html>';
|
||||
@$doc->loadHTML($body);
|
||||
$body = $doc->saveHTML();
|
||||
if (str_contains($doc->documentElement->textContent, 'Ã')) {
|
||||
// Need to do this utf8 workaround to deal with special characters
|
||||
// DOMDocument doesn't seem to deal with them very well
|
||||
// See: https://stackoverflow.com/questions/8218230/php-domdocument-loadhtml-not-encoding-utf-8-correctly/47396055#47396055
|
||||
$body = \RegularLabs\Library\StringHelper::utf8_decode($doc->saveHTML($doc->documentElement));
|
||||
}
|
||||
// Remove temporary document structures and surrounding div
|
||||
$body = \RegularLabs\Library\RegEx::replace('^.*?<html>.*?(?:<head>(.*)</head>.*?)?<body>\s*<div>(.*)</div>\s*</body>.*?$', '\1\2', $body);
|
||||
// Remove leading/trailing empty paragraph
|
||||
$body = \RegularLabs\Library\RegEx::replace('(^\s*<div>\s*</div>|<div>\s*</div>\s*$)', '', $body);
|
||||
// Remove leading/trailing empty paragraph
|
||||
$body = \RegularLabs\Library\RegEx::replace('(^\s*<div>\s*</div>|<div>\s*</div>\s*$)', '', $body);
|
||||
// Remove leading/trailing empty paragraph
|
||||
$body = \RegularLabs\Library\RegEx::replace('(^\s*<p(?: [^>]*)?>\s*</p>|<p(?: [^>]*)?>\s*</p>\s*$)', '', $body);
|
||||
return $pre . $body . $post;
|
||||
}
|
||||
/**
|
||||
* Protect plugin style tags and php
|
||||
*/
|
||||
private static function protectSpecialCode(string $string): string
|
||||
{
|
||||
// Protect PHP code
|
||||
\RegularLabs\Library\Protect::protectByRegex($string, '(<|<)\?php\s.*?\?(>|>)');
|
||||
// Protect {...} tags
|
||||
\RegularLabs\Library\Protect::protectByRegex($string, '\{[a-z0-9].*?\}');
|
||||
// Protect [...] tags
|
||||
\RegularLabs\Library\Protect::protectByRegex($string, '\[[a-z0-9].*?\]');
|
||||
// Protect scripts
|
||||
\RegularLabs\Library\Protect::protectByRegex($string, '<script[^>]*>.*?</script>');
|
||||
// Protect css
|
||||
\RegularLabs\Library\Protect::protectByRegex($string, '<style[^>]*>.*?</style>');
|
||||
\RegularLabs\Library\Protect::convertProtectionToHtmlSafe($string);
|
||||
return $string;
|
||||
}
|
||||
/**
|
||||
* Remove <p> tags around block elements
|
||||
*/
|
||||
private static function removeParagraphsAroundBlockElements(string $string): string
|
||||
{
|
||||
if (!str_contains($string, '</p>')) {
|
||||
return $string;
|
||||
}
|
||||
\RegularLabs\Library\Protect::protectHtmlCommentTags($string);
|
||||
$string = \RegularLabs\Library\RegEx::replace('<p(?: [^>]*)?>\s*' . '((?:<\!--[^>]*-->\s*)*</?(?:' . implode('|', self::getBlockElements()) . ')' . '(?: [^>]*)?>)', '\1', $string);
|
||||
$string = \RegularLabs\Library\RegEx::replace('(</?(?:' . implode('|', self::getBlockElements()) . ')' . '(?: [^>]*)?>(?:\s*<\!--[^>]*-->)*)' . '(?:\s*</p>)', '\1', $string);
|
||||
\RegularLabs\Library\Protect::unprotect($string);
|
||||
return $string;
|
||||
}
|
||||
/**
|
||||
* Remove <p> tags around comments
|
||||
*/
|
||||
private static function removeParagraphsAroundComments(string $string): string
|
||||
{
|
||||
if (!str_contains($string, '</p>')) {
|
||||
return $string;
|
||||
}
|
||||
\RegularLabs\Library\Protect::protectHtmlCommentTags($string);
|
||||
$string = \RegularLabs\Library\RegEx::replace('(?:<p(?: [^>]*)?>\s*)' . '(<\!--[^>]*-->)' . '(?:\s*</p>)', '\1', $string);
|
||||
\RegularLabs\Library\Protect::unprotect($string);
|
||||
return $string;
|
||||
}
|
||||
/**
|
||||
* Unprotect protected tags
|
||||
*/
|
||||
private static function unprotectSpecialCode(string $string): string
|
||||
{
|
||||
\RegularLabs\Library\Protect::unprotectHtmlSafe($string);
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
124
libraries/regularlabs/src/HtmlTag.php
Normal file
124
libraries/regularlabs/src/HtmlTag.php
Normal file
@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
class HtmlTag
|
||||
{
|
||||
/**
|
||||
* Combine 2 opening html tags into one
|
||||
*/
|
||||
public static function combine(string $tag1, string $tag2): string
|
||||
{
|
||||
// Return if tags are the same
|
||||
if ($tag1 == $tag2) {
|
||||
return $tag1;
|
||||
}
|
||||
if (!\RegularLabs\Library\RegEx::match('<([a-z][a-z0-9]*)', $tag1, $tag_type)) {
|
||||
return $tag2;
|
||||
}
|
||||
$tag_type = $tag_type[1];
|
||||
$attribs = self::combineAttributes($tag1, $tag2);
|
||||
if (!$attribs) {
|
||||
return '<' . $tag_type . '>';
|
||||
}
|
||||
return '<' . $tag_type . ' ' . $attribs . '>';
|
||||
}
|
||||
/**
|
||||
* Combine attribute values from 2 given html tag strings (or arrays of attributes)
|
||||
* And return as a string of attributes (if $flatten = true)
|
||||
*/
|
||||
public static function combineAttributes(string|array $string1, string|array $string2, bool $flatten = \true): string|array
|
||||
{
|
||||
$attribsutes1 = is_array($string1) ? $string1 : self::getAttributes($string1);
|
||||
$attribsutes2 = is_array($string2) ? $string2 : self::getAttributes($string2);
|
||||
$duplicate_attributes = array_intersect_key($attribsutes1, $attribsutes2);
|
||||
// Fill $attributes with the unique ids
|
||||
$attributes = array_diff_key($attribsutes1, $attribsutes2) + array_diff_key($attribsutes2, $attribsutes1);
|
||||
// List of attrubute types that can only contain one value
|
||||
$single_value_attributes = ['id', 'href'];
|
||||
// Add/combine the duplicate ids
|
||||
foreach ($duplicate_attributes as $key => $val) {
|
||||
if (in_array($key, $single_value_attributes, \true)) {
|
||||
$attributes[$key] = $attribsutes2[$key];
|
||||
continue;
|
||||
}
|
||||
// Combine strings, but remove duplicates
|
||||
// "aaa bbb" + "aaa ccc" = "aaa bbb ccc"
|
||||
// use a ';' as a concatenated for javascript values (keys beginning with 'on')
|
||||
// Otherwise use a space (like for classes)
|
||||
$glue = str_starts_with($key, 'on') ? ';' : ' ';
|
||||
$attributes[$key] = implode($glue, [...explode($glue, $attribsutes1[$key]), ...explode($glue, $attribsutes2[$key])]);
|
||||
}
|
||||
return $flatten ? self::flattenAttributes($attributes) : $attributes;
|
||||
}
|
||||
/**
|
||||
* Convert array or object of attributes to a html style string
|
||||
*/
|
||||
public static function flattenAttributes(array|object $attributes, string $prefix = ''): string
|
||||
{
|
||||
$output = [];
|
||||
foreach ($attributes as $key => $val) {
|
||||
if (is_null($val) || $val === '') {
|
||||
continue;
|
||||
}
|
||||
if ($val === \false) {
|
||||
$val = 'false';
|
||||
}
|
||||
if ($val === \true) {
|
||||
$val = 'true';
|
||||
}
|
||||
$val = str_replace('"', '"', $val);
|
||||
$output[] = $prefix . $key . '="' . $val . '"';
|
||||
}
|
||||
return implode(' ', $output);
|
||||
}
|
||||
/**
|
||||
* Extract attribute value from a html tag string by given attribute key
|
||||
*/
|
||||
public static function getAttributeValue(string $key, string $string): string
|
||||
{
|
||||
if (empty($key) || empty($string)) {
|
||||
return '';
|
||||
}
|
||||
\RegularLabs\Library\RegEx::match(\RegularLabs\Library\RegEx::quote($key) . '="([^"]*)"', $string, $match);
|
||||
if (empty($match)) {
|
||||
return '';
|
||||
}
|
||||
return $match[1];
|
||||
}
|
||||
/**
|
||||
* Extract all attributes from a html tag string
|
||||
*/
|
||||
public static function getAttributes(string $string): array
|
||||
{
|
||||
if (empty($string)) {
|
||||
return [];
|
||||
}
|
||||
\RegularLabs\Library\RegEx::matchAll('([a-z0-9-_]+)="([^"]*)"', $string, $matches);
|
||||
if (empty($matches)) {
|
||||
return [];
|
||||
}
|
||||
$attribs = [];
|
||||
foreach ($matches as $match) {
|
||||
$attribs[$match[1]] = $match[2];
|
||||
}
|
||||
return $attribs;
|
||||
}
|
||||
/**
|
||||
* Returns true/false based on whether the html tag type is a single tag
|
||||
*/
|
||||
public static function isSelfClosingTag(string $type): bool
|
||||
{
|
||||
return in_array($type, ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'], \true);
|
||||
}
|
||||
}
|
||||
117
libraries/regularlabs/src/Http.php
Normal file
117
libraries/regularlabs/src/Http.php
Normal file
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
use Joomla\CMS\Http\HttpFactory as JHttpFactory;
|
||||
use Joomla\Registry\Registry;
|
||||
use RuntimeException;
|
||||
/**
|
||||
* Class Http
|
||||
*
|
||||
* @package RegularLabs\Library
|
||||
*/
|
||||
class Http
|
||||
{
|
||||
/**
|
||||
* Get the contents of the given internal url
|
||||
*/
|
||||
public static function get(string $url, int $timeout = 20, string $default = ''): string
|
||||
{
|
||||
if (\RegularLabs\Library\Uri::isExternal($url)) {
|
||||
return $default;
|
||||
}
|
||||
return @file_get_contents($url, \false, stream_context_create(['http' => ['timeout' => $timeout]])) || self::getFromUrl($url, $timeout, $default);
|
||||
}
|
||||
/**
|
||||
* Get the contents of the given external url from the Regular Labs server
|
||||
*/
|
||||
public static function getFromServer(string $url, int $timeout = 20, string $default = ''): string
|
||||
{
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
$cache_ttl = \RegularLabs\Library\Input::getInt('cache', 0);
|
||||
if ($cache_ttl) {
|
||||
$cache->useFiles($cache_ttl > 1 ? $cache_ttl : null);
|
||||
}
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
// only allow url calls from administrator
|
||||
if (!\RegularLabs\Library\Document::isClient('administrator')) {
|
||||
die;
|
||||
}
|
||||
// only allow when logged in
|
||||
$user = JFactory::getApplication()->getIdentity() ?: JFactory::getUser();
|
||||
if (!$user->id) {
|
||||
die;
|
||||
}
|
||||
if (!str_starts_with($url, 'http')) {
|
||||
$url = 'http://' . $url;
|
||||
}
|
||||
// only allow url calls to regularlabs.com domain
|
||||
if (!\RegularLabs\Library\RegEx::match('^https?://([^/]+\.)?regularlabs\.com/', $url)) {
|
||||
die;
|
||||
}
|
||||
// only allow url calls to certain files
|
||||
if (!str_contains($url, 'download.regularlabs.com/extensions.php') && !str_contains($url, 'download.regularlabs.com/extensions.json') && !str_contains($url, 'download.regularlabs.com/extensions.xml') && !str_contains($url, 'download.regularlabs.com/check_key.php')) {
|
||||
die;
|
||||
}
|
||||
$content = self::getContents($url, $timeout);
|
||||
$format = str_contains($url, '.json') || str_contains($url, 'format=json') ? 'application/json' : 'text/xml';
|
||||
header("Pragma: public");
|
||||
header("Expires: 0");
|
||||
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
|
||||
header("Cache-Control: public");
|
||||
header("Content-type: " . $format);
|
||||
if (empty($content)) {
|
||||
return $default;
|
||||
}
|
||||
return $cache->set($content ?: $default);
|
||||
}
|
||||
/**
|
||||
* Get the contents of the given url
|
||||
*/
|
||||
public static function getFromUrl(string $url, int $timeout = 20, string $default = ''): string
|
||||
{
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
$cache_ttl = \RegularLabs\Library\Input::getInt('cache', 0);
|
||||
if ($cache_ttl) {
|
||||
$cache->useFiles($cache_ttl > 1 ? $cache_ttl : null);
|
||||
}
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
$content = self::getContents($url, $timeout);
|
||||
if (empty($content)) {
|
||||
return $default;
|
||||
}
|
||||
return $cache->set($content ?: $default);
|
||||
}
|
||||
/**
|
||||
* Load the contents of the given url
|
||||
*/
|
||||
private static function getContents(string $url, int $timeout = 20, string $default = ''): string
|
||||
{
|
||||
try {
|
||||
// Adding a valid user agent string, otherwise some feed-servers returning an error
|
||||
$options = new Registry(['userAgent' => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0']);
|
||||
$response = JHttpFactory::getHttp($options)->get($url, [], $timeout);
|
||||
$content = $response->body ?? $default;
|
||||
} catch (RuntimeException $e) {
|
||||
return $default;
|
||||
}
|
||||
// Remove prefix and postfix stuff added by SocketTransport
|
||||
$content = preg_replace('#^\s*1c\s*(\{.*\})\s*0\s*$#s', '$1', $content);
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
760
libraries/regularlabs/src/Image.php
Normal file
760
libraries/regularlabs/src/Image.php
Normal file
@ -0,0 +1,760 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
require_once dirname(__FILE__, 2) . '/vendor/autoload.php';
|
||||
use Exception;
|
||||
use RegularLabs\Scoped\Intervention\Image\Exception\NotReadableException as NotReadableException;
|
||||
use RegularLabs\Scoped\Intervention\Image\ImageManagerStatic as ImageManager;
|
||||
use Joomla\CMS\Filesystem\File as JFile;
|
||||
use Joomla\CMS\Uri\Uri as JUri;
|
||||
class Image
|
||||
{
|
||||
static $data_files = [];
|
||||
private $attributes;
|
||||
private $description;
|
||||
private $file;
|
||||
private $input;
|
||||
private $is_resized;
|
||||
private $output;
|
||||
private $settings;
|
||||
/**
|
||||
* @param object $attributes @deprecated use SET methods instead
|
||||
*/
|
||||
public function __construct(string $file = null, object $attributes = null)
|
||||
{
|
||||
$this->settings = (object) ['resize' => (object) ['enabled' => \true, 'quality' => 70, 'method' => 'crop', 'folder' => 'resized', 'max_age' => 0, 'force_overwrite' => \false, 'use_retina' => \true, 'retina_pixel_density' => 1.5], 'title' => (object) ['enabled' => \true, 'format' => 'uppercase_first', 'lowercase_words' => 'a,the,to,at,in,with,and,but,or'], 'lazy_loading' => \false];
|
||||
if ($file) {
|
||||
$this->setFile($file);
|
||||
}
|
||||
if ($attributes) {
|
||||
$this->setFromOldAttributes($attributes);
|
||||
}
|
||||
$this->resetOutput();
|
||||
}
|
||||
public static function cleanPath(string $path): string
|
||||
{
|
||||
$path = str_replace('\\', '/', $path);
|
||||
$path_site = str_replace('\\', '/', JPATH_SITE) . '/';
|
||||
if (str_starts_with($path, $path_site)) {
|
||||
$path = substr($path, strlen($path_site));
|
||||
}
|
||||
$path = ltrim(str_replace(JUri::root(), '', $path), '/');
|
||||
$path = strtok($path, '?');
|
||||
$path = strtok($path, '#');
|
||||
return $path;
|
||||
}
|
||||
public function createResizeFolder(): self
|
||||
{
|
||||
$path = $this->getResizeFolderPath();
|
||||
if (is_dir($path)) {
|
||||
return $this;
|
||||
}
|
||||
if (!@mkdir($path, 0755, \true)) {
|
||||
$this->settings->resize->folder = '';
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function exists(?string $file = null): bool
|
||||
{
|
||||
$file = urldecode($file ?: $this->getFilePath());
|
||||
return $file && file_exists($file) && is_file($file);
|
||||
}
|
||||
public function getAlt(): string
|
||||
{
|
||||
if (isset($this->attributes->alt)) {
|
||||
return $this->attributes->alt;
|
||||
}
|
||||
$alt = $this->getDataFileDataByType('alt');
|
||||
if (!is_null($alt)) {
|
||||
return htmlentities($alt);
|
||||
}
|
||||
return $this->getTitle(\true);
|
||||
}
|
||||
public function getDataFileData(): mixed
|
||||
{
|
||||
$image_data = $this->getFolderFileData();
|
||||
return $image_data[$this->getFileStem()] ?? null;
|
||||
}
|
||||
public function getDataFileDataByType(string $type = 'title'): mixed
|
||||
{
|
||||
$image_data = $this->getDataFileData();
|
||||
if (isset($image_data[$type])) {
|
||||
return $image_data[$type];
|
||||
}
|
||||
$default_data = $this->getDefaultDataFileData();
|
||||
return $default_data[$type] ?? null;
|
||||
}
|
||||
public function getDefaultDataFileData(): mixed
|
||||
{
|
||||
$image_data = $this->getFolderFileData();
|
||||
return $image_data['*'] ?? null;
|
||||
}
|
||||
public function getDescription(): string
|
||||
{
|
||||
if (!is_null($this->description)) {
|
||||
return $this->description;
|
||||
}
|
||||
return $this->getDataFileDataByType('description') ?? '';
|
||||
}
|
||||
public function getFile(): string
|
||||
{
|
||||
$this->prepareInput();
|
||||
return $this->input->file;
|
||||
}
|
||||
public function getFileExtension(): string
|
||||
{
|
||||
$this->prepareInput();
|
||||
return $this->input->file_extension;
|
||||
}
|
||||
public function getFileInfo(string $file, string $file_path): object
|
||||
{
|
||||
$file_path = urldecode($file_path);
|
||||
$path_info = @pathinfo($file_path);
|
||||
if (\RegularLabs\Library\File::isInternal($file_path)) {
|
||||
$size_info = @getimagesize($file_path);
|
||||
}
|
||||
$file_name = $path_info['basename'] ?? basename($file_path);
|
||||
$file_stem = $path_info['filename'] ?? JFile::stripExt($file_name);
|
||||
$file_extension = $path_info['extension'] ?? JFile::getExt($file_name);
|
||||
return (object) ['folder' => \RegularLabs\Library\File::getDirName($file), 'folder_path' => $path_info['dirname'] ?? null, 'file' => $file, 'file_path' => $file_path, 'file_name' => $file_name, 'file_stem' => $file_stem, 'file_extension' => $file_extension, 'mime' => $size_info['mime'] ?? null, 'width' => $size_info[0] ?? null, 'height' => $size_info[1] ?? null];
|
||||
}
|
||||
public function getFileName(): string
|
||||
{
|
||||
$this->prepareInput();
|
||||
return $this->input->file_name;
|
||||
}
|
||||
public function getFilePath(): string
|
||||
{
|
||||
$this->prepareInput();
|
||||
return $this->input->file_path;
|
||||
}
|
||||
public function getFileStem(): string
|
||||
{
|
||||
$this->prepareInput();
|
||||
return $this->input->file_stem;
|
||||
}
|
||||
public function getFolder(): string
|
||||
{
|
||||
$this->prepareInput();
|
||||
return $this->input->folder;
|
||||
}
|
||||
public function getFolderPath(): string
|
||||
{
|
||||
$this->prepareInput();
|
||||
return $this->input->folder_path;
|
||||
}
|
||||
public function getHeight(): int
|
||||
{
|
||||
$this->prepareOutput();
|
||||
return $this->output->height;
|
||||
}
|
||||
public function getOriginalHeight(): int
|
||||
{
|
||||
$this->prepareInput();
|
||||
return $this->input->height;
|
||||
}
|
||||
public function getOriginalWidth(): int
|
||||
{
|
||||
$this->prepareInput();
|
||||
return $this->input->width;
|
||||
}
|
||||
public function getOutputFile(): string
|
||||
{
|
||||
$this->prepareInput();
|
||||
if ($this->isExternal() || !$this->exists()) {
|
||||
return $this->input->file;
|
||||
}
|
||||
$this->prepareOutput();
|
||||
return $this->output->file;
|
||||
}
|
||||
public function getOutputFilePath(): string
|
||||
{
|
||||
$this->prepareOutput();
|
||||
return $this->output->file_path;
|
||||
}
|
||||
/**
|
||||
* @depecated Use getOutputFile() instead
|
||||
*/
|
||||
public function getPath(): string
|
||||
{
|
||||
return $this->getOutputFile();
|
||||
}
|
||||
public function getSrcSet(?string $pixel_density = null): ?string
|
||||
{
|
||||
if ($this->isExternal()) {
|
||||
return null;
|
||||
}
|
||||
if (!$this->settings->resize->use_retina) {
|
||||
return null;
|
||||
}
|
||||
if ($this->getFilePath() == $this->getOutputFilePath()) {
|
||||
return null;
|
||||
}
|
||||
$pixel_density = $pixel_density ?: $this->settings->resize->retina_pixel_density;
|
||||
$single = $this->getOutputFile();
|
||||
$double = $this->getOutputFile2x();
|
||||
if ($double == $single) {
|
||||
return null;
|
||||
}
|
||||
return $double . ' ' . (float) $pixel_density . 'x, ' . $single . ' 1x';
|
||||
}
|
||||
public function getTagAttributes(): object
|
||||
{
|
||||
$ordered_keys = ['src', 'srcset', 'alt', 'title', 'width', 'height', 'class', 'loading'];
|
||||
krsort($ordered_keys);
|
||||
$tag_width = $this->output->width;
|
||||
$tag_height = $this->output->height;
|
||||
$this->attributes = $this->attributes ?: (object) [];
|
||||
$this->attributes->src = $this->getOutputFile();
|
||||
$this->attributes->srcset = $this->getSrcset();
|
||||
$this->attributes->alt = $this->getAlt();
|
||||
$this->attributes->title = $this->getTitle(\true);
|
||||
$this->attributes->width = $this->output->width ?: $this->attributes->width ?? 0;
|
||||
$this->attributes->height = $this->output->height ?: $this->attributes->height ?? 0;
|
||||
if ($this->attributes->width < $tag_width) {
|
||||
$this->attributes->width = $tag_width;
|
||||
$this->attributes->height = round($this->attributes->height * ($tag_width / $this->attributes->width));
|
||||
}
|
||||
if ($this->attributes->height < $tag_height) {
|
||||
$this->attributes->height = $tag_height;
|
||||
$this->attributes->width = round($this->attributes->width * ($tag_height / $this->attributes->height));
|
||||
}
|
||||
$this->attributes->width = $this->attributes->width ?: null;
|
||||
$this->attributes->height = $this->attributes->height ?: null;
|
||||
$attributes = (array) $this->attributes;
|
||||
foreach ($ordered_keys as $key) {
|
||||
if (!key_exists($key, $attributes)) {
|
||||
continue;
|
||||
}
|
||||
$value = $attributes[$key];
|
||||
if (is_null($value)) {
|
||||
continue;
|
||||
}
|
||||
unset($attributes[$key]);
|
||||
$attributes = [$key => $value, ...$attributes];
|
||||
}
|
||||
return (object) $attributes;
|
||||
}
|
||||
public function getTitle(bool $force = \false): string
|
||||
{
|
||||
if (isset($this->attributes->title)) {
|
||||
return $this->attributes->title;
|
||||
}
|
||||
$title = $this->getDataFileDataByType('title');
|
||||
if (!is_null($title)) {
|
||||
// Remove HTML tags
|
||||
$title = strip_tags($title);
|
||||
return htmlentities($title);
|
||||
}
|
||||
return $this->getTitleFromName($force);
|
||||
}
|
||||
public function getWidth(): int
|
||||
{
|
||||
$this->prepareOutput();
|
||||
return $this->output->width;
|
||||
}
|
||||
public function isResized(): bool
|
||||
{
|
||||
if (!is_null($this->is_resized)) {
|
||||
return $this->is_resized;
|
||||
}
|
||||
$this->is_resized = \false;
|
||||
$this->prepareInput();
|
||||
$parent_folder_name = \RegularLabs\Library\File::getBaseName($this->input->folder_path);
|
||||
$resize_folder_name = $this->settings->resize->folder;
|
||||
// Image is not inside the resize folder
|
||||
if ($parent_folder_name != $resize_folder_name) {
|
||||
return \false;
|
||||
}
|
||||
$parent_folder = \RegularLabs\Library\File::getDirName($this->input->folder_path);
|
||||
$file_name = $this->input->file_name;
|
||||
// Check if image with same name exists in parent folder
|
||||
if ($this->exists($parent_folder . '/' . \RegularLabs\Library\StringHelper::utf8_decode($file_name))) {
|
||||
$this->is_resized = \true;
|
||||
return \true;
|
||||
}
|
||||
// Remove any dimensions from the file
|
||||
// image_300x200.jpg => image.jpg
|
||||
$file_name = \RegularLabs\Library\RegEx::replace('_[0-9]+x[0-9]*(\.[^.]+)$', '\1', $file_name);
|
||||
// Check again if image with same name (but without dimensions) exists in parent folder
|
||||
if ($this->exists($parent_folder . '/' . \RegularLabs\Library\StringHelper::utf8_decode($file_name))) {
|
||||
$this->is_resized = \true;
|
||||
return \true;
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
public function outputExists(): bool
|
||||
{
|
||||
$file = $this->getOutputFilePath();
|
||||
return $file && file_exists($file) && is_file($file);
|
||||
}
|
||||
public function render(string $outer_class = ''): string
|
||||
{
|
||||
$attributes = (array) $this->getTagAttributes();
|
||||
$image_tag = '<img ' . \RegularLabs\Library\HtmlTag::flattenAttributes($attributes) . ' />';
|
||||
if (!$outer_class) {
|
||||
return $image_tag;
|
||||
}
|
||||
return '<div class="' . htmlspecialchars($outer_class) . '">' . $image_tag . '</div>';
|
||||
}
|
||||
/**
|
||||
* @depecated Use render() instead
|
||||
*/
|
||||
public function renderTag(): string
|
||||
{
|
||||
return $this->render($this->attributes->{'outer-class'} ?? '');
|
||||
}
|
||||
public function setAlt($alt): self
|
||||
{
|
||||
return $this->setTagAttribute('alt', $alt);
|
||||
}
|
||||
public function setAutoTitles(bool $enabled, string $title_format = 'titlecase', string $lowercase_words = 'a,the,to,at,in,with,and,but,or'): self
|
||||
{
|
||||
$this->settings->title->enabled = $enabled;
|
||||
$this->settings->title->format = $title_format;
|
||||
$this->settings->title->lowercase_words = $lowercase_words;
|
||||
return $this;
|
||||
}
|
||||
public function setDescription($description): self
|
||||
{
|
||||
$this->description = $description;
|
||||
return $this;
|
||||
}
|
||||
public function setDimensions(int|float|string $width, int|float|string $height): self
|
||||
{
|
||||
$this->setResizeMethod(empty($width) || empty($height) ? 'scale' : 'crop');
|
||||
$this->setOutputSetting('width', (int) $width);
|
||||
$this->setOutputSetting('height', (int) $height);
|
||||
return $this;
|
||||
}
|
||||
public function setEnableResize(bool $enabled): self
|
||||
{
|
||||
$this->settings->resize->enabled = $enabled;
|
||||
return $this;
|
||||
}
|
||||
public function setFile($file): self
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->resetInput();
|
||||
return $this;
|
||||
}
|
||||
public function setHeight(int|float|string $height): self
|
||||
{
|
||||
return $this->setOutputSetting('height', (int) $height);
|
||||
}
|
||||
public function setItemProp(?string $itemprop): self
|
||||
{
|
||||
$itemprop = $itemprop ? 'image' : null;
|
||||
$this->setTagAttribute('itemprop', $itemprop);
|
||||
return $this;
|
||||
}
|
||||
public function setLazyLoading(?bool $enabled): self
|
||||
{
|
||||
return $this->setTagAttribute('loading', $enabled ? 'lazy' : null);
|
||||
}
|
||||
public function setLowerCaseWords(array $words): self
|
||||
{
|
||||
$this->settings->title->lowercase_words = $words;
|
||||
return $this;
|
||||
}
|
||||
public function setOutputFileData(): self
|
||||
{
|
||||
if (!empty($this->output->file)) {
|
||||
return $this;
|
||||
}
|
||||
$this->prepareInput();
|
||||
$output = clone $this->input;
|
||||
if (!empty($this->output->width) || !empty($this->output->height)) {
|
||||
$output->width = $this->output->width;
|
||||
$output->height = $this->output->height;
|
||||
}
|
||||
$this->output = $output;
|
||||
return $this;
|
||||
}
|
||||
public function setOutputSetting(string $key, mixed $value): self
|
||||
{
|
||||
if (is_null($this->output)) {
|
||||
$this->output = (object) ['width' => 0, 'height' => 0];
|
||||
}
|
||||
if ($this->output->{$key} == $value) {
|
||||
return $this;
|
||||
}
|
||||
$this->output->{$key} = $value;
|
||||
$this->resetOutput();
|
||||
return $this;
|
||||
}
|
||||
public function setResizeAttribute(string $key, mixed $value): self
|
||||
{
|
||||
if ($this->settings->resize->{$key} == $value) {
|
||||
return $this;
|
||||
}
|
||||
$this->settings->resize->{$key} = $value;
|
||||
$this->resetOutput();
|
||||
return $this;
|
||||
}
|
||||
public function setResizeFolder(string $folder = 'resized'): self
|
||||
{
|
||||
return $this->setResizeAttribute('folder', $folder);
|
||||
}
|
||||
public function setResizeMaxAge(int $age_in_days): self
|
||||
{
|
||||
return $this->setResizeAttribute('max_age', $age_in_days);
|
||||
}
|
||||
public function forceOverwriteResized(): self
|
||||
{
|
||||
return $this->setResizeAttribute('force_overwrite', 1.0E-5);
|
||||
}
|
||||
public function setResizeMethod(string $method): self
|
||||
{
|
||||
$this->settings->resize->method = $method;
|
||||
return $this;
|
||||
}
|
||||
public function setResizeQuality(string|int $quality): self
|
||||
{
|
||||
return $this->setResizeAttribute('quality', $this->parseQuality($quality));
|
||||
}
|
||||
public function setRetinaPixelDensity(string $pixel_density): self
|
||||
{
|
||||
return $this->setResizeAttribute('retina_pixel_density', $pixel_density);
|
||||
}
|
||||
public function setTagAttribute(string $key, mixed $value): self
|
||||
{
|
||||
if (is_null($this->attributes)) {
|
||||
$this->attributes = (object) [];
|
||||
}
|
||||
$this->attributes->{$key} = $value;
|
||||
return $this;
|
||||
}
|
||||
public function setTagAttributes(object $attributes): self
|
||||
{
|
||||
foreach ($attributes as $key => $value) {
|
||||
$this->setTagAttribute($key, $value);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function setTitle(string $title): self
|
||||
{
|
||||
return $this->setTagAttribute('title', $title);
|
||||
}
|
||||
public function setUseRetina(bool $use_retina): self
|
||||
{
|
||||
return $this->setResizeAttribute('use_retina', $use_retina);
|
||||
}
|
||||
public function setWidth(int|float|string $width): self
|
||||
{
|
||||
return $this->setOutputSetting('width', (int) $width);
|
||||
}
|
||||
private function getFolderFileData(): array
|
||||
{
|
||||
$folder = $this->getFolderPath();
|
||||
if (isset(self::$data_files[$folder])) {
|
||||
return self::$data_files[$folder];
|
||||
}
|
||||
self::$data_files[$folder] = [];
|
||||
if (!$this->exists($folder . '/data.txt')) {
|
||||
return self::$data_files[$folder];
|
||||
}
|
||||
$data = file_get_contents($folder . '/data.txt');
|
||||
$data = str_replace("\r", '', $data);
|
||||
$data = explode("\n", $data);
|
||||
foreach ($data as $data_line) {
|
||||
if (empty($data_line) || $data_line[0] == '#' || !str_contains($data_line, '=')) {
|
||||
continue;
|
||||
}
|
||||
[$key, $val] = explode('=', $data_line, 2);
|
||||
if (!\RegularLabs\Library\RegEx::match('^(?<file>.*?)\[(?<type>.*)\]$', $key, $match)) {
|
||||
continue;
|
||||
}
|
||||
$file = $match['file'];
|
||||
$type = $match['type'];
|
||||
if (!isset(self::$data_files[$folder][$file])) {
|
||||
self::$data_files[$folder][$file] = [];
|
||||
}
|
||||
self::$data_files[$folder][$file][$type] = $val;
|
||||
}
|
||||
return self::$data_files[$folder];
|
||||
}
|
||||
private function getLowercaseWords(): array
|
||||
{
|
||||
$words = $this->settings->title->lowercase_words;
|
||||
$words = \RegularLabs\Library\ArrayHelper::implode($words, ',');
|
||||
$words = \RegularLabs\Library\StringHelper::strtolower($words);
|
||||
return explode(',', ' ' . str_replace(',', ' , ', $words . ' '));
|
||||
}
|
||||
private function getOutputFile2x(): string
|
||||
{
|
||||
if ($this->isExternal()) {
|
||||
return $this->getOutputFile();
|
||||
}
|
||||
$double_width = $this->output->width * 2;
|
||||
$double_height = $this->output->height * 2;
|
||||
if ($double_width == $this->input->width && $double_height == $this->input->height) {
|
||||
return $this->getOutputFile();
|
||||
}
|
||||
$double_size = \RegularLabs\Library\ObjectHelper::clone($this);
|
||||
$double_size->setDimensions($double_width, $double_height);
|
||||
return $double_size->getOutputFile();
|
||||
}
|
||||
private function getResizeBoundry(): string
|
||||
{
|
||||
if ($this->input->width / $this->output->width > $this->input->height / $this->output->height) {
|
||||
return 'width';
|
||||
}
|
||||
return 'height';
|
||||
}
|
||||
private function getResizeDimensions(): array
|
||||
{
|
||||
if (!$this->output->width) {
|
||||
return [null, $this->output->height];
|
||||
}
|
||||
if (!$this->output->height) {
|
||||
return [$this->output->width, null];
|
||||
}
|
||||
if ($this->input->width / $this->output->width > $this->input->height / $this->output->height) {
|
||||
return [null, $this->output->height];
|
||||
}
|
||||
return [$this->output->width, null];
|
||||
}
|
||||
private function getResizeFolder(): string
|
||||
{
|
||||
if (!$this->settings->resize->folder) {
|
||||
$this->setResizeFolder();
|
||||
}
|
||||
return $this->getFolder() . '/' . $this->settings->resize->folder;
|
||||
}
|
||||
private function getResizeFolderPath(): string
|
||||
{
|
||||
if (!$this->settings->resize->folder) {
|
||||
$this->setResizeFolder();
|
||||
}
|
||||
return $this->getFolderPath() . '/' . $this->settings->resize->folder;
|
||||
}
|
||||
private function getResizedFileName(): string
|
||||
{
|
||||
$this->prepareInput();
|
||||
return $this->input->file_stem . '_' . $this->output->width . 'x' . $this->output->height . '.' . $this->input->file_extension;
|
||||
}
|
||||
private function getTitleFromName(bool $force = \false): string
|
||||
{
|
||||
if (!$force && !$this->settings->title->enabled) {
|
||||
return '';
|
||||
}
|
||||
$title = \RegularLabs\Library\StringHelper::toSpaceSeparated($this->input->file_stem);
|
||||
switch ($this->settings->title->format) {
|
||||
case 'lowercase':
|
||||
return \RegularLabs\Library\StringHelper::strtolower($title);
|
||||
case 'uppercase':
|
||||
return \RegularLabs\Library\StringHelper::strtoupper($title);
|
||||
case 'uppercase_first':
|
||||
return \RegularLabs\Library\StringHelper::strtoupper(\RegularLabs\Library\StringHelper::substr($title, 0, 1)) . \RegularLabs\Library\StringHelper::strtolower(\RegularLabs\Library\StringHelper::substr($title, 1));
|
||||
case 'titlecase':
|
||||
return function_exists('mb_convert_case') ? mb_convert_case(\RegularLabs\Library\StringHelper::strtolower($title), \MB_CASE_TITLE) : ucwords(strtolower($title));
|
||||
case 'titlecase_smart':
|
||||
$title = function_exists('mb_convert_case') ? mb_convert_case(\RegularLabs\Library\StringHelper::strtolower($title), \MB_CASE_TITLE) : ucwords(strtolower($title));
|
||||
$lowercase_words = $this->getLowercaseWords();
|
||||
return str_ireplace($lowercase_words, $lowercase_words, $title);
|
||||
default:
|
||||
return $title;
|
||||
}
|
||||
}
|
||||
private function handleDimensions(): self
|
||||
{
|
||||
if (!$this->input->width || !$this->input->height) {
|
||||
return $this;
|
||||
}
|
||||
// Width and height are both not set, so revert to original dimensions
|
||||
if (!$this->output->height && !$this->output->width) {
|
||||
$this->output->width = $this->input->width;
|
||||
$this->output->height = $this->input->height;
|
||||
return $this;
|
||||
}
|
||||
if (!$this->outputExists()) {
|
||||
return $this;
|
||||
}
|
||||
if ($this->settings->resize->method == 'crop') {
|
||||
$this->output->width = $this->output->width ?: $this->output->height;
|
||||
$this->output->height = $this->output->height ?: $this->output->width;
|
||||
return $this->resize();
|
||||
}
|
||||
// Width and height are both set
|
||||
if ($this->output->width && $this->output->height) {
|
||||
$boundry = $this->getResizeBoundry();
|
||||
$this->output->width = $boundry == 'width' ? $this->output->width : round($this->output->height / $this->input->height * $this->input->width);
|
||||
$this->output->height = $boundry == 'height' ? $this->output->height : round($this->output->width / $this->input->width * $this->input->height);
|
||||
return $this->resize();
|
||||
}
|
||||
$this->output->width = $this->output->width ?: round($this->output->height / $this->input->height * $this->input->width);
|
||||
$this->output->height = $this->output->height ?: round($this->output->width / $this->input->width * $this->input->height);
|
||||
return $this->resize();
|
||||
}
|
||||
private function isExternal(): bool
|
||||
{
|
||||
$this->prepareInput();
|
||||
return \RegularLabs\Library\File::isExternal($this->input->file);
|
||||
}
|
||||
private function limitDimensions(): self
|
||||
{
|
||||
if ($this->output->width <= $this->input->width && $this->output->height <= $this->input->height) {
|
||||
return $this;
|
||||
}
|
||||
if ($this->output->width > $this->input->width) {
|
||||
$this->output->height = $this->output->height / $this->output->width * $this->input->width;
|
||||
$this->output->width = $this->input->width;
|
||||
}
|
||||
if ($this->output->height > $this->input->height) {
|
||||
$this->output->width = $this->output->width / $this->output->height * $this->input->height;
|
||||
$this->output->height = $this->input->height;
|
||||
}
|
||||
$this->output->width = round($this->output->width);
|
||||
$this->output->height = round($this->output->height);
|
||||
return $this;
|
||||
}
|
||||
private function parseQuality(string|int $quality = 90): int
|
||||
{
|
||||
if (is_int($quality)) {
|
||||
return $quality;
|
||||
}
|
||||
return match ($quality) {
|
||||
'low' => 30,
|
||||
'medium' => 60,
|
||||
default => 90,
|
||||
};
|
||||
}
|
||||
private function prepareInput(): self
|
||||
{
|
||||
if (!is_null($this->input)) {
|
||||
return $this;
|
||||
}
|
||||
if (!$this->file) {
|
||||
throw new Exception('No file set');
|
||||
}
|
||||
if (\RegularLabs\Library\File::isExternal($this->file)) {
|
||||
$this->input = $this->getFileInfo($this->file, $this->file);
|
||||
return $this;
|
||||
}
|
||||
$file = self::cleanPath($this->file);
|
||||
$this->input = $this->getFileInfo($file, JPATH_ROOT . '/' . ltrim($file, '/'));
|
||||
return $this;
|
||||
}
|
||||
private function prepareOutput(): self
|
||||
{
|
||||
if (!empty($this->output->file)) {
|
||||
return $this;
|
||||
}
|
||||
$this->prepareInput();
|
||||
if (empty($this->output->width) && empty($this->output->height)) {
|
||||
$this->output = clone $this->input;
|
||||
return $this;
|
||||
}
|
||||
$this->setOutputFileData();
|
||||
$this->handleDimensions();
|
||||
return $this;
|
||||
}
|
||||
private function resetInput(): self
|
||||
{
|
||||
$this->input = null;
|
||||
$this->resetOutput();
|
||||
return $this;
|
||||
}
|
||||
private function resetOutput(): self
|
||||
{
|
||||
if (is_null($this->output)) {
|
||||
$this->output = (object) ['width' => 0, 'height' => 0];
|
||||
}
|
||||
unset($this->output->file);
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Method to create a resized version of the current image and save them to disk
|
||||
*/
|
||||
private function resize(?string $width = null, ?string $height = null, ?int $quality = null): self
|
||||
{
|
||||
if (!$this->settings->resize->enabled) {
|
||||
return $this;
|
||||
}
|
||||
if ($this->isResized()) {
|
||||
return $this;
|
||||
}
|
||||
if ($this->isExternal()) {
|
||||
return $this;
|
||||
}
|
||||
if (!is_null($width) || !is_null($height)) {
|
||||
$this->setDimensions($width, $height);
|
||||
}
|
||||
if (!is_null($quality)) {
|
||||
$this->setResizeQuality($quality);
|
||||
}
|
||||
if ($this->output->width == $this->input->width && $this->output->height == $this->input->height) {
|
||||
$this->output = clone $this->input;
|
||||
return $this;
|
||||
}
|
||||
$this->limitDimensions();
|
||||
$file = $this->getResizedFileName();
|
||||
$this->output->file = $this->getResizeFolder() . '/' . $file;
|
||||
$this->output->file_path = $this->getResizeFolderPath() . '/' . $file;
|
||||
$file_exists = $this->outputExists();
|
||||
$file_is_outdated = $this->settings->resize->force_overwrite;
|
||||
if (!$file_is_outdated && $file_exists && $this->settings->resize->max_age > 0) {
|
||||
$max_age_in_seconds = ceil($this->settings->resize->max_age * 60 * 60 * 24);
|
||||
$min_time = time() - $max_age_in_seconds;
|
||||
$file_is_outdated = filemtime($this->output->file_path) < $min_time;
|
||||
}
|
||||
if ($file_exists && !$file_is_outdated) {
|
||||
//$this->output = $this->getFileInfo($this->output->file, $this->output->file_path);
|
||||
return $this;
|
||||
}
|
||||
[$resize_width, $resize_height] = $this->getResizeDimensions();
|
||||
try {
|
||||
$resized = ImageManager::make($this->getFilePath())->orientate()->resize($resize_width, $resize_height, function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
});
|
||||
if ($this->settings->resize->method == 'crop' || $this->output->width && $this->output->height) {
|
||||
$resized->crop($this->output->width, $this->output->height);
|
||||
}
|
||||
$this->createResizeFolder();
|
||||
$resized->save($this->output->file_path, $this->settings->resize->quality);
|
||||
} catch (NotReadableException $exception) {
|
||||
$resized = null;
|
||||
}
|
||||
if (!$resized) {
|
||||
$this->output = clone $this->input;
|
||||
$this->is_resized = \false;
|
||||
}
|
||||
$this->output = $this->getFileInfo($this->output->file, $this->output->file_path);
|
||||
return $this;
|
||||
}
|
||||
private function setFromOldAttributes(object $attributes): void
|
||||
{
|
||||
if (isset($attributes->alt)) {
|
||||
$this->setAlt($attributes->alt);
|
||||
}
|
||||
if (isset($attributes->title)) {
|
||||
$this->setTitle($attributes->title);
|
||||
}
|
||||
if (isset($attributes->class)) {
|
||||
$this->setTagAttribute('class', $attributes->class);
|
||||
}
|
||||
if (isset($attributes->{'outer-class'})) {
|
||||
$this->setTagAttribute('outer-class', $attributes->{'outer-class'});
|
||||
}
|
||||
if (isset($attributes->{'resize-folder'})) {
|
||||
$folder = \RegularLabs\Library\File::getBaseName($attributes->{'resize-folder'});
|
||||
$this->setResizeFolder($folder);
|
||||
}
|
||||
if (isset($attributes->quality)) {
|
||||
$this->setResizeQuality($attributes->quality);
|
||||
}
|
||||
$this->setDimensions($attributes->width ?? 0, $attributes->height ?? 0);
|
||||
}
|
||||
}
|
||||
113
libraries/regularlabs/src/Input.php
Normal file
113
libraries/regularlabs/src/Input.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
/**
|
||||
* string getAlphaNumeric($name, $default = null) Get an alphanumeric string.
|
||||
* string getBase64($name, $default = null) Get a base64 encoded string.
|
||||
* boolean getBool($name, $default = null) Get a boolean value.
|
||||
* string getCmd($name, $default = null) Get a CMD filtered string.
|
||||
* float getFloat($name, $default = null) Get a floating-point number.
|
||||
* string getHtml($name, $default = null) Get a HTML string.
|
||||
* integer getInt($name, $default = null) Get a signed integer.
|
||||
* string getPath($name, $default = null) Get a file path.
|
||||
* mixed getRaw($name, $default = null) Get an unfiltered value.
|
||||
* string getString($name, $default = null) Get a string.
|
||||
* integer getUint($name, $default = null) Get an unsigned integer.
|
||||
* string getUsername($name, $default = null) Get a username.
|
||||
* string getWord($name, $default = null) Get a word.
|
||||
*/
|
||||
class Input
|
||||
{
|
||||
public static function get(string $name, mixed $default = null, string $filter = 'none'): mixed
|
||||
{
|
||||
return JFactory::getApplication()->getInput()->get($name, $default, $filter);
|
||||
}
|
||||
public static function getAlphaNumeric(string $name, mixed $default = null): string
|
||||
{
|
||||
return (string) (self::convertFromArray($name) ?? JFactory::getApplication()->getInput()->getAlnum($name, $default));
|
||||
}
|
||||
public static function getArray(array $vars = [], mixed $datasource = null): array
|
||||
{
|
||||
return JFactory::getApplication()->getInput()->getArray($vars, $datasource);
|
||||
}
|
||||
public static function getAsArray(string $name, ?array $default = []): array
|
||||
{
|
||||
return (array) JFactory::getApplication()->getInput()->get($name, $default ?? [], 'array');
|
||||
}
|
||||
public static function getBase64(string $name, mixed $default = null): string
|
||||
{
|
||||
return (string) (self::convertFromArray($name) ?? JFactory::getApplication()->getInput()->getBase64($name, $default));
|
||||
}
|
||||
public static function getBool(string $name, ?bool $default = \false): bool
|
||||
{
|
||||
return (bool) (self::convertFromArray($name) ?? JFactory::getApplication()->getInput()->getBool($name, $default));
|
||||
}
|
||||
public static function getCmd(string $name, mixed $default = null): string
|
||||
{
|
||||
return (string) (self::convertFromArray($name) ?? JFactory::getApplication()->getInput()->getCmd($name, $default));
|
||||
}
|
||||
public static function getFloat(string $name, mixed $default = null): float
|
||||
{
|
||||
return (float) (self::convertFromArray($name) ?? JFactory::getApplication()->getInput()->getFloat($name, $default));
|
||||
}
|
||||
public static function getHtml(string $name, mixed $default = null): string
|
||||
{
|
||||
return (string) (self::convertFromArray($name) ?? JFactory::getApplication()->getInput()->getHtml($name, $default));
|
||||
}
|
||||
public static function getInt(string $name, mixed $default = null): int
|
||||
{
|
||||
return (int) (self::convertFromArray($name) ?? JFactory::getApplication()->getInput()->getInt($name, $default));
|
||||
}
|
||||
public static function getPath(string $name, mixed $default = null): string
|
||||
{
|
||||
return (string) (self::convertFromArray($name) ?? JFactory::getApplication()->getInput()->getPath($name, $default));
|
||||
}
|
||||
public static function getRaw(string $name, mixed $default = null): mixed
|
||||
{
|
||||
return JFactory::getApplication()->getInput()->getRaw($name, $default);
|
||||
}
|
||||
public static function getString(string $name, mixed $default = null): string
|
||||
{
|
||||
return (string) (self::convertFromArray($name) ?? JFactory::getApplication()->getInput()->getString($name, $default));
|
||||
}
|
||||
public static function getUint(string $name, mixed $default = null): int
|
||||
{
|
||||
return (int) (self::convertFromArray($name) ?? JFactory::getApplication()->getInput()->getUint($name, $default));
|
||||
}
|
||||
public static function getUsername(string $name, mixed $default = null): string
|
||||
{
|
||||
return (string) (self::convertFromArray($name) ?? JFactory::getApplication()->getInput()->getUsername($name, $default));
|
||||
}
|
||||
public static function getWord(string $name, mixed $default = null): string
|
||||
{
|
||||
return (string) (self::convertFromArray($name) ?? JFactory::getApplication()->getInput()->getWord($name, $default));
|
||||
}
|
||||
public static function set(string $name, mixed $value): void
|
||||
{
|
||||
JFactory::getApplication()->getInput()->set($name, $value);
|
||||
}
|
||||
public static function setCookie(string $name, mixed $value, array $options = []): void
|
||||
{
|
||||
JFactory::getApplication()->getInput()->cookie->set($name, $value, $options);
|
||||
}
|
||||
private static function convertFromArray(string $name): mixed
|
||||
{
|
||||
$value = JFactory::getApplication()->getInput()->get($name, null);
|
||||
if (is_array($value)) {
|
||||
return $value[0] ?? null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
29
libraries/regularlabs/src/Language.php
Normal file
29
libraries/regularlabs/src/Language.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
class Language
|
||||
{
|
||||
/**
|
||||
* Load the language of the given extension
|
||||
*/
|
||||
public static function load(string $extension = 'plg_system_regularlabs', string $basePath = '', bool $reload = \false): bool
|
||||
{
|
||||
if ($basePath && JFactory::getApplication()->getLanguage()->load($extension, $basePath, null, $reload)) {
|
||||
return \true;
|
||||
}
|
||||
$basePath = \RegularLabs\Library\Extension::getPath($extension, $basePath, 'language');
|
||||
return JFactory::getApplication()->getLanguage()->load($extension, $basePath, null, $reload);
|
||||
}
|
||||
}
|
||||
35
libraries/regularlabs/src/Layout.php
Normal file
35
libraries/regularlabs/src/Layout.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Layout\FileLayout as JFileLayout;
|
||||
class Layout
|
||||
{
|
||||
static $layouts = [];
|
||||
public static function get($layout_id, $layout_path, $extension)
|
||||
{
|
||||
$key = $extension . '.' . $layout_id;
|
||||
if (isset(self::$layouts[$key])) {
|
||||
return self::$layouts[$key];
|
||||
}
|
||||
$layout = new JFileLayout($layout_id);
|
||||
$default_paths = $layout->getDefaultIncludePaths();
|
||||
$default_paths = array_reverse($default_paths);
|
||||
$layout->addIncludePath($layout_path);
|
||||
foreach ($default_paths as $path) {
|
||||
$layout->addIncludePath($path . '/' . $extension);
|
||||
}
|
||||
self::$layouts[$key] = $layout;
|
||||
return self::$layouts[$key];
|
||||
}
|
||||
}
|
||||
44
libraries/regularlabs/src/License.php
Normal file
44
libraries/regularlabs/src/License.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
class License
|
||||
{
|
||||
/**
|
||||
* Render the license message for Free versions
|
||||
*/
|
||||
public static function getMessage(string $name, bool $check_pro = \false): string
|
||||
{
|
||||
if (!$name) {
|
||||
return '';
|
||||
}
|
||||
$alias = \RegularLabs\Library\Extension::getAliasByName($name);
|
||||
$name = \RegularLabs\Library\Extension::getNameByAlias($name);
|
||||
if ($check_pro && self::isPro($alias)) {
|
||||
return '';
|
||||
}
|
||||
return '<div class="rl-license rl-alert alert alert-warning rl-alert-light">' . '<div>' . JText::sprintf('RL_IS_FREE_VERSION', $name) . '</div>' . '<div>' . JText::_('RL_FOR_MORE_GO_PRO') . '</div>' . '<div>' . '<a href="https://regularlabs.com/purchase/cart/add/' . $alias . '" target="_blank" class="btn btn-sm btn-primary">' . '<span class="icon-basket"></span> ' . \RegularLabs\Library\StringHelper::html_entity_decoder(JText::_('RL_GO_PRO')) . '</a>' . '</div>' . '</div>';
|
||||
}
|
||||
/**
|
||||
* Check if the installed version of the extension is a Pro version
|
||||
*/
|
||||
private static function isPro(string $element_name): bool
|
||||
{
|
||||
$version = \RegularLabs\Library\Extension::getXMLValue('version', $element_name);
|
||||
if (!$version) {
|
||||
return \false;
|
||||
}
|
||||
return stripos($version, 'PRO') !== \false;
|
||||
}
|
||||
}
|
||||
26
libraries/regularlabs/src/MobileDetect.php
Normal file
26
libraries/regularlabs/src/MobileDetect.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
require_once dirname(__FILE__, 2) . '/vendor/autoload.php';
|
||||
class MobileDetect extends \RegularLabs\Scoped\Detection\MobileDetect
|
||||
{
|
||||
public function isCurl(): bool
|
||||
{
|
||||
return $this->match('curl', $this->getUserAgent());
|
||||
}
|
||||
public function isMac(): bool
|
||||
{
|
||||
return $this->match('(Mac OS|Mac_PowerPC|Macintosh)', $this->getUserAgent());
|
||||
}
|
||||
}
|
||||
76
libraries/regularlabs/src/ObjectHelper.php
Normal file
76
libraries/regularlabs/src/ObjectHelper.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use RegularLabs\Scoped\DeepCopy\DeepCopy;
|
||||
require_once dirname(__FILE__, 2) . '/vendor/autoload.php';
|
||||
class ObjectHelper
|
||||
{
|
||||
/**
|
||||
* Change the case of object keys
|
||||
* $key_format: 'camel', 'dash', 'dot', 'underscore'
|
||||
*/
|
||||
public static function changeKeyCase(object|array|null $object, $format, bool $to_lowercase = \true): object
|
||||
{
|
||||
return (object) \RegularLabs\Library\ArrayHelper::applyMethodToKeys([$object, $format, $to_lowercase], '\RegularLabs\Library\StringHelper', 'toCase');
|
||||
}
|
||||
/**
|
||||
* Deep clone an object
|
||||
*/
|
||||
public static function clone(object $object): object
|
||||
{
|
||||
return (new DeepCopy())->copy($object);
|
||||
}
|
||||
/**
|
||||
* Return the value by the object property key
|
||||
* A list of keys can be given. The first one that is not empty will get returned
|
||||
*/
|
||||
public static function getValue(object $object, string|array $keys, mixed $default = null): mixed
|
||||
{
|
||||
$keys = \RegularLabs\Library\ArrayHelper::toArray($keys);
|
||||
foreach ($keys as $key) {
|
||||
if (empty($object->{$key})) {
|
||||
continue;
|
||||
}
|
||||
return $object->{$key};
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
/**
|
||||
* Merge 2 objects
|
||||
*/
|
||||
public static function merge(object $object1, object $object2): object
|
||||
{
|
||||
return (object) [...(array) $object1, ...(array) $object2];
|
||||
}
|
||||
/**
|
||||
* Replace key names
|
||||
*/
|
||||
public static function replaceKeys(string|object $object, array $replacements, bool $include_prefixes = \false, string $prefix_delimiter = '_'): string|object
|
||||
{
|
||||
$json = json_encode($object);
|
||||
foreach ($replacements as $to => $froms) {
|
||||
if (!is_array($froms)) {
|
||||
$froms = [$froms];
|
||||
}
|
||||
foreach ($froms as $from) {
|
||||
$json = str_replace('"' . $from . '":', '"' . $to . '":', $json);
|
||||
if (!$include_prefixes) {
|
||||
continue;
|
||||
}
|
||||
$json = \RegularLabs\Library\RegEx::replace('"' . \RegularLabs\Library\RegEx::quote($from . $prefix_delimiter) . '([^"]+":)', '"' . $to . $prefix_delimiter . '\1', $json);
|
||||
}
|
||||
}
|
||||
return json_decode($json);
|
||||
}
|
||||
}
|
||||
164
libraries/regularlabs/src/Parameters.php
Normal file
164
libraries/regularlabs/src/Parameters.php
Normal file
@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Component\ComponentHelper as JComponentHelper;
|
||||
use Joomla\CMS\Plugin\PluginHelper as JPluginHelper;
|
||||
use RegularLabs\Library\ObjectHelper as RL_Object;
|
||||
class Parameters
|
||||
{
|
||||
/**
|
||||
* Get a usable parameter object for the component
|
||||
*/
|
||||
public static function getComponent(string $name, object|array|string|null $params = null, bool $use_cache = \true): object
|
||||
{
|
||||
$name = 'com_' . \RegularLabs\Library\RegEx::replace('^com_', '', $name);
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($use_cache && $cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
if (empty($params) && JComponentHelper::isInstalled($name)) {
|
||||
$params = JComponentHelper::getParams($name);
|
||||
}
|
||||
return $cache->set(self::getObjectFromRegistry($params, JPATH_ADMINISTRATOR . '/components/' . $name . '/config.xml'));
|
||||
}
|
||||
/**
|
||||
* Get a usable parameter object for the module
|
||||
*/
|
||||
public static function getModule(string $name, bool $admin = \true, object|array|string|null $params = null, bool $use_cache = \true): object
|
||||
{
|
||||
$name = 'mod_' . \RegularLabs\Library\RegEx::replace('^mod_', '', $name);
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($use_cache && $cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
if (empty($params)) {
|
||||
$params = null;
|
||||
}
|
||||
return $cache->set(self::getObjectFromRegistry($params, ($admin ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/modules/' . $name . '/' . $name . '.xml'));
|
||||
}
|
||||
/**
|
||||
* Get a usable parameter object based on the Joomla Registry object
|
||||
* The object will have all the available parameters with their value (default value if none is set)
|
||||
*/
|
||||
public static function getObjectFromRegistry(object|array|string|null $params, string $path = '', string $default = '', bool $use_cache = \true): object
|
||||
{
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($use_cache && $cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
$xml = self::loadXML($path, $default);
|
||||
if (empty($params)) {
|
||||
return $cache->set((object) $xml);
|
||||
}
|
||||
if (is_array($params)) {
|
||||
$params = (object) $params;
|
||||
}
|
||||
if (is_string($params)) {
|
||||
$params = json_decode($params);
|
||||
}
|
||||
if (is_object($params) && method_exists($params, 'toObject')) {
|
||||
$params = $params->toObject();
|
||||
}
|
||||
if (is_null($xml)) {
|
||||
$xml = (object) [];
|
||||
}
|
||||
if (!$params) {
|
||||
return $cache->set((object) $xml);
|
||||
}
|
||||
if (empty($xml)) {
|
||||
return $cache->set($params);
|
||||
}
|
||||
foreach ($xml as $key => $val) {
|
||||
if (isset($params->{$key}) && $params->{$key} != '') {
|
||||
continue;
|
||||
}
|
||||
$params->{$key} = $val;
|
||||
}
|
||||
return $cache->set($params);
|
||||
}
|
||||
/**
|
||||
* Get a usable parameter object for the plugin
|
||||
*/
|
||||
public static function getPlugin(string $name, string $type = 'system', object|array|string|null $params = null, bool $use_cache = \true): object
|
||||
{
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($use_cache && $cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
if (empty($params)) {
|
||||
$plugin = JPluginHelper::getPlugin($type, $name);
|
||||
$params = is_object($plugin) && isset($plugin->params) ? $plugin->params : null;
|
||||
}
|
||||
return $cache->set(self::getObjectFromRegistry($params, JPATH_PLUGINS . '/' . $type . '/' . $name . '/' . $name . '.xml'));
|
||||
}
|
||||
/**
|
||||
* Returns an array based on the data in a given xml file
|
||||
*/
|
||||
public static function loadXML(string $path, ?string $default = '', bool $use_cache = \true, bool $full_info = \false): array
|
||||
{
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($use_cache && $cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
if (!$path || !file_exists($path)) {
|
||||
return $cache->set([]);
|
||||
}
|
||||
$file = file_get_contents($path);
|
||||
if (!$file) {
|
||||
return $cache->set([]);
|
||||
}
|
||||
$xml = [];
|
||||
$xml_parser = xml_parser_create();
|
||||
xml_parse_into_struct($xml_parser, $file, $fields);
|
||||
xml_parser_free($xml_parser);
|
||||
$default = $default ? strtoupper($default) : 'DEFAULT';
|
||||
foreach ($fields as $field) {
|
||||
if ($field['tag'] != 'FIELD' || !isset($field['attributes']) || !isset($field['attributes']['NAME']) || $field['attributes']['NAME'] == '' || $field['attributes']['NAME'][0] == '@' || !isset($field['attributes']['TYPE']) || $field['attributes']['TYPE'] == 'spacer') {
|
||||
continue;
|
||||
}
|
||||
if ($full_info) {
|
||||
$full_object = $xml[$field['attributes']['NAME']] = RL_Object::changeKeyCase($field['attributes'], 'lower');
|
||||
$full_object->multiple ??= 'false';
|
||||
}
|
||||
if (isset($field['attributes'][$default])) {
|
||||
$field['attributes']['DEFAULT'] = $field['attributes'][$default];
|
||||
}
|
||||
if (!isset($field['attributes']['DEFAULT'])) {
|
||||
$field['attributes']['DEFAULT'] = '';
|
||||
}
|
||||
if ($field['attributes']['TYPE'] == 'textarea') {
|
||||
$field['attributes']['DEFAULT'] = str_replace('<br>', "\n", $field['attributes']['DEFAULT']);
|
||||
}
|
||||
if ($full_info) {
|
||||
$full_object->value = $field['attributes']['DEFAULT'];
|
||||
continue;
|
||||
}
|
||||
$xml[$field['attributes']['NAME']] = $field['attributes']['DEFAULT'];
|
||||
}
|
||||
return $cache->set($xml);
|
||||
}
|
||||
public static function overrideFromObject(object $params, ?object $object = null): object
|
||||
{
|
||||
if (empty($object)) {
|
||||
return $params;
|
||||
}
|
||||
foreach ($params as $key => $value) {
|
||||
if (!isset($object->{$key})) {
|
||||
continue;
|
||||
}
|
||||
$params->{$key} = $object->{$key};
|
||||
}
|
||||
return $params;
|
||||
}
|
||||
}
|
||||
143
libraries/regularlabs/src/Php.php
Normal file
143
libraries/regularlabs/src/Php.php
Normal file
@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Application\CMSApplication as JCMSApplication;
|
||||
use Joomla\CMS\Application\CMSApplicationInterface as JCMSApplicationInterface;
|
||||
use Joomla\CMS\Document\Document as JDocument;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
use Joomla\CMS\Filesystem\File as JFile;
|
||||
use Joomla\CMS\Version as JVersion;
|
||||
class Php
|
||||
{
|
||||
static $rl_variables;
|
||||
public static function execute(string $rl_string, object|false|null $rl_article = null, object|false|null $rl_module = null, bool $has_own_return = \false): mixed
|
||||
{
|
||||
self::prepareString($rl_string);
|
||||
$function_name = self::getFunctionName($rl_string);
|
||||
if (!$function_name) {
|
||||
// Something went wrong!
|
||||
return \true;
|
||||
}
|
||||
if (!$rl_article && str_contains($rl_string, '$article')) {
|
||||
if (\RegularLabs\Library\Input::get('option', '') == 'com_content' && \RegularLabs\Library\Input::get('view', '') == 'article') {
|
||||
$rl_article = \RegularLabs\Library\Article::get(\RegularLabs\Library\Input::getInt('id'));
|
||||
}
|
||||
}
|
||||
$rl_pre_variables = array_keys(get_defined_vars());
|
||||
ob_start();
|
||||
$rl_post_variables = $function_name(self::$rl_variables, $rl_article, $rl_module);
|
||||
$rl_output = ob_get_contents();
|
||||
ob_end_clean();
|
||||
if ($has_own_return) {
|
||||
return $rl_post_variables;
|
||||
}
|
||||
if (!is_array($rl_post_variables)) {
|
||||
return $rl_output;
|
||||
}
|
||||
$rl_diff_variables = array_diff(array_keys($rl_post_variables), $rl_pre_variables);
|
||||
foreach ($rl_diff_variables as $rl_diff_key) {
|
||||
if (in_array($rl_diff_key, ['Itemid', 'mainframe', 'app', 'document', 'doc', 'database', 'db', 'user', 'article', 'module'], \true) || substr($rl_diff_key, 0, 4) == 'rl_') {
|
||||
continue;
|
||||
}
|
||||
self::$rl_variables[$rl_diff_key] = $rl_post_variables[$rl_diff_key];
|
||||
}
|
||||
return $rl_output;
|
||||
}
|
||||
public static function getApplication(): JCMSApplicationInterface
|
||||
{
|
||||
if (\RegularLabs\Library\Input::get('option', '') != 'com_finder') {
|
||||
return JFactory::getApplication();
|
||||
}
|
||||
return JCMSApplication::getInstance('site');
|
||||
}
|
||||
public static function getDocument(): JDocument
|
||||
{
|
||||
if (\RegularLabs\Library\Input::get('option', '') != 'com_finder') {
|
||||
return \RegularLabs\Library\Document::get();
|
||||
}
|
||||
$lang = JFactory::getApplication()->getLanguage();
|
||||
$version = new JVersion();
|
||||
$attributes = ['charset' => 'utf-8', 'lineend' => 'unix', 'tab' => "\t", 'language' => $lang->getTag(), 'direction' => $lang->isRtl() ? 'rtl' : 'ltr', 'mediaversion' => $version->getMediaVersion()];
|
||||
return JDocument::getInstance('html', $attributes);
|
||||
}
|
||||
private static function createFunctionInMemory(string $string): void
|
||||
{
|
||||
$file_name = getmypid() . '_' . md5($string);
|
||||
$tmp_path = JFactory::getApplication()->get('tmp_path', JPATH_ROOT . '/tmp');
|
||||
$temp_file = $tmp_path . '/regularlabs/custom_php/' . $file_name;
|
||||
// Write file
|
||||
if (!file_exists($temp_file) || is_writable($temp_file)) {
|
||||
JFile::write($temp_file, $string);
|
||||
}
|
||||
// Include file
|
||||
include_once $temp_file;
|
||||
// Delete file
|
||||
if (!JFactory::getApplication()->get('debug')) {
|
||||
@chmod($temp_file, 0777);
|
||||
@unlink($temp_file);
|
||||
}
|
||||
}
|
||||
private static function extractUseStatements(string &$string): string
|
||||
{
|
||||
$use_statements = [];
|
||||
$string = trim($string);
|
||||
\RegularLabs\Library\RegEx::matchAll('^use\s+[^\s;]+\s*;', $string, $matches, 'm');
|
||||
foreach ($matches as $match) {
|
||||
$use_statements[] = $match[0];
|
||||
$string = str_replace($match[0], '', $string);
|
||||
}
|
||||
$string = trim($string);
|
||||
return implode("\n", $use_statements);
|
||||
}
|
||||
private static function generateFileContents(string $function_name = 'rl_function', string $string = ''): string
|
||||
{
|
||||
$use_statements = self::extractUseStatements($string);
|
||||
$init_variables = self::getVarInits();
|
||||
$init_variables[] = 'if (is_array($rl_variables)) {' . 'foreach ($rl_variables as $rl_key => $rl_value) {' . '${$rl_key} = $rl_value;' . '}' . '}';
|
||||
$contents = ['<?php', 'defined(\'_JEXEC\') or die;', $use_statements, 'function ' . $function_name . '($rl_variables, $article, $module){', implode("\n", $init_variables), $string . ';', 'return get_defined_vars();', ';}'];
|
||||
$contents = implode("\n", $contents);
|
||||
// Remove Zero Width spaces / (non-)joiners
|
||||
$contents = str_replace(["", "", ""], '', $contents);
|
||||
return $contents;
|
||||
}
|
||||
private static function getFunctionName(string $string): string|false
|
||||
{
|
||||
$function_name = 'regularlabs_php_' . md5($string);
|
||||
if (function_exists($function_name)) {
|
||||
return $function_name;
|
||||
}
|
||||
$contents = self::generateFileContents($function_name, $string);
|
||||
self::createFunctionInMemory($contents);
|
||||
if (!function_exists($function_name)) {
|
||||
// Something went wrong!
|
||||
return \false;
|
||||
}
|
||||
return $function_name;
|
||||
}
|
||||
private static function getVarInits(): array
|
||||
{
|
||||
return ['$app = $mainframe = RegularLabs\Library\Php::getApplication();', '$document = $doc = RegularLabs\Library\Php::getDocument();', '$database = $db = Joomla\CMS\Factory::getDbo();', '$user = $app->getIdentity() ?: Joomla\CMS\Factory::getUser();', '$Itemid = $app->getInput()->getInt(\'Itemid\');'];
|
||||
}
|
||||
private static function prepareString(string &$string): void
|
||||
{
|
||||
$string = trim($string);
|
||||
$string = str_replace('?><?php', '', $string . '<?php ;');
|
||||
if (!str_starts_with($string, '<?php')) {
|
||||
$string = '?>' . $string;
|
||||
return;
|
||||
}
|
||||
$string = substr($string, 5);
|
||||
$string = trim($string);
|
||||
}
|
||||
}
|
||||
400
libraries/regularlabs/src/PluginTag.php
Normal file
400
libraries/regularlabs/src/PluginTag.php
Normal file
@ -0,0 +1,400 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
class PluginTag
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
static $protected_characters = ['=' => '[[:EQUAL:]]', '"' => '[[:QUOTE:]]', ',' => '[[:COMMA:]]', '|' => '[[:BAR:]]', ':' => '[[:COLON:]]'];
|
||||
/**
|
||||
* Cleans the given tag word
|
||||
*
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function clean($string = '')
|
||||
{
|
||||
return \RegularLabs\Library\RegEx::replace('[^a-z0-9-_]', '', $string);
|
||||
}
|
||||
/**
|
||||
* Get the attributes from plugin style string
|
||||
*
|
||||
* @param string $string
|
||||
* @param string $main_key
|
||||
* @param array $known_boolean_keys
|
||||
* @param string $key_format (empty, 'underscore', 'dash')
|
||||
* @param array $keep_escaped_chars
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public static function getAttributesFromString($string = '', $main_key = 'title', $known_boolean_keys = [], $key_format = '', $keep_escaped_chars = null, $convert_numerals = null)
|
||||
{
|
||||
if (empty($string)) {
|
||||
return (object) [];
|
||||
}
|
||||
if (is_object($string)) {
|
||||
return $string;
|
||||
}
|
||||
if (is_array($string)) {
|
||||
return (object) $string;
|
||||
}
|
||||
// Replace html entity quotes to normal quotes
|
||||
if (!str_contains($string, '"')) {
|
||||
$string = str_replace('"', '"', $string);
|
||||
}
|
||||
self::protectSpecialChars($string);
|
||||
// replace weird whitespace
|
||||
$string = str_replace(chr(194) . chr(160), ' ', $string);
|
||||
// Replace html entity spaces between attributes to normal spaces
|
||||
$string = \RegularLabs\Library\RegEx::replace('((?:^|")\s*) (\s*(?:[a-z]|$))', '\1 \2', $string);
|
||||
// Only one value, so return simple key/value object
|
||||
if (!str_contains($string, '|') && !\RegularLabs\Library\RegEx::match('=\s*["\']', $string)) {
|
||||
self::unprotectSpecialChars($string, $keep_escaped_chars);
|
||||
return (object) [$main_key => $string];
|
||||
}
|
||||
// Cannot find right syntax, so return simple key/value object
|
||||
if (!\RegularLabs\Library\RegEx::matchAll('(?:^|\s)(?<key>[a-z0-9-_\:]+)\s*(?<not>\!?)=\s*(["\'])(?<value>.*?)\3', $string, $matches)) {
|
||||
self::unprotectSpecialChars($string, $keep_escaped_chars);
|
||||
return (object) [$main_key => $string];
|
||||
}
|
||||
$tag = (object) [];
|
||||
foreach ($matches as $match) {
|
||||
$key = \RegularLabs\Library\StringHelper::toCase($match['key'], $key_format);
|
||||
$tag->{$key} = self::getAttributeValueFromMatch($match, $known_boolean_keys, $keep_escaped_chars, $convert_numerals);
|
||||
}
|
||||
return $tag;
|
||||
}
|
||||
/**
|
||||
* Extract the plugin style div tags with the possible attributes. like:
|
||||
* {div width:100|float:left}...{/div}
|
||||
*
|
||||
* @param string $start_tag
|
||||
* @param string $end_tag
|
||||
* @param string $tag_start
|
||||
* @param string $tag_end
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getDivTags($start_tag = '', $end_tag = '', $tag_start = '{', $tag_end = '}')
|
||||
{
|
||||
$tag_start = \RegularLabs\Library\RegEx::quote($tag_start);
|
||||
$tag_end = \RegularLabs\Library\RegEx::quote($tag_end);
|
||||
$start_div = ['pre' => '', 'tag' => '', 'post' => ''];
|
||||
$end_div = ['pre' => '', 'tag' => '', 'post' => ''];
|
||||
if (!empty($start_tag) && \RegularLabs\Library\RegEx::match('^(?<pre>.*?)(?<tag>' . $tag_start . 'div(?: .*?)?' . $tag_end . ')(?<post>.*)$', $start_tag, $match)) {
|
||||
$start_div = $match;
|
||||
}
|
||||
if (!empty($end_tag) && \RegularLabs\Library\RegEx::match('^(?<pre>.*?)(?<tag>' . $tag_start . '/div' . $tag_end . ')(?<post>.*)$', $end_tag, $match)) {
|
||||
$end_div = $match;
|
||||
}
|
||||
if (empty($start_div['tag']) || empty($end_div['tag'])) {
|
||||
return [$start_div, $end_div];
|
||||
}
|
||||
$attribs = trim(\RegularLabs\Library\RegEx::replace($tag_start . 'div(.*)' . $tag_end, '\1', $start_div['tag']));
|
||||
$start_div['tag'] = '<div>';
|
||||
$end_div['tag'] = '</div>';
|
||||
if (empty($attribs)) {
|
||||
return [$start_div, $end_div];
|
||||
}
|
||||
$attribs = self::getDivAttributes($attribs);
|
||||
$style = [];
|
||||
if (isset($attribs->width)) {
|
||||
if (is_numeric($attribs->width)) {
|
||||
$attribs->width .= 'px';
|
||||
}
|
||||
$style[] = 'width:' . $attribs->width;
|
||||
}
|
||||
if (isset($attribs->height)) {
|
||||
if (is_numeric($attribs->height)) {
|
||||
$attribs->height .= 'px';
|
||||
}
|
||||
$style[] = 'height:' . $attribs->height;
|
||||
}
|
||||
if (isset($attribs->align)) {
|
||||
$style[] = 'float:' . $attribs->align;
|
||||
}
|
||||
if (!isset($attribs->align) && isset($attribs->float)) {
|
||||
$style[] = 'float:' . $attribs->float;
|
||||
}
|
||||
$attribs = isset($attribs->class) ? 'class="' . $attribs->class . '"' : '';
|
||||
if (!empty($style)) {
|
||||
$attribs .= ' style="' . implode(';', $style) . ';"';
|
||||
}
|
||||
$start_div['tag'] = trim('<div ' . trim($attribs)) . '>';
|
||||
return [$start_div, $end_div];
|
||||
}
|
||||
/**
|
||||
* Return the Regular Expressions string to match:
|
||||
* Plugin type tags inside others
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getRegexInsideTag($start_character = '{', $end_character = '}')
|
||||
{
|
||||
$s = \RegularLabs\Library\RegEx::quote($start_character);
|
||||
$e = \RegularLabs\Library\RegEx::quote($end_character);
|
||||
return '(?:[^' . $s . $e . ']*' . $s . '[^' . $e . ']*' . $e . ')*.*?';
|
||||
}
|
||||
/**
|
||||
* Return the Regular Expressions string to match:
|
||||
* html before plugin tag
|
||||
*
|
||||
* @param string $group_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getRegexLeadingHtml($group_id = '')
|
||||
{
|
||||
$group = 'leading_block_element';
|
||||
$html_tag_group = 'html_tag';
|
||||
if ($group_id) {
|
||||
$group .= '_' . $group_id;
|
||||
$html_tag_group .= '_' . $group_id;
|
||||
}
|
||||
$block_elements = \RegularLabs\Library\Html::getBlockElements(['div']);
|
||||
$block_element = '(?<' . $group . '>' . implode('|', $block_elements) . ')';
|
||||
$other_html = '[^<]*(<(?<' . $html_tag_group . '>[a-z][a-z0-9_-]*)[\s>]([^<]*</(?P=' . $html_tag_group . ')>)?[^<]*)*';
|
||||
// Grab starting block element tag and any html after it (that is not the same block element starting/ending tag).
|
||||
return '(?:' . '<' . $block_element . '(?: [^>]*)?>' . $other_html . ')?';
|
||||
}
|
||||
/**
|
||||
* Return the Regular Expressions string to match:
|
||||
* Different types of spaces
|
||||
*
|
||||
* @param string $modifier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getRegexSpaces($modifier = '+')
|
||||
{
|
||||
return '(?:\s| |&\#160;)' . $modifier;
|
||||
}
|
||||
/**
|
||||
* Return the Regular Expressions string to match:
|
||||
* Trailing html tag
|
||||
*
|
||||
* @param array $elements
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getRegexSurroundingTagPost($elements = [])
|
||||
{
|
||||
$elements = $elements ?? null ?: [...\RegularLabs\Library\Html::getBlockElements(), 'span'];
|
||||
return '(?:(?:\s*<br ?/?>)*\s*<\/(?:' . implode('|', $elements) . ')>)?';
|
||||
}
|
||||
/**
|
||||
* Return the Regular Expressions string to match:
|
||||
* Leading html tag
|
||||
*
|
||||
* @param array $elements
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getRegexSurroundingTagPre($elements = [])
|
||||
{
|
||||
$elements = $elements ?? null ?: [...\RegularLabs\Library\Html::getBlockElements(), 'span'];
|
||||
return '(?:<(?:' . implode('|', $elements) . ')(?: [^>]*)?>\s*(?:<br ?/?>\s*)*)?';
|
||||
}
|
||||
/**
|
||||
* Return the Regular Expressions string to match:
|
||||
* Closing html tags
|
||||
*
|
||||
* @param array $block_elements
|
||||
* @param array $inline_elements
|
||||
* @param array $excluded_block_elements
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getRegexSurroundingTagsPost($block_elements = [], $inline_elements = ['span', 'strong', 'b', 'em', 'i'], $excluded_block_elements = [])
|
||||
{
|
||||
$block_elements = $block_elements ?? null ?: \RegularLabs\Library\Html::getBlockElements($excluded_block_elements);
|
||||
$regex = '';
|
||||
if (!empty($inline_elements)) {
|
||||
$regex .= '(?:(?:\s*<br ?/?>)*\s*<\/(?:' . implode('|', $inline_elements) . ')>){0,3}';
|
||||
}
|
||||
$regex .= '(?:(?:\s*<br ?/?>)*\s*<\/(?:' . implode('|', $block_elements) . ')>)?';
|
||||
return $regex;
|
||||
}
|
||||
/**
|
||||
* Return the Regular Expressions string to match:
|
||||
* Opening html tags
|
||||
*
|
||||
* @param array $block_elements
|
||||
* @param array $inline_elements
|
||||
* @param array $excluded_block_elements
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getRegexSurroundingTagsPre($block_elements = [], $inline_elements = ['span', 'strong', 'b', 'em', 'i'], $excluded_block_elements = [])
|
||||
{
|
||||
$block_elements = $block_elements ?? null ?: \RegularLabs\Library\Html::getBlockElements($excluded_block_elements);
|
||||
$regex = '(?:<(?:' . implode('|', $block_elements) . ')(?: [^>]*)?>\s*(?:<br ?/?>\s*)*)?';
|
||||
if (!empty($inline_elements)) {
|
||||
$regex .= '(?:<(?:' . implode('|', $inline_elements) . ')(?: [^>]*)?>\s*(?:<br ?/?>\s*)*){0,3}';
|
||||
}
|
||||
return $regex;
|
||||
}
|
||||
/**
|
||||
* Return the Regular Expressions string to match:
|
||||
* Plugin style tags
|
||||
*
|
||||
* @param array|string $tags
|
||||
* @param bool $include_no_attributes
|
||||
* @param bool $include_ending
|
||||
* @param array $required_attributes
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getRegexTags($tags, $include_no_attributes = \true, $include_ending = \true, $required_attributes = [])
|
||||
{
|
||||
$tags = \RegularLabs\Library\ArrayHelper::toArray($tags);
|
||||
$tags = count($tags) > 1 ? '(?:' . implode('|', $tags) . ')' : $tags[0];
|
||||
$value = '(?:\s*=\s*(?:"[^"]*"|\'[^\']*\'|[a-z0-9-_]+))?';
|
||||
$attributes = '(?:\s+[a-z0-9-_]+' . $value . ')+';
|
||||
$required_attributes = \RegularLabs\Library\ArrayHelper::toArray($required_attributes);
|
||||
if (!empty($required_attributes)) {
|
||||
$attributes = '(?:' . $attributes . ')?' . '(?:\s+' . implode('|', $required_attributes) . ')' . $value . '(?:' . $attributes . ')?';
|
||||
}
|
||||
if ($include_no_attributes) {
|
||||
$attributes = '\s*(?:' . $attributes . ')?';
|
||||
}
|
||||
if (!$include_ending) {
|
||||
return '<' . $tags . $attributes . '\s*/?>';
|
||||
}
|
||||
return '<(?:\/' . $tags . '|' . $tags . $attributes . '\s*/?)\s*/?>';
|
||||
}
|
||||
/**
|
||||
* Return the Regular Expressions string to match:
|
||||
* html after plugin tag
|
||||
*
|
||||
* @param string $group_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getRegexTrailingHtml($group_id = '')
|
||||
{
|
||||
$group = 'leading_block_element';
|
||||
if ($group_id) {
|
||||
$group .= '_' . $group_id;
|
||||
}
|
||||
// If the grouped name is found, then grab all content till ending html tag is found. Otherwise grab nothing.
|
||||
return '(?(<' . $group . '>)' . '(?:.*?</(?P=' . $group . ')>)?' . ')';
|
||||
}
|
||||
/**
|
||||
* Replace special characters in the string with the protected versions
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public static function protectSpecialChars(&$string)
|
||||
{
|
||||
$unescaped_chars = array_keys(self::$protected_characters);
|
||||
array_walk($unescaped_chars, function (&$char) {
|
||||
$char = '\\' . $char;
|
||||
});
|
||||
// replace escaped characters with special markup
|
||||
$string = str_replace($unescaped_chars, array_values(self::$protected_characters), $string);
|
||||
if (!\RegularLabs\Library\RegEx::matchAll('(<[a-z][a-z0-9-_]*(?: [a-z0-9-_]*=".*?")* ?/?>|{.*?}|\[.*?\])', $string, $tags, null, \PREG_PATTERN_ORDER)) {
|
||||
return;
|
||||
}
|
||||
foreach ($tags[0] as $tag) {
|
||||
// replace unescaped characters with special markup
|
||||
$protected = str_replace(['=', '"'], [self::$protected_characters['='], self::$protected_characters['"']], $tag);
|
||||
$string = str_replace($tag, $protected, $string);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Replace keys aliases with the main key names in an object
|
||||
*
|
||||
* @param object|string $attributes
|
||||
* @param array $key_aliases
|
||||
* @param bool $handle_plurals
|
||||
*
|
||||
* @deprecated Use ObjectHelper::replaceKeys()
|
||||
*/
|
||||
public static function replaceKeyAliases(&$attributes, $key_aliases = [], $handle_plurals = \false)
|
||||
{
|
||||
return \RegularLabs\Library\ObjectHelper::replaceKeys($attributes, $key_aliases);
|
||||
}
|
||||
/**
|
||||
* Replace protected characters in the string with the original special versions
|
||||
*
|
||||
* @param string $string
|
||||
* @param array $keep_escaped_chars
|
||||
*/
|
||||
public static function unprotectSpecialChars(&$string, $keep_escaped_chars = null)
|
||||
{
|
||||
$unescaped_chars = array_keys(self::$protected_characters);
|
||||
$keep_escaped_chars = !is_null($keep_escaped_chars) ? \RegularLabs\Library\ArrayHelper::toArray($keep_escaped_chars) : [];
|
||||
if (!empty($keep_escaped_chars)) {
|
||||
array_walk($unescaped_chars, function (&$char, $key, $keep_escaped_chars) {
|
||||
if (is_array($keep_escaped_chars) && !in_array($char, $keep_escaped_chars, \true)) {
|
||||
return;
|
||||
}
|
||||
$char = '\\' . $char;
|
||||
}, $keep_escaped_chars);
|
||||
}
|
||||
// replace special markup with unescaped characters
|
||||
$string = str_replace(array_values(self::$protected_characters), $unescaped_chars, $string);
|
||||
}
|
||||
/**
|
||||
* Get the value from a found attribute match
|
||||
*
|
||||
* @param array $match
|
||||
* @param array $known_boolean_keys
|
||||
* @param array $keep_escaped_chars
|
||||
*
|
||||
* @return bool|int|string
|
||||
*/
|
||||
private static function getAttributeValueFromMatch($match, $known_boolean_keys = [], $keep_escaped_chars = [','], $convert_numerals = \true)
|
||||
{
|
||||
$value = $match['value'];
|
||||
self::unprotectSpecialChars($value, $keep_escaped_chars);
|
||||
if (is_numeric($value) && (in_array($match['key'], $known_boolean_keys, \true) || in_array(strtolower($match['key']), $known_boolean_keys, \true))) {
|
||||
$value = $value ? 'true' : 'false';
|
||||
}
|
||||
// Convert numeric values to ints/floats
|
||||
if ($convert_numerals && is_numeric($value) && \RegularLabs\Library\RegEx::match('^[0-9\.]+$', $value)) {
|
||||
$value = $value + 0;
|
||||
}
|
||||
// Convert boolean values to actual booleans
|
||||
if ($value === 'true' || $value === \true) {
|
||||
return $match['not'] ? \false : \true;
|
||||
}
|
||||
if ($value === 'false' || $value === \false) {
|
||||
return $match['not'] ? \true : \false;
|
||||
}
|
||||
return $match['not'] ? '!NOT!' . $value : $value;
|
||||
}
|
||||
/**
|
||||
* Get the attributes from a plugin style div tag
|
||||
*/
|
||||
private static function getDivAttributes(string $string): object
|
||||
{
|
||||
if (str_contains($string, '="')) {
|
||||
return self::getAttributesFromString($string);
|
||||
}
|
||||
$parts = explode('|', $string);
|
||||
$attributes = (object) [];
|
||||
foreach ($parts as $e) {
|
||||
if (!str_contains($e, ':')) {
|
||||
continue;
|
||||
}
|
||||
[$key, $val] = explode(':', $e, 2);
|
||||
$attributes->{$key} = $val;
|
||||
}
|
||||
return $attributes;
|
||||
}
|
||||
}
|
||||
640
libraries/regularlabs/src/Protect.php
Normal file
640
libraries/regularlabs/src/Protect.php
Normal file
@ -0,0 +1,640 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Access\Access as JAccess;
|
||||
class Protect
|
||||
{
|
||||
static $html_safe_end = '___/RL_PROTECTED___';
|
||||
static $html_safe_start = '___RL_PROTECTED___';
|
||||
static $html_safe_tags_end = '___/RL_PROTECTED_TAGS___';
|
||||
static $html_safe_tags_start = '___RL_PROTECTED_TAGS___';
|
||||
static $protect_end = '___RL_PROTECTED___ -->';
|
||||
static $protect_start = '<!-- ___RL_PROTECTED___';
|
||||
static $protect_tags_end = '___RL_PROTECTED_TAGS___ -->';
|
||||
static $protect_tags_start = '<!-- ___RL_PROTECTED_TAGS___';
|
||||
static $sourcerer_characters = '{.}';
|
||||
static $sourcerer_tag;
|
||||
/**
|
||||
* Check if article passes security levels
|
||||
*/
|
||||
public static function articlePassesSecurity(?object &$article, array|string $securtiy_levels = []): bool
|
||||
{
|
||||
if (!isset($article->created_by)) {
|
||||
return \true;
|
||||
}
|
||||
if (empty($securtiy_levels)) {
|
||||
return \true;
|
||||
}
|
||||
if (is_string($securtiy_levels)) {
|
||||
$securtiy_levels = [$securtiy_levels];
|
||||
}
|
||||
if (!is_array($securtiy_levels) || in_array('-1', $securtiy_levels)) {
|
||||
return \true;
|
||||
}
|
||||
// Lookup group level of creator
|
||||
$user_groups = new JAccess();
|
||||
$user_groups = $user_groups->getGroupsByUser($article->created_by);
|
||||
// Return true if any of the security levels are found in the users groups
|
||||
return count(array_intersect($user_groups, $securtiy_levels)) > 0;
|
||||
}
|
||||
/**
|
||||
* Replace any protected text to original
|
||||
*/
|
||||
public static function convertProtectionToHtmlSafe(string &$string): void
|
||||
{
|
||||
$string = str_replace([self::$protect_start, self::$protect_end, self::$protect_tags_start, self::$protect_tags_end], [self::$html_safe_start, self::$html_safe_end, self::$html_safe_tags_start, self::$html_safe_tags_end], $string);
|
||||
}
|
||||
/**
|
||||
* Get the html end comment tags
|
||||
*/
|
||||
public static function getCommentEndTag(string $name = ''): string
|
||||
{
|
||||
return '<!-- END: ' . $name . ' -->';
|
||||
}
|
||||
/**
|
||||
* Get the html start comment tags
|
||||
*/
|
||||
public static function getCommentStartTag(string $name = ''): string
|
||||
{
|
||||
return '<!-- START: ' . $name . ' -->';
|
||||
}
|
||||
/**
|
||||
* Get the html comment tags
|
||||
*/
|
||||
public static function getCommentTags(string $name = ''): array
|
||||
{
|
||||
return [self::getCommentStartTag($name), self::getCommentEndTag($name)];
|
||||
}
|
||||
/**
|
||||
* Return the Regular Expressions string to match:
|
||||
* The edit form
|
||||
*/
|
||||
public static function getFormRegex(array|string $form_classes = []): string
|
||||
{
|
||||
$form_classes = \RegularLabs\Library\ArrayHelper::toArray($form_classes);
|
||||
return '(<form\s[^>]*(' . '(id|name)="(adminForm|postform|submissionForm|default_action_user|seblod_form|spEntryForm)"' . '|action="[^"]*option=com_myjspace&(amp;)?view=see"' . (!empty($form_classes) ? '|class="([^"]* )?(' . implode('|', $form_classes) . ')( [^"]*)?"' : '') . '))';
|
||||
}
|
||||
/**
|
||||
* Get the start and end parts for the inline comment tags for scripts/styles
|
||||
*/
|
||||
public static function getInlineCommentTags(string $name = '', ?string $type = '', bool $regex = \false): array
|
||||
{
|
||||
if ($regex) {
|
||||
return self::getInlineCommentTagsRegEx($name, $type);
|
||||
}
|
||||
if ($type) {
|
||||
$type = ': ' . $type;
|
||||
}
|
||||
$start = '/* START: ' . $name . $type . ' */';
|
||||
$end = '/* END: ' . $name . $type . ' */';
|
||||
return [$start, $end];
|
||||
}
|
||||
/**
|
||||
* Get the start and end parts for the inline comment tags for scripts/styles
|
||||
*/
|
||||
public static function getInlineCommentTagsRegEx(string $name = '', ?string $type = ''): array
|
||||
{
|
||||
$name = str_replace(' ', ' ?', \RegularLabs\Library\RegEx::quote($name));
|
||||
$type = $type ? ':? ' . \RegularLabs\Library\RegEx::quote($type) : '(:? [a-z0-9]*)?';
|
||||
$start = '/\* START: ' . $name . $type . ' \*/';
|
||||
$end = '/\* END: ' . $name . $type . ' \*/';
|
||||
return [$start, $end];
|
||||
}
|
||||
/**
|
||||
* Create a html comment from given comment string
|
||||
*/
|
||||
public static function getMessageCommentTag(string $name, string $comment): string
|
||||
{
|
||||
[$start, $end] = self::getMessageCommentTags($name);
|
||||
return $start . $comment . $end;
|
||||
}
|
||||
/**
|
||||
* Get the start and end parts for the html message comment tag
|
||||
*/
|
||||
public static function getMessageCommentTags(string $name = ''): array
|
||||
{
|
||||
return ['<!-- ' . $name . ' Message: ', ' -->'];
|
||||
}
|
||||
/**
|
||||
* Return the sourcerer tag name and characters
|
||||
*/
|
||||
public static function getSourcererTag(): array
|
||||
{
|
||||
if (!is_null(self::$sourcerer_tag)) {
|
||||
return [self::$sourcerer_tag, self::$sourcerer_characters];
|
||||
}
|
||||
$parameters = \RegularLabs\Library\Parameters::getPlugin('sourcerer');
|
||||
self::$sourcerer_tag = $parameters->syntax_word ?? '';
|
||||
self::$sourcerer_characters = $parameters->tag_characters ?? '{.}';
|
||||
return [self::$sourcerer_tag, self::$sourcerer_characters];
|
||||
}
|
||||
/**
|
||||
* Check if the component is installed
|
||||
*/
|
||||
public static function isComponentInstalled(string $extension_alias): bool
|
||||
{
|
||||
return file_exists(JPATH_ADMINISTRATOR . '/components/com_' . $extension_alias . '/' . $extension_alias . '.xml');
|
||||
}
|
||||
/**
|
||||
* Check if page should be protected for given extension
|
||||
*/
|
||||
public static function isDisabledByUrl(string $extension_alias = ''): bool
|
||||
{
|
||||
// return if disabled via url
|
||||
return $extension_alias && \RegularLabs\Library\Input::get('disable_' . $extension_alias);
|
||||
}
|
||||
/**
|
||||
* @deprecated Use isDisabledByUrl() and isRestrictedPage()
|
||||
*/
|
||||
public static function isProtectedPage(string $extension_alias = '', bool $hastags = \false, array $exclude_formats = []): bool
|
||||
{
|
||||
if (self::isDisabledByUrl($extension_alias)) {
|
||||
return \true;
|
||||
}
|
||||
return self::isRestrictedPage($hastags, $exclude_formats);
|
||||
}
|
||||
/**
|
||||
* Check if the page is a restricted component
|
||||
*/
|
||||
public static function isRestrictedComponent(array|string $restricted_components, string $area = 'component'): bool
|
||||
{
|
||||
if ($area != 'component' && !($area == 'article' && \RegularLabs\Library\Input::get('option', '') == 'com_content')) {
|
||||
return \false;
|
||||
}
|
||||
$restricted_components = \RegularLabs\Library\ArrayHelper::toArray(str_replace('|', ',', $restricted_components));
|
||||
$restricted_components = \RegularLabs\Library\ArrayHelper::clean($restricted_components);
|
||||
if (!empty($restricted_components) && in_array(\RegularLabs\Library\Input::get('option', ''), $restricted_components, \true)) {
|
||||
return \true;
|
||||
}
|
||||
if (\RegularLabs\Library\Input::get('option', '') == 'com_acymailing' && !in_array(\RegularLabs\Library\Input::get('ctrl', ''), ['user', 'archive'], \true) && !in_array(\RegularLabs\Library\Input::get('view', ''), ['user', 'archive'], \true)) {
|
||||
return \true;
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Check if page should be protected for given extension
|
||||
*/
|
||||
public static function isRestrictedPage(bool $hastags = \false, array $restricted_formats = []): bool
|
||||
{
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
// return if current page is in protected formats
|
||||
// return if current page is an image
|
||||
// return if current page is an installation page
|
||||
// return if current page is Regular Labs QuickPage
|
||||
// return if current page is a JoomFish or Josetta page
|
||||
$is_restricted = in_array(\RegularLabs\Library\Input::get('format', ''), $restricted_formats, \true) || in_array(\RegularLabs\Library\Input::get('type', ''), ['image', 'img'], \true) || in_array(\RegularLabs\Library\Input::get('task', ''), ['install.install', 'install.ajax_upload'], \true) || $hastags && \RegularLabs\Library\Input::getInt('rl_qp', 0) || $hastags && in_array(\RegularLabs\Library\Input::get('option', ''), ['com_joomfishplus', 'com_josetta'], \true) || \RegularLabs\Library\Document::isClient('administrator') && in_array(\RegularLabs\Library\Input::get('option', ''), ['com_jdownloads'], \true);
|
||||
return $cache->set($is_restricted);
|
||||
}
|
||||
/**
|
||||
* Check if the component is installed
|
||||
*/
|
||||
public static function isSystemPluginInstalled(string $extension_alias): bool
|
||||
{
|
||||
return file_exists(JPATH_PLUGINS . '/system/' . $extension_alias . '/' . $extension_alias . '.xml');
|
||||
}
|
||||
/**
|
||||
* Protect text by given regex
|
||||
*/
|
||||
public static function protectByRegex(string &$string, string $regex, int|string $group = 0): void
|
||||
{
|
||||
\RegularLabs\Library\RegEx::matchAll($regex, $string, $matches);
|
||||
if (empty($matches)) {
|
||||
return;
|
||||
}
|
||||
$replacements = [];
|
||||
foreach ($matches as $match) {
|
||||
if (isset($replacements[$match[0]])) {
|
||||
continue;
|
||||
}
|
||||
$replacements[$match[0]] = self::protectString($match[$group] ?? $match[0]);
|
||||
}
|
||||
$string = str_replace(array_keys($replacements), $replacements, $string);
|
||||
}
|
||||
/**
|
||||
* Protect all text based form fields
|
||||
*/
|
||||
public static function protectFields(string &$string, array $search_strings = []): void
|
||||
{
|
||||
// No specified strings tags found in the string
|
||||
if (!self::containsStringsToProtect($string, $search_strings)) {
|
||||
return;
|
||||
}
|
||||
$parts = \RegularLabs\Library\StringHelper::split($string, ['</label>', '</select>']);
|
||||
foreach ($parts as &$part) {
|
||||
if (!self::containsStringsToProtect($part, $search_strings)) {
|
||||
continue;
|
||||
}
|
||||
self::protectFieldsPart($part);
|
||||
}
|
||||
$string = implode('', $parts);
|
||||
}
|
||||
/**
|
||||
* Protect complete AdminForm
|
||||
*/
|
||||
public static function protectForm(string &$string, array $tags = [], bool $include_closing_tags = \true, array|string $form_classes = []): void
|
||||
{
|
||||
if (!\RegularLabs\Library\Document::isEditPage()) {
|
||||
return;
|
||||
}
|
||||
[$tags, $protected_tags] = self::prepareTags($tags, $include_closing_tags);
|
||||
$string = \RegularLabs\Library\RegEx::replace(self::getFormRegex($form_classes), '<!-- TMP_START_EDITOR -->\1', $string);
|
||||
$string = explode('<!-- TMP_START_EDITOR -->', $string);
|
||||
foreach ($string as $i => &$string_part) {
|
||||
if (empty($string_part) || !fmod($i, 2)) {
|
||||
continue;
|
||||
}
|
||||
self::protectFormPart($string_part, $tags, $protected_tags);
|
||||
}
|
||||
$string = implode('', $string);
|
||||
}
|
||||
/**
|
||||
* Protect all html comment tags
|
||||
*/
|
||||
public static function protectHtmlCommentTags(string &$string, array $ignores = []): void
|
||||
{
|
||||
$regex = '<\!--.*?-->';
|
||||
if (!empty($ignores) && \RegularLabs\Library\StringHelper::contains($string, $ignores)) {
|
||||
$regex = '<\!--((?!' . \RegularLabs\Library\RegEx::quote($ignores) . ').)*-->';
|
||||
}
|
||||
self::protectByRegex($string, $regex);
|
||||
}
|
||||
/**
|
||||
* Protect all html tags with some type of attributes/content
|
||||
*/
|
||||
public static function protectHtmlTags(string &$string): void
|
||||
{
|
||||
// protect comment tags
|
||||
self::protectHtmlCommentTags($string);
|
||||
// protect html tags
|
||||
self::protectByRegex($string, '<[a-z][^>]*(?:="[^"]*"|=\'[^\']*\')+[^>]*>');
|
||||
}
|
||||
/**
|
||||
* Protect the script tags
|
||||
*/
|
||||
public static function protectScripts(string &$string): void
|
||||
{
|
||||
if (!str_contains($string, '</script>')) {
|
||||
return;
|
||||
}
|
||||
self::protectByRegex($string, '<script[\s>].*?</script>');
|
||||
}
|
||||
/**
|
||||
* Protect all Sourcerer blocks
|
||||
*/
|
||||
public static function protectSourcerer(string &$string): void
|
||||
{
|
||||
[$tag, $characters] = self::getSourcererTag();
|
||||
if (empty($tag)) {
|
||||
return;
|
||||
}
|
||||
[$start, $end] = explode('.', $characters);
|
||||
if (!str_contains($string, $start . '/' . $tag . $end)) {
|
||||
return;
|
||||
}
|
||||
$regex = \RegularLabs\Library\RegEx::quote($start . $tag) . '[\s\}].*?' . \RegularLabs\Library\RegEx::quote($start . '/' . $tag . $end);
|
||||
\RegularLabs\Library\RegEx::matchAll($regex, $string, $matches, null, \PREG_PATTERN_ORDER);
|
||||
if (empty($matches)) {
|
||||
return;
|
||||
}
|
||||
$matches = array_unique($matches[0]);
|
||||
foreach ($matches as $match) {
|
||||
$string = str_replace($match, self::protectString($match), $string);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Encode string
|
||||
*/
|
||||
public static function protectString(string $string, bool $is_tag = \false): string
|
||||
{
|
||||
if ($is_tag) {
|
||||
return self::$protect_tags_start . base64_encode($string) . self::$protect_tags_end;
|
||||
}
|
||||
return self::$protect_start . base64_encode($string) . self::$protect_end;
|
||||
}
|
||||
/**
|
||||
* Protect given plugin style tags
|
||||
*/
|
||||
public static function protectTags(string &$string, array $tags = [], bool $include_closing_tags = \true): void
|
||||
{
|
||||
[$tags, $protected] = self::prepareTags($tags, $include_closing_tags);
|
||||
$string = str_replace($tags, $protected, $string);
|
||||
}
|
||||
/**
|
||||
* Remove area comments in html
|
||||
*/
|
||||
public static function removeAreaTags(string &$string, string $prefix = ''): void
|
||||
{
|
||||
$string = \RegularLabs\Library\RegEx::replace('<!-- (START|END): ' . $prefix . '_[A-Z]+ -->', '', $string, 's');
|
||||
}
|
||||
/**
|
||||
* Remove comments in html
|
||||
*/
|
||||
public static function removeCommentTags(string &$string, string $name = ''): void
|
||||
{
|
||||
[$start, $end] = self::getCommentTags($name);
|
||||
$string = str_replace([$start, $end, htmlentities($start), htmlentities($end), urlencode($start), urlencode($end)], '', $string);
|
||||
$start = str_replace(' -->', 'REGEX_PLACEHOLDER -->', $start);
|
||||
$end = str_replace(' -->', 'REGEX_PLACEHOLDER -->', $end);
|
||||
$regex = '(' . \RegularLabs\Library\RegEx::quote($start) . '|' . \RegularLabs\Library\RegEx::quote($end) . ')';
|
||||
$regex = str_replace('REGEX_PLACEHOLDER', '(:? [a-z0-9]*)?', $regex);
|
||||
$string = \RegularLabs\Library\RegEx::replace($regex, '', $string);
|
||||
[$start, $end] = self::getMessageCommentTags($name);
|
||||
$string = \RegularLabs\Library\RegEx::replace(\RegularLabs\Library\RegEx::quote($start) . '.*?' . \RegularLabs\Library\RegEx::quote($end), '', $string);
|
||||
}
|
||||
/**
|
||||
* Remove tags from tag attributes
|
||||
*/
|
||||
public static function removeFromHtmlTagAttributes(string &$string, array $tags, string $attributes = 'ALL', bool $include_closing_tags = \true): void
|
||||
{
|
||||
[$tags, $protected] = self::prepareTags($tags, $include_closing_tags);
|
||||
if ($attributes == 'ALL') {
|
||||
$attributes = ['[a-z][a-z0-9-_]*'];
|
||||
}
|
||||
if (!is_array($attributes)) {
|
||||
$attributes = [$attributes];
|
||||
}
|
||||
\RegularLabs\Library\RegEx::matchAll('\s(?:' . implode('|', $attributes) . ')\s*=\s*".*?"', $string, $matches, null, \PREG_PATTERN_ORDER);
|
||||
if (empty($matches) || empty($matches[0])) {
|
||||
return;
|
||||
}
|
||||
$matches = array_unique($matches[0]);
|
||||
// preg_quote all tags
|
||||
$tags_regex = \RegularLabs\Library\RegEx::quote($tags) . '.*?\}';
|
||||
foreach ($matches as $match) {
|
||||
if (!\RegularLabs\Library\StringHelper::contains($match, $tags)) {
|
||||
continue;
|
||||
}
|
||||
$title = $match;
|
||||
$title = \RegularLabs\Library\RegEx::replace($tags_regex, '', $title);
|
||||
$string = \RegularLabs\Library\StringHelper::replaceOnce($match, $title, $string);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Remove tags from title tags
|
||||
*/
|
||||
public static function removeFromHtmlTagContent(string &$string, array $tags, bool $include_closing_tags = \true, array $html_tags = ['title']): void
|
||||
{
|
||||
[$tags, $protected] = self::prepareTags($tags, $include_closing_tags);
|
||||
if (!is_array($html_tags)) {
|
||||
$html_tags = [$html_tags];
|
||||
}
|
||||
\RegularLabs\Library\RegEx::matchAll('(<(' . implode('|', $html_tags) . ')(?:\s[^>]*?)>)(.*?)(</\2>)', $string, $matches);
|
||||
if (empty($matches)) {
|
||||
return;
|
||||
}
|
||||
foreach ($matches as $match) {
|
||||
$content = $match[3];
|
||||
foreach ($tags as $tag) {
|
||||
$content = \RegularLabs\Library\RegEx::replace(\RegularLabs\Library\RegEx::quote($tag) . '.*?\}', '', $content);
|
||||
}
|
||||
$string = str_replace($match[0], $match[1] . $content . $match[4], $string);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Remove inline comments in scrips and styles
|
||||
*/
|
||||
public static function removeInlineComments(string &$string, string $name): void
|
||||
{
|
||||
[$start, $end] = \RegularLabs\Library\Protect::getInlineCommentTags($name, '', \true);
|
||||
$string = \RegularLabs\Library\RegEx::replace('(' . $start . '|' . $end . ')', "\n", $string);
|
||||
}
|
||||
/**
|
||||
* Remove leftover plugin tags
|
||||
*/
|
||||
public static function removePluginTags(string &$string, array $tags, string $character_start = '{', string $character_end = '}', bool $keep_content = \true): void
|
||||
{
|
||||
$regex_character_start = \RegularLabs\Library\RegEx::quote($character_start);
|
||||
$regex_character_end = \RegularLabs\Library\RegEx::quote($character_end);
|
||||
foreach ($tags as $tag) {
|
||||
if (!is_array($tag)) {
|
||||
$tag = [$tag, $tag];
|
||||
}
|
||||
if (count($tag) < 2) {
|
||||
$tag = [$tag[0], $tag[0]];
|
||||
}
|
||||
if (!\RegularLabs\Library\StringHelper::contains($string, $character_start . '/' . $tag[1] . $character_end)) {
|
||||
continue;
|
||||
}
|
||||
$regex = $regex_character_start . \RegularLabs\Library\RegEx::quote($tag[0]) . '(?:\s.*?)?' . $regex_character_end . '(.*?)' . $regex_character_start . '/' . \RegularLabs\Library\RegEx::quote($tag[1]) . $regex_character_end;
|
||||
$replace = $keep_content ? '\1' : '';
|
||||
$string = \RegularLabs\Library\RegEx::replace($regex, $replace, $string);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Replace any protected text to original
|
||||
*/
|
||||
public static function unprotect(string|array &$string): void
|
||||
{
|
||||
if (is_array($string)) {
|
||||
foreach ($string as &$part) {
|
||||
self::unprotect($part);
|
||||
}
|
||||
return;
|
||||
}
|
||||
self::unprotectByDelimiters($string, [self::$protect_tags_start, self::$protect_tags_end]);
|
||||
self::unprotectByDelimiters($string, [self::$protect_start, self::$protect_end]);
|
||||
if (\RegularLabs\Library\StringHelper::contains($string, [self::$protect_tags_start, self::$protect_tags_end, self::$protect_start, self::$protect_end])) {
|
||||
self::unprotect($string);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Replace any protected text to original
|
||||
*/
|
||||
public static function unprotectHtmlSafe(string &$string): void
|
||||
{
|
||||
$string = str_replace([self::$html_safe_start, self::$html_safe_end, self::$html_safe_tags_start, self::$html_safe_tags_end], [self::$protect_start, self::$protect_end, self::$protect_tags_start, self::$protect_tags_end], $string);
|
||||
self::unprotect($string);
|
||||
}
|
||||
/**
|
||||
* Replace any protected tags to original
|
||||
*/
|
||||
public static function unprotectTags(string &$string, array $tags = [], bool $include_closing_tags = \true): void
|
||||
{
|
||||
[$tags, $protected] = self::prepareTags($tags, $include_closing_tags);
|
||||
$string = str_replace($protected, $tags, $string);
|
||||
}
|
||||
/**
|
||||
* Wraps a style or javascript declaration with comment tags
|
||||
*/
|
||||
public static function wrapDeclaration(string $content = '', string $name = '', string $type = 'styles', bool $minify = \true): string
|
||||
{
|
||||
if (empty($name)) {
|
||||
return $content;
|
||||
}
|
||||
[$start, $end] = self::getInlineCommentTags($name, $type);
|
||||
$spacer = $minify ? ' ' : "\n";
|
||||
return $start . $spacer . $content . $spacer . $end;
|
||||
}
|
||||
/**
|
||||
* Wrap string in comment tags
|
||||
*/
|
||||
public static function wrapInCommentTags(string $name, string $string): string
|
||||
{
|
||||
[$start, $end] = self::getCommentTags($name);
|
||||
return $start . $string . $end;
|
||||
}
|
||||
/**
|
||||
* Wraps a javascript declaration with comment tags
|
||||
*/
|
||||
public static function wrapScriptDeclaration(string $content = '', string $name = '', bool $minify = \true): string
|
||||
{
|
||||
return self::wrapDeclaration($content, $name, 'scripts', $minify);
|
||||
}
|
||||
/**
|
||||
* Wraps a stylesheet declaration with comment tags
|
||||
*/
|
||||
public static function wrapStyleDeclaration(string $content = '', string $name = '', bool $minify = \true): string
|
||||
{
|
||||
return self::wrapDeclaration($content, $name, 'styles', $minify);
|
||||
}
|
||||
/**
|
||||
* Check if the string contains certain substrings to protect
|
||||
*/
|
||||
private static function containsStringsToProtect(string $string, array $search_strings = []): bool
|
||||
{
|
||||
if (empty($string) || !str_contains($string, '<input') && !str_contains($string, '<textarea') && !str_contains($string, '<select')) {
|
||||
return \false;
|
||||
}
|
||||
// No specified strings tags found in the string
|
||||
if (!empty($search_strings) && !\RegularLabs\Library\StringHelper::contains($string, $search_strings)) {
|
||||
return \false;
|
||||
}
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* Prepare the tags and protected tags array
|
||||
*/
|
||||
private static function prepareTags(array|string $tags, $include_closing_tags = \true): array
|
||||
{
|
||||
if (!is_array($tags)) {
|
||||
$tags = [$tags];
|
||||
}
|
||||
$cache = new \RegularLabs\Library\Cache();
|
||||
if ($cache->exists()) {
|
||||
return $cache->get();
|
||||
}
|
||||
foreach ($tags as $i => $tag) {
|
||||
if (\RegularLabs\Library\StringHelper::is_alphanumeric($tag[0])) {
|
||||
$tag = '{' . $tag;
|
||||
}
|
||||
$tags[$i] = $tag;
|
||||
if ($include_closing_tags) {
|
||||
$tags[] = \RegularLabs\Library\RegEx::replace('^([^a-z0-9]+)', '\1/', $tag);
|
||||
}
|
||||
}
|
||||
return $cache->set([$tags, self::protectArray($tags, \true)]);
|
||||
}
|
||||
/**
|
||||
* Encode array of strings
|
||||
*/
|
||||
private static function protectArray(array $array, bool $is_tag = \false): array
|
||||
{
|
||||
foreach ($array as &$string) {
|
||||
$string = self::protectString($string, $is_tag);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
/**
|
||||
* Protect the input fields in the string
|
||||
*/
|
||||
private static function protectFieldsInputFields(string &$string): void
|
||||
{
|
||||
if (!str_contains($string, '<input')) {
|
||||
return;
|
||||
}
|
||||
$type_values = '(?:text|email|hidden)';
|
||||
// must be of certain type
|
||||
$param_type = '\s+type\s*=\s*(?:"' . $type_values . '"|\'' . $type_values . '\'])';
|
||||
// must have a non-empty value or placeholder attribute
|
||||
$param_value = '\s+(?:value|placeholder)\s*=\s*(?:"[^"]+"|\'[^\']+\'])';
|
||||
// Regex to match any other parameter
|
||||
$params = '(?:\s+[a-z][a-z0-9-_]*(?:\s*=\s*(?:"[^"]*"|\'[^\']*\'|[0-9]+))?)*';
|
||||
self::protectByRegex($string, '(?:(?:' . '<input' . $params . $param_type . $params . $param_value . $params . '\s*/?>' . '|<input' . $params . $param_value . $params . $param_type . $params . '\s*/?>' . ')\s*)+');
|
||||
}
|
||||
/**
|
||||
* Protect the fields in the string
|
||||
*/
|
||||
private static function protectFieldsPart(string &$string): void
|
||||
{
|
||||
self::protectFieldsTextAreas($string);
|
||||
self::protectFieldsInputFields($string);
|
||||
}
|
||||
/**
|
||||
* Protect the textarea fields in the string
|
||||
*/
|
||||
private static function protectFieldsTextAreas(string &$string): void
|
||||
{
|
||||
if (!str_contains($string, '<textarea')) {
|
||||
return;
|
||||
}
|
||||
// Only replace non-empty textareas
|
||||
// Todo: maybe also prevent empty textareas but with a non-empty placeholder attribute
|
||||
// Temporarily replace empty textareas
|
||||
$temp_tag = '___TEMP_TEXTAREA___';
|
||||
$string = \RegularLabs\Library\RegEx::replace('<textarea((?:\s[^>]*)?)>(\s*)</textarea>', '<' . $temp_tag . '\1>\2</' . $temp_tag . '>', $string);
|
||||
self::protectByRegex($string, '(?:' . '<textarea.*?</textarea>' . '\s*)+');
|
||||
// Replace back the temporarily replaced empty textareas
|
||||
$string = str_replace($temp_tag, 'textarea', $string);
|
||||
}
|
||||
/**
|
||||
* Protect part of the AdminForm
|
||||
*/
|
||||
private static function protectFormPart(string &$string, array $tags = [], array $protected_tags = []): void
|
||||
{
|
||||
if (!str_contains($string, '</form>')) {
|
||||
return;
|
||||
}
|
||||
// Protect entire form
|
||||
if (empty($tags)) {
|
||||
$form_parts = explode('</form>', $string, 2);
|
||||
$form_parts[0] = self::protectString($form_parts[0] . '</form>');
|
||||
$string = implode('', $form_parts);
|
||||
return;
|
||||
}
|
||||
$regex_tags = \RegularLabs\Library\RegEx::quote($tags);
|
||||
if (!\RegularLabs\Library\RegEx::match($regex_tags, $string)) {
|
||||
return;
|
||||
}
|
||||
$form_parts = explode('</form>', $string, 2);
|
||||
// protect tags only inside form fields
|
||||
\RegularLabs\Library\RegEx::matchAll('(?:<textarea[^>]*>.*?<\/textarea>|<input[^>]*>)', $form_parts[0], $matches, null, \PREG_PATTERN_ORDER);
|
||||
if (empty($matches)) {
|
||||
return;
|
||||
}
|
||||
$matches = array_unique($matches[0]);
|
||||
foreach ($matches as $match) {
|
||||
$field = str_replace($tags, $protected_tags, $match);
|
||||
$form_parts[0] = str_replace($match, $field, $form_parts[0]);
|
||||
}
|
||||
$string = implode('</form>', $form_parts);
|
||||
}
|
||||
private static function unprotectByDelimiters(string &$string, array $delimiters): void
|
||||
{
|
||||
if (!\RegularLabs\Library\StringHelper::contains($string, $delimiters)) {
|
||||
return;
|
||||
}
|
||||
$regex = \RegularLabs\Library\RegEx::preparePattern(\RegularLabs\Library\RegEx::quote($delimiters), 's', $string);
|
||||
$parts = preg_split($regex, $string);
|
||||
foreach ($parts as $i => &$part) {
|
||||
if ($i % 2 == 0) {
|
||||
continue;
|
||||
}
|
||||
$part = base64_decode($part);
|
||||
}
|
||||
$string = implode('', $parts);
|
||||
}
|
||||
}
|
||||
166
libraries/regularlabs/src/RegEx.php
Normal file
166
libraries/regularlabs/src/RegEx.php
Normal file
@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
class RegEx
|
||||
{
|
||||
/**
|
||||
* Perform a regular expression match
|
||||
*/
|
||||
public static function match(string $pattern, string $string, &$match = null, ?string $options = null, int $flags = 0): int
|
||||
{
|
||||
if (empty($string) || empty($pattern)) {
|
||||
return \false;
|
||||
}
|
||||
$pattern = self::preparePattern($pattern, $options, $string);
|
||||
$result = preg_match($pattern, $string, $match, $flags);
|
||||
// Remove all numeric keys except 0
|
||||
$no_numeric_values = array_filter($match, fn($key) => !is_int($key) || $key === 0, \ARRAY_FILTER_USE_KEY);
|
||||
// If the leftover array counts more than 2 (so contains named groups), replace $match
|
||||
if (count($no_numeric_values) > 1) {
|
||||
$match = $no_numeric_values;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
/**
|
||||
* Perform a global regular expression match
|
||||
*/
|
||||
public static function matchAll(string $pattern, string $string, &$matches = null, ?string $options = null, int $flags = \PREG_SET_ORDER): int
|
||||
{
|
||||
if (empty($string) || empty($pattern)) {
|
||||
$matches = [];
|
||||
return \false;
|
||||
}
|
||||
$pattern = self::preparePattern($pattern, $options, $string);
|
||||
$result = preg_match_all($pattern, $string, $matches, $flags);
|
||||
if (!$result) {
|
||||
return \false;
|
||||
}
|
||||
if ($flags == \PREG_OFFSET_CAPTURE) {
|
||||
// Remove all numeric keys except 0
|
||||
$no_numeric_values = array_filter($matches, fn($key) => !is_int($key) || $key === 0, \ARRAY_FILTER_USE_KEY);
|
||||
// If the leftover array counts less than 2 (so no named groups), don't continue
|
||||
if (count($no_numeric_values) < 2) {
|
||||
return $result;
|
||||
}
|
||||
$matches = $no_numeric_values;
|
||||
return $result;
|
||||
}
|
||||
if ($flags != \PREG_SET_ORDER) {
|
||||
return $result;
|
||||
}
|
||||
foreach ($matches as &$match) {
|
||||
// Remove all numeric keys except 0
|
||||
$no_numeric_values = array_filter($match, fn($key) => !is_int($key) || $key === 0, \ARRAY_FILTER_USE_KEY);
|
||||
// If the leftover array counts less than 2 (so no named groups), don't continue
|
||||
if (count($no_numeric_values) < 2) {
|
||||
break;
|
||||
}
|
||||
$match = $no_numeric_values;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
/**
|
||||
* preg_quote the given string or array of strings
|
||||
*/
|
||||
public static function nameGroup(string $data, string $name = ''): string
|
||||
{
|
||||
return '(?<' . $name . '>' . $data . ')';
|
||||
}
|
||||
/**
|
||||
* Make a string a valid regular expression pattern
|
||||
*/
|
||||
public static function preparePattern(string|array $pattern, ?string $options = null, string $string = ''): string|array
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$pattern, $options, $string]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
if (!str_starts_with($pattern, '#')) {
|
||||
$options = !is_null($options) ? $options : 'si';
|
||||
$pattern = '#' . $pattern . '#' . $options;
|
||||
}
|
||||
if (\RegularLabs\Library\StringHelper::detectUTF8($string)) {
|
||||
// use utf-8
|
||||
return $pattern . 'u';
|
||||
}
|
||||
return $pattern;
|
||||
}
|
||||
/**
|
||||
* preg_quote the given string or array of strings
|
||||
*/
|
||||
public static function quote(string|array $data, string $name = '', string $delimiter = '#'): string
|
||||
{
|
||||
if (is_array($data)) {
|
||||
if (count($data) === 1) {
|
||||
return self::quote(array_pop($data), $name, $delimiter);
|
||||
}
|
||||
$array = self::quoteArray($data, $delimiter);
|
||||
$prefix = '?:';
|
||||
if (!empty($name)) {
|
||||
$prefix = $name ? '?<' . $name . '>' : '';
|
||||
}
|
||||
return '(' . $prefix . implode('|', $array) . ')';
|
||||
}
|
||||
if (!empty($name)) {
|
||||
return '(?<' . $name . '>' . preg_quote($data, $delimiter) . ')';
|
||||
}
|
||||
return preg_quote($data, $delimiter);
|
||||
}
|
||||
/**
|
||||
* preg_quote the given array of strings
|
||||
*/
|
||||
public static function quoteArray(array $array, string $delimiter = '#'): array
|
||||
{
|
||||
array_walk($array, function (&$part, $key, $delimiter) {
|
||||
$part = self::quote($part, '', $delimiter);
|
||||
}, $delimiter);
|
||||
return $array;
|
||||
}
|
||||
/**
|
||||
* Perform a regular expression search and replace
|
||||
*/
|
||||
public static function replace(string $pattern, string $replacement, string $string, ?string $options = null, int $limit = -1, ?int &$count = null): string|null
|
||||
{
|
||||
if (empty($string) || empty($pattern)) {
|
||||
return $string;
|
||||
}
|
||||
$pattern = self::preparePattern($pattern, $options, $string);
|
||||
return preg_replace($pattern, $replacement, $string, $limit, $count);
|
||||
}
|
||||
/**
|
||||
* Perform a regular expression search and replace once
|
||||
*/
|
||||
public static function replaceOnce(string $pattern, string $replacement, string $string, ?string $options = null): string
|
||||
{
|
||||
return self::replace($pattern, $replacement, $string, $options, 1);
|
||||
}
|
||||
/**
|
||||
* Perform a regular expression split
|
||||
*/
|
||||
public static function split(string $pattern, string $string, ?string $options = null, int $limit = -1, int $flags = \PREG_SPLIT_DELIM_CAPTURE): array
|
||||
{
|
||||
if (empty($string) || empty($pattern)) {
|
||||
return [$string];
|
||||
}
|
||||
$pattern = self::preparePattern($pattern, $options, $string);
|
||||
return preg_split($pattern, $string, $limit, $flags);
|
||||
}
|
||||
/**
|
||||
* reverse preg_quote the given string
|
||||
*/
|
||||
public static function unquote(string $string, string $delimiter = '#'): string
|
||||
{
|
||||
return strtr($string, ['\\' . $delimiter => $delimiter, '\.' => '.', '\\\\' => '\\', '\+' => '+', '\*' => '*', '\?' => '?', '\[' => '[', '\^' => '^', '\]' => ']', '\$' => '$', '\(' => '(', '\)' => ')', '\{' => '{', '\}' => '}', '\=' => '=', '\!' => '!', '\<' => '<', '\>' => '>', '\|' => '|', '\:' => ':', '\-' => '-']);
|
||||
}
|
||||
}
|
||||
38
libraries/regularlabs/src/ShowOn.php
Normal file
38
libraries/regularlabs/src/ShowOn.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Form\FormHelper as JFormHelper;
|
||||
class ShowOn
|
||||
{
|
||||
public static function close()
|
||||
{
|
||||
return '</div>';
|
||||
}
|
||||
public static function open(string $condition = '', string $formControl = '', string $group = '', string $class = ''): string
|
||||
{
|
||||
if (!$condition) {
|
||||
return self::close();
|
||||
}
|
||||
\RegularLabs\Library\Document::useScript('showon');
|
||||
$json = json_encode(JFormHelper::parseShowOnConditions($condition, $formControl, $group));
|
||||
return '<div data-showon=\'' . $json . '\' class="hidden ' . $class . '"">';
|
||||
}
|
||||
public static function show(string $string = '', string $condition = '', string $formControl = '', string $group = '', bool $animate = \true, string $class = ''): string
|
||||
{
|
||||
if (!$condition || !$string) {
|
||||
return $string;
|
||||
}
|
||||
return self::open($condition, $formControl, $group, $animate, $class) . $string . self::close();
|
||||
}
|
||||
}
|
||||
36
libraries/regularlabs/src/SimpleCategory.php
Normal file
36
libraries/regularlabs/src/SimpleCategory.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
class SimpleCategory
|
||||
{
|
||||
public static function save(string $table, int $item_id, string $category, string $id_column = 'id'): void
|
||||
{
|
||||
$db = \RegularLabs\Library\DB::get();
|
||||
$query = $db->getQuery(\true)->select(\RegularLabs\Library\DB::quoteName($id_column))->from(\RegularLabs\Library\DB::quoteName('#__' . $table))->where(\RegularLabs\Library\DB::quoteName($id_column) . ' = ' . $item_id);
|
||||
$item_exists = $db->setQuery($query)->loadResult();
|
||||
if ($item_exists) {
|
||||
$query = $db->getQuery(\true)->update(\RegularLabs\Library\DB::quoteName('#__' . $table))->set(\RegularLabs\Library\DB::quoteName('category') . ' = ' . \RegularLabs\Library\DB::quote($category))->where(\RegularLabs\Library\DB::quoteName($id_column) . ' = ' . $item_id);
|
||||
$db->setQuery($query)->execute();
|
||||
return;
|
||||
}
|
||||
$query = 'SHOW COLUMNS FROM `#__' . $table . '`';
|
||||
$db->setQuery($query);
|
||||
$columns = $db->loadColumn();
|
||||
$values = array_fill_keys($columns, '');
|
||||
$values[$id_column] = $item_id;
|
||||
$values['category'] = $category;
|
||||
$query = $db->getQuery(\true)->insert(\RegularLabs\Library\DB::quoteName('#__' . $table))->columns(\RegularLabs\Library\DB::quoteName($columns))->values(implode(',', \RegularLabs\Library\DB::quote($values)));
|
||||
$db->setQuery($query)->execute();
|
||||
}
|
||||
}
|
||||
615
libraries/regularlabs/src/StringHelper.php
Normal file
615
libraries/regularlabs/src/StringHelper.php
Normal file
@ -0,0 +1,615 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\String\Normalise as JNormalise;
|
||||
use Normalizer;
|
||||
class StringHelper extends \Joomla\String\StringHelper
|
||||
{
|
||||
/**
|
||||
* Adds postfix to a string
|
||||
*/
|
||||
public static function addPostfix(string $string, string $postfix): string
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string, $postfix]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
if (empty($postfix)) {
|
||||
return $string;
|
||||
}
|
||||
if (!is_string($string) && !is_numeric($string)) {
|
||||
return $string;
|
||||
}
|
||||
return $string . $postfix;
|
||||
}
|
||||
/**
|
||||
* Adds prefix to a string
|
||||
*/
|
||||
public static function addPrefix(string $string, string $prefix, bool $keep_leading_slash = \true): string
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string, $prefix, $keep_leading_slash]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
if (empty($prefix)) {
|
||||
return $string;
|
||||
}
|
||||
if (!is_string($string) && !is_numeric($string)) {
|
||||
return $string;
|
||||
}
|
||||
if ($keep_leading_slash && !empty($string) && $string[0] == '/') {
|
||||
return $string[0] . $prefix . substr($string, 1);
|
||||
}
|
||||
return $prefix . $string;
|
||||
}
|
||||
public static function applyConversion(string $type, string $string, ?object $attributes): string
|
||||
{
|
||||
switch ($type) {
|
||||
case 'escape':
|
||||
return addslashes($string);
|
||||
case 'lowercase':
|
||||
return self::toLowerCase($string);
|
||||
case 'uppercase':
|
||||
return self::toUpperCase($string);
|
||||
case 'notags':
|
||||
return strip_tags($string);
|
||||
case 'nowhitespace':
|
||||
return str_replace(' ', '', strip_tags($string));
|
||||
case 'toalias':
|
||||
return \RegularLabs\Library\Alias::get($string);
|
||||
case 'replace':
|
||||
if (!isset($attributes->from)) {
|
||||
return $string;
|
||||
}
|
||||
$case_insensitive = isset($attributes->{'case-insensitive'}) && $attributes->{'case-insensitive'} == 'true';
|
||||
return \RegularLabs\Library\RegEx::replace($attributes->from, $attributes->to ?? '', $string, $case_insensitive ? 'is' : 's');
|
||||
default:
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Check if any of the needles are found in any of the haystacks
|
||||
*/
|
||||
public static function contains(string|array $haystacks, string|array $needles): bool
|
||||
{
|
||||
$haystacks = \RegularLabs\Library\ArrayHelper::toArray($haystacks);
|
||||
$needles = \RegularLabs\Library\ArrayHelper::toArray($needles);
|
||||
if (empty($haystacks) || empty($needles)) {
|
||||
return \false;
|
||||
}
|
||||
foreach ($haystacks as $haystack) {
|
||||
foreach ($needles as $needle) {
|
||||
if (!str_contains($haystack, $needle)) {
|
||||
continue;
|
||||
}
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Converts a string to a UTF-8 encoded string
|
||||
*/
|
||||
public static function convertToUtf8(string $string = ''): string
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
if (self::detectUTF8($string)) {
|
||||
// Already UTF-8, so skip
|
||||
return $string;
|
||||
}
|
||||
if (!function_exists('iconv')) {
|
||||
// Still need to find a stable fallback
|
||||
return $string;
|
||||
}
|
||||
$utf8_string = @iconv('UTF8', 'UTF-8//IGNORE', $string);
|
||||
if (empty($utf8_string)) {
|
||||
return $string;
|
||||
}
|
||||
return $utf8_string;
|
||||
}
|
||||
public static function countWords(string $string, int|string $format = 0): array|int
|
||||
{
|
||||
$format = match ($format) {
|
||||
'array', 1 => 'array',
|
||||
'numbered', 2 => 'numbered',
|
||||
default => 'number',
|
||||
};
|
||||
$words = preg_split('#[^\p{L}\p{N}\']+#u', $string, -1, $format == 'numbered' ? \PREG_SPLIT_OFFSET_CAPTURE : null);
|
||||
switch ($format) {
|
||||
case 'array':
|
||||
return $words;
|
||||
case 'numbered':
|
||||
$numbered = [];
|
||||
foreach ($words as $word) {
|
||||
$numbered[$word[1]] = $word[0];
|
||||
}
|
||||
return $numbered;
|
||||
case 'number':
|
||||
default:
|
||||
return count($words);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Check whether string is a UTF-8 encoded string
|
||||
*/
|
||||
public static function detectUTF8(string $string = ''): bool
|
||||
{
|
||||
// Try to check the string via the mb_check_encoding function
|
||||
if (function_exists('mb_check_encoding')) {
|
||||
return mb_check_encoding($string, 'UTF-8');
|
||||
}
|
||||
// Otherwise: Try to check the string via the iconv function
|
||||
if (function_exists('iconv')) {
|
||||
$converted = iconv('UTF-8', 'UTF-8//IGNORE', $string);
|
||||
return md5($converted) == md5($string);
|
||||
}
|
||||
// As last fallback, check if the preg_match finds anything using the unicode flag
|
||||
return preg_match('#.#u', $string);
|
||||
}
|
||||
public static function escape(string $string): string
|
||||
{
|
||||
return htmlspecialchars($string, \ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
/**
|
||||
* Converts a camelcased string to a space separated string
|
||||
* eg: FooBar => Foo Bar
|
||||
*/
|
||||
public static function fromCamelCase(string $string): string|array|object
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
$parts = JNormalise::fromCamelCase($string, \true);
|
||||
$parts = \RegularLabs\Library\ArrayHelper::trim($parts);
|
||||
return implode(' ', $parts);
|
||||
}
|
||||
/**
|
||||
* Decode html entities in string (or array of strings)
|
||||
*/
|
||||
public static function html_entity_decoder(string $string, int $quote_style = \ENT_QUOTES, string $encoding = 'UTF-8'): string|array|object
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string, $quote_style, $encoding]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
if (!is_string($string)) {
|
||||
return $string;
|
||||
}
|
||||
$string = html_entity_decode($string, $quote_style | \ENT_HTML5, $encoding);
|
||||
$string = str_replace(chr(194) . chr(160), ' ', $string);
|
||||
return $string;
|
||||
}
|
||||
/**
|
||||
* Check if string is alphanumerical
|
||||
*/
|
||||
public static function is_alphanumeric(string $string): bool
|
||||
{
|
||||
if (function_exists('ctype_alnum')) {
|
||||
return (bool) ctype_alnum($string);
|
||||
}
|
||||
return (bool) \RegularLabs\Library\RegEx::match('^[a-z0-9]+$', $string);
|
||||
}
|
||||
/**
|
||||
* Check if string is a valid key / alias (alphanumeric with optional _ or - chars)
|
||||
*/
|
||||
public static function is_key(string $string): bool
|
||||
{
|
||||
return \RegularLabs\Library\RegEx::match('^[a-z][a-z0-9-_]*$', trim($string));
|
||||
}
|
||||
/**
|
||||
* UTF-8 aware alternative to lcfirst
|
||||
*/
|
||||
public static function lcfirst(string $string): string
|
||||
{
|
||||
switch (utf8_strlen($string)) {
|
||||
case 0:
|
||||
return '';
|
||||
case 1:
|
||||
return utf8_strtolower($string);
|
||||
default:
|
||||
preg_match('/^(.{1})(.*)$/us', $string, $matches);
|
||||
return utf8_strtolower($matches[1]) . $matches[2];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Converts the first letter to lowercase
|
||||
* eg: FooBar => fooBar
|
||||
* eg: Foo bar => foo bar
|
||||
* eg: FOO_BAR => fOO_BAR
|
||||
*/
|
||||
public static function lowerCaseFirst(string|array|object $string): string|array|null
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string]);
|
||||
if (!is_string($string)) {
|
||||
return $array;
|
||||
}
|
||||
return self::lcfirst($string);
|
||||
}
|
||||
public static function minify(string $string): string
|
||||
{
|
||||
// place new lines around string to make regex searching easier
|
||||
$string = "\n" . $string . "\n";
|
||||
// Remove comment lines
|
||||
$string = \RegularLabs\Library\RegEx::replace('\n\s*//.*?\n', '', $string);
|
||||
// Remove comment blocks
|
||||
$string = \RegularLabs\Library\RegEx::replace('/\*.*?\*/', '', $string);
|
||||
// Remove enters
|
||||
$string = \RegularLabs\Library\RegEx::replace('\n\s*', ' ', $string);
|
||||
// Remove surrounding whitespace
|
||||
$string = trim($string);
|
||||
return $string;
|
||||
}
|
||||
/**
|
||||
* Normalizes the input provided and returns the normalized string
|
||||
*/
|
||||
public static function normalize(string $string, bool $to_lowercase = \false): string|array|object
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string, $to_lowercase]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
// Normalizer-class missing!
|
||||
if (class_exists('Normalizer', \false)) {
|
||||
$string = Normalizer::normalize($string);
|
||||
}
|
||||
return $to_lowercase ? self::toLowerCase($string) : $string;
|
||||
}
|
||||
/**
|
||||
* Removes html tags from string
|
||||
*/
|
||||
public static function removeHtml(string $string, bool $remove_comments = \false): string|array|object
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string, $remove_comments]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
return \RegularLabs\Library\Html::removeHtmlTags($string, $remove_comments);
|
||||
}
|
||||
/**
|
||||
* Removes the trailing part of a string if it matches the given $postfix
|
||||
*/
|
||||
public static function removePostfix(string $string, string $postfix): string|array|object
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string, $postfix]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
if (empty($string) || empty($postfix)) {
|
||||
return $string;
|
||||
}
|
||||
if (!is_string($string) && !is_numeric($string)) {
|
||||
return $string;
|
||||
}
|
||||
$string_length = strlen($string);
|
||||
$postfix_length = strlen($postfix);
|
||||
$start = $string_length - $postfix_length;
|
||||
if (substr($string, $start) !== $postfix) {
|
||||
return $string;
|
||||
}
|
||||
return substr($string, 0, $start);
|
||||
}
|
||||
/**
|
||||
* Removes the first part of a string if it matches the given $prefix
|
||||
*/
|
||||
public static function removePrefix(string $string, string $prefix, bool $keep_leading_slash = \true): string|array|object
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string, $prefix, $keep_leading_slash]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
if (empty($string) || empty($prefix)) {
|
||||
return $string;
|
||||
}
|
||||
if (!is_string($string) && !is_numeric($string)) {
|
||||
return $string;
|
||||
}
|
||||
$prefix_length = strlen($prefix);
|
||||
$start = 0;
|
||||
if ($keep_leading_slash && $prefix[0] !== '/' && $string[0] == '/') {
|
||||
$start = 1;
|
||||
}
|
||||
if (substr($string, $start, $prefix_length) !== $prefix) {
|
||||
return $string;
|
||||
}
|
||||
return substr($string, 0, $start) . substr($string, $start + $prefix_length);
|
||||
}
|
||||
/**
|
||||
* Replace the given replace string once in the main string
|
||||
*/
|
||||
public static function replaceOnce(?string $search, ?string $replace, string $string): string
|
||||
{
|
||||
if (empty($search) || empty($string)) {
|
||||
return $string;
|
||||
}
|
||||
if (!str_contains($string, $search)) {
|
||||
return $string;
|
||||
}
|
||||
if (empty($replace)) {
|
||||
$replace = '';
|
||||
}
|
||||
return substr_replace($string, $replace, strpos($string, $search), strlen($search));
|
||||
}
|
||||
/**
|
||||
* Split a long string into parts (array)
|
||||
*
|
||||
* @param array $delimiters Array of strings to split the string on
|
||||
* @param int $max_length Maximum length of each part
|
||||
* @param bool $maximize_parts If true, the different parts will be made as large as possible (combining consecutive short string elements)
|
||||
*/
|
||||
public static function split(string $string, array $delimiters = [], int $max_length = 10000, bool $maximize_parts = \true): array
|
||||
{
|
||||
// String is too short to split
|
||||
if (strlen($string) < $max_length) {
|
||||
return [$string];
|
||||
}
|
||||
// No delimiters given or found
|
||||
if (empty($delimiters) || !self::contains($string, $delimiters)) {
|
||||
return [$string];
|
||||
}
|
||||
// preg_quote all delimiters
|
||||
$array = preg_split('#(' . \RegularLabs\Library\RegEx::quote($delimiters) . ')#s', $string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
|
||||
if (!$maximize_parts) {
|
||||
return $array;
|
||||
}
|
||||
$new_array = [];
|
||||
foreach ($array as $i => $part) {
|
||||
// First element, add to new array
|
||||
if (!count($new_array)) {
|
||||
$new_array[] = $part;
|
||||
continue;
|
||||
}
|
||||
$last_part = end($new_array);
|
||||
$last_key = key($new_array);
|
||||
// This is the delimiter so add to previous part
|
||||
if ($i % 2) {
|
||||
// Concatenate part to previous part
|
||||
$new_array[$last_key] .= $part;
|
||||
continue;
|
||||
}
|
||||
// If last and current parts are shorter than or same as max_length, then add to previous part
|
||||
if (strlen($last_part) + strlen($part) <= $max_length) {
|
||||
$new_array[$last_key] .= $part;
|
||||
continue;
|
||||
}
|
||||
$new_array[] = $part;
|
||||
}
|
||||
return $new_array;
|
||||
}
|
||||
/**
|
||||
* Converts a string to a camel case
|
||||
* eg: foo bar => fooBar
|
||||
* eg: foo_bar => fooBar
|
||||
* eg: foo-bar => fooBar
|
||||
*/
|
||||
public static function toCamelCase(string $string, bool $keep_duplicate_separators = \true): string
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
if (empty($string)) {
|
||||
return $string;
|
||||
}
|
||||
return JNormalise::toVariable(self::toSpaceSeparated($string, $keep_duplicate_separators));
|
||||
}
|
||||
/**
|
||||
* Converts a string to a certain case
|
||||
*/
|
||||
public static function toCase(string $string, string $format, bool $to_lowercase = \true): string
|
||||
{
|
||||
$format = strtolower(str_replace('case', '', $format));
|
||||
return match ($format) {
|
||||
'lower' => self::toLowerCase($string),
|
||||
'upper' => self::toUpperCase($string),
|
||||
'lcfirst', 'lower-first' => self::lowerCaseFirst($string),
|
||||
'ucfirst', 'upper-first' => self::upperCaseFirst($string),
|
||||
'title' => self::toTitleCase($string),
|
||||
'camel' => self::toCamelCase($string),
|
||||
'dash' => self::toDashCase($string, $to_lowercase),
|
||||
'dot' => self::toDotCase($string, $to_lowercase),
|
||||
'pascal' => self::toPascalCase($string),
|
||||
'underscore' => self::toUnderscoreCase($string, $to_lowercase),
|
||||
default => $to_lowercase ? self::toLowerCase($string) : $string,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Converts a string to a camel case
|
||||
* eg: FooBar => foo-bar
|
||||
* eg: foo_bar => foo-bar
|
||||
*/
|
||||
public static function toDashCase(string|array|object $string, bool $to_lowercase = \true, bool $keep_duplicate_separators = \true): string|array|object
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string, $to_lowercase]);
|
||||
if (!is_string($string)) {
|
||||
return $array;
|
||||
}
|
||||
$string = preg_replace(self::getSeparatorRegex($keep_duplicate_separators), '-', self::toSpaceSeparated($string, $keep_duplicate_separators));
|
||||
return $to_lowercase ? self::toLowerCase($string) : $string;
|
||||
}
|
||||
/**
|
||||
* Converts a string to a camel case
|
||||
* eg: FooBar => foo.bar
|
||||
* eg: foo_bar => foo.bar
|
||||
*/
|
||||
public static function toDotCase(string|array|object $string, bool $to_lowercase = \true): string|array|object
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string, $to_lowercase]);
|
||||
if (!is_string($string)) {
|
||||
return $array;
|
||||
}
|
||||
$string = self::toDashCase($string, $to_lowercase);
|
||||
return str_replace('-', '.', $string);
|
||||
}
|
||||
/**
|
||||
* Converts a string to a lower case
|
||||
* eg: FooBar => foobar
|
||||
* eg: foo_bar => foo_bar
|
||||
*/
|
||||
public static function toLowerCase(string|array|object $string): string|array
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string]);
|
||||
if (!is_string($string)) {
|
||||
return $array;
|
||||
}
|
||||
return self::strtolower($string);
|
||||
}
|
||||
/**
|
||||
* Converts a string to a camel case
|
||||
* eg: foo bar => FooBar
|
||||
* eg: foo_bar => FooBar
|
||||
* eg: foo-bar => FooBar
|
||||
*/
|
||||
public static function toPascalCase(string $string, bool $keep_duplicate_separators = \true): string|array|object
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
return JNormalise::toCamelCase(self::toSpaceSeparated($string, $keep_duplicate_separators));
|
||||
}
|
||||
/**
|
||||
* Converts a string into space separated form
|
||||
* eg: FooBar => Foo Bar
|
||||
* eg: foo-bar => foo bar
|
||||
*/
|
||||
public static function toSpaceSeparated(string $string, bool $keep_duplicate_separators = \true): string|array|object
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
return preg_replace(self::getSeparatorRegex($keep_duplicate_separators), ' ', self::fromCamelCase($string));
|
||||
}
|
||||
/**
|
||||
* Converts an object or array to a single string
|
||||
*/
|
||||
public static function toString(string|array|object $string): string
|
||||
{
|
||||
if (is_string($string)) {
|
||||
return $string;
|
||||
}
|
||||
foreach ($string as &$part) {
|
||||
$part = self::toString($part);
|
||||
}
|
||||
return \RegularLabs\Library\ArrayHelper::implode((array) $string);
|
||||
}
|
||||
/**
|
||||
* Converts a string to a camel case
|
||||
* eg: foo bar => Foo Bar
|
||||
* eg: foo_bar => Foo Bar
|
||||
* eg: foo-bar => Foo Bar
|
||||
*/
|
||||
public static function toTitleCase(string $string, bool $keep_duplicate_separators = \true): string|array|object
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
return self::ucwords(self::toSpaceSeparated($string, $keep_duplicate_separators));
|
||||
}
|
||||
/**
|
||||
* Converts a string to a underscore separated string
|
||||
* eg: FooBar => foo_bar
|
||||
* eg: foo-bar => foo_bar
|
||||
*/
|
||||
public static function toUnderscoreCase(string $string, bool $to_lowercase = \true, bool $keep_duplicate_separators = \true): string|array|object
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string, $to_lowercase]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
$string = preg_replace(self::getSeparatorRegex($keep_duplicate_separators), '_', self::toSpaceSeparated($string, $keep_duplicate_separators));
|
||||
return $to_lowercase ? self::toLowerCase($string) : $string;
|
||||
}
|
||||
/**
|
||||
* Converts a string to a lower case
|
||||
* eg: FooBar => FOOBAR
|
||||
* eg: foo_bar => FOO_BAR
|
||||
*/
|
||||
public static function toUpperCase(string|array|object $string): string|array|object
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string]);
|
||||
if (!is_string($string)) {
|
||||
return $array;
|
||||
}
|
||||
return self::strtoupper($string);
|
||||
}
|
||||
public static function truncate(string $string, int $maxlen): string
|
||||
{
|
||||
if (self::strlen($string) <= $maxlen) {
|
||||
return $string;
|
||||
}
|
||||
return self::substr($string, 0, $maxlen - 3) . '…';
|
||||
}
|
||||
/**
|
||||
* Converts the first letter to uppercase
|
||||
* eg: fooBar => FooBar
|
||||
* eg: foo bar => Foo bar
|
||||
* eg: foo_bar => Foo_bar
|
||||
*/
|
||||
public static function upperCaseFirst(string|array|object $string): string|array|object
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string]);
|
||||
if (!is_string($string)) {
|
||||
return $array;
|
||||
}
|
||||
return self::ucfirst($string);
|
||||
}
|
||||
/**
|
||||
* utf8 decode a string (or array of strings)
|
||||
*/
|
||||
public static function utf8_decode(string $string): string|array|object
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
if (!is_string($string)) {
|
||||
return $string;
|
||||
}
|
||||
if (!function_exists('mb_decode_numericentity')) {
|
||||
return $string;
|
||||
}
|
||||
return mb_decode_numericentity($string, [0x80, 0xffff, 0, ~0], 'UTF-8');
|
||||
}
|
||||
/**
|
||||
* utf8 encode a string (or array of strings)
|
||||
*/
|
||||
public static function utf8_encode(string $string): string|array|object
|
||||
{
|
||||
$array = \RegularLabs\Library\ArrayHelper::applyMethodToValues([$string]);
|
||||
if (!is_null($array)) {
|
||||
return $array;
|
||||
}
|
||||
if (!is_string($string)) {
|
||||
return $string;
|
||||
}
|
||||
if (!function_exists('mb_decode_numericentity')) {
|
||||
return $string;
|
||||
}
|
||||
return mb_encode_numericentity($string, [0x80, 0xffff, 0, ~0], 'UTF-8');
|
||||
}
|
||||
private static function getSeparatorRegex(bool $keep_duplicate_separators = \true): string
|
||||
{
|
||||
$regex = '[ \-_]';
|
||||
if (!$keep_duplicate_separators) {
|
||||
$regex .= '+';
|
||||
}
|
||||
return '#' . $regex . '#';
|
||||
}
|
||||
}
|
||||
380
libraries/regularlabs/src/StringReplacer.php
Normal file
380
libraries/regularlabs/src/StringReplacer.php
Normal file
@ -0,0 +1,380 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
/**
|
||||
* Class StringReplacer
|
||||
* Handles string replacement operations with the ability to exclude certain parts of the string
|
||||
*/
|
||||
class StringReplacer
|
||||
{
|
||||
private bool $enable_clean = \true;
|
||||
private array $parts = [];
|
||||
public function __construct(string $string = '')
|
||||
{
|
||||
$this->set($string ?? '');
|
||||
}
|
||||
public function clean(): self
|
||||
{
|
||||
$this->enable_clean = \true;
|
||||
$this->cleanParts();
|
||||
return $this;
|
||||
}
|
||||
public function contains(string $string): bool
|
||||
{
|
||||
return str_contains($this->toString(), $string);
|
||||
}
|
||||
public function disableCleaning(): self
|
||||
{
|
||||
$this->enable_clean = \false;
|
||||
return $this;
|
||||
}
|
||||
public function excludeExceptHtmlTags(array $tags = ['*']): self
|
||||
{
|
||||
$regex = $this->getHtmlTagsRegex();
|
||||
$this->excludeExceptRegex($regex);
|
||||
if (in_array('*', $tags)) {
|
||||
return $this;
|
||||
}
|
||||
return $this->excludeHtmlTags($tags);
|
||||
}
|
||||
public function excludeExceptRegex(string $regex): self
|
||||
{
|
||||
$all_parts = [];
|
||||
foreach ($this->parts as $key => &$string) {
|
||||
if ($this->shouldSkip($key, $string)) {
|
||||
$all_parts[] = $string;
|
||||
continue;
|
||||
}
|
||||
$parts = \RegularLabs\Library\RegEx::split($regex, $string);
|
||||
$parts = ['', ...$parts, ''];
|
||||
array_push($all_parts, ...$parts);
|
||||
}
|
||||
$this->setParts($all_parts);
|
||||
return $this;
|
||||
}
|
||||
public function excludeExceptStrings(array $strings = []): self
|
||||
{
|
||||
$regex = \RegularLabs\Library\RegEx::quote($strings);
|
||||
return $this->excludeExceptRegex($regex);
|
||||
}
|
||||
public function excludeForm(array $form_classes = []): self
|
||||
{
|
||||
// Exclude the complete adminForm (to prevent replacements messing stuff up when editing articles and such)
|
||||
$regexes = $this->getFormRegexes($form_classes);
|
||||
return $this->excludeRegexBetween($regexes->start, $regexes->end, \true);
|
||||
}
|
||||
public function excludeHtmlTags(array $except_tags = []): self
|
||||
{
|
||||
$regex = $this->getHtmlTagsRegex();
|
||||
if (in_array('*', $except_tags)) {
|
||||
return $this;
|
||||
}
|
||||
$this->disableCleaning();
|
||||
$this->excludeRegex($regex);
|
||||
if (empty($except_tags)) {
|
||||
$this->clean();
|
||||
return $this;
|
||||
}
|
||||
$this->includeHtmlTags($except_tags);
|
||||
$this->clean();
|
||||
return $this;
|
||||
}
|
||||
public function excludeOutsideStrings(string $start, string $end, $exclude_strings = \false): self
|
||||
{
|
||||
if ($start == '' && $end == '') {
|
||||
return $this;
|
||||
}
|
||||
$start = $start ?: '^';
|
||||
$end = $end ?: '$';
|
||||
$regex = $exclude_strings ? '()(' . \RegularLabs\Library\RegEx::quote($start) . ')(.*?)(' . \RegularLabs\Library\RegEx::quote($end) . ')()' : '(' . \RegularLabs\Library\RegEx::quote($start) . '.*?' . \RegularLabs\Library\RegEx::quote($end) . ')';
|
||||
return $this->excludeExceptRegex($regex);
|
||||
}
|
||||
public function excludeRegex(string $regex): self
|
||||
{
|
||||
$all_parts = [];
|
||||
foreach ($this->parts as $key => &$string) {
|
||||
if ($this->shouldSkip($key, $string)) {
|
||||
$all_parts[] = $string;
|
||||
continue;
|
||||
}
|
||||
$parts = \RegularLabs\Library\RegEx::split($regex, $string);
|
||||
if (empty($parts)) {
|
||||
$all_parts[] = $string;
|
||||
continue;
|
||||
}
|
||||
array_push($all_parts, ...$parts);
|
||||
}
|
||||
$this->setParts($all_parts);
|
||||
return $this;
|
||||
}
|
||||
public function excludeRegexBetween(string $start, string $end, $exclude_matches = \false): self
|
||||
{
|
||||
$all_parts = [];
|
||||
foreach ($this->parts as $key => &$string) {
|
||||
if ($this->shouldSkip($key, $string)) {
|
||||
$all_parts[] = $string;
|
||||
continue;
|
||||
}
|
||||
$start_parts = \RegularLabs\Library\RegEx::split($start, $string);
|
||||
if (count($start_parts) < 2) {
|
||||
$all_parts[] = $string;
|
||||
continue;
|
||||
}
|
||||
$first_part = array_shift($start_parts);
|
||||
if (!$exclude_matches) {
|
||||
$first_part .= array_shift($start_parts);
|
||||
}
|
||||
$search_part = implode($start_parts);
|
||||
$end_parts = (new \RegularLabs\Library\StringReplacer($search_part))->excludeRegex($end)->getParts();
|
||||
if (count($end_parts) < 2) {
|
||||
$all_parts[] = $string;
|
||||
continue;
|
||||
}
|
||||
$protected_part = array_shift($end_parts);
|
||||
if ($exclude_matches) {
|
||||
$protected_part .= array_shift($end_parts);
|
||||
}
|
||||
$last_part = implode($end_parts);
|
||||
array_push($all_parts, $first_part, $protected_part, $last_part);
|
||||
}
|
||||
$this->setParts($all_parts);
|
||||
return $this;
|
||||
}
|
||||
public function excludeRegexNested(string $regex_outer, string $regex_inner): self
|
||||
{
|
||||
$all_parts = [];
|
||||
foreach ($this->parts as $key => $string) {
|
||||
if (trim($string) == '' || $this->rowIsExcluded($key)) {
|
||||
$all_parts[] = $string;
|
||||
continue;
|
||||
}
|
||||
if (!\RegularLabs\Library\RegEx::match($regex_outer, $string) || !\RegularLabs\Library\RegEx::match($regex_inner, $string)) {
|
||||
$all_parts[] = $string;
|
||||
continue;
|
||||
}
|
||||
$nested = (new \RegularLabs\Library\StringReplacer($string))->excludeRegex($regex_inner);
|
||||
array_push($all_parts, ...$nested->getParts());
|
||||
}
|
||||
$this->setParts($all_parts);
|
||||
return $this;
|
||||
}
|
||||
public function excludeStrings(array $strings = []): self
|
||||
{
|
||||
$regex = \RegularLabs\Library\RegEx::quote($strings);
|
||||
return $this->excludeRegex($regex);
|
||||
}
|
||||
public function getHtmlTagsRegex(): string
|
||||
{
|
||||
return '(</?[a-zA-Z][^>]*>)';
|
||||
}
|
||||
public function getParts(): array
|
||||
{
|
||||
return $this->parts;
|
||||
}
|
||||
public function includeRegex(string $regex): self
|
||||
{
|
||||
$all_parts = [];
|
||||
foreach ($this->parts as $key => $string) {
|
||||
if (trim($string) == '' || !$this->rowIsExcluded($key)) {
|
||||
$all_parts[] = $string;
|
||||
continue;
|
||||
}
|
||||
if (!\RegularLabs\Library\RegEx::match($regex, $string)) {
|
||||
$all_parts[] = $string;
|
||||
continue;
|
||||
}
|
||||
$parts = \RegularLabs\Library\RegEx::split($regex, $string);
|
||||
array_push($all_parts, ...$parts);
|
||||
}
|
||||
$this->setParts($all_parts);
|
||||
return $this;
|
||||
}
|
||||
public function includeRegexNested(string $regex_outer, string $regex_inner): self
|
||||
{
|
||||
$all_parts = [];
|
||||
foreach ($this->parts as $key => $string) {
|
||||
if (trim($string) == '' || !$this->rowIsExcluded($key)) {
|
||||
$all_parts[] = $string;
|
||||
continue;
|
||||
}
|
||||
if (!\RegularLabs\Library\RegEx::match($regex_outer, $string) || !\RegularLabs\Library\RegEx::match($regex_inner, $string)) {
|
||||
$all_parts[] = $string;
|
||||
continue;
|
||||
}
|
||||
// using exclude on this excluded row to get the reverse result
|
||||
$nested = (new \RegularLabs\Library\StringReplacer($string))->excludeRegex($regex_inner);
|
||||
array_push($all_parts, ...$nested->getParts());
|
||||
}
|
||||
$this->setParts($all_parts);
|
||||
return $this;
|
||||
}
|
||||
public function replace($search, $replace): self
|
||||
{
|
||||
foreach ($this->parts as $key => &$string) {
|
||||
if ($this->shouldSkip($key, $string)) {
|
||||
continue;
|
||||
}
|
||||
$string = str_replace($search, $replace, $string);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function replaceRegex(string $search, string $replace): self
|
||||
{
|
||||
foreach ($this->parts as $key => &$string) {
|
||||
if ($this->shouldSkip($key, $string)) {
|
||||
continue;
|
||||
}
|
||||
$string = \RegularLabs\Library\RegEx::replace($search, $replace, $string);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function run($callback, $on_excluded = \false): self
|
||||
{
|
||||
foreach ($this->parts as $key => &$string) {
|
||||
if (trim($string) == '' || $this->rowIsExcluded($key) && !$on_excluded) {
|
||||
continue;
|
||||
}
|
||||
$callback($string);
|
||||
}
|
||||
$this->flattenParts();
|
||||
return $this;
|
||||
}
|
||||
public function set(string $string): void
|
||||
{
|
||||
$this->parts = [$string];
|
||||
}
|
||||
public function stillContains(string $string): bool
|
||||
{
|
||||
foreach ($this->parts as $key => $value) {
|
||||
if (trim($value) == '' || $this->rowIsExcluded($key)) {
|
||||
continue;
|
||||
}
|
||||
if (str_contains($this->toString(), $string)) {
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
public function toString(): string
|
||||
{
|
||||
return implode('', $this->parts);
|
||||
}
|
||||
private static function includeHtmlTagsOnString(string &$string, array $tags): void
|
||||
{
|
||||
$replacer = new \RegularLabs\Library\StringReplacer($string);
|
||||
foreach ($tags as $tag_name => $tag_params) {
|
||||
self::includeSingleHtmlTag($replacer, $tag_name, $tag_params);
|
||||
}
|
||||
$string = $replacer->getParts();
|
||||
}
|
||||
private static function includeSingleHtmlTag(\RegularLabs\Library\StringReplacer &$replacer, $tag_name, $tag_params): void
|
||||
{
|
||||
if ($tag_name == '*') {
|
||||
$tag_name = '[a-zA-Z][^> ]*';
|
||||
}
|
||||
$regex_tag = '(</?' . $tag_name . '(?: [^>]*)?>)';
|
||||
if (!count($tag_params)) {
|
||||
// include the whole tag (exclude on an excluded row)
|
||||
$replacer->excludeRegex($regex_tag);
|
||||
return;
|
||||
}
|
||||
// only include the parameter values
|
||||
$regex_params = '()(' . \RegularLabs\Library\RegEx::quote($tag_params) . '=")([^"]*)';
|
||||
$replacer->excludeRegexNested($regex_tag, $regex_params);
|
||||
}
|
||||
private function cleanParts(): void
|
||||
{
|
||||
if (!$this->enable_clean) {
|
||||
return;
|
||||
}
|
||||
$delimiter = '<!-- ___RL_DELIMITER___ -->';
|
||||
$temp_string = implode($delimiter, $this->parts);
|
||||
$temp_string = str_replace($delimiter . $delimiter, '', $temp_string);
|
||||
$this->parts = explode($delimiter, $temp_string);
|
||||
}
|
||||
private function flattenParts(): void
|
||||
{
|
||||
// move any nested parts to the parent
|
||||
$all_parts = [];
|
||||
foreach ($this->parts as $string) {
|
||||
if (!is_array($string)) {
|
||||
$all_parts[] = $string;
|
||||
continue;
|
||||
}
|
||||
array_push($all_parts, ...$string);
|
||||
}
|
||||
$this->setParts($all_parts);
|
||||
}
|
||||
private function getFormRegexes(array $form_classes = []): object
|
||||
{
|
||||
$form_classes = \RegularLabs\Library\ArrayHelper::toArray($form_classes);
|
||||
$start = '(<form\s[^>]*(?:' . '(?:id|name)="(?:adminForm|postform|submissionForm|default_action_user|seblod_form|spEntryForm)"' . '|action="[^"]*option=com_myjspace&(?:amp;)?view=see"' . (!empty($form_classes) ? '|class="(?:[^"]* )?(?:' . implode('|', $form_classes) . ')(?: [^"]*)?"' : '') . '))';
|
||||
$end = '(</form>)';
|
||||
return (object) compact('start', 'end');
|
||||
}
|
||||
private function getHtmlTagArray(array $tags = []): array
|
||||
{
|
||||
$search_tags = [];
|
||||
foreach ($tags as $tag) {
|
||||
if (!strlen($tag)) {
|
||||
continue;
|
||||
}
|
||||
$tag = trim($tag, ']');
|
||||
$tag_parts = explode('[', $tag);
|
||||
$tag_name = trim($tag_parts[0]);
|
||||
if ($tag_name == '*') {
|
||||
return [];
|
||||
}
|
||||
if (count($tag_parts) < 2) {
|
||||
$search_tags[$tag_name] = [];
|
||||
continue;
|
||||
}
|
||||
$tag_params = $tag_parts[1];
|
||||
// Trim and remove empty values
|
||||
$tag_params = array_diff(array_map('trim', explode(',', $tag_params)), ['']);
|
||||
if (in_array('*', $tag_params)) {
|
||||
// Make array empty if asterisk is found
|
||||
// (the whole tag should be allowed)
|
||||
$search_tags[$tag_name] = [];
|
||||
continue;
|
||||
}
|
||||
$search_tags[$tag_name] = $tag_params;
|
||||
}
|
||||
return $search_tags;
|
||||
}
|
||||
private function includeHtmlTags(array $tags = []): void
|
||||
{
|
||||
$tags = $this->getHtmlTagArray($tags);
|
||||
if (!count($tags)) {
|
||||
return;
|
||||
}
|
||||
$this->run(function (&$string) use ($tags) {
|
||||
self::includeHtmlTagsOnString($string, $tags);
|
||||
}, \true);
|
||||
}
|
||||
private function rowIsExcluded(int $key): bool
|
||||
{
|
||||
// uneven count = excluded
|
||||
return fmod($key, 2);
|
||||
}
|
||||
private function setParts(array $parts): void
|
||||
{
|
||||
$this->parts = $parts;
|
||||
$this->cleanParts();
|
||||
}
|
||||
private function shouldSkip(int $key, string $string): bool
|
||||
{
|
||||
return trim($string) == '' || $this->rowIsExcluded($key);
|
||||
}
|
||||
}
|
||||
519
libraries/regularlabs/src/SystemPlugin.php
Normal file
519
libraries/regularlabs/src/SystemPlugin.php
Normal file
@ -0,0 +1,519 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Application\CMSApplication as JCMSApplication;
|
||||
use Joomla\CMS\Factory as JFactory;
|
||||
use Joomla\CMS\Form\Form as JForm;
|
||||
use Joomla\CMS\Language\Text as JText;
|
||||
use Joomla\CMS\Plugin\CMSPlugin as JCMSPlugin;
|
||||
use Joomla\CMS\Plugin\PluginHelper as JPluginHelper;
|
||||
use Joomla\Component\Finder\Administrator\Indexer\Helper as JIndexerHelper;
|
||||
use Joomla\Component\Finder\Administrator\Indexer\Result as JIndexerResult;
|
||||
use Joomla\Database\DatabaseDriver as JDatabaseDriver;
|
||||
use Joomla\Event\DispatcherInterface as JDispatcherInterface;
|
||||
use Joomla\Registry\Registry as JRegistry;
|
||||
use stdClass;
|
||||
class SystemPlugin extends JCMSPlugin
|
||||
{
|
||||
public $_alias = '';
|
||||
public $_lang_prefix = '';
|
||||
public $_title = '';
|
||||
protected $_can_disable_by_url = \true;
|
||||
protected $_doc_ready = \false;
|
||||
protected $_enable_in_admin = \false;
|
||||
protected $_enable_in_frontend = \true;
|
||||
protected $_enable_in_indexer = \true;
|
||||
protected $_id = 0;
|
||||
protected $_jversion = 4;
|
||||
protected $_page_types = ['html', 'feed', 'pdf', 'xml', 'ajax', 'json', 'raw'];
|
||||
protected $_pass;
|
||||
/**
|
||||
* @var JCMSApplication
|
||||
*/
|
||||
protected $app;
|
||||
protected $autoloadLanguage = \true;
|
||||
/**
|
||||
* @var JDatabaseDriver
|
||||
*/
|
||||
protected $db;
|
||||
public function __construct(JDispatcherInterface &$subject, array $config = [])
|
||||
{
|
||||
if (isset($config['id'])) {
|
||||
$this->_id = $config['id'];
|
||||
}
|
||||
parent::__construct($subject, $config);
|
||||
$this->app = JFactory::getApplication();
|
||||
$this->db = JFactory::getDbo();
|
||||
if (empty($this->_alias)) {
|
||||
$this->_alias = $this->_name;
|
||||
}
|
||||
if (empty($this->_title)) {
|
||||
$this->_title = strtoupper($this->_alias);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param JIndexerResult $item The search result
|
||||
* @param array $query The search query of this result
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handleOnFinderResult(JIndexerResult $item, $query)
|
||||
{
|
||||
$description = $item->description ?? '';
|
||||
$summary = $item->getElement('summary') ?? '';
|
||||
if (empty($description) && empty($summary)) {
|
||||
return;
|
||||
}
|
||||
$article = (object) ['id' => $item->getElement('id')];
|
||||
if (!empty($description)) {
|
||||
$article->fulltext = $description;
|
||||
\RegularLabs\Library\Article::processText('fulltext', $article, $this, 'processArticle', ['article', 'com_finder.index', $article]);
|
||||
$item->description = JIndexerHelper::parse($article->fulltext);
|
||||
}
|
||||
if ($description == $summary) {
|
||||
$item->setElement('summary', $item->description);
|
||||
return;
|
||||
}
|
||||
if (!empty($summary)) {
|
||||
$article->fulltext = $summary;
|
||||
\RegularLabs\Library\Article::processText('fulltext', $article, $this, 'processArticle', ['article', 'com_finder.index', $article]);
|
||||
$item->setElement('summary', $article->fulltext);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param string $extension The extension for which a language file should be loaded
|
||||
* @param string $basePath The basepath to use
|
||||
*
|
||||
* @return bool True, if the file has successfully loaded.
|
||||
*/
|
||||
public function loadLanguage($extension = '', $basePath = JPATH_ADMINISTRATOR)
|
||||
{
|
||||
parent::loadLanguage('plg_system_regularlabs', JPATH_LIBRARIES . '/regularlabs');
|
||||
return parent::loadLanguage();
|
||||
}
|
||||
public function onAfterDispatch(): void
|
||||
{
|
||||
if (!$this->passChecks()) {
|
||||
return;
|
||||
}
|
||||
$this->handleOnAfterDispatch();
|
||||
$buffer = \RegularLabs\Library\Document::getComponentBuffer();
|
||||
$this->loadStylesAndScripts($buffer);
|
||||
if (!$buffer) {
|
||||
return;
|
||||
}
|
||||
$this->changeDocumentBuffer($buffer);
|
||||
\RegularLabs\Library\Document::setComponentBuffer($buffer);
|
||||
}
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function onAfterInitialise(): void
|
||||
{
|
||||
if (!$this->passChecks()) {
|
||||
return;
|
||||
}
|
||||
$this->handleOnAfterInitialise();
|
||||
}
|
||||
public function onAfterRender(): void
|
||||
{
|
||||
if (!$this->passChecks()) {
|
||||
return;
|
||||
}
|
||||
$this->handleOnAfterRender();
|
||||
$html = $this->app->getBody();
|
||||
if ($html == '') {
|
||||
return;
|
||||
}
|
||||
if (!$this->changeFinalHtmlOutput($html)) {
|
||||
return;
|
||||
}
|
||||
$this->cleanFinalHtmlOutput($html);
|
||||
$this->app->setBody($html);
|
||||
}
|
||||
/**
|
||||
* @param object $module
|
||||
* @param array $params
|
||||
*/
|
||||
public function onAfterRenderModule(&$module, &$params): void
|
||||
{
|
||||
if (!$this->passChecks()) {
|
||||
return;
|
||||
}
|
||||
$this->handleOnAfterRenderModule($module, $params);
|
||||
}
|
||||
/**
|
||||
* @param string $buffer
|
||||
* @param array $params
|
||||
*/
|
||||
public function onAfterRenderModules(&$buffer, &$params): void
|
||||
{
|
||||
if (!$this->passChecks()) {
|
||||
return;
|
||||
}
|
||||
$this->handleOnAfterRenderModules($buffer, $params);
|
||||
if (empty($buffer)) {
|
||||
return;
|
||||
}
|
||||
$this->changeModulePositionOutput($buffer, $params);
|
||||
}
|
||||
public function onAfterRoute(): void
|
||||
{
|
||||
$this->_doc_ready = \true;
|
||||
if (!$this->passChecks()) {
|
||||
return;
|
||||
}
|
||||
$this->handleOnAfterRoute();
|
||||
}
|
||||
public function onBeforeCompileHead(): void
|
||||
{
|
||||
if (!$this->passChecks()) {
|
||||
return;
|
||||
}
|
||||
$this->handleOnBeforeCompileHead();
|
||||
}
|
||||
/**
|
||||
* @param string $context The context of the content being passed to the plugin.
|
||||
* @param mixed &$row An object with a "text" property
|
||||
* @param mixed &$params Additional parameters. See {@see PlgContentContent()}.
|
||||
* @param integer $page Optional page number. Unused. Defaults to zero.
|
||||
*/
|
||||
public function onContentPrepare($context, &$article, &$params, $page = 0): void
|
||||
{
|
||||
if (!$this->passChecks()) {
|
||||
return;
|
||||
}
|
||||
$area = isset($article->created_by) ? 'article' : 'other';
|
||||
$context = $params instanceof JRegistry && $params->get('rl_search') ? 'com_search.' . $params->get('readmore_limit') : $context;
|
||||
if (!$this->handleOnContentPrepare($area, $context, $article, $params, $page)) {
|
||||
return;
|
||||
}
|
||||
\RegularLabs\Library\Article::process($article, $context, $this, 'processArticle', [$area, $context, $article, $page]);
|
||||
}
|
||||
/**
|
||||
* @param JForm $form The form
|
||||
* @param stdClass $data The data
|
||||
*/
|
||||
public function onContentPrepareForm(JForm $form, $data): bool
|
||||
{
|
||||
if (!$this->passChecks()) {
|
||||
return \true;
|
||||
}
|
||||
return $this->handleOnContentPrepareForm($form, $data);
|
||||
}
|
||||
/**
|
||||
* @param JIndexerResult $item The search result
|
||||
* @param array $query The search query of this result
|
||||
*/
|
||||
public function onFinderResult(JIndexerResult $item, $query)
|
||||
{
|
||||
if (!$this->passChecks()) {
|
||||
return;
|
||||
}
|
||||
$this->handleOnFinderResult($item, $query);
|
||||
}
|
||||
/**
|
||||
* @param string &$string
|
||||
* @param string $area
|
||||
* @param string $context The context of the content being passed to the plugin.
|
||||
* @param mixed $article An object with a "text" property
|
||||
* @param int $page Optional page number. Unused. Defaults to zero.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function processArticle(&$string, $area = 'article', $context = '', $article = null, $page = 0)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* @param string $buffer
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function changeDocumentBuffer(&$buffer)
|
||||
{
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* @param string $html
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function changeFinalHtmlOutput(&$html)
|
||||
{
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* @param string $buffer
|
||||
* @param string $params
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function changeModulePositionOutput(&$buffer, &$params)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* @param string $html
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function cleanFinalHtmlOutput(&$html)
|
||||
{
|
||||
}
|
||||
protected function extraChecks()
|
||||
{
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function handleFeedArticles()
|
||||
{
|
||||
if (!empty($this->_page_types) && !in_array('feed', $this->_page_types, \true)) {
|
||||
return;
|
||||
}
|
||||
if (!\RegularLabs\Library\Document::isFeed() && \RegularLabs\Library\Input::get('option', '') != 'com_acymailing') {
|
||||
return;
|
||||
}
|
||||
if (!isset(\RegularLabs\Library\Document::get()->items)) {
|
||||
return;
|
||||
}
|
||||
$context = 'feed';
|
||||
$items = \RegularLabs\Library\Document::get()->items;
|
||||
$params = null;
|
||||
foreach ($items as $item) {
|
||||
$this->handleOnContentPrepare('article', $context, $item, $params);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function handleOnAfterDispatch()
|
||||
{
|
||||
$this->handleFeedArticles();
|
||||
}
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function handleOnAfterInitialise()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* @return void
|
||||
*
|
||||
* Consider using changeFinalHtmlOutput instead
|
||||
*/
|
||||
protected function handleOnAfterRender()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* @param object $module
|
||||
* @param array $params
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handleOnAfterRenderModule(&$module, &$params)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* @param string $buffer
|
||||
* @param array $params
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handleOnAfterRenderModules(&$buffer, &$params)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function handleOnAfterRoute()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function handleOnBeforeCompileHead()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* @param string $area
|
||||
* @param string $context The context of the content being passed to the plugin.
|
||||
* @param mixed $article An object with a "text" property
|
||||
* @param mixed &$params Additional parameters. See {@see PlgContentContent()}.
|
||||
* @param int $page Optional page number. Unused. Defaults to zero.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function handleOnContentPrepare($area, $context, &$article, &$params, $page = 0)
|
||||
{
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* @param JForm $form The form
|
||||
* @param stdClass $data The data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function handleOnContentPrepareForm(JForm $form, $data)
|
||||
{
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function is3rdPartyEditPage()
|
||||
{
|
||||
// // Disable on Gridbox edit form: option=com_gridbox&view=gridbox
|
||||
// if (Input::get('option', '') == 'com_gridbox' && Input::get('view', '') == 'gridbox')
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// Disable on SP PageBuilder edit form: option=com_sppagebuilder&view=form
|
||||
if (\RegularLabs\Library\Input::get('option', '') == 'com_sppagebuilder' && \RegularLabs\Library\Input::get('view', '') == 'form') {
|
||||
return \true;
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* @param string $buffer
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function loadStylesAndScripts(&$buffer)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function passChecks()
|
||||
{
|
||||
if (!is_null($this->_pass)) {
|
||||
return $this->_pass;
|
||||
}
|
||||
$this->setPass(\false);
|
||||
if (!$this->isFrameworkEnabled()) {
|
||||
return \false;
|
||||
}
|
||||
if ($this->is3rdPartyEditPage()) {
|
||||
return \false;
|
||||
}
|
||||
if ($this->_doc_ready && !$this->passPageTypes()) {
|
||||
return \false;
|
||||
}
|
||||
if (!$this->_enable_in_frontend && $this->app->isClient('site')) {
|
||||
return \false;
|
||||
}
|
||||
$is_indexer = $this->app->input->get('option') == 'com_finder' && $this->app->input->get('task') == 'batch';
|
||||
if ($this->app->input->get('option')) {
|
||||
$this->resetPass();
|
||||
}
|
||||
if (!$this->_enable_in_indexer && $is_indexer) {
|
||||
return \false;
|
||||
}
|
||||
$is_admin = !$this->app->isClient('site') && !$is_indexer;
|
||||
if (!$this->_enable_in_admin && $is_admin) {
|
||||
return \false;
|
||||
}
|
||||
// disabled by url?
|
||||
if ($this->_can_disable_by_url && \RegularLabs\Library\Protect::isDisabledByUrl($this->_alias)) {
|
||||
return \false;
|
||||
}
|
||||
if (!$this->extraChecks()) {
|
||||
return \false;
|
||||
}
|
||||
$this->setPass(\true);
|
||||
return \true;
|
||||
}
|
||||
protected function passPageTypes()
|
||||
{
|
||||
if (empty($this->_page_types)) {
|
||||
return \true;
|
||||
}
|
||||
if (in_array('*', $this->_page_types, \true)) {
|
||||
return \true;
|
||||
}
|
||||
if (\RegularLabs\Library\Document::isFeed()) {
|
||||
return in_array('feed', $this->_page_types, \true);
|
||||
}
|
||||
if (\RegularLabs\Library\Document::isPDF()) {
|
||||
return in_array('pdf', $this->_page_types, \true);
|
||||
}
|
||||
$page_type = \RegularLabs\Library\Document::get()->getType();
|
||||
return in_array($page_type, $this->_page_types, \true);
|
||||
}
|
||||
/**
|
||||
* Place an error in the message queue
|
||||
*/
|
||||
protected function throwError($error)
|
||||
{
|
||||
$user = JFactory::getApplication()->getIdentity() ?: JFactory::getUser();
|
||||
// Return if page is not an admin page or the admin login page
|
||||
if (!JFactory::getApplication()->isClient('administrator') || $user->get('guest')) {
|
||||
return;
|
||||
}
|
||||
// load the admin language file
|
||||
JFactory::getApplication()->getLanguage()->load('plg_' . $this->_type . '_' . $this->_name, JPATH_PLUGINS . '/' . $this->_type . '/' . $this->_name);
|
||||
$text = JText::sprintf($this->_lang_prefix . '_' . $error, JText::_($this->_title));
|
||||
$text = JText::_($text) . ' ' . JText::sprintf($this->_lang_prefix . '_EXTENSION_CAN_NOT_FUNCTION', JText::_($this->_title));
|
||||
// Check if message is not already in queue
|
||||
$messagequeue = JFactory::getApplication()->getMessageQueue();
|
||||
foreach ($messagequeue as $message) {
|
||||
if ($message['message'] == $text) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
JFactory::getApplication()->enqueueMessage($text, 'error');
|
||||
}
|
||||
/**
|
||||
* Check if the Regular Labs Library is enabled
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isFrameworkEnabled(): bool
|
||||
{
|
||||
if (!defined('REGULAR_LABS_LIBRARY_ENABLED')) {
|
||||
$this->setIsFrameworkEnabled();
|
||||
}
|
||||
if (!REGULAR_LABS_LIBRARY_ENABLED) {
|
||||
$this->throwError('REGULAR_LABS_LIBRARY_NOT_ENABLED');
|
||||
}
|
||||
return REGULAR_LABS_LIBRARY_ENABLED;
|
||||
}
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private function resetPass(): void
|
||||
{
|
||||
$this->_pass = null;
|
||||
}
|
||||
/**
|
||||
* Set the define with whether the Regular Labs Library is enabled
|
||||
*/
|
||||
private function setIsFrameworkEnabled(): void
|
||||
{
|
||||
if (!JPluginHelper::isEnabled('system', 'regularlabs')) {
|
||||
$this->throwError('REGULAR_LABS_LIBRARY_NOT_ENABLED');
|
||||
define('REGULAR_LABS_LIBRARY_ENABLED', \false);
|
||||
return;
|
||||
}
|
||||
define('REGULAR_LABS_LIBRARY_ENABLED', \true);
|
||||
}
|
||||
private function setPass(bool $pass): void
|
||||
{
|
||||
if (!$this->_doc_ready) {
|
||||
return;
|
||||
}
|
||||
$this->_pass = (bool) $pass;
|
||||
}
|
||||
}
|
||||
76
libraries/regularlabs/src/Title.php
Normal file
76
libraries/regularlabs/src/Title.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
class Title
|
||||
{
|
||||
/**
|
||||
* Cleans the string to make it usable as a title
|
||||
*/
|
||||
public static function clean(string $string = '', bool $strip_tags = \false, bool $strip_spaces = \true): string
|
||||
{
|
||||
if (empty($string)) {
|
||||
return '';
|
||||
}
|
||||
// remove comment tags
|
||||
$string = \RegularLabs\Library\RegEx::replace('<\!--.*?-->', '', $string);
|
||||
// replace weird whitespace
|
||||
$string = str_replace(chr(194) . chr(160), ' ', $string);
|
||||
if ($strip_tags) {
|
||||
// remove svgs
|
||||
$string = \RegularLabs\Library\RegEx::replace('<svg.*?</svg>', '', $string);
|
||||
// remove html tags
|
||||
$string = \RegularLabs\Library\RegEx::replace('</?[a-z][^>]*>', '', $string);
|
||||
// remove comments tags
|
||||
$string = \RegularLabs\Library\RegEx::replace('<\!--.*?-->', '', $string);
|
||||
}
|
||||
if ($strip_spaces) {
|
||||
// Replace html spaces
|
||||
$string = str_replace([' ', ' '], ' ', $string);
|
||||
// Remove duplicate whitespace
|
||||
$string = \RegularLabs\Library\RegEx::replace('[ \n\r\t]+', ' ', $string);
|
||||
}
|
||||
return trim($string);
|
||||
}
|
||||
/**
|
||||
* Creates an array of different syntaxes of titles to match against a url variable
|
||||
*/
|
||||
public static function getUrlMatches(array $titles = []): array
|
||||
{
|
||||
$matches = [];
|
||||
foreach ($titles as $title) {
|
||||
$matches[] = $title;
|
||||
$matches[] = \RegularLabs\Library\StringHelper::strtolower($title);
|
||||
}
|
||||
$matches = array_unique($matches);
|
||||
foreach ($matches as $title) {
|
||||
$matches[] = htmlspecialchars(\RegularLabs\Library\StringHelper::html_entity_decoder($title));
|
||||
}
|
||||
$matches = array_unique($matches);
|
||||
foreach ($matches as $title) {
|
||||
$matches[] = urlencode($title);
|
||||
if (function_exists('mb_convert_encoding')) {
|
||||
$matches[] = mb_convert_encoding($title, 'ISO-8859-1', 'UTF-8');
|
||||
}
|
||||
$matches[] = str_replace(' ', '', $title);
|
||||
$matches[] = trim(\RegularLabs\Library\RegEx::replace('[^a-z0-9]', '', $title));
|
||||
$matches[] = trim(\RegularLabs\Library\RegEx::replace('[^a-z]', '', $title));
|
||||
}
|
||||
$matches = array_unique($matches);
|
||||
foreach ($matches as $i => $title) {
|
||||
$matches[$i] = trim(str_replace('?', '', $title));
|
||||
}
|
||||
$matches = array_diff(array_unique($matches), ['', '-']);
|
||||
return $matches;
|
||||
}
|
||||
}
|
||||
178
libraries/regularlabs/src/Uri.php
Normal file
178
libraries/regularlabs/src/Uri.php
Normal file
@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Regular Labs Library
|
||||
* @version 24.11.1459
|
||||
*
|
||||
* @author Peter van Westen <info@regularlabs.com>
|
||||
* @link https://regularlabs.com
|
||||
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
|
||||
* @license GNU General Public License version 2 or later
|
||||
*/
|
||||
namespace RegularLabs\Library;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
use Joomla\CMS\Router\Route as JRoute;
|
||||
use Joomla\CMS\Uri\Uri as JUri;
|
||||
class Uri
|
||||
{
|
||||
/**
|
||||
* Adds the given url parameter (key + value) to the url or replaces it already exists
|
||||
*/
|
||||
public static function addParameter(string $url, string $key, string $value = '', bool $replace = \true): string
|
||||
{
|
||||
if (empty($key)) {
|
||||
return $url;
|
||||
}
|
||||
$uri = parse_url($url);
|
||||
$query = self::parse_query($uri['query'] ?? '');
|
||||
if (!$replace && isset($query[$key])) {
|
||||
return $url;
|
||||
}
|
||||
$query[$key] = $value;
|
||||
$uri['query'] = http_build_query($query);
|
||||
return self::createUrlFromArray($uri);
|
||||
}
|
||||
/**
|
||||
* Appends the given hash to the url or replaces it if there is already one
|
||||
*/
|
||||
public static function appendHash(string $url = '', string $hash = ''): string
|
||||
{
|
||||
if (empty($hash)) {
|
||||
return $url;
|
||||
}
|
||||
$uri = parse_url($url);
|
||||
$uri['fragment'] = $hash;
|
||||
return self::createUrlFromArray($uri);
|
||||
}
|
||||
/**
|
||||
* Converts an array of url parts (like made by parse_url) to a string
|
||||
*/
|
||||
public static function createUrlFromArray(array $uri): string
|
||||
{
|
||||
$user = $uri['user'] ?? '';
|
||||
$pass = !empty($uri['pass']) ? ':' . $uri['pass'] : '';
|
||||
return (!empty($uri['scheme']) ? $uri['scheme'] . '://' : '') . ($user || $pass ? $user . $pass . '@' : '') . (!empty($uri['host']) ? $uri['host'] : '') . (!empty($uri['port']) ? ':' . $uri['port'] : '') . (!empty($uri['path']) ? $uri['path'] : '') . (!empty($uri['query']) ? '?' . $uri['query'] : '') . (!empty($uri['fragment']) ? '#' . $uri['fragment'] : '');
|
||||
}
|
||||
public static function decode(string $string, bool $urldecode = \true): string
|
||||
{
|
||||
if ($urldecode) {
|
||||
$string = urldecode($string);
|
||||
}
|
||||
$string = base64_decode($string);
|
||||
$deflated = @gzinflate($string);
|
||||
if ($string === $deflated || !$deflated) {
|
||||
return $string;
|
||||
}
|
||||
return $deflated;
|
||||
}
|
||||
public static function encode(string $string, bool $urlencode = \true): string
|
||||
{
|
||||
$string = base64_encode(gzdeflate($string));
|
||||
if ($urlencode) {
|
||||
$string = urlencode($string);
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
/**
|
||||
* Returns the full uri and optionally adds/replaces the hash
|
||||
*/
|
||||
public static function get(string $hash = ''): string
|
||||
{
|
||||
$url = JUri::getInstance()->toString();
|
||||
if ($hash == '') {
|
||||
return $url;
|
||||
}
|
||||
return self::appendHash($url, $hash);
|
||||
}
|
||||
public static function getCompressedAttributes(): string
|
||||
{
|
||||
$compressed = '';
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$compressed .= \RegularLabs\Library\Input::getString('rlatt_' . $i, '');
|
||||
}
|
||||
return self::decode($compressed, \false);
|
||||
}
|
||||
/**
|
||||
* Get the value of a given url parameter from the url
|
||||
*/
|
||||
public static function getParameter(string $url, string $key): mixed
|
||||
{
|
||||
if (empty($key)) {
|
||||
return '';
|
||||
}
|
||||
$uri = parse_url($url);
|
||||
if (!isset($uri['query'])) {
|
||||
return '';
|
||||
}
|
||||
$query = self::parse_query($uri['query']);
|
||||
return $query[$key] ?? '';
|
||||
}
|
||||
/**
|
||||
* Get all url parameters from the url
|
||||
*/
|
||||
public static function getParameters(string $url): object
|
||||
{
|
||||
$uri = parse_url($url);
|
||||
if (!isset($uri['query'])) {
|
||||
return (object) [];
|
||||
}
|
||||
$query = self::parse_query($uri['query']);
|
||||
return (object) $query;
|
||||
}
|
||||
public static function isExternal(string $url): bool
|
||||
{
|
||||
if (!str_contains($url, '://')) {
|
||||
return \false;
|
||||
}
|
||||
// hostname: give preference to SERVER_NAME, because this includes subdomains
|
||||
$hostname = $_SERVER['SERVER_NAME'] ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST'];
|
||||
return !str_starts_with(\RegularLabs\Library\RegEx::replace('^.*?://', '', $url), $hostname);
|
||||
}
|
||||
/**
|
||||
* removes the given url parameter from the url
|
||||
*/
|
||||
public static function removeParameter(string $url, string $key): string
|
||||
{
|
||||
if (empty($key)) {
|
||||
return $url;
|
||||
}
|
||||
$uri = parse_url($url);
|
||||
if (!isset($uri['query'])) {
|
||||
return $url;
|
||||
}
|
||||
$query = self::parse_query($uri['query']);
|
||||
unset($query[$key]);
|
||||
$uri['query'] = http_build_query($query);
|
||||
return self::createUrlFromArray($uri);
|
||||
}
|
||||
public static function route(string $url): string
|
||||
{
|
||||
return JRoute::_(JUri::root(\true) . '/' . $url);
|
||||
}
|
||||
/**
|
||||
* Parse a query string into an associative array.
|
||||
*/
|
||||
private static function parse_query(string $string): array
|
||||
{
|
||||
$result = [];
|
||||
if ($string === '') {
|
||||
return $result;
|
||||
}
|
||||
$decoder = fn($value) => rawurldecode(str_replace('+', ' ', $value));
|
||||
foreach (explode('&', $string) as $kvp) {
|
||||
$parts = explode('=', $kvp, 2);
|
||||
$key = $decoder($parts[0]);
|
||||
$value = isset($parts[1]) ? $decoder($parts[1]) : null;
|
||||
if (!isset($result[$key])) {
|
||||
$result[$key] = $value;
|
||||
continue;
|
||||
}
|
||||
if (!is_array($result[$key])) {
|
||||
$result[$key] = [$result[$key]];
|
||||
}
|
||||
$result[$key][] = $value;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user