*
* UPGRADE NOTE:
* Do not edit or add to this file if you wish to upgrade AbanteCart to newer
* versions in the future. If you wish to customize AbanteCart for your
* needs please refer to http://www.AbanteCart.com for more information.
*/
if (!defined('DIR_CORE')) {
header('Location: static_pages/');
}
/**
* Class AHtml
* @method SelectboxHtmlElement buildSelectBox(array $data)
* @method MultiSelectboxHtmlElement buildMultiSelectBox(array $data)
* @method HiddenHtmlElement buildHidden(array $data)
* @method MultiValueHtmlElement buildMultiValue(array $data)
* @method MultiValueListHtmlElement buildMultiValueList(array $data)
* @method SubmitHtmlElement buildSubmit(array $data)
* @method InputHtmlElement buildInput(array $data)
* @method PasswordHtmlElement buildPassword(array $data)
* @method TextareaHtmlElement buildTextarea(array $data)
* @method TextEditorHtmlElement buildTextEditor(array $data)
* @method CheckboxHtmlElement buildCheckbox(array $data)
* @method CheckboxGroupHtmlElement buildCheckboxGroup(array $data)
* @method FileHtmlElement buildFile(array $data)
* @method RadioHtmlElement buildRadio(array $data)
* @method ButtonHtmlElement buildButton(array $data)
* @method RatingHtmlElement buildRating(array $data)
* @method CaptchaHtmlElement buildCaptcha(array $data)
* @method ReCaptchaHtmlElement buildReCaptcha(array $data)
* @method PasswordSetHtmlElement buildPasswordSet(array $data)
* @method ResourceHtmlElement buildResource(array $data)
* @method ResourceImageHtmlElement buildResourceImage(array $data)
* @method DateHtmlElement buildDate(array $data)
* @method EmailHtmlElement buildEmail(array $data)
* @method NumberHtmlElement buildNumber(array $data)
* @method PhoneHtmlElement buildPhone(array $data)
* @method IPAddressHtmlElement buildIPAddress(array $data)
* @method CountriesHtmlElement buildCountries(array $data)
* @method ZonesHtmlElement buildZones(array $data)
* @method PaginationHtmlElement buildPagination(array $data)
* @method ModalHtmlElement buildModal(array $data)
* @method LabelHtmlElement buildLabel(array $data)
*/
class AHtml extends AController
{
/**
* @var Registry
*/
protected $registry;
/**
* @var array
*/
protected $args = [];
/**
* @var ARequest
*/
protected $request;
/**
* @param Registry $registry
*/
public function __construct($registry)
{
$this->registry = $registry;
$this->request = $this->registry->get('request');
}
/**
* Magic method for html-element classes calls
*
* @param string $function_name
* @param $args
*
* @return null|string
* @throws AException
*/
public function __call(string $function_name, $args)
{
$class_name = ltrim($function_name, 'build') . 'HtmlElement';
if (class_exists($class_name)) {
/**
* @var SelectboxHtmlElement|HiddenHtmlElement| $item
*/
$item = new $class_name($args[0]);
if (method_exists($item, 'getHtml')) {
return $item->getHtml();
} else {
unset($item);
}
}
return null;
}
/**
* PR Build sub URL
*
* @param string $rt
* @param string $params
*
* @return string
* @throws AException
*/
private function buildURL($rt, $params = '')
{
$subUrl = '';
//#PR Add admin path if we are in admin
if (IS_ADMIN) {
$subUrl .= '&s=' . ADMIN_PATH;
}
//add template if present
if (!empty($this->request->get['sf'])) {
$subUrl .= '&sf=' . $this->request->get['sf'];
}
//if in embed mode add response prefix
if ($this->registry->get('config')->get('embed_mode')) {
$subUrl .= '&embed_mode=1';
if (substr($rt, 0, 2) != 'r/') {
$rt = 'r/' . $rt;
}
}
return '?' . ($rt ? 'rt=' . $rt : '') . $params . $subUrl;
}
/**
* Get non-secure home URL.
*
* @return string
*
* Note: Non-secure URL is base on store_url setting. If this setting is using https URL, all URLs will be secure
* @throws AException
*/
public function getHomeURL()
{
$seo_prefix = $this->registry->get('config')->get('seo_prefix');
//for embed mode get home link with getURL
if ($this->registry->get('config')->get('embed_mode')) {
return $this->getURL('index/home');
} else {
//get config_url first
$home_url = $this->registry->get('config')->get('config_url') . $seo_prefix;
if (!$home_url) {
$home_url = defined('HTTP_SERVER')
? HTTP_SERVER . $seo_prefix
: 'http://' . REAL_HOST . get_url_path($_SERVER['PHP_SELF']);
}
return $home_url;
}
}
/**
* Get non-secure URL. Read note below.
*
* @param string $rt
* @param string $params
* @param string $encode
*
* @return string
*
* Note: Non-secure URL is base on store_url setting. If this setting is using https URL, all URLs will be secure
* @throws AException
*/
public function getNonSecureURL($rt, $params = '', $encode = '')
{
return $this->getURL($rt, $params, $encode, true);
}
/**
* Get URL with auto-detection for protocol
*
* @param string $rt
* @param string $params
* @param string $encode
* @param bool $nonsecure - force to be non-secure
*
* @return string
* @throws AException
*/
public function getURL($rt, $params = '', $encode = '', $nonsecure = false)
{
$seo_prefix = $this->registry->get('config')->get('seo_prefix');
//detect if request is using HTTPS
if ($nonsecure === false && HTTPS === true) {
$server = defined('HTTPS_SERVER')
? HTTPS_SERVER . $seo_prefix
: 'https://' . REAL_HOST . get_url_path($_SERVER['PHP_SELF']);
} else {
//to prevent garbage session need to check constant HTTP_SERVER
$server = defined('HTTP_SERVER')
? HTTP_SERVER . $seo_prefix
: 'http://' . REAL_HOST . get_url_path($_SERVER['PHP_SELF']);
}
if ($this->registry->get('config')->get('storefront_template_debug')
&& isset($this->request->get['tmpl_debug'])
) {
$params .= '&tmpl_debug=' . $this->request->get['tmpl_debug'];
}
// add session id for cross-domain transition in secure mode
if ($this->registry->get('config')->get('config_shared_session') && HTTPS === true) {
$params .= '&session_id=' . session_id();
}
//add token for embed mode with forbidden 3d-party cookies
if ($this->registry->get('session')->data['session_mode'] == 'embed_token') {
$params .= '&' . EMBED_TOKEN_NAME . '=' . session_id();
}
return $server . INDEX_FILE . $this->url_encode($this->buildURL($rt, $params), $encode);
}
/**
* Build secure URL with session token
*
* @param string $rt
* @param string $params
* @param string $encode
*
* @return string
* @throws AException
*/
public function getSecureURL($rt, $params = '', $encode = '')
{
$session = $this->registry->get('session');
$config = $this->registry->get('config');
$seo_prefix = $config->get('seo_prefix');
// add session id for cross-domain transition in non-secure mode
if ($config->get('config_shared_session') && HTTPS !== true) {
$params .= '&session_id=' . session_id();
}
$subUrl = $this->buildURL($rt, $params);
if (IS_ADMIN === true || (defined('IS_API') && IS_API === true)) {
//Add session token for admin and API
if (isset($session->data['token']) && $session->data['token']) {
$subUrl .= '&token=' . $this->registry->get('session')->data['token'];
}
}
//add token for embed mode with forbidden 3d-party cookies
if ($session->data['session_mode'] == 'embed_token') {
$subUrl .= '&' . EMBED_TOKEN_NAME . '=' . session_id();
}
if ($config->get('storefront_template_debug') && isset($this->request->get['tmpl_debug'])) {
$subUrl .= '&tmpl_debug=' . $this->request->get['tmpl_debug'];
}
return HTTPS_SERVER . $seo_prefix . INDEX_FILE . $this->url_encode($subUrl, $encode);
}
/**
* Build non-secure SEO URL
*
* @param string $rt
* @param string $params
* @param string $encode
*
* @return string
* @throws AException
*/
public function getSEOURL($rt, $params = '', $encode = '')
{
//skip SEO for embed mode
if ($this->registry->get('config')->get('embed_mode')) {
return $this->getURL($rt, $params);
}
$this->loadModel('tool/seo_url');
//#PR Generate SEO URL based on standard URL
//NOTE: SEO URL is non-secure url
return $this->url_encode($this->model_tool_seo_url->rewrite($this->getNonSecureURL($rt, $params)), $encode);
}
/**
* Build secure SEO URL
*
* @param string $rt
* @param string $params
* @param string $encode
*
* @return string
* @throws AException
*/
public function getSecureSEOURL($rt, $params = '', $encode = '')
{
//add token for embed mode with forbidden 3d-party cookies
if ($this->registry->get('session')->data['session_mode'] == 'embed_token') {
$params .= '&' . EMBED_TOKEN_NAME . '=' . session_id();
}
//#PR Generate SEO URL based on standard URL
$this->loadModel('tool/seo_url');
return $this->url_encode($this->model_tool_seo_url->rewrite($this->getSecureURL($rt, $params)), $encode);
}
/**
* This builds URL to the catalog to be used in admin
*
* @param string $rt
* @param string $params
* @param string $encode
* @param bool $ssl
*
* @return string
* @throws AException
*/
public function getCatalogURL($rt, $params = '', $encode = '', $ssl = false)
{
$seo_prefix = $this->registry->get('config')->get('seo_prefix');
//add token for embed mode with forbidden 3d-party cookies
if ($this->registry->get('session')->data['session_mode'] == 'embed_token') {
$params .= '&' . EMBED_TOKEN_NAME . '=' . session_id();
}
$subUrl = '?' . ($rt ? 'rt=' . $rt : '') . $params;
if ($this->registry->get('config')->get('config_ssl') == 2) {
$ssl = true;
}
if ($ssl && parse_url($this->registry->get('config')->get('config_ssl_url'), PHP_URL_SCHEME) == 'https') {
$HTTPS_SERVER = $this->registry->get('config')->get('config_ssl_url') . $seo_prefix;
} else {
$HTTPS_SERVER = HTTPS_SERVER . $seo_prefix;
}
$http = $ssl ? $HTTPS_SERVER : HTTP_SERVER . $seo_prefix;
return $http . INDEX_FILE . $this->url_encode($subUrl, $encode);
}
/**
* encode URL for & to be &
*
* @param string $url
* @param bool $encode
*
* @return string
*/
public function url_encode($url, $encode = false)
{
if ($encode) {
return str_replace('&', '&', (string)$url);
} else {
return $url;
}
}
/**
* Current URL built based on get params with ability to exclude params
*
* @param $filter_params array - array of vars to filter
*
* @return string - url without unwanted filter parameters
* @throws AException
*/
public function currentURL($filter_params = [])
{
$params_arr = $this->request->get;
//detect if there is RT in the params.
$rt = 'index/home';
if (has_value($params_arr['rt'])) {
$rt = $params_arr['rt'];
$filter_params[] = 'rt';
}
if (has_value($params_arr['s'])) {
$filter_params[] = 's';
}
$URI = '&' . $this->buildURI($params_arr, $filter_params);
return $this->getURL($rt, $URI);
}
/**
* URI encrypt parameters in URI
*
* @param $uri
*
* @return string - url without unwanted filter parameters
* @internal param array $filter_params - array of vars to filter
*/
public function encryptURI($uri)
{
$encrypted = base64_encode($uri);
if (strlen($encrypted) <= 250) {
return '__e=' . $encrypted;
} else {
return $uri;
}
}
/**
* Build URI from array provided
*
* @param $params_arr array - data array to process
* @param $filter_params array - array of vars to filter
*
* @return string - url without unwanted filter parameters
*/
public function buildURI($params_arr, $filter_params = [])
{
foreach ($filter_params as $rv) {
unset($params_arr[$rv]);
}
return urldecode(http_build_query($params_arr, '', '&'));
}
/**
* Filter query parameters from url.
*
* @param $url string - url to process
* @param $filter_params string|array - single var or array of vars
*
* @return string - url without unwanted filter query parameters
*/
public function filterQueryParams($url, $filter_params = [])
{
list($url_part, $q_part) = explode('?', $url);
parse_str($q_part, $q_vars);
//build array if passed as string
if (!is_array($filter_params)) {
$filter_params = [$filter_params];
}
foreach ($filter_params as $rv) {
unset($q_vars[$rv]);
}
foreach ($q_vars as $key => $val) {
$q_vars[$key] = $this->request->clean($val);
}
$new_qs = urldecode(http_build_query($q_vars, '', '&'));
return $url_part . '?' . $new_qs;
}
/**
* function returns text error or empty
*
* @param string $query
* @param string $keyword
*
* @return string
* @throws AException
*/
public function isSEOKeywordExists($query = '', $keyword = '')
{
if (!$keyword) {
return '';
}
$seo_key = SEOEncode($keyword);
$db = $this->registry->get('db');
$sql = "SELECT *
FROM " . $db->table('url_aliases') . "
WHERE query<>'" . $db->escape($query) . "' AND keyword='" . $db->escape($seo_key) . "'";
$result = $db->query($sql);
$kList = array_merge(
array_column($result->rows, 'keyword'),
array_map('basename', glob(DIR_ROOT . '/*', GLOB_ONLYDIR))
);
if (in_array($seo_key, $kList)) {
$url = HTTP_CATALOG . $seo_key;
return $this->language->getAndReplace('error_seo_keyword', '', [$url, $seo_key]);
}
return '';
}
/**
* create html code based on passed data
*
* @param $data - array with element data
* sample
* $data = array(
* 'type' => 'input' //(hidden, textarea, selectbox, file...)
* 'name' => 'input name'
* 'value' => 'input value' // can be an array for select
* 'style' => 'my-form'
* 'form' => 'form id' // needed for unique element ID *
* );
*
* @return object
* @throws AException
*/
public function buildElement($data)
{
return HtmlElementFactory::create($data);
}
/**
* @return string
* @throws AException
*/
public function getStoreSwitcher()
{
$registry = $this->registry;
$view = new AView($this->registry, 0);
//check if store_id is passed or in the session
$store_id = $registry->get('config')->get('current_store_id');
//set store selector
$stores = [];
$hidden = [];
$stores[0] = ['name' => $registry->get('language')->get('text_default')];
$registry->get('load')->model('setting/store');
/**
* @var ModelSettingStore $model
*/
$model = $registry->get('model_setting_store');
//if loaded not default store - hide store switcher
$default_store_settings = $model->getStore(0);
if ($this->registry->get('config')->get('config_url') != $default_store_settings['config_url']) {
return '';
}
$result_stores = $model->getStores();
if (sizeof($result_stores) <= 1) {
//hide store switcher if only one store
return '';
} else {
foreach ($result_stores as $rs) {
$stores[$rs['store_id']] = [
'name' => $rs['alias'] ?: $rs['name'],
'store_id' => $rs['store_id'],
];
}
foreach ($registry->get('request')->get as $name => $value) {
if ($name == 'store_id') {
continue;
}
$hidden[$name] = $value;
}
$view->assign('all_stores', $stores);
$view->assign('current_store', $stores[$store_id]['name']);
$view->assign('hiddens', $hidden);
$view->assign('text_select_store', $registry->get('language')->get('text_select_store'));
return $view->fetch('form/store_switcher.tpl');
}
}
/**
* @return string
* @throws AException
*/
public function getContentLanguageSwitcher()
{
$registry = $this->registry;
$view = new AView($this->registry, 0);
$registry->get('load')->model('localisation/language');
$results = $registry->get('model_localisation_language')->getLanguages();
$template['languages'] = [];
foreach ($results as $result) {
if ($result['status']) {
$template['languages'][] = [
'name' => $result['name'],
'code' => $result['code'],
'image' => $result['image'],
];
}
}
if (sizeof($template['languages']) > 1) {
//selected in selectbox
$template['language_code'] = $registry->get('language')->getContentLanguageCode();
foreach ($registry->get('request')->get as $name => $value) {
if ($name == 'content_language_code') {
continue;
}
$template['hiddens'][$name] = $value;
}
} else {
$template['languages'] = [];
}
$view->batchAssign($template);
return $view->fetch('form/language_switcher.tpl');
}
/**
* @return string
* @throws AException
*/
public function getContentLanguageFlags()
{
$registry = $this->registry;
$view = new AView($this->registry, 0);
$registry->get('load')->model('localisation/language');
$results = $registry->get('model_localisation_language')->getLanguages();
$template['languages'] = [];
foreach ($results as $result) {
if ($result['status']) {
$template['languages'][] = [
'name' => $result['name'],
'code' => $result['code'],
'image' => $result['image'],
];
}
}
if (sizeof($template['languages']) > 1) {
//selected in selectbox
$template['language_code'] = $registry->get('language')->getContentLanguageCode();
foreach ($registry->get('request')->get as $name => $value) {
if ($name == 'content_language_code') {
continue;
}
$template['hiddens'][$name] = $value;
}
} else {
$template['languages'] = [];
}
$view->batchAssign($template);
return $view->fetch('form/language_flags.tpl');
}
/**
* @param string $html - text that might contain internal links #admin# or #storefront#
* $mode - 'href' create complete a tag or default just replace URL
* @param string $type - can be 'message' to convert url into tag or empty
* @param bool $for_admin - force mode for converting links to admin side from storefront scope (see AIM-class etc.)
*
* @return string - html code with parsed internal URLs
* @throws AException
*/
public function convertLinks($html, $type = '', $for_admin = false)
{
$is_admin = (IS_ADMIN === true || $for_admin);
$route_sections = $is_admin ? ["admin", "storefront"] : ["storefront"];
foreach ($route_sections as $rt_type) {
preg_match_all(
'/(#' . $rt_type . '#rt=)[A-z0-9\/_\-?&=%#]{1,255}(\b|")/',
$html,
$matches,
PREG_OFFSET_CAPTURE
);
if ($matches) {
foreach ($matches[0] as $match) {
$href = str_replace('?', '&', (string)$match[0]);
if ($rt_type == 'admin') {
if ($for_admin && IS_ADMIN !== true) {
$href .= '&s=' . ADMIN_PATH;
}
$new_href = str_replace('#admin#', $this->getSecureURL('') . '&', $href);
} else {
$new_href = str_replace('#storefront#', $this->getCatalogURL('') . '&', $href);
}
$new_href = str_replace(['&', '&&', '&?'], '&', $new_href);
$new_href = str_replace('?&', '?', $new_href);
$new_href = str_replace('&', '&', $new_href);
switch ($type) {
case 'message':
$new_href = '#link-text#';
break;
default:
break;
}
$html = str_replace($match[0], $new_href, $html);
}
}
}
return $html;
}
}
/**
* Class HtmlElementFactory
*/
class HtmlElementFactory
{
static private $available_elements = [
'I' => [
'type' => 'input',
'method' => 'buildInput',
'class' => 'InputHtmlElement',
],
'T' => [
'type' => 'textarea',
'method' => 'buildTextarea',
'class' => 'TextareaHtmlElement',
],
'S' => [
'type' => 'selectbox',
'method' => 'buildSelectbox',
'class' => 'SelectboxHtmlElement',
],
'M' => [
'type' => 'multiselectbox',
'method' => 'buildMultiselectbox',
'class' => 'MultiSelectboxHtmlElement',
],
'R' => [
'type' => 'radio',
'method' => 'buildRadio',
'class' => 'RadioHtmlElement',
],
'C' => [
'type' => 'checkbox',
'method' => 'buildCheckbox',
'class' => 'CheckboxHtmlElement',
],
'G' => [
'type' => 'checkboxgroup',
'method' => 'buildCheckboxgroup',
'class' => 'CheckboxgroupHtmlElement',
],
'U' => [
'type' => 'file',
'method' => 'buildFile',
'class' => 'FileHtmlElement',
],
'K' => [
'type' => 'captcha',
'method' => 'buildCaptcha',
'class' => 'CaptchaHtmlElement',
],
'J' => [
'type' => 'recaptcha',
'method' => 'buildReCaptcha',
'class' => 'ReCaptchaHtmlElement',
],
'H' => [
'type' => 'hidden',
'method' => 'buildHidden',
'class' => 'HiddenHtmlElement',
],
'P' => [
'type' => 'multivalue',
'method' => 'buildMultivalue',
'class' => 'MultiValueHtmlElement',
],
'L' => [
'type' => 'multivaluelist',
'method' => 'buildMultivalueList',
'class' => 'MultivalueListHtmlElement',
],
'D' => [
'type' => 'date',
'method' => 'buildDateInput',
'class' => 'DateInputHtmlElement',
],
'E' => [
'type' => 'email',
'method' => 'buildEmail',
'class' => 'EmailHtmlElement',
],
'N' => [
'type' => 'number',
'method' => 'buildNumber',
'class' => 'NumberHtmlElement',
],
'F' => [
'type' => 'phone',
'method' => 'buildPhone',
'class' => 'PhoneHtmlElement',
],
'A' => [
'type' => 'IPaddress',
'method' => 'buildIPaddress',
'class' => 'IPaddressHtmlElement',
],
'O' => [
'type' => 'countries',
'method' => 'buildCountries',
'class' => 'CountriesHtmlElement',
],
'Z' => [
'type' => 'zones',
'method' => 'buildZones',
'class' => 'ZonesHtmlElement',
],
'B' => [
'type' => 'label',
'method' => 'buildLabel',
'class' => 'LabelHtmlElement',
],
];
static private $elements_with_options = [
'S',
'M',
'R',
'G',
'O',
'Z',
];
static private $multivalue_elements = [
'M',
'R',
'G',
];
static private $elements_with_placeholder = [
'S',
'I',
'M',
'O',
'Z',
'F',
'N',
'E',
'D',
'U',
'T',
];
/**
* return array of HTML elements supported
* array key - code of element
* [
* type - element type
* method - method in html class to get element html
* class - element class
* ]
*
* @static
* @return array
*/
static function getAvailableElements()
{
return self::$available_elements;
}
/**
* return array of elements indexes for elements which has options
*
* @static
* @return array
*/
static function getElementsWithOptions()
{
return self::$elements_with_options;
}
/**
* return array of elements indexes for elements which has options
*
* @static
* @return array
*/
static function getElementsWithPlaceholder()
{
return self::$elements_with_placeholder;
}
/**
* return array of elements indexes for elements which has options
*
* @static
* @return array
*/
static function getMultivalueElements()
{
return self::$multivalue_elements;
}
/**
* return element type
*
* @static
*
* @param $code - element code ( from $available_elements )
*
* @return null | string
*/
static function getElementType($code)
{
if (!array_key_exists($code, self::$available_elements)) {
return null;
}
return self::$available_elements[$code]['type'];
}
/**
* @param $data
*
* @return HiddenHtmlElement | MultivalueListHtmlElement | MultivalueHtmlElement | SubmitHtmlElement
* @return InputHtmlElement | PasswordHtmlElement | PaginationHtmlElement | TextareaHtmlElement
* @return SelectboxHtmlElement | MultiSelectboxHtmlElement | CheckboxHtmlElement
* @return CheckboxGroupHtmlElement | FileHtmlElement | RadioHtmlElement | ButtonHtmlElement
* @return FormHtmlElement | RatingHtmlElement | CaptchaHtmlElement | ReCaptchaHtmlElement
* @return PasswordSetHtmlElement | ResourceHtmlElement | ResourceImageHtmlElement | DateHtmlElement
* @return EmailHtmlElement | NumberHtmlElement | PhoneHtmlElement | IPaddressHtmlElement
* @return CountriesHtmlElement | ZonesHtmlElement | ModalHtmlElement
*
* @throws AException
*/
static function create($data)
{
$class = ucfirst($data['type'] . 'HtmlElement');
if (!class_exists($class)) {
throw new AException(AC_ERR_LOAD, 'Error: Could not load HTML element ' . $data['type'] . '!');
}
return new $class($data);
}
}
/**
* @abstract
* Class HtmlElement
* @property mixed $value
* @property array $options
* @property array $disabled_options
* @property bool $required
* @property bool $multilingual
* @property string $template
* @property array $history
* @property AMessage $messages
*
* @property ARequest $request
* @property AConfig $config
* @property ALoader $load
* @property ALanguageManager|ALanguage $language
* @property AHtml $html
* @property ADocument $document
* @property CSRFToken $csrftoken
*/
abstract class HtmlElement
{
/** @var array */
protected $data = [];
/** @var string */
public $element_id;
/** @var AView */
protected $view;
/**
* @param array $data
*
* @throws AException
*/
function __construct($data)
{
if (!isset($data['value'])) {
$data['value'] = '';
}
if (isset($data['required']) && $data['required'] == 1) {
$data['required'] = 'Y';
}
$this->data = $data;
$this->element_id = ($data['id'] ?? '')
? preformatTextID($data['id'])
: preformatTextID($data['name'] ?? '');
if ($data['form'] ?? '') {
$this->element_id = $data['form'] . '_' . $this->element_id;
}
$this->view = new AView(Registry::getInstance(), 0);
}
/**
* @param string $name
*
* @return null|string
*/
public function __get($name)
{
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
return Registry::getInstance()->get($name);
}
/**
* @param string $name
* @param mixed $value
*
* @return void
*/
public function __set(string $name, $value)
{
$this->data[$name] = $value;
}
/**
* @param string $name
*
* @return bool
*/
public function __isset($name)
{
return isset($this->data[$name]);
}
/**
* @return string
*/
public function __toString()
{
$javascript = '';
$this->data['javascript'] = $this->data['javascript'] ?? '';
if ($this->data['javascript']) {
$javascript = $this->data['javascript'];
}
return $javascript . $this->getHtml();
}
public function __serialize(): array
{
$viewData = $this->view->getData();
$this->data['view_data'] = $viewData;
$this->view = null;
return (array)$this;
}
public function __unserialize($data)
{
$this->view = new AView(Registry::getInstance(), 0);
$this->view->batchAssign((array)$this->data['view_data']);
unset($this->data['view_data']);
if ($data) {
foreach ($data as $key => $val) {
$this->{$key} = $val;
}
}
}
public function addHookVars(array $vars)
{
if (!$vars) {
return;
}
//add hook variables into tpl. can be used in *.post.tpl or *.pre.tpl
foreach ($vars as $hkvName => $hkvValue) {
$this->view->addHookVar($hkvName, $hkvValue);
}
}
protected function extendAndBatchAssign(array $array)
{
$this->view->batchAssign(
array_merge($this->data, $array)
);
}
protected function getMultiLingual()
{
if (is_object($this->language) && sizeof($this->language->getActiveLanguages()) > 1) {
$multilingual = $this->multilingual;
} else {
$multilingual = false;
}
return $multilingual;
}
/**
* @return null
*/
public function getHtml()
{
return null;
}
protected function _validate_options()
{
$this->disabled_options = (array)$this->disabled_options;
//check case when all options are disabled
$all_disabled = true;
foreach ((array)$this->options as $id => $text) {
if (!in_array($id, $this->disabled_options)) {
$all_disabled = false;
break;
}
}
//if all disabled and options presents (for select-chosen element or empty)
if ($all_disabled && $this->options) {
if (in_array($this->data['type'], ['selectbox', 'multiselectbox'])) {
$this->options = ['' => '------'] + $this->options;
}
$this->value = [0];
if ($this->required) {
$seo_prefix = $this->config->get('seo_prefix');
$url = HTTPS_SERVER . $seo_prefix;
$query_string = $this->request->server['QUERY_STRING'];
if (!str_contains((string)$query_string, '_route_=')) {
$url .= '?';
} else {
$query_string = str_replace('_route_=', '', $query_string);
}
$url .= $query_string;
$this->messages->saveWarning(
'Form Field #' . $this->element_id . ' Issue',
'Abnormal situation. All options of required field "' . $this->data['name']
. '" are disabled. URL: ' . $url . ""
);
}
}
}
}
/**
* Class HiddenHtmlElement
*
* @property string $element_id
* @property string $name
* @property string $value
* @property string $attr
*/
class HiddenHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
$this->extendAndBatchAssign(
[
'id' => $this->element_id,
'name' => $this->name,
'value' => $this->value,
'attr' => $this->attr,
]
);
return $this->view->fetch($this->template ?: 'form/hidden.tpl');
}
}
/**
* Class MultiValueListHtmlElement
*
* @property string $element_id
* @property string $name
* @property array $values
* @property array $postvars
* @property string $content_url
* @property string $edit_url
* @property string $form
* @property string $multivalue_hidden_id
* @property string $return_to
* @property string $with_sorting
* @property array $text
*/
class MultiValueListHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
$data = [
'id' => $this->element_id,
'name' => $this->name,
'values' => $this->values,
'content_url' => $this->content_url,
'edit_url' => $this->edit_url,
'postvars' => $this->postvars,
'form_name' => $this->form,
'multivalue_hidden_id' => $this->multivalue_hidden_id,
'return_to' => ($this->return_to ?: $this->form . '_' . $this->multivalue_hidden_id . '_item_count'),
'with_sorting' => $this->with_sorting,
];
$data['text']['delete'] = $this->text['delete'] ?: 'delete';
$data['text']['delete_confirm'] = $this->text['delete_confirm'] ?: 'Confirm to delete?';
$data['text']['column_action'] = $this->language->get('column_action');
$data['text']['column_sort_order'] = $this->language->get('text_sort_order');
$this->extendAndBatchAssign($data);
return $this->view->fetch($this->template ?: 'form/multivalue_list.tpl');
}
}
/**
* Class MultiValueHtmlElement
*
* @property string $element_id
* @property string $name
* @property string $selected_name
* @property string $title
* @property string $selected
* @property string $content_url
* @property string $form
* @property string $return_to
* @property string $no_save
* @property array $text
* @property int $popup_height
* @property int $popup_width
* @property array $js
* @property array $postvars
*/
class MultiValueHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
$data = [
'id' => $this->element_id,
'name' => $this->name,
'selected_name' => ($this->selected_name ?: 'selected[]'),
'title' => $this->title,
'selected' => $this->selected,
'content_url' => $this->content_url,
'postvars' => ($this->postvars ? json_encode($this->postvars) : ''),
'form_name' => $this->form,
'return_to' => ($this->return_to ?: $this->element_id . '_item_count'),
'no_save' => (isset($this->no_save) && $this->no_save),
'popup_height' => ((int)$this->popup_height ?: 620),
'popup_width' => ((int)$this->popup_width ?: 800),
// custom triggers for dialog events (custom functions calls)
'js' => [
'apply' => $this->js['apply'],
'cancel' => $this->js['cancel'],
],
'text_selected' => $this->text['selected'],
'text_edit' => $this->text['edit'] ?: 'Add / Edit',
'text_apply' => $this->text['apply'] ?: 'apply',
'text_save' => $this->text['save'] ?: 'save',
'text_reset' => $this->text['reset'] ?: 'reset',
];
$this->extendAndBatchAssign($data);
return $this->view->fetch($this->template ?: 'form/multivalue_hidden.tpl');
}
}
/**
* Class SubmitHtmlElement
*
* @property string $form,
* @property string $name
* @property string $value
* @property string $attr
* @property string $style
* @property string $icon
*/
class SubmitHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
$this->extendAndBatchAssign(
[
'form' => $this->form,
'name' => $this->name,
'value' => $this->value,
'attr' => $this->attr,
'style' => $this->style,
'icon' => $this->icon,
]
);
return $this->view->fetch($this->template ?: 'form/submit.tpl');
}
}
/**
* Class InputHtmlElement
*
* @property string $element_id
* @property string $default
* @property string $value
* @property string $name
* @property string $attr
* @property string $required
* @property string $style
* @property string $placeholder
* @property string $regexp_pattern
* @property string $error_text
* @property string $help_url
* @property bool $multilingual
* @property array $list
*/
class InputHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
if (!isset($this->default)) {
$this->default = '';
}
if ($this->value == '' && !empty($this->default)) {
$this->value = $this->default;
}
$history_url = '';
if ($this->history) {
// Check if a field name contains square brackets or block_ prefix
if (preg_match('/.*\[(.*?)\]$/', $this->name, $matches)) {
$fieldName = $matches[1];
} else if (preg_match('/block_(.*?)$/', $this->name, $matches)) {
$fieldName = $matches[1];
} else {
$fieldName = $this->name;
}
$history_url = $this->html->getSecureURL(
'r/common/common/getDescriptionHistory',
'&' . http_build_query(
[
'field' => $fieldName,
'table_name' => $this->history['table'],
'record_id' => $this->history['record_id'],
//element ID (need to paste selected value back to the form field)
'elm_id' => $this->element_id
]
)
);
if (is_object($this->language)) {
$button_field_history = $this->language->get('button_field_history');
}
}
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'type' => 'text',
'value' => str_replace('"', '"', (string)$this->value),
'default' => $this->default,
'attr' => $this->attr,
'required' => $this->required,
'style' => $this->style,
'placeholder' => $this->placeholder,
'regexp_pattern' => trim((string)$this->regexp_pattern, '/'),
'error_text' => $this->error_text,
'multilingual' => $this->getMultiLingual(),
'help_url' => $this->help_url,
'list' => $this->list,
'history_url' => $history_url,
'button_field_history' => $button_field_history ?? '',
]
);
return $this->view->fetch($this->template ?: 'form/input.tpl');
}
}
/**
* Class InputHtmlElement
*
* @property string $element_id
* @property string $default
* @property string $value
* @property string $name
* @property string $attr
* @property string $required
* @property string $style
* @property string $placeholder
* @property string $regexp_pattern
* @property string $error_text
* @property string $help_url
* @property bool $multilingual
*/
class ColorHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
if (!isset($this->default)) {
$this->default = '';
}
if ($this->value == '' && !empty($this->default)) {
$this->value = $this->default;
}
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'type' => 'color',
'value' => str_replace('"', '"', (string)$this->value),
'default' => $this->default,
'attr' => $this->attr,
'required' => $this->required,
'style' => $this->style,
'error_text' => $this->error_text,
'multilingual' => $this->getMultiLingual(),
'help_url' => $this->help_url,
]
);
return $this->view->fetch($this->template ?: 'form/input.tpl');
}
}
/**
* Class PasswordHtmlElement
*
* @property string $element_id
* @property string $default
* @property string $value
* @property string $name
* @property string $attr
* @property string $required
* @property string $style
* @property string $placeholder
* @property string $regexp_pattern
* @property string $error_text
*/
class PasswordHtmlElement extends HtmlElement
{
static $starPassword = '**********';
/**
* @return string
* @throws AException
*/
public function getHtml()
{
if (!isset($this->default)) {
$this->default = '';
}
if ($this->value == '' && !empty($this->default)) {
$this->value = $this->default;
}
if (!$this->required && $this->value) {
$value = self::$starPassword;
} else {
$value = '';
}
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'type' => 'password',
'value' => $value,
'has_value' => ($this->value) ? 'Y' : 'N',
'attr' => $this->attr,
'required' => $this->required,
'style' => $this->style,
'placeholder' => $this->placeholder,
'regexp_pattern' => trim((string)$this->regexp_pattern, '/'),
'error_text' => $this->error_text,
]
);
return $this->view->fetch($this->template ?: 'form/input.tpl');
}
}
/**
* Class TextareaHtmlElement
*
* @property string $element_id
* @property string $value
* @property string $name
* @property string $attr
* @property string $required
* @property string $style
* @property string $placeholder
* @property string $label_text
* @property bool $multilingual
* @property string $help_url
*/
class TextareaHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
$history_url = '';
if ($this->history) {
// Check if a field name contains square brackets or block_ prefix
if (preg_match('/.*\[(.*?)\]$/', $this->name, $matches)) {
$fieldName = $matches[1];
} else if (preg_match('/block_(.*?)$/', $this->name, $matches)) {
$fieldName = $matches[1];
} else {
$fieldName = $this->name;
}
$history_url = $this->html->getSecureURL(
'r/common/common/getDescriptionHistory',
'&' . http_build_query(
[
'field' => $fieldName,
'table_name' => $this->history['table'],
'record_id' => $this->history['record_id'],
//element ID (need to paste selected value back to the form field)
'elm_id' => $this->element_id
]
)
);
if (is_object($this->language)) {
$button_field_history = $this->language->get('button_field_history');
}
}
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'value' => $this->value,
'ovalue' => htmlentities($this->value, ENT_QUOTES, 'UTF-8'),
'attr' => $this->attr,
'required' => $this->required,
'style' => $this->style,
'placeholder' => $this->placeholder,
'label_text' => $this->label_text,
'multilingual' => $this->getMultiLingual(),
'help_url' => $this->help_url,
'history_url' => $history_url,
'button_field_history' => $button_field_history ?? '',
]
);
return $this->view->fetch($this->template ?: 'form/textarea.tpl');
}
}
/**
* Class TextEditorHtmlElement
*
* @property ALanguage $language
* @property string $element_id
* @property string $value
* @property string $name
* @property string $attr
* @property string $required
* @property string $style
* @property string $placeholder
* @property string $base_url - need for inserting pictures into html for emails
* @property bool $preview - enable/disable visual mode of tinymce. default true
* @property string $preview_url - custom preview url
* @property string $js_onload - custom js-code will be run on doc ready
* @property bool $multilingual
* @property array $history - array with table, record_id
*/
class TextEditorHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
$this->multilingual = $this->multilingual ?? '';
$data = [
'name' => $this->name,
'id' => $this->element_id,
'value' => $this->value,
'ovalue' => htmlentities($this->value, ENT_QUOTES, 'UTF-8'),
'attr' => $this->attr ?? '',
'required' => $this->required ?? false,
'style' => $this->style ?? '',
'placeholder' => $this->placeholder ?? '',
'base_url' => $this->base_url ?? '',
'preview' => $this->preview ?? true,
'preview_url' => $this->preview_url ?? '',
'js_onload' => $this->js_onload ?? ''
];
if ($this->history) {
// Check if a field name contains square brackets or
if (preg_match('/.*\[(.*?)\]$/', $this->name, $matches)) {
$fieldName = $matches[1];
} else if (preg_match('/block_(.*?)$/', $this->name, $matches)) {
$fieldName = $matches[1];
} else {
$fieldName = $this->name;
}
$data['history_url'] = $this->html->getSecureURL(
'r/common/common/getDescriptionHistory',
'&' . http_build_query(
[
'field' => $fieldName,
'table_name' => $this->history['table'],
'record_id' => $this->history['record_id'],
//element ID (need to paste selected value back to the form field)
'elm_id' => $this->element_id
]
)
);
}
if (is_object($this->language)) {
if (sizeof($this->language->getActiveLanguages()) > 1) {
$data['multilingual'] = $this->multilingual;
}
$data['language_code'] = $this->language->getContentLanguageCode();
$data['tab_text'] = $this->language->get('tab_text');
$data['tab_visual'] = $this->language->get('tab_visual');
$data['button_add_media'] = $this->language->get('button_add_media');
$data['button_preview'] = $this->language->get('button_preview');
$data['button_field_history'] = $this->language->get('button_field_history');
}
$this->extendAndBatchAssign($data);
return $this->view->fetch($this->template ?: 'form/text_editor.tpl');
}
}
/**
* Class SelectboxHtmlElement
*
* @property string $element_id
* @property string $value
* @property string $name
* @property string $attr
* @property string $required
* @property string $style
* @property string $placeholder
* @property array $options
* @property array $disabled_options
* @property bool $disabled
* @property string $ajax_url
* @property string $search_mode
* @property string $help_url
*/
class SelectboxHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
if (!is_array($this->value)) {
$this->value = [$this->value => (string)$this->value];
}
$this->options = !$this->options ? [] : (array)$this->options;
foreach ($this->options as &$opt) {
$opt = (string)$opt;
}
unset($opt);
$text_continue_typing = $text_looking_for = '';
if (is_object($this->language)) {
$text_continue_typing = $this->language->get('text_continue_typing', '', true);
$text_looking_for = $this->language->get('text_looking_for', '', true);
}
$text_continue_typing = !$text_continue_typing
|| $text_continue_typing == 'text_continue_typing' ? 'Continue typing ...' : $text_continue_typing;
$text_looking_for =
!$text_looking_for || $text_looking_for == 'text_looking_for' ? 'Looking for' : $text_looking_for;
$this->_validate_options();
$data = [
'name' => $this->name,
'id' => $this->element_id,
'value' => $this->value,
'ovalue' => $this->value,
'options' => $this->options,
'disabled' => $this->disabled,
'disabled_options' => $this->disabled_options,
'attr' => $this->attr,
'required' => $this->required,
'style' => $this->style,
'placeholder' => $this->placeholder,
'ajax_url' => $this->ajax_url, //if mode of data load is ajax based
'search_mode' => $this->search_mode,
'text_continue_typing' => $text_continue_typing,
'text_looking_for' => $text_looking_for,
'help_url' => $this->help_url,
];
if ($this->template) {
$template = $this->template;
} elseif (str_contains((string)$this->style, 'chosen')) {
$data['ajax_url'] = $this->ajax_url; //if mode of data load is ajax based
$data['text_continue_typing'] = $text_continue_typing;
$data['text_looking_for'] = $text_looking_for;
$template = 'form/chosen_select.tpl';
} else {
$template = 'form/selectbox.tpl';
}
$this->extendAndBatchAssign($data);
return $this->view->fetch($template);
}
}
/**
* Class MultiSelectBoxHtmlElement
*
* @property string $element_id
* @property array|mixed $value
* @property string $name
* @property string $attr
* @property string $required
* @property string $style
* @property string $placeholder
* @property array $options
* @property array $disabled_options
* @property string $filter_params - some additional parameters
* @property string $ajax_url
* @property string|array $option_attr
* @property string $help_url
* @property bool $disabled
*/
class MultiSelectBoxHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
if (!is_array($this->value)) {
$this->value = [$this->value => $this->value];
}
$this->_validate_options();
$data = [
'name' => $this->name,
'id' => $this->element_id,
'value' => $this->value,
'options' => $this->options,
'disabled_options' => $this->disabled_options,
'disabled' => $this->disabled,
'attr' => $this->attr . ' multiple="multiple" ',
'required' => $this->required,
'style' => $this->style,
'placeholder' => $this->placeholder,
'filter_params' => $this->filter_params,
'help_url' => $this->help_url,
];
if ($this->template) {
$template = $this->template;
} elseif (str_contains((string)$this->style, 'chosen')) {
$option_attr = $this->option_attr && !is_array($this->option_attr)
? [$this->option_attr]
: $this->option_attr;
$option_attr = $option_attr ?: [];
$data['ajax_url'] = $this->ajax_url; //if mode of data load is ajax based
$data['option_attr'] = $option_attr; //list of custom html5 attributes for options of selectbox
$data['text_continue_typing'] = $this->language->get('text_continue_typing', '', true);
$data['text_looking_for'] = $this->language->get('text_looking_for', '', true);
$template = 'form/chosen_select.tpl';
} else {
$template = 'form/selectbox.tpl';
}
$this->extendAndBatchAssign($data);
return $this->view->fetch($template);
}
}
/**
* Class CheckboxHtmlElement
*
* @property string|int $value
* @property bool $checked
* @property string $element_id
* @property string $name
* @property string $attr
* @property string $required
* @property string $style
* @property string $label_text
* @property string $help_url
*/
class CheckboxHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
$checked = false;
if ($this->template) {
$tpl = $this->template;
} elseif (str_contains((string)$this->style, 'btn_switch')) { //for switch button NOTE: value is binary (1 or 0)!!!
$checked = is_null($this->checked) && $this->value || (bool)$this->checked;
if ($checked) {
$this->value = 1;
} else {
$this->value = 0;
}
$tpl = 'form/switch.tpl';
} else {//for generic checkbox NOTE: in this case value must be any and goes to tpl as-is
$checked = !is_null($this->checked) ? $this->checked : false;
$tpl = 'form/checkbox.tpl';
}
$text_on = $text_off = '';
if (is_object($this->language)) {
$text_on = $this->language->get('text_on', '', true);
$text_off = $this->language->get('text_off', '', true);
}
$text_on = !$text_on || $text_on == 'text_on' ? 'ON' : $text_on;
$text_off = !$text_off || $text_off == 'text_off' ? 'OFF' : $text_off;
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'value' => $this->value,
'attr' => $this->attr,
'required' => $this->required,
'label_text' => $this->label_text,
'checked' => $checked,
'style' => $this->style,
'text_on' => $text_on,
'text_off' => $text_off,
'help_url' => $this->help_url,
]
);
return $this->view->fetch($tpl);
}
}
/**
* Class CheckboxGroupHtmlElement
*
* @property string|int $value
* @property array $options
* @property array $disabled_options
* @property string $element_id
* @property string $name
* @property string $attr
* @property string $required
* @property string $style
* @property bool $scrollbox
* @property string $help_url
* @property string $placeholder
*/
class CheckboxGroupHtmlElement extends HtmlElement
{
public function getHtml()
{
$this->value = !is_array($this->value) ? [$this->value => $this->value] : $this->value;
$this->_validate_options();
if ($this->options && is_array($this->options)) {
$option_keys = array_keys($this->options);
foreach ($this->value as $value) {
if ($value && !in_array($value, $option_keys)) {
$this->options += [$value => 'unknown'];
}
}
}
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'value' => $this->value,
'options' => $this->options,
'disabled_options' => $this->disabled_options,
'attr' => $this->attr . ' multiple="multiple" ',
'required' => $this->required,
'scrollbox' => $this->scrollbox,
'style' => $this->style,
'placeholder' => $this->placeholder,
'help_url' => $this->help_url,
]
);
if ($this->template) {
$template = $this->template;
} elseif (str_contains((string)$this->style, 'chosen')) {
$template = 'form/chosen_select.tpl';
} else {
$template = 'form/checkboxgroup.tpl';
}
return $this->view->fetch($template);
}
}
/**
* Class FileHtmlElement
*
* @property string $element_id
* @property string $name
* @property string $attr
* @property string $required
* @property string $style
* @property string $help_url
* @property string $placeholder
*/
class FileHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'attr' => $this->attr,
'required' => $this->required,
'style' => $this->style,
'default_text' => $this->language->get('text_click_browse_file'),
'text_browse' => $this->language->get('text_browse'),
'placeholder' => $this->placeholder,
'help_url' => $this->help_url,
]
);
return $this->view->fetch($this->template ?: 'form/file.tpl');
}
}
/**
* Class RadioHtmlElement
*
* @property string $value
* @property string $element_id
* @property string $name
* @property string $attr
* @property string $required
* @property string $style
* @property array $options
* @property array $disabled_options
* @property array $disabled
* @property string $help_url
*/
class RadioHtmlElement extends HtmlElement
{
public function getHtml()
{
//if no option provided, default to value
if (empty($this->options) && has_value($this->value)) {
$this->options = [$this->value => $this->value];
}
$this->_validate_options();
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'value' => $this->value,
'options' => $this->options,
'disabled_options' => $this->disabled_options,
'disabled' => $this->disabled,
'attr' => $this->attr,
'required' => $this->required,
'style' => $this->style,
'help_url' => $this->help_url,
]
);
return $this->view->fetch($this->template ?: 'form/radio.tpl');
}
}
/**
* Class ButtonHtmlElement
*
* @property string $element_id
* @property string $text
* @property string $title
* @property string $attr
* @property string $href
* @property string $style
* @property string $href_class
* @property string $icon
* @property string $target
*/
class ButtonHtmlElement extends HtmlElement
{
public function getHtml()
{
$this->extendAndBatchAssign(
[
'text' => $this->text,
'title' => $this->title,
'id' => $this->element_id,
'attr' => $this->attr,
'style' => $this->style,
'href' => $this->href,
'href_class' => $this->href_class,
'icon' => $this->icon,
'target' => $this->target,
]
);
return $this->view->fetch($this->template ?: 'form/button.tpl');
}
}
/**
* Class FormHtmlElement
*
* @property string $name
* @property string $action
* @property string $attr
* @property string $method
* @property string $style
* @property string $enctype
* @property bool $csrf
*/
class FormHtmlElement extends HtmlElement
{
public function getHtml()
{
$this->method = $this->method ?: 'post';
$this->enctype = $this->enctype ?: 'application/x-www-form-urlencoded';
$data = [
'id' => $this->name,
'name' => $this->name,
'action' => $this->action,
'method' => $this->method,
'attr' => $this->attr,
'style' => $this->style,
'enctype' => $this->enctype,
];
//add CSRF token
if ($this->csrf === true) {
$csrftoken = $this->csrftoken;
$data['csrfinstance'] = $csrftoken->setInstance();
$data['csrftoken'] = $csrftoken->setToken();
}
$this->extendAndBatchAssign($data);
return $this->view->fetch($this->template ?: 'form/form_open.tpl') . $this->view->fetch('form/form_csrf.tpl');
}
}
/**
* Class RatingHtmlElement
*
* @property string $element_id
* @property string $name
* @property string $value
* @property array $options
* @property bool $required
*/
class RatingHtmlElement extends HtmlElement
{
public function getHtml()
{
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'value' => $this->value,
'options' => $this->options,
'style' => 'star',
'required' => $this->required,
]
);
return $this->view->fetch($this->template ?: 'form/rating.tpl');
}
}
/**
* Class CaptchaHtmlElement
*
* @property string $element_id
* @property string $name
* @property string $style
* @property string $attr
* @property bool $required
* @property string $placeholder
* @property Registry $registry
*/
class CaptchaHtmlElement extends HtmlElement
{
public function getHtml()
{
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
//TODO: remove deprecated attribute aform_field_type
'attr' => 'aform_field_type="captcha" ' . $this->attr . ' data-aform-field-type="captcha"',
'style' => $this->style,
'required' => $this->required,
'captcha_url' => $this->html->getURL('common/captcha'),
'placeholder' => $this->placeholder,
]
);
return $this->view->fetch($this->template ?: 'form/captcha.tpl');
}
}
/**
* Class ReCaptchaHtmlElement
*
* @property string $element_id
* @property string $name
* @property string $attr
* @property string $language_code
* @property string $recaptcha_site_key
*/
class ReCaptchaHtmlElement extends HtmlElement
{
public function getHtml()
{
$this->extendAndBatchAssign(
[
'name' => $this->name ?: 'g-recaptcha-response',
'id' => $this->element_id,
'attr' => $this->attr . ' data-aform-field-type="captcha"',
'language_code' => $this->language_code,
'recaptcha_site_key' => trim((string)$this->recaptcha_site_key),
'recaptcha_v3' => $this->config->get('account_recaptcha_v3') ?: 0,
]
);
return $this->view->fetch($this->template ?: 'form/recaptcha.tpl');
}
}
/**
* Class PasswordsetHtmlElement
*
* @property string $element_id
* @property string $name
* @property string $value
* @property string $style
* @property string $attr
* @property bool $required
* @property string $placeholder
*/
class PasswordsetHtmlElement extends HtmlElement
{
public function getHtml()
{
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'value' => $this->value,
'attr' => $this->attr,
'style' => $this->style,
'required' => $this->required,
'text_confirm_password' => $this->language->get('text_confirm_password'),
'placeholder' => $this->placeholder,
]
);
return $this->view->fetch($this->template ?: 'form/passwordset.tpl');
}
}
/**
* Class ResourceHtmlElement
*
* @property string $rl_type - image or audio or pdf etc
* @property string $element_id
* @property string $name
* @property string $resource_path
* @property int $resource_id
* @property string $object_name
* @property string $object_id
* @property bool $hide - sign to hide image preview
* @property string $placeholder
*/
class ResourceHtmlElement extends HtmlElement
{
function __construct($data)
{
parent::__construct($data);
}
public function getHtml()
{
if (empty($this->rl_type)) {
throw new AException(
AC_ERR_LOAD,
'Error: Could not load HTML element of resource library. Resource type not given!'
);
}
$data = [
'id' => $this->element_id,
'wrapper_id' => $this->element_id . '_wrapper',
'name' => $this->name,
'resource_path' => $this->resource_path,
'resource_id' => $this->resource_id,
'object_name' => $this->object_name,
'object_id' => $this->object_id,
'rl_type' => $this->rl_type,
'hide' => (bool)$this->hide,
];
if (!$data['resource_id'] && $data['resource_path']) {
$path = ltrim($data['resource_path'], $data['rl_type'] . '/');
$r = new AResource($data['rl_type']);
$data['resource_id'] = $r->getIdFromHexPath($path);
}
if ($data['resource_id'] && !$data['resource_path']) {
$r = new AResource($data['rl_type']);
$info = $r->getResource($data['resource_id']);
if ($info['resource_path']) {
$data['resource_path'] = $data['rl_type'] . '/' . $info['resource_path'];
} else {
//for code-resources
$data['resource_path'] = $data['resource_id'];
}
}
$this->extendAndBatchAssign($data);
return $this->view->fetch($this->template ?: 'form/resource.tpl');
}
}
/**
* Class ResourceImageHtmlElement
*
* @property int $width
* @property int $height
* @property string $attr
* @property string $url
*/
class ResourceImageHtmlElement extends HtmlElement
{
function __construct($data)
{
parent::__construct($data);
}
public function getHtml()
{
$this->extendAndBatchAssign(
[
'url' => $this->url,
'width' => $this->width,
'height' => $this->height,
'attr' => $this->attr,
]
);
return $this->view->fetch($this->template ?: 'common/resource_image.tpl');
}
}
/**
* Class DateHtmlElement
*
* @property string $element_id
* @property string $name
* @property string $end_date_name
* @property string $start_date_name
* @property string $value
* @property string $default
* @property string $style
* @property string $attr
* @property array $js_custom_config
* @property string $mode
* @property bool $required
* @property string $dateformat
* @property string $highlight
* @property string $help_url
*/
class DateHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
if (!isset($this->default)) {
$this->default = '';
}
if ($this->value == '' && !empty($this->default)) {
$this->value = $this->default;
}
$this->element_id = preg_replace('/[\[+\]]/', '_', $this->element_id);
if ($this->end_date_name || $this->start_date_name) {
$this->mode = 'range';
}
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'type' => 'text',
'value' => $this->value,
'default' => $this->default,
'required' => $this->required,
'attr' => $this->attr,
//js config of initialization of date field
'js_custom_config' => (object)$this->js_custom_config,
'mode' => in_array($this->mode, ["single", "multiple", "range"]) ? $this->mode : "single",
'style' => $this->style,
'dateformat' => $this->dateformat ?: format4Datepicker($this->language->get('date_format_short')),
'help_url' => $this->help_url,
'end_date_name' => $this->end_date_name,
'start_date_name' => $this->start_date_name,
'text_reset' => $this->language->get('button_reset'),
]
);
/** @see public_html/admin/view/default/template/form/date.tpl */
return $this->view->fetch($this->template ?: 'form/date.tpl');
}
}
/**
* Class EmailHtmlElement
*
* @property string $element_id
* @property string $name
* @property string $value
* @property string $default
* @property string $style
* @property string $attr
* @property bool $required
* @property string $placeholder
* @property string $regexp_pattern
* @property string $error_text
* @property string $help_url
*/
class EmailHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
if (!isset($this->default)) {
$this->default = '';
}
if ($this->value == '' && !empty($this->default)) {
$this->value = $this->default;
}
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'type' => 'email',
'value' => str_replace('"', '"', (string)$this->value),
'default' => $this->default,
//TODO: remove deprecated attribute aform_field_type
'attr' => 'aform_field_type="email" ' . $this->attr . ' data-aform-field-type="captcha"',
'required' => $this->required,
'style' => $this->style,
'placeholder' => $this->placeholder,
'regexp_pattern' => trim((string)$this->regexp_pattern, '/'),
'error_text' => $this->error_text,
'help_url' => $this->help_url,
]
);
return $this->view->fetch($this->template ?: 'form/input.tpl');
}
}
/**
* Class NumberHtmlElement
*
* @property string $element_id
* @property string $name
* @property string $value
* @property int $min
* @property int $max
* @property string $default
* @property string $style
* @property string $attr
* @property bool $required
* @property string $placeholder
* @property string $regexp_pattern
* @property string $error_text
* @property string $help_url
*/
class NumberHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
if (!isset($this->default)) {
$this->default = '';
}
if ($this->value == '' && !empty($this->default)) {
$this->value = $this->default;
}
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'type' => 'number',
'value' => str_replace('"', '"', (string)$this->value),
'min' => $this->min,
'max' => $this->max,
'default' => $this->default,
//TODO: remove deprecated attribute aform_field_type
'attr' => 'aform_field_type="number" ' . $this->attr
. ' data-aform-field-type="captcha"',
'required' => $this->required,
'style' => $this->style,
'placeholder' => $this->placeholder,
'regexp_pattern' => trim((string)$this->regexp_pattern, '/'),
'error_text' => $this->error_text,
'help_url' => $this->help_url,
]
);
return $this->view->fetch($this->template ?: 'form/input.tpl');
}
}
/**
* Class PhoneHtmlElement
*
* @property string $element_id
* @property string $name
* @property string $value
* @property string $default
* @property string $style
* @property string $attr
* @property bool $required
* @property string $placeholder
* @property string $regexp_pattern
* @property string $error_text
* @property string $help_url
*/
class PhoneHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
if (!isset($this->default)) {
$this->default = '';
}
if ($this->value == '' && !empty($this->default)) {
$this->value = $this->default;
}
$telJs = '/javascript/intl-tel-input/js/intlTelInput.min.js';
if (is_file($this->view->templateResource($telJs, 'file'))) {
$this->document->addScript($this->view->templateResource($telJs));
$this->document->addStyle(
[
'href' => $this->view->templateResource('/javascript/intl-tel-input/css/intlTelInput.css'),
'rel' => 'stylesheet',
]
);
}
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'type' => 'tel',
'value' => str_replace('"', '"', (string)$this->value),
'default' => $this->default,
'attr' => $this->attr,
'required' => $this->required,
'style' => $this->style,
'placeholder' => $this->placeholder,
'regexp_pattern' => trim((string)$this->regexp_pattern, '/'),
'error_text' => $this->error_text,
'help_url' => $this->help_url,
]
);
return $this->view->fetch($this->template ?: 'form/phone.tpl');
}
}
/**
* Class IPaddressHtmlElement
*
* @property string $element_id
* @property string $name
* @property string $attr
*/
class IPAddressHtmlElement extends HtmlElement
{
public function getHtml()
{
$this->extendAndBatchAssign(
[
'id' => $this->element_id,
'name' => $this->name,
'value' => $this->request->getRemoteIP(),
//TODO: remove deprecated attribute aform_field_type
'attr' => 'aform_field_type="ipaddress" ' . $this->attr . ' data-aform-field-type="captcha"',
]
);
return $this->view->fetch($this->template ?: 'form/hidden.tpl');
}
}
/**
* Class CountriesHtmlElement
*
* @property string $element_id
* @property string $name
* @property string $value
* @property array $options
* @property string $style
* @property string $attr
* @property bool $required
* @property string $placeholder
* @property string $help_url
*/
class CountriesHtmlElement extends HtmlElement
{
public function __construct($data)
{
parent::__construct($data);
/** @var ModelLocalisationCountry $mdl */
$mdl = $this->load->model('localisation/country');
$results = $mdl->getCountries();
$this->options = array_column($results, 'name', 'name');
}
public function getHtml()
{
if (!is_array($this->value)) {
$this->value = [$this->value => (string)$this->value];
}
$this->options = !$this->options ? [] : $this->options;
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'value' => $this->value,
'options' => $this->options,
'attr' => $this->attr,
'required' => $this->required,
'style' => $this->style,
'placeholder' => $this->placeholder,
'help_url' => $this->help_url,
]
);
return $this->view->fetch($this->template ?: 'form/selectbox.tpl');
}
}
/**
* Class ZonesHtmlElement
*
* @property string $element_id
* @property string $name
* @property string $value
* @property string $submit_mode
* @property int|array $default_value
* @property string $zone_field_name
* @property string $default_zone_field_name
* @property string $default_zone_name
* @property array $default_zone_value
* @property string $zone_name
* @property array $options
* @property array $zone_options
* @property array|string|int $zone_value
* @property string $style
* @property string $attr
* @property bool $required
* @property string $placeholder
* @property string $help_url
*/
class ZonesHtmlElement extends HtmlElement
{
public function __construct($data)
{
parent::__construct($data);
/** @var ModelLocalisationCountry $mdl */
$mdl = $this->load?->model('localisation/country');
$results = $mdl->getCountries();
$this->zone_options = [];
$this->default_zone_field_name = 'zone_id';
$config_country_id = $this->config->get('config_country_id');
$options = [];
foreach ($results as $c) {
if ($c['country_id'] == $config_country_id) {
$this->default_value = $this->submit_mode == 'id'
? [$config_country_id]
: [$c['name'] => $c['name']];
}
if ($this->submit_mode == 'id') {
$options[$c['country_id']] = $c['name'];
} else {
$options[$c['name']] = $c['name'];
}
}
$this->options = $options;
}
public function getHtml()
{
if (!is_array($this->value)) {
if (!$this->value) {
$this->value = [];
} else {
$this->value = [$this->value => (string)$this->value];
}
}
$this->zone_name = !$this->zone_name ? '' : urlencode($this->zone_name);
$this->default_zone_value = [];
$this->options = !$this->options ? [] : $this->options;
$this->element_id = preg_replace('/[\[+\]+]/', '_', $this->element_id);
$html = new AHtml(Registry::getInstance());
if ($this->submit_mode == 'id') {
$url = $html->getSecureURL('common/zone');
} else {
$url = $html->getSecureURL('common/zone/names');
}
/** @var ModelLocalisationZone $model_zone */
$model_zone = $this->load->model('localisation/zone');
$config_country_id = $this->config->get('config_country_id');
if ($this->submit_mode == 'id') {
$id = $this->value ? key($this->value) : $config_country_id;
$results = $model_zone->getZonesByCountryId($id);
} else {
if ($this->value) {
$name = current($this->value);
} else {
/** @var ModelLocalisationCountry $mdl */
$mdl = $this->load->model('localisation/country');
$temp = $mdl->getCountry($config_country_id);
$name = $temp['name'];
}
$results = $model_zone->getZonesByCountryName($name);
}
if (!is_array($this->zone_value)) {
$this->zone_value =
$this->zone_value ? [(string)$this->zone_value => (string)$this->zone_value] : [];
}
$config_zone_id = $this->config->get('config_zone_id');
$zone_options = [];
foreach ($results as $result) {
// default zone_id is zone of shop
if ($result['zone_id'] == $config_zone_id) {
$this->default_zone_value = $this->submit_mode == 'id'
? [$config_zone_id]
: [$result['name'] => $result['name']];
$this->default_zone_name = $result['name'];
}
if ($this->submit_mode == 'id') {
$zone_options[$result['zone_id']] = $result['name'];
} else {
$zone_options[$result['name']] = $result['name'];
}
$this->zone_options = $zone_options;
}
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'value' => $this->value ?: $this->default_value,
'options' => $this->options,
'attr' => $this->attr,
'required' => $this->required,
'style' => $this->style,
'url' => $url,
'zone_field_name' => $this->zone_field_name ?: $this->default_zone_field_name,
'zone_name' => $this->zone_name ?: $this->default_zone_name,
'zone_value' => (array)($this->zone_value ?: $this->default_zone_value),
'zone_options' => $this->zone_options,
'submit_mode' => $this->submit_mode,
'placeholder' => $this->placeholder,
'help_url' => $this->help_url,
]
);
return $this->view->fetch($this->template ?: 'form/countries_zones.tpl');
}
}
/*
* Build pagination HTML element based on the template.
* @since 1.1.5
*/
class PaginationHtmlElement extends HtmlElement
{
public $sts = [];
/**
* @param array $data
*
* @throws AException
*/
public function __construct($data)
{
parent::__construct($data);
//default settings
$this->sts['total'] = 0;
$this->sts['page'] = 1;
$this->sts['limit'] = (int)$this->config?->get('config_catalog_limit') ?: 20;
$this->sts['split'] = $data['split'] ?: 10;
$this->sts['limits'] = [];
//max pages to show in pagination
$this->sts['num_links'] = $data['num_links'] ?: 10;
$this->sts['url'] = '';
$this->sts['text'] = $this->language->get('text_pagination_pages_info', '', true);
$this->sts['text'] = $this->sts['text'] == 'text_pagination_pages_info'
? 'Showing {start} to {end} of {total} ({pages} Pages)'
: $this->sts['text'];
$this->sts['text_limit'] = $this->language->get('text_per_page', '', true);
$this->sts['text_limit'] = $this->sts['text_limit'] == 'text_per_page' ? 'Per Page' : $this->sts['text_limit'];
$this->sts['text_first'] = $this->language->get('text_first', '', true);
$this->sts['text_first'] = $this->sts['text_first'] == 'text_first' ? '|<<' : $this->sts['text_first'];
$this->sts['text_last'] = $this->language->get('text_last', '', true);
$this->sts['text_last'] = $this->sts['text_last'] == 'text_last' ? '>>|' : $this->sts['text_last'];
$this->sts['text_next'] = $this->language->get('text_next', '', true);
$this->sts['text_next'] = $this->sts['text_next'] == 'text_next' ? '>' : $this->sts['text_next'];
$this->sts['text_prev'] = $this->language->get('text_previous', '', true);
$this->sts['text_prev'] = $this->sts['text_prev'] == 'text_previous' ? '<' : $this->sts['text_prev'];
$this->sts['style_links'] = 'links';
$this->sts['style_results'] = 'results';
$this->sts['style_limits'] = 'limits';
//override default
foreach ($this->data as $key => $val) {
if (isset($val)) {
$this->sts[$key] = $val;
}
}
}
/**
* @return string
* @throws AException
*/
public function getHtml()
{
//Build pagination data and display
$registry = Registry::getInstance();
$html = new AHtml($registry);
$s = $this->sts;
$s['no_perpage'] = $s['no_perpage'] ?? 0;
//some more defaults
if ($s['page'] < 1 || !is_numeric($s['page'])) {
$s['page'] = 1;
}
if (!$s['limit'] || !is_numeric($s['limit'])) {
$s['limit'] = 10;
}
//count limits if needed
if (!$s['no_perpage'] && !$s['limits']) {
$s['limits'][0] = $x = ($s['split'] ?: $registry->get('config')->get('config_catalog_limit'));
while ($x <= 50) {
$s['limits'][] = $x;
$x += $s['limits'][0];
}
}
$s['url'] = str_replace('--limit--', $s['limit'], (string)$s['url']);
$s['direct_url'] = str_replace('--limit--', $s['limit'], (string)$s['direct_url']);
$s['total_pages'] = ceil($s['total'] / $s['limit']);
if ($s['page'] > 1) {
//not first page
$this->view->assign('first_url', str_replace('--page--', 1, (string)$s['url']));
$this->view->assign('prev_url', str_replace('--page--', $s['page'] - 1, (string)$s['url']));
}
if ($s['total_pages'] > 1) {
if ($s['total_pages'] <= $s['num_links']) {
$s['start'] = 1;
$s['end'] = $s['total_pages'];
} else {
$s['start'] = $s['page'] - floor($s['num_links'] / 2);
$s['end'] = $s['page'] + floor($s['num_links'] / 2);
if ($s['start'] < 1) {
$s['end'] += abs($s['start']) + 1;
$s['start'] = 1;
}
if ($s['end'] > $s['total_pages']) {
$s['start'] -= ($s['end'] - $s['total_pages']);
$s['end'] = $s['total_pages'];
}
}
} else {
$s['start'] = $s['end'] = 1;
}
if ($s['page'] < $s['total_pages']) {
$this->view->assign('next_url', str_replace('--page--', $s['page'] + 1, (string)$s['url']));
$this->view->assign('last_url', str_replace('--page--', $s['total_pages'], (string)$s['url']));
}
$replace = [
($s['total']) ? (($s['page'] - 1) * $s['limit']) + 1 : 0,
((($s['page'] - 1) * $s['limit']) > ($s['total'] - $s['limit'])) ? $s['total']
: ((($s['page'] - 1) * $s['limit']) + $s['limit']),
$s['total'],
$s['total_pages'],
];
if (!$s['no_perpage']) {
if (!in_array($s['limit'], $s['limits'])) {
$s['limits'][] = $s['limit'];
sort($s['limits']);
}
$options = [];
foreach ($s['limits'] as $item) {
$options[$item] = $item;
}
$limit_url = str_replace('--page--', 1, (string)$s['url']);
$limit_url = str_replace('&limit=' . $s['limit'], '', $limit_url);
$limit_select = $html->buildSelectbox(
[
'name' => 'limit',
'value' => $s['limit'],
'options' => $options,
'style' => 'input-mini',
'attr' => ' onchange="location=\'' . $limit_url . '&limit=\'+this.value;"',
]
);
$limit_select = str_replace('&', '&', (string)$limit_select);
$this->view->assign('limit_select', $limit_select);
}
$find = [
'{start}',
'{end}',
'{total}',
'{pages}',
'--limit--',
];
$s['text'] = str_replace($find, $replace, (string)$s['text']);
$this->extendAndBatchAssign($s);
return $this->view->fetch($this->template ?: 'form/pagination.tpl');
}
}
/**
* Class ModalHtmlElement
*
* @property string $id
* @property string $title
* @property string $modal_type
* @property string $content
* @property string $footer
* @property string $data_source
* @property string $js_onshow
* @property string $js_onload
* @property string $js_onclose
*/
class ModalHtmlElement extends HtmlElement
{
/**
* @param array $data
*
* @throws AException
*/
public function __construct($data)
{
parent::__construct($data);
}
/**
* @return string
* @throws AException
*/
public function getHtml()
{
$modal_type = $this->modal_type ?: 'lg';
$this->extendAndBatchAssign(
[
'id' => $this->id,
'title' => $this->title,
'content' => $this->content,
'footer' => $this->footer,
'modal_type' => $modal_type,
// if 'ajax' we clean up modal content after it close
'data_source' => (string)$this->data_source,
// js-triggers for modal events
'js_onshow' => (string)$this->js_onshow,
'js_onload' => ($this->data_source == 'ajax' ? (string)$this->js_onload : ';'), //if content
'js_onclose' => (string)$this->js_onclose,
]
);
/** @see public_html/admin/view/default/template/form/modal.tpl */
return $this->view->fetch($this->template ?: 'form/modal.tpl');
}
}
/**
* Class LabelHtmlElement
* NOTE: only for storefront
*
* @property string $element_id
* @property string $name
* @property string $text
* @property string $value
* @property string $style
* @property string $help_url
* @property string $attr
*/
class LabelHtmlElement extends HtmlElement
{
/**
* @return string
* @throws AException
*/
public function getHtml()
{
if (IS_ADMIN === true) {
ADebug::error('labelHtmlElement', E_USER_ERROR, 'You cannot to build Label-field from Admin-side!');
return null;
}
$this->extendAndBatchAssign(
[
'name' => $this->name,
'id' => $this->element_id,
'text' => str_replace('"', '"', ($this->text ?: $this->value)),
'attr' => $this->attr,
'style' => $this->style,
'help_url' => $this->help_url,
]
);
return $this->view->fetch($this->template ?: 'form/label.tpl');
}
}
/**
* @property string $name
* @property float|int $min
* @property float|int $max
* @property float|int $step
* @property float|int $from
* @property float|int $to
* @property boolean $disabled
*/
class RangeHtmlElement extends HtmlElement
{
public function getHtml()
{
$data = [
'id' => $this->element_id,
'name' => $this->name,
'min' => $this->min,
'max' => $this->max,
'step' => $this->step,
'from' => $this->from,
'to' => $this->to,
'disabled' => $this->disabled,
];
$this->view->batchAssign($data);
return $this->view->fetch($this->template ?: 'form/range.tpl');
}
}