%PDF- %PDF- 403WebShell
403Webshell
Server IP : 37.220.80.31  /  Your IP : 18.217.198.254
Web Server : Apache/2.4.52 (Ubuntu)
System : Linux 3051455-guretool.twc1.net 5.15.0-107-generic #117-Ubuntu SMP Fri Apr 26 12:26:49 UTC 2024 x86_64
User : www-root ( 1010)
PHP Version : 7.4.33
Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,
MySQL : OFF  |  cURL : ON  |  WGET : OFF  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /var/www/www-root/data/www/dev.artlot24.ru/bitrix/modules/sale/lib/internals/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/www-root/data/www/dev.artlot24.ru/bitrix/modules/sale/lib/internals/input.php
<?php

namespace Bitrix\Sale\Internals\Input;

use Bitrix\Location\Service\FormatService;
use Bitrix\Main\Event;
use	Bitrix\Main\SystemException,
	Bitrix\Main\Localization\Loc;
use Bitrix\Main\EventResult;
use Bitrix\Main\Loader;
use Bitrix\Main\Web\Json;

Loc::loadMessages(__FILE__);

// TODO integrate with input.js on adding multiple item
class Manager
{
	static function initJs()
	{
		static $done = false;

		if (! $done)
		{
			$done = true;

			if (Loader::includeModule('location'))
			{
				\Bitrix\Main\UI\Extension::load('sale.address');
			}

			\CJSCore::RegisterExt('input', array(
				'js'   => [
					'/bitrix/js/sale/input.js'
				],
				'lang' => '/bitrix/modules/sale/lang/'.LANGUAGE_ID.'/lib/internals/input.php',
			));
			\CJSCore::Init(array('input'));

			print('<div style="display:none">');
			$GLOBALS['APPLICATION']->IncludeComponent("bitrix:sale.location.selector.".\Bitrix\Sale\Location\Admin\LocationHelper::getWidgetAppearance(), "", array(
				"ID" => '',
				"CODE" => '',
				"INPUT_NAME" => 'SALE_LOCATION_SELECTOR_RESOURCES',
				"PROVIDE_LINK_BY" => 'code',

				"FILTER_BY_SITE" => 'Y',

				"SHOW_DEFAULT_LOCATIONS" => 'Y',
				"SEARCH_BY_PRIMARY" => 'Y',

				"JS_CONTROL_GLOBAL_ID" => 'SALE_LOCATION_SELECTOR_RESOURCES',
				//"INITIALIZE_BY_GLOBAL_EVENT" => 'sale-event-never-happen',
				"USE_JS_SPAWN" => 'Y'
			),
				false,
				array('HIDE_ICONS' => 'Y')
			);
			print('</div>');
		}
	}

	protected static $types = array();

	/** Return html representation of value.
	 * @param array $input - input settings values
	 * @param mixed $value - value to render
	 * @return string - html
	 * @throws SystemException
	 */
	static function getViewHtml(array $input, $value = null)
	{
		if (! static::$initialized)
			static::initialize();

		if ($type = static::$types[$input['TYPE']])
			return call_user_func(array($type['CLASS'], __FUNCTION__), $input, $value);
		else
			throw new SystemException('invalid input type in '.print_r($input, true), 0, __FILE__, __LINE__);
	}

	/** Return html input control for value.
	 * @param string $name - name for input control (eg: 'email', 'person[1][name]')
	 * @param array $input - input settings values
	 * @param mixed $value - value to render
	 * @return string - html
	 * @throws SystemException
	 */
	static function getEditHtml($name, array $input, $value = null)
	{
		if (! static::$initialized)
			static::initialize();

		if ($type = static::$types[$input['TYPE']])
			return call_user_func(array($type['CLASS'], __FUNCTION__), $name, $input, $value);
		else
			throw new SystemException('invalid input type in '.print_r($input, true), 0, __FILE__, __LINE__);
	}

	/**
	 * @param $name
	 * @param array $input
	 * @param null $value
	 * @return mixed
	 * @throws SystemException
	 */
	static function getFilterEditHtml($name, array $input, $value = null)
	{
		if (! static::$initialized)
			static::initialize();

		if ($type = static::$types[$input['TYPE']])
			return call_user_func(array($type['CLASS'], __FUNCTION__), $name, $input, $value);
		else
			throw new SystemException('invalid input type in '.print_r($input, true), 0, __FILE__, __LINE__);
	}

	/** Get user input validation errors.
	 * @param array $input - input settings values
	 * @param string|array|null $value - value to validate
	 * @return array - empty array on success OR array ([error code] => error message) on failure
	 * @throws \Bitrix\Main\SystemException
	 */
	static function getError(array $input, $value)
	{
		if (! static::$initialized)
			static::initialize();

		if ($type = static::$types[$input['TYPE']])
			return call_user_func(array($type['CLASS'], __FUNCTION__), $input, $value);
		else
			throw new SystemException('invalid input type in '.print_r($input, true), 0, __FILE__, __LINE__);
	}

	/**
	 * @param array $input
	 * @param $value
	 *
	 * @return mixed
	 * @throws SystemException
	 */
	static function getRequiredError(array $input, $value)
	{
		if (! static::$initialized)
			static::initialize();

		if ($type = static::$types[$input['TYPE']])
		{
			return call_user_func(array($type['CLASS'], __FUNCTION__), $input, $value);
		}
		else
		{
			throw new SystemException('invalid input type in '.print_r($input, true), 0, __FILE__, __LINE__);
		}
	}

	/** Get normalized user input value (for example to save to database).
	 * Before saving to database check value for errors with Manager::getError!
	 * @param array $input - input settings values
	 * @param string|array|null $value - value to normalize
	 * @return mixed result
	 * @throws \Bitrix\Main\SystemException
	 */
	static function getValue(array $input, $value)
	{
		if (! static::$initialized)
			static::initialize();

		if ($type = static::$types[$input['TYPE']])
			return call_user_func(array($type['CLASS'], __FUNCTION__), $input, $value);
		else
			throw new SystemException('invalid input type in '.print_r($input, true), 0, __FILE__, __LINE__);
	}

	/** Get multiple value.
	 * @param array $input
	 * @param mixed $value
	 * @return array - if value is single, wrap it in array (except null, which gets empty array)
	 * @throws \Bitrix\Main\SystemException
	 */
	static function asMultiple(array $input, $value)
	{
		if (! static::$initialized)
			static::initialize();

		if ($type = static::$types[$input['TYPE']])
			return call_user_func(array($type['CLASS'], __FUNCTION__), $value);
		else
			throw new SystemException('invalid input type in '.print_r($input, true), 0, __FILE__, __LINE__);
	}

	/** Get settings inputs for user control.
	 * @param array $input - input settings values
	 * @param string|null $reload - javascript form reload action
	 * @return array - ([setting name] => input array)
	 * @throws \Bitrix\Main\SystemException
	 */
	static function getSettings(array $input, $reload = null)
	{
		if (! static::$initialized)
			static::initialize();

		if ($type = static::$types[$input['TYPE']])
			return call_user_func(array($type['CLASS'], __FUNCTION__), $input, $reload);
		else
			throw new SystemException('invalid input type in '.print_r($input, true), 0, __FILE__, __LINE__);
	}

	/** Get settings, common to all input types.
	 * @param array $input - input settings values
	 * @param string|null $reload - javascript form reload action
	 * @return array - ([setting name] => input array)
	 */
	static function getCommonSettings(array $input, $reload = null)
	{
		if (! static::$initialized)
			static::initialize();

		$typeOptions = array();

		foreach (static::$types as $k => $v)
			$typeOptions[$k] = $v['NAME']." [$k]";

		$hasMultipleSupport = true;
		if (isset(static::$types[$input['TYPE']]))
		{
			/** @var Base $typeClass */
			$typeClass = static::$types[$input['TYPE']]['CLASS'];

			if (!$typeClass::hasMultipleValuesSupport())
			{
				$hasMultipleSupport = false;
			}
		}

		$multiple = array('TYPE' => 'Y/N' , 'LABEL' => Loc::getMessage('INPUT_MULTIPLE'));

		if (!$hasMultipleSupport)
		{
			$multiple['DISABLED_YN'] = 'N';
		}
		else
		{
			$multiple['ONCLICK'] = $reload;
		}

		$result = [
			'TYPE'     => array('TYPE' => 'ENUM', 'LABEL' => Loc::getMessage('INPUT_TYPE'), 'OPTIONS' => $typeOptions, 'REQUIRED' => 'Y', 'ONCHANGE' => $reload),
			'REQUIRED' => array('TYPE' => 'Y/N' , 'LABEL' => Loc::getMessage('INPUT_REQUIRED')),
			'MULTIPLE' => $multiple,
			'VALUE'    => array('LABEL' => Loc::getMessage('INPUT_VALUE'), 'REQUIRED' => 'N') + $input,
		];

		return $result;
	}

	/** Get all registered types.
	 * @return array - ([TYPE NAME] => array('CLASS', 'NAME', ...))
	 */
	static function getTypes()
	{
		if (! static::$initialized)
			static::initialize();

		return static::$types;
	}

	/** Register new type.
	 * @param string $name - type name
	 * @param array $type - type parameters
	 *      'CLASS' => __NAMESPACE__.'ClassName'
	 *      'NAME' => Loc::getMessage('CLASS_LOCALIZED_NAME')
	 * @return void
	 * @throws SystemException
	 */
	static function register($name, array $type)
	{
		if (isset(static::$types[$name]))
		{
			throw new SystemException('duplicate type '.$name, 0, __FILE__, __LINE__);
		}

		if (! class_exists($type['CLASS']))
		{
			throw new SystemException('undefined CLASS in '.print_r($type, true), 0, __FILE__, __LINE__);
		}

		if (! is_subclass_of($type['CLASS'], __NAMESPACE__.'\Base'))
		{
			throw new SystemException($type['CLASS'].' does not implement Input\Base', 0, __FILE__, __LINE__);
		}

		static::$types[$name] = $type;
	}

	protected static $initialized;

	protected static function initialize()
	{
		static::$initialized = true;

		/** @var Event $event */
		$event = new Event('sale', 'registerInputTypes', static::$types);
		$event->send();

		if ($event->getResults())
		{
			foreach($event->getResults() as $eventResult)
			{
				if ($eventResult->getType() != EventResult::SUCCESS)
					continue;

				if ($params = $eventResult->getParameters())
				{
					if(!empty($params) && is_array($params))
					{
						static::$types = array_merge(static::$types, $params);
					}
				}
			}
		}
	}
}

abstract class Base
{
	const MULTITAG = 'div';

	/** Check if value is multiple.
	 * @param $value
	 * @return bool
	 */
	static function isMultiple($value)
	{
		return is_array($value);
	}

	/** Get single value.
	 * @param $value
	 * @return mixed - if value is multiple, get first meaningful value (which is not null)
	 */
	static function asSingle($value)
	{
		if (static::isMultiple($value))
		{
			$v = null;

			foreach ($value as $v)
				if ($v) // !== null) TODO maybe??
					break;

			return $v;
		}
		else
		{
			return $value;
		}
	}

	static function asMultiple($value)
	{
		if (static::isMultiple($value))
		{
			return array_diff($value, array("", NULL, false));
		}
		else
		{
			return $value === null ? array() : array($value);
		}
	}

	public static function getViewHtml(array $input, $value = null)
	{
		if ($value === null)
			$value = $input['VALUE'];

		if ($input['MULTIPLE'] == 'Y')
		{
			$tag = isset($input['MULTITAG']) ? htmlspecialcharsbx($input['MULTITAG']) : static::MULTITAG;
			[$startTag, $endTag] = $tag ? array("<$tag>", "</$tag>") : array('', '');

			$html = '';

			foreach (static::asMultiple($value) as $value)
				$html .= $startTag.static::getViewHtmlSingle($input, $value).$endTag;

			return $html;
		}
		else
		{
			return static::getViewHtmlSingle($input, static::asSingle($value));
		}
	}

	public static function getViewHtmlSingle(array $input, $value)
	{
		$output = $valueText = htmlspecialcharsbx($value);
		if ($input['IS_EMAIL'] == 'Y')
		{
			$output = '<a href="mailto:'.$valueText.'">'.$valueText.'</a>';
		}

		return $output;
	}

	public static function getEditHtml($name, array $input, $value = null)
	{
		$name = htmlspecialcharsbx($name);

		if ($value === null)
			$value = $input['VALUE'];

		$html = '';

		if ($input['HIDDEN'] == 'Y')
		{
			$html .= static::getHiddenRecursive($name
				, $input['MULTIPLE'] == 'Y' ? static::asMultiple($value) : static::asSingle($value)
				, static::extractAttributes($input, array('DISABLED'=>''), array('FORM'=>''), false));
		}
		else
		{
			if ($input['MULTIPLE'] == 'Y')
			{
				$tag = isset($input['MULTITAG']) ? htmlspecialcharsbx($input['MULTITAG']) : static::MULTITAG;
				[$startTag, $endTag] = $tag ? array("<$tag>", "</$tag>") : array('', '');

				$index = -1;

				foreach (static::asMultiple($value) as $value)
				{
					$namix = $name.'['.(++$index).']';
					$html .= $startTag
						.static::getEditHtmlSingle($namix, $input, $value)
						.static::getEditHtmlSingleDelete($namix, $input)
						.$endTag;
				}

				$replace = '##INPUT##NAME##';

				if ($input['DISABLED'] !== 'Y') // TODO
					$html .= static::getEditHtmlInsert($tag, $replace, $name
						, static::getEditHtmlSingle($replace, $input, null).static::getEditHtmlSingleDelete($replace, $input)
						, static::getEditHtmlSingleAfterInsert());
			}
			else
			{
				$html .= static::getEditHtmlSingle($name, $input, static::asSingle($value));
			}
		}

		if ($input['ADDITIONAL_HIDDEN'] === 'Y')
		{
			$html .= static::getHiddenRecursive($name
				, $input['MULTIPLE'] == 'Y' ? static::asMultiple($value) : static::asSingle($value)
				, static::extractAttributes($input, array(), array('FORM'=>''), false));
		}

		return $html;
	}

	/** @return string */
	public static function getEditHtmlSingle($name, array $input, $value)
	{
		throw new SystemException("you must implement [getEditHtmlSingle] or override [getEditHtml] in yor class", 0, __FILE__, __LINE__);
	}

	public static function getEditHtmlSingleDelete($name, array $input)
	{
		return '<label> '.Loc::getMessage('INPUT_DELETE').' <input type="checkbox" onclick="'

			."this.parentNode.previousSibling.disabled = this.checked;"

			.'"> </label>';
	}

	public static function getEditHtmlInsert($tag, $replace, $name, $sample, $after)
	{
		$name = \CUtil::JSEscape($name);
		$sample = \CUtil::JSEscape(htmlspecialcharsbx($sample));

		return '<input type="button" value="'.Loc::getMessage('INPUT_ADD').'" onclick="'

			."var parent = this.parentNode;"
			."var container = document.createElement('$tag');"
			."container.innerHTML = '$sample'.replace(/$replace/g, '{$name}['+parent.childNodes.length+']');"
			."parent.insertBefore(container, this);"

			.$after.'">';
	}

	public static function getEditHtmlSingleAfterInsert()
	{
		return "container.firstChild.focus();";
	}

	public static function getError(array $input, $value)
	{
		$errors = array();
		if ($value === null)
			$value = $input['VALUE'];

		if ($input['MULTIPLE'] == 'Y')
		{

			$index = -1;

			foreach (static::asMultiple($value) as $value)
			{
				if (($value !== '' && $value !== null) && ($error = static::getErrorSingle($input, $value)))
				{
					$errors[++$index] = $error;
				}
			}
		}
		else
		{
			$value = static::asSingle($value);

			if ($value !== '' && $value !== null)
			{
				return static::getErrorSingle($input, $value);
			}
		}

		return $errors;
	}

	/**
	 * @param array $input
	 * @param $value
	 *
	 * @return bool
	 */
	public static function getRequiredError(array $input, $value)
	{
		$errors = array();

		if ($value === null)
			$value = $input['VALUE'];

		if ($input['MULTIPLE'] == 'Y')
		{
			$index = -1;
			foreach (static::asMultiple($value) as $value)
			{
				if ($value === '' || $value === null)
				{
					if ($input['REQUIRED'] == 'Y')
						$errors[++$index] = array('REQUIRED' => Loc::getMessage('INPUT_REQUIRED_ERROR'));
				}
			}
		}
		else
		{
			$value = static::asSingle($value);

			if ($value === '' || $value === null)
			{
				return ($input['REQUIRED'] == 'Y')
					? array('REQUIRED' => Loc::getMessage('INPUT_REQUIRED_ERROR'))
					: array();
			}
		}

		return $errors;
	}

	/**
	 * @param array $input
	 * @param $value
	 *
	 * @throws SystemException
	 */
	public static function getErrorSingle(array $input, $value)
	{
		throw new SystemException("you must implement [getErrorSingle] or override [getError] in yor class", 0, __FILE__, __LINE__);
	}

	public static function getValue(array $input, $value)
	{
		if ($input['DISABLED'] == 'Y')
			return null; // TODO maybe??

		if ($value === null)
			$value = $input['VALUE'];

		if ($input['MULTIPLE'] == 'Y')
		{
			$values = array();

			foreach (static::asMultiple($value) as $value)
			{
				$value = static::getValueSingle($input, $value);
				if ($value !== null)
					$values []= $value;
			}

			return $values ? $values : null;
		}
		else
		{
			return static::getValueSingle($input, static::asSingle($value));
		}
	}

	public static function getValueSingle(array $input, $value)
	{
		return $value;
	}

	public static function getSettings(array $input, $reload)
	{
		return array(); // no settings
	}

	// utils

	protected static function getHiddenRecursive($name, $value, $attributes)
	{
		if (is_array($value))
		{
			$html = '';

			foreach ($value as $k => $v)
				$html .= self::getHiddenRecursive($name.'['.htmlspecialcharsbx($k).']', $v, $attributes);

			return $html;
		}
		else
		{
			return '<input type="hidden" name="'.$name.'" value="'.htmlspecialcharsbx($value).'"'.$attributes.'>';
		}
	}

	/** @deprecated */
	protected static function extractAttributes(array $input, array $boolean, array $other, $withGlobal = true)
	{
		$string = '';

		// add boolean attributes with predefined values or no value

		unset($boolean['REQUIRED']); // TODO remove with HTML5

		static $globalBoolean = array('CONTENTEDITABLE'=>'', 'DRAGGABLE'=>'true', 'SPELLCHECK'=>'', 'TRANSLATE'=>'yes');

		if ($withGlobal)
			$boolean = $globalBoolean + $boolean;

		foreach (array_intersect_key($input, $boolean) as $k => $v)
			if ($v === 'Y' || $v === true)
				$string .= ' '.mb_strtolower($k).($boolean[$k] ? '="'.$boolean[$k].'"' : '');

		// add event attributes with values
		if ($withGlobal)
		{
			static $globalEvents = array(
				'ONABORT'=>1, 'ONBLUR'=>1, 'ONCANPLAY'=>1, 'ONCANPLAYTHROUGH'=>1, 'ONCHANGE'=>1, 'ONCLICK'=>1,
				'ONCONTEXTMENU'=>1, 'ONDBLCLICK'=>1, 'ONDRAG'=>1, 'ONDRAGEND'=>1, 'ONDRAGENTER'=>1, 'ONDRAGLEAVE'=>1,
				'ONDRAGOVER'=>1, 'ONDRAGSTART'=>1, 'ONDROP'=>1, 'ONDURATIONCHANGE'=>1, 'ONEMPTIED'=>1, 'ONENDED'=>1,
				'ONERROR'=>1, 'ONFOCUS'=>1, 'ONINPUT'=>1, 'ONINVALID'=>1, 'ONKEYDOWN'=>1, 'ONKEYPRESS'=>1, 'ONKEYUP'=>1,
				'ONLOAD'=>1, 'ONLOADEDDATA'=>1, 'ONLOADEDMETADATA'=>1, 'ONLOADSTART'=>1, 'ONMOUSEDOWN'=>1, 'ONMOUSEMOVE'=>1,
				'ONMOUSEOUT'=>1, 'ONMOUSEOVER'=>1, 'ONMOUSEUP'=>1, 'ONMOUSEWHEEL'=>1, 'ONPAUSE'=>1, 'ONPLAY'=>1,
				'ONPLAYING'=>1, 'ONPROGRESS'=>1, 'ONRATECHANGE'=>1, 'ONREADYSTATECHANGE'=>1, 'ONRESET'=>1, 'ONSCROLL'=>1,
				'ONSEEKED'=>1, 'ONSEEKING'=>1, 'ONSELECT'=>1, 'ONSHOW'=>1, 'ONSTALLED'=>1, 'ONSUBMIT'=>1, 'ONSUSPEND'=>1,
				'ONTIMEUPDATE'=>1, 'ONVOLUMECHANGE'=>1, 'ONWAITING'=>1,
			);

			$events = array_intersect_key($input, $globalEvents);
			$other = array_diff_key($other, $events);

			foreach ($events as $k => $v)
				if ($v)
					$string .= ' '.mb_strtolower($k).'="'.$v.'"';
		}

		// add other attributes with values

		static $globalOther = array(
			'ACCESSKEY'=>1, 'CLASS'=>1, 'CONTEXTMENU'=>1, 'DIR'=>1, 'DROPZONE'=>1, 'LANG'=>1, 'STYLE'=>1, 'TABINDEX'=>1,
			'TITLE'=>1, 'ID' => 1,
			'XML:LANG'=>1, 'XML:SPACE'=>1, 'XML:BASE'=>1
		);

		if ($withGlobal)
			$other += $globalOther;

		foreach (array_intersect_key($input, $other) as $k => $v)
			if ($v)
				$string .= ' '.mb_strtolower($k).'="'.htmlspecialcharsbx($v).'"';

		// add data attributes
		if ($withGlobal && is_array($input['DATA']))
		{
			foreach ($input['DATA'] as $k => $v)
				$string .= ' data-'.htmlspecialcharsbx($k).'="'.htmlspecialcharsbx($v).'"';
		}

		return $string;
	}

	/**
	 * @return bool
	 */
	public static function hasMultipleValuesSupport()
	{
		return true;
	}
}

/**
 * String
 */
class StringInput extends Base // String reserved in php 7
{
	protected static $patternDelimiters = array('/', '#', '~');

	public static function getEditHtmlSingle($name, array $input, $value)
	{
		if ($input['MULTILINE'] == 'Y')
		{
			$attributes = static::extractAttributes($input,
				array('DISABLED'=>'', 'READONLY'=>'', 'AUTOFOCUS'=>'', 'REQUIRED'=>''),
				array('FORM'=>1, 'MAXLENGTH'=>1, 'PLACEHOLDER'=>1, 'DIRNAME'=>1, 'ROWS'=>1, 'COLS'=>1, 'WRAP'=>1));

			return '<textarea name="'.$name.'"'.$attributes.'>'.htmlspecialcharsbx($value).'</textarea>';
		}
		else
		{
			$attributes = static::extractAttributes($input,
				array('DISABLED'=>'', 'READONLY'=>'', 'AUTOFOCUS'=>'', 'REQUIRED'=>'', 'AUTOCOMPLETE'=>'on'),
				array('FORM'=>1, 'MAXLENGTH'=>1, 'PLACEHOLDER'=>1, 'DIRNAME'=>1, 'SIZE'=>1, 'LIST'=>1));

			return '<input type="text" name="'.$name.'" value="'.htmlspecialcharsbx($value).'"'.$attributes.'>';
		}
	}

	/**
	 * @param $name
	 * @param array $input
	 * @param $value
	 * @return string
	 */
	public static function getFilterEditHtml($name, array $input, $value)
	{
		return static::getEditHtmlSingle($name, $input, $value);
	}

	public static function getErrorSingle(array $input, $value)
	{
		$errors = array();

		$value = trim($value);

		if ($input['MINLENGTH'] && mb_strlen($value) < $input['MINLENGTH'])
			$errors['MINLENGTH'] = Loc::getMessage('INPUT_STRING_MINLENGTH_ERROR', array("#NUM#" => $input['MINLENGTH']));

		if ($input['MAXLENGTH'] && mb_strlen($value) > $input['MAXLENGTH'])
			$errors['MAXLENGTH'] = Loc::getMessage('INPUT_STRING_MAXLENGTH_ERROR', array("#NUM#" => $input['MAXLENGTH']));



		if (strval(trim($input['PATTERN'])) != "")
		{
			$issetDelimiter = false;
			$pattern = trim($input['PATTERN']);

			if (isset($pattern[0]) && in_array($pattern[0], static::$patternDelimiters) && mb_strrpos($pattern, $pattern[0]) !== false)
			{
				$issetDelimiter = true;
			}

			$matchPattern = $pattern;
			if (!$issetDelimiter)
			{
				$matchPattern = "/".$pattern."/";
			}

			if (!preg_match($matchPattern, $value))
				$errors['PATTERN'] = Loc::getMessage('INPUT_STRING_PATTERN_ERROR');
		}



		return $errors;
	}

	static function getSettings(array $input, $reload)
	{
		$settings = array(
			'MINLENGTH' => array('TYPE' => 'NUMBER', 'LABEL' => Loc::getMessage('INPUT_STRING_MINLENGTH'), 'MIN' => 0, 'STEP' => 1),
			'MAXLENGTH' => array('TYPE' => 'NUMBER', 'LABEL' => Loc::getMessage('INPUT_STRING_MAXLENGTH'), 'MIN' => 0, 'STEP' => 1),
			'PATTERN'   => array('TYPE' => 'STRING', 'LABEL' => Loc::getMessage('INPUT_STRING_PATTERN'  )),
			'MULTILINE' => array('TYPE' => 'Y/N'   , 'LABEL' => Loc::getMessage('INPUT_STRING_MULTILINE'), 'ONCLICK' => $reload),
		);

		if ($input['MULTILINE'] == 'Y')
		{
			$settings['COLS'] = array('TYPE' => 'NUMBER', 'LABEL' => Loc::getMessage('INPUT_STRING_SIZE'), 'MIN' => 0, 'STEP' => 1);
			$settings['ROWS'] = array('TYPE' => 'NUMBER', 'LABEL' => Loc::getMessage('INPUT_STRING_ROWS'), 'MIN' => 0, 'STEP' => 1);
		}
		else
		{
			$settings['SIZE'] = array('TYPE' => 'NUMBER', 'LABEL' => Loc::getMessage('INPUT_STRING_SIZE'), 'MIN' => 0, 'STEP' => 1);
		}

		return $settings;
	}

	/**
	 * @param $value
	 *
	 * @return bool
	 */
	public static function isDeletedSingle($value)
	{
		return is_array($value) && $value['DELETE'];
	}

}

Manager::register('STRING', array(
	'CLASS' => __NAMESPACE__.'\StringInput',
	'NAME' => Loc::getMessage('INPUT_STRING'),
));

/**
 * Number
 */
class Number extends Base
{
	public static function getEditHtmlSingle($name, array $input, $value)
	{
		// TODO HTML5 from IE10: remove SIZE; Add MIN, MAX, STEP; Change type="number"

		$size = 5;

		if (($s = mb_strlen(strval($input['MIN']))) && $s > $size)
			$size = $s;

		if (($s = mb_strlen(strval($input['MAX']))) && $s > $size)
			$size = $s;

		if (($s = mb_strlen(strval($input['STEP']))) && $s > $size)
			$size = $s;

		$input['SIZE'] = $size;

		$attributes = static::extractAttributes($input,
			array('DISABLED'=>'', 'READONLY'=>'', 'AUTOFOCUS'=>'', 'REQUIRED'=>'', 'AUTOCOMPLETE'=>'on'),
			array('FORM'=>1, 'LIST'=>1, 'PLACEHOLDER'=>1, 'SIZE'=>1));

		return '<input type="text" name="'.$name.'" value="'.htmlspecialcharsbx($value).'"'.$attributes.'>';
	}

	/**
	 * @param $name
	 * @param array $input
	 * @param $value
	 * @return string
	 */
	public static function getFilterEditHtml($name, array $input, $value)
	{
		return static::getEditHtmlSingle($name, $input, $value);
	}

	public static function getErrorSingle(array $input, $value)
	{
		$errors = array();

		if (is_numeric($value))
		{
			$value = (double) $value;

			if (!empty($input['MIN']) && $value < $input['MIN'])
				$errors['MIN'] = Loc::getMessage('INPUT_NUMBER_MIN_ERROR', array("#NUM#" => $input['MIN']));

			if (!empty($input['MAX']) && $value > $input['MAX'])
				$errors['MAX'] = Loc::getMessage('INPUT_NUMBER_MAX_ERROR', array("#NUM#" => $input['MAX']));

			if ($input['STEP'])
			{
				$step = (double) $input['STEP'];

				$value = (double) abs($value - ($input['MIN'] ? $input['MIN'] : 0.0));

				if (! ($value / pow(2.0, 53) > $step))
				{
					$remainder = (double) abs($value - $step * round($value / $step));
					$acceptableError = (double) ($step / pow(2.0, 24));

					if ($acceptableError < $remainder && ($step - $acceptableError) > $remainder)
						$errors['STEP'] = Loc::getMessage('INPUT_NUMBER_STEP_ERROR', array("#NUM#" => $input['STEP']));
				}
			}
		}
		else
		{
			$errors['NUMERIC'] = Loc::getMessage('INPUT_NUMBER_NUMERIC_ERROR');
		}

		return $errors;
	}

	public static function getSettings(array $input, $reload)
	{
		return array(
			'MIN'  => array('TYPE' => 'NUMBER', 'LABEL' => Loc::getMessage('INPUT_NUMBER_MIN' )),
			'MAX'  => array('TYPE' => 'NUMBER', 'LABEL' => Loc::getMessage('INPUT_NUMBER_MAX' )),
			'STEP' => array('TYPE' => 'NUMBER', 'LABEL' => Loc::getMessage('INPUT_NUMBER_STEP')),
		);
	}
}

Manager::register('NUMBER', array(
	'CLASS' => __NAMESPACE__.'\Number',
	'NAME' => Loc::getMessage('INPUT_NUMBER'),
));

/**
 * Either Y or N
 */
class EitherYN extends Base
{
	public static function getViewHtmlSingle(array $input, $value)
	{
		return $value == 'Y' ? Loc::getMessage('INPUT_EITHERYN_Y') : Loc::getMessage('INPUT_EITHERYN_N');
	}

	public static function getEditHtmlSingle($name, array $input, $value)
	{
		$hiddenAttributes = static::extractAttributes($input, array('DISABLED'=>''), array('FORM'=>1), false);
		$checkboxAttributes = static::extractAttributes($input, array('DISABLED'=>'', 'AUTOFOCUS'=>'', 'REQUIRED'=>''), array('FORM'=>1));

		if (isset($input['DISABLED_YN']))
		{
			return '<input type="hidden" name="'.$name.'" value="' . (($input['DISABLED_YN'] == 'Y') ? 'Y' : 'N') . '">'
				.'<input type="checkbox" '.($input['DISABLED_YN'] == 'Y' ? ' checked' : '').'disabled'.'>';
		}
		else
		{
			return '<input type="hidden" name="'.$name.'" value="N"'.$hiddenAttributes.'>'
				.'<input type="checkbox" name="'.$name.'" value="Y"'.($value == 'Y' ? ' checked' : '').$checkboxAttributes.'>';
		}

	}

	/**
	 * @param $name
	 * @param array $input
	 * @param $value
	 * @return string
	 */
	public static function getFilterEditHtml($name, array $input, $value)
	{
		$hiddenAttributes = static::extractAttributes($input, array('DISABLED'=>''), array('FORM'=>1), false);

		$checkboxAttributes = static::extractAttributes($input, array('DISABLED'=>'', 'AUTOFOCUS'=>'', 'REQUIRED'=>''), array('FORM'=>1));

		return '<select name="'.$name.'" '.$hiddenAttributes.'>
					<option value="">'.Loc::getMessage('INPUT_EITHERYN_ALL').'</option>
					<option value="Y"'.($value=="Y" ? " selected" : '').' '.$checkboxAttributes.'>'.Loc::getMessage('INPUT_EITHERYN_Y').'</option>
					<option value="N"'.($value=="N" ? " selected" : '').' '.$checkboxAttributes.'>'.Loc::getMessage('INPUT_EITHERYN_N').'</option>
				</select>';
	}

	public static function getErrorSingle(array $input, $value)
	{
		if ($input['REQUIRED'] == 'Y' && ($value === '' || $value === null))
			return array('REQUIRED' => Loc::getMessage('INPUT_REQUIRED_ERROR'));

		return ($value == 'N' || $value == 'Y')
			? array()
			: array('INVALID' => Loc::getMessage('INPUT_INVALID_ERROR'));
	}

	public static function getValueSingle(array $input, $value)
	{
		return $value == 'Y' ? 'Y' : 'N';
	}
}

Manager::register('Y/N', array(
	'CLASS' => __NAMESPACE__.'\EitherYN',
	'NAME'  => Loc::getMessage('INPUT_EITHERYN'),
));

/**
 * Enumeration
 */
class Enum extends Base
{
	private static function flatten(array $array)
	{
		$result = array();

		foreach ($array as $key => $value)
		{
			if (is_array($value))
			{
				$result = $result + $value;
			}
			else
			{
				$result[$key] = $value;
			}
		}

		return $result;
	}

	public static function getViewHtmlSingle(array $input, $value) // TODO optimize to getViewHtml
	{
		$options = $input['OPTIONS'];

		if (is_array($options))
		{
			$options = self::flatten($options);

			if ($v = $options[$value])
				$value = $v;
		}

		return htmlspecialcharsbx($value);
	}

	/**
	 * @param $name
	 * @param array $input
	 * @param $value
	 * @return string
	 */
	public static function getFilterEditHtml($name, array $input, $value)
	{
		return static::getEditHtml($name, $input, $value);
	}

	public static function getEditHtml($name, array $input, $value = null)
	{
		$options = $input['OPTIONS'];

		if (! is_array($options))
			return Loc::getMessage('INPUT_ENUM_OPTIONS_ERROR');

		$multiple = $input['MULTIPLE'] == 'Y';

		$name = htmlspecialcharsbx($name);

		if ($value === null && isset($input['VALUE']))
			$value = $input['VALUE'];

		$originalValue = $value;
		$html = '';

		if ($input['HIDDEN'] == 'Y')
		{
			$html .= static::getHiddenRecursive($name
				, $multiple ? static::asMultiple($value) : static::asSingle($value)
				, static::extractAttributes($input, array('DISABLED'=>''), array('FORM'=>1), false));
		}
		else
		{
			if ($value === null)
				$value = array();
			else
				$value = $multiple ? array_flip(static::asMultiple($value)) : array(static::asSingle($value) => true);

			if ($input['MULTIELEMENT'] == 'Y')
			{
				$tag = isset($input['MULTITAG']) ? htmlspecialcharsbx($input['MULTITAG']) : static::MULTITAG;
				[$startTag, $endTag] = $tag ? array("<$tag>", "</$tag>") : array('', '');

				$attributes = static::extractAttributes($input, array('DISABLED'=>''), array('FORM'=>1), false);

				$type = 'radio';

				if ($multiple)
				{
					$type = 'checkbox';
					$name .= '[]';
				}

				$html .= self::getEditOptionsHtml($options, $value, ' checked',
					'<fieldset><legend>{GROUP}</legend>{OPTIONS}</fieldset>',
					$startTag.'<label><input type="'.$type.'" name="'.$name.'" value="{VALUE}"{SELECTED}'.$attributes.'> {TEXT} </label>'.$endTag
				);
			}
			else // select
			{
				$attributes = static::extractAttributes($input, array('DISABLED'=>'', 'AUTOFOCUS'=>'', 'REQUIRED'=>''), array('FORM'=>1, 'SIZE'=>1));

				$html .= '<select'.$attributes.' name="'.$name.($multiple ? '[]" multiple>' : '">');

				$html .= self::getEditOptionsHtml($options, $value, ' selected',
					'<optgroup label="{GROUP}">{OPTIONS}</optgroup>',
					'<option value="{VALUE}"{SELECTED}>{TEXT}</option>'
				);

				$html .= '</select>';
			}
		}

		if ($input['ADDITIONAL_HIDDEN'] === 'Y')
		{
			$html .= static::getHiddenRecursive($name
				, $multiple ? static::asMultiple($originalValue) : static::asSingle($originalValue)
				, static::extractAttributes($input, array(), array('FORM'=>1), false));
		}

		return $html;
	}

	private static function getEditOptionsHtml(array $options, array $selected, $selector, $group, $option)
	{
		$result = '';

		foreach ($options as $key => $value)
		{
			$result .= is_array($value)
				? str_replace(
					array('{GROUP}', '{OPTIONS}'),
					array(
						htmlspecialcharsEx($key),
						self::getEditOptionsHtml($value, $selected, $selector, $group, $option),
					),
					$group
				)
				: str_replace(
					array('{VALUE}', '{SELECTED}', '{TEXT}'),
					array(
						htmlspecialcharsEx($key),
						isset($selected[$key]) ? $selector : '',
						htmlspecialcharsEx($value) ?: htmlspecialcharsEx($key),
					),
					$option
				);
		}

		return $result;
	}

	public static function getErrorSingle(array $input, $value)  // TODO optimize to getError
	{
		$options = $input['OPTIONS'];

		if (is_array($options))
		{
			$options = self::flatten($options);

			return isset($options[$value])
				? array()
				: array('INVALID' => Loc::getMessage('INPUT_INVALID_ERROR'));
		}
		else
		{
			return array('OPTIONS' => Loc::getMessage('INPUT_ENUM_OPTIONS_ERROR'));
		}
	}

	static function getSettings(array $input, $reload)
	{
		$settings = array(
			// TODO maybe??? 'OPTIONS' => array('TYPE' => 'TUPLE'),
			'MULTIELEMENT' => array('TYPE' => 'Y/N', 'LABEL' => Loc::getMessage('INPUT_ENUM_MULTIELEMENT'), 'ONCLICK' => $reload),
		);

		if ($input['MULTIELEMENT'] != 'Y')
			$settings['SIZE'] = array('TYPE' => 'NUMBER', 'LABEL' => Loc::getMessage('INPUT_ENUM_SIZE'), 'MIN' => 0, 'STEP' => 1);

		return $settings;
	}
}

Manager::register('ENUM', array(
	'CLASS' => __NAMESPACE__.'\Enum',
	'NAME' => Loc::getMessage('INPUT_ENUM'),
));

/**
 * File
 * Must use: File::getPostWithFiles before using this type!
 */
class File extends Base
{
	/** Normalize $_FILES structure and join it with $_POST.
	 * Must be called before using File type!
	 *
	 * PHP default $_FILES structure:
	 *
	 * Array([name]     => Array([0] => photo.jpg     , [1] =>  )
	 *       [type]     => Array([0] => image/jpeg    , [1] =>  )
	 *       [tmp_name] => Array([0] => /tmp/dsk4le5se, [1] =>  )
	 *       [error]    => Array([0] => 0             , [1] => 4)
	 *       [size]     => Array([0] => 45673         , [1] => 0))
	 *
	 * Normalized files structure:
	 *
	 * Array(
	 *     [0] => Array(
	 *         [name]     => photo.jpg
	 *         [type]     => image/jpeg
	 *         [tmp_name] => /tmp/dsk4le5se
	 *         [error]    => 0
	 *         [size]     => 45673
	 *     )
	 *     [1] => Array(
	 *         [name]     =>
	 *         [type]     =>
	 *         [tmp_name] =>
	 *         [error]    => 4
	 *         [size]     =>
	 *     )
	 * )
	 *
	 * Example: <input type="file" name="PROFILE[5][PHOTOS][]"> - will be normalized as expected in post
	 *
	 * @param array $post  - $_POST
	 * @param array $files - $_FILES
	 * @return array       - post + fixed files
	 */
	static function getPostWithFiles(array $post, array $files)
	{
		foreach ($files as $key => $file)
		{
			if (! is_array($post[$key]))
				$post[$key] = array();

			foreach ($file as $property => $value)
			{
				if (is_array($value))
					self::getPostWithFilesRecursive($post[$key], $value, $property);
				else
					$post[$key][$property] = $value;
			}
		}

		return $post;
	}

	private static function getPostWithFilesRecursive(array &$root, array $values, $property)
	{
		foreach ($values as $key => $value)
		{
			if (! is_array($root[$key]))
				$root[$key] = array();

			if (is_array($value))
				self::getPostWithFilesRecursive($root[$key], $value, $property);
			else
				$root[$key][$property] = $value;
		}
	}

	/** @deprecated
	 * Load file array from database.
	 * @param $value
	 * @return array - file array
	 */
	static function loadInfo($value)
	{
		if (! $multiple = static::isMultiple($value))
			$value = array($value);

		foreach ($value as &$file)
			$file = self::loadInfoSingle($file);

		return $multiple ? $value : reset($value);
	}

	/** deprecated */
	static function loadInfoSingle($file)
	{
		if (is_array($file))
		{
			if ($file['SRC'])
				return $file; // already loaded

			$fileId = $file['ID'];
		}
		else
		{
			$fileId = $file;
		}

		if ($fileId && is_numeric($fileId) && ($row = \CFile::GetFileArray($fileId)))
		{
			$file = (is_array($file) ? $file : array('ID' => $fileId)) + $row;
		}

		return $file;
	}

	/** Check if file is marked for deletion.
	 * @param $value
	 * @return bool
	 */
	static function isDeletedSingle($value)
	{
		return is_array($value) && $value['DELETE'];
	}

	/** Check if file is uploaded.
	 * @param $value
	 * @return bool
	 */
	static function isUploadedSingle($value)
	{
		return is_array($value) && $value['error'] == UPLOAD_ERR_OK && is_uploaded_file($value['tmp_name']);
	}

	// input methods ///////////////////////////////////////////////////////////////////////////////////////////////////

	static function isMultiple($value)
	{
		$isMultiple = false;

		if (isset($value['ID']))
		{
			return $isMultiple;
		}

		if (\is_array($value))
		{
			$file = current($value);
			if (\is_array($file) || ((int)$file > 0))
			{
				$isMultiple = true;
			}
		}

		return $isMultiple;
	}

	public static function getViewHtmlSingle(array $input, $value)
	{
		if (! is_array($value))
			$value = array('ID' => $value);

		if ($src = $value['SRC'])
		{
			$attributes = ' href="'.htmlspecialcharsbx($src).'" title="'.htmlspecialcharsbx(Loc::getMessage('INPUT_FILE_DOWNLOAD')).'"';

			if (\CFile::IsImage($src, $value['CONTENT_TYPE']) && $value['FILE_SIZE'] > 100000)
			{
				$previewImage = \CFile::ResizeImageGet($value['ID'], array(200,200), BX_RESIZE_IMAGE_PROPORTIONAL);
				if (is_array($previewImage))
					$src = $previewImage['src'];
			}

			$content = \CFile::IsImage($value['SRC'], $value['CONTENT_TYPE'])
				? '<img src="'.$src.'" border="0" alt="" style="max-height:100px; max-width:100px">'
				: htmlspecialcharsbx($value['ORIGINAL_NAME']);
		}
		else
		{
			$attributes = '';
			$content = htmlspecialcharsbx($value['ORIGINAL_NAME']);
		}

		if (! $content)
			$content = $value['FILE_NAME'];

		if (! $content)
			$content = $value['ID'];

		return "<a$attributes>$content</a>";
	}

	/**
	 * @param $name
	 * @param array $input
	 * @param $value
	 * @return string
	 */
	public static function getFilterEditHtml($name, array $input, $value)
	{
		return static::getEditHtmlSingle($name, $input, $value);
	}

	public static function getEditHtmlSingle($name, array $input, $value)
	{
		if (! is_array($value))
		{
			$value = array('ID' => $value);
		}

		if ($value['DELETE'])
		{
			unset($value['ID']);
		}

		$input['ONCHANGE'] =
			"var anchor = this.previousSibling.previousSibling;".
			"if (anchor.firstChild) anchor.removeChild(anchor.firstChild);".
			"anchor.appendChild(document.createTextNode(this.value.split(/(\\\\|\\/)/g).pop()));".
			$input['ONCHANGE'];

		// TODO HTML5 add MULTIPLE
		$fileAttributes = static::extractAttributes($input,
			array('DISABLED'=>'', 'AUTOFOCUS'=>'', 'REQUIRED'=>''),
			array('FORM'=>1, 'ACCEPT'=>1));

		$otherAttributes = static::extractAttributes($input, array('DISABLED'=>''), array('FORM'=>1), false);

		return static::getViewHtmlSingle($input, $value)
			.'<input type="hidden" name="'.$name.'[ID]" value="'.htmlspecialcharsbx($value['ID']).'"'.$otherAttributes.'>'
			.'<input type="file" name="'.$name.'" style="position:absolute; visibility:hidden"'.$fileAttributes.'>'
			.'<input type="button" value="'.Loc::getMessage('INPUT_FILE_BROWSE').'" onclick="this.previousSibling.click()">'
			.(
			$input['NO_DELETE']
				? ''
				: '<label> '.Loc::getMessage('INPUT_DELETE').' <input type="checkbox" name="'.$name.'[DELETE]" onclick="'

				."var button = this.parentNode.previousSibling, file = button.previousSibling;"
				."button.disabled = file.disabled = this.checked;"

				.'"'.$otherAttributes.'> </label>'
			);
	}

	public static function getEditHtmlSingleDelete($name, array $input)
	{
		return '';
	}

	public static function getErrorSingle(array $input, $value)
	{
		if (is_array($value))
		{
			if ($value['DELETE'])
			{
				return $input['REQUIRED'] == 'Y'
					? array('REQUIRED' => Loc::getMessage('INPUT_REQUIRED_ERROR'))
					: array();
			}
			elseif (is_uploaded_file($value['tmp_name']))
			{
				$errors = array();

				if ($input['MAXSIZE'] && $value['size'] > $input['MAXSIZE'])
					$errors['MAXSIZE'] = Loc::getMessage('INPUT_FILE_MAXSIZE_ERROR');

				// TODO check: file name, mime type, extension
				//$info = pathinfo($value['name']);

				if ($error = \CFile::CheckFile($value, 0, false, $input['ACCEPT']))
					$errors['CFILE'] = $error;

				return $errors;
			}
			else
			{
				switch ($value['error'])
				{
					case UPLOAD_ERR_OK: return array();	//file uploaded successfully

					case UPLOAD_ERR_INI_SIZE:
					case UPLOAD_ERR_FORM_SIZE: return array('MAXSIZE' => Loc::getMessage('INPUT_FILE_MAXSIZE_ERROR'));

					case UPLOAD_ERR_PARTIAL: return array('PARTIAL' => Loc::getMessage('INPUT_FILE_PARTIAL_ERROR'));

					case UPLOAD_ERR_NO_FILE:

						return $input['REQUIRED'] == 'Y' && (! is_numeric($value['ID']) || $value['DELETE'])
							? array('REQUIRED' => Loc::getMessage('INPUT_REQUIRED_ERROR'))
							: array();

					// TODO case UPLOAD_ERR_NO_TMP_DIR  UPLOAD_ERR_CANT_WRITE  UPLOAD_ERR_EXTENSION
					default: return array('INVALID' => Loc::getMessage('INPUT_INVALID_ERROR'));
				}
			}
		}
		elseif (is_numeric($value))
		{
			// TODO check if file id exists maybe ???
			return array();
		}
		else
		{
			return array('INVALID' => Loc::getMessage('INPUT_INVALID_ERROR'));
		}
	}

	public static function getValueSingle(array $input, $value)
	{
		if (is_array($value))
		{
			if ($value['DELETE'])
				return null;

			$value = $value['ID'];
		}

		return is_numeric($value) ? $value : null;
	}

	public static function getSettings(array $input, $reload)
	{
		return array(
			'MAXSIZE' => array('TYPE' => 'NUMBER', 'LABEL' => Loc::getMessage('INPUT_FILE_MAXSIZE'), 'MIN' => 0, 'STEP' => 1),
			'ACCEPT'  => array('TYPE' => 'STRING', 'LABEL' => Loc::getMessage('INPUT_FILE_ACCEPT' ), 'PLACEHOLDER' => 'png, doc, zip'),
		);
	}
}

Manager::register('FILE', array(
	'CLASS' => __NAMESPACE__.'\File',
	'NAME' => Loc::getMessage('INPUT_FILE'),
));

/**
 * Date
 */
class Date extends Base
{
	public static function getEditHtmlSingle($name, array $input, $value)
	{
		$showTime = $input['TIME'] == 'Y';

		// TODO HTML5 input="date|datetime|datetime-local" & min & max & step(date:integer|datetime..:float)

		$textAttributes = static::extractAttributes($input,
			array('DISABLED'=>'', 'AUTOCOMPLETE'=>'on', 'AUTOFOCUS'=>'', 'READONLY'=>'',  'REQUIRED'=>''),
			array('FORM'=>1, 'LIST'=>1));

		$buttonAttributes = static::extractAttributes($input, array('DISABLED'=>''), array(), false);

		return '<input type="text" name="'.$name.'" size="'.($showTime ? 20 : 10).'" value="'.htmlspecialcharsbx($value).'"'.$textAttributes.'>'
			.'<input type="button" value="'.Loc::getMessage('INPUT_DATE_SELECT').'"'.$buttonAttributes.' onclick="'
			."BX.calendar({node:this, field:'$name', form:'', bTime:".($showTime ? 'true' : 'false').", bHideTime:false});"
			.'">';
	}

	/**
	 * @param $name
	 * @param array $input
	 * @param $value
	 * @return string
	 */
	public static function getFilterEditHtml($name, array $input, $value)
	{
		return static::getEditHtmlSingle($name, $input, $value);
	}

	public static function getEditHtmlSingleDelete($name, array $input)
	{
		return '<label> '.Loc::getMessage('INPUT_DELETE').' <input type="checkbox" onclick="'

			."var disabled = this.checked;"
			."var button = this.parentNode.previousSibling;"
			."button.disabled = disabled;"
			."button.previousSibling.disabled = disabled;"

			.'"> </label>';
	}

	public static function getErrorSingle(array $input, $value)
	{
		return CheckDateTime($value, FORMAT_DATE)
			? array()
			: array('INVALID' => Loc::getMessage('INPUT_INVALID_ERROR'));
	}

	static function getSettings(array $input, $reload)
	{
		return array(
			'TIME' => array('TYPE' => 'Y/N', 'LABEL' => Loc::getMessage('INPUT_DATE_TIME'), 'ONCLICK' => $reload),
			// TODO min, max, step
		);
	}
}

Manager::register('DATE', array(
	'CLASS' => __NAMESPACE__.'\Date',
	'NAME' => Loc::getMessage('INPUT_DATE'),
));

/**
 * Location
 */
class Location extends Base
{
	public static function getViewHtmlSingle(array $input, $value)
	{
		if((string) $value == '')
			return '';

		try
		{
			$result = \Bitrix\Sale\Location\LocationTable::getPathToNodeByCode($value, array(
				'select' => array('CHAIN' => 'NAME.NAME'),
				'filter' => array('NAME.LANGUAGE_ID' => LANGUAGE_ID),
			));

			$path = array();

			while($row = $result->fetch())
				$path[] = $row['CHAIN'];

			return htmlspecialcharsbx(implode(', ', $path));
		}
		catch(\Bitrix\Main\SystemException $e)
		{
			return '';
		}
	}

	/**
	 * @param $name
	 * @param array $input
	 * @param $value
	 * @return string
	 */
	public static function getFilterEditHtml($name, array $input, $value)
	{
		return static::getEditHtml($name, $input, $value);
	}

	public static function getEditHtml($name, array $input, $value = null)
	{
		$name = htmlspecialcharsbx($name);

		if ($value === null)
			$value = $input['VALUE'];

		$html = '';

		if ($input['HIDDEN'] == 'Y')
		{
			$html .= static::getHiddenRecursive($name
				, $input['MULTIPLE'] == 'Y' ? static::asMultiple($value) : static::asSingle($value)
				, static::extractAttributes($input, array('DISABLED'=>''), array('FORM'=>1), false));
		}
		else
		{
			$selector = md5("location input selector $name");
			$input["LOCATION_SELECTOR"] = $selector;

			if ($onChange = $input['ONCHANGE'])
			{
				$functionName = 'OnLocationChange'.$selector;
				$html .= "<script>function $functionName (){ $onChange }; BX.proxy($functionName, this);</script>";
				$input['JS_CALLBACK'] = $functionName;
			}
			else
			{
				$input['JS_CALLBACK'] = null;
			}

			if ($input['MULTIPLE'] == 'Y')
			{
				$tag = isset($input['MULTITAG']) ? htmlspecialcharsbx($input['MULTITAG']) : static::MULTITAG;
				[$startTag, $endTag] = $tag ? array("<$tag>", "</$tag>") : array('', '');

				$index = -1;

				$values = static::asMultiple($value);
				if (empty($value))
				{
					$values = array(null);
				}
				foreach ($values as $value)
					$html .= $startTag
						.static::getEditHtmlSingle($name.'['.(++$index).']', $input, $value)
						.$endTag;

				$replace = '##INPUT##NAME##';

				if ($input['DISABLED'] !== 'Y') // TODO
					$html .= static::getEditHtmlInsert($tag, $replace, $name
						, static::getEditHtmlSingle($replace, $input, null)
						, "var location = BX.locationSelectors['$selector'].spawn(container, {selectedItem: false, useSpawn: false});"
						."location.clearSelected();"
					//."location.focus();" // TODO
					);
			}
			else
			{
				$html .= static::getEditHtmlSingle($name, $input, static::asSingle($value));
			}
		}

		if ($input['ADDITIONAL_HIDDEN'] === 'Y')
		{
			$html .= static::getHiddenRecursive($name
				, $input['MULTIPLE'] == 'Y' ? static::asMultiple($value) : static::asSingle($value)
				, static::extractAttributes($input, array(), array('FORM'=>1), false));
		}

		return $html;
	}

	public static function getEditHtmlSingle($name, array $input, $value)
	{
		$filterMode = isset($input['IS_FILTER_FIELD']) && $input['IS_FILTER_FIELD'] === true;
		$isSearchLine = isset($input['IS_SEARCH_LINE']) && $input['IS_SEARCH_LINE'] === true;
		$parameters = array(
			'CODE' => $value,
			'INPUT_NAME' => $name,
			'PROVIDE_LINK_BY' => 'code',
			'SELECT_WHEN_SINGLE' => 'N',
			'FILTER_BY_SITE' => 'N',
			'SHOW_DEFAULT_LOCATIONS' => 'N',
			'SEARCH_BY_PRIMARY' => 'N',
			'JS_CONTROL_GLOBAL_ID' => $input["LOCATION_SELECTOR"],
			'JS_CALLBACK' => $input['JS_CALLBACK']
		);

		ob_start();

		if($filterMode)
		{
			print('<div style="width: 100%; margin-left: 12px">');
			$parameters['INITIALIZE_BY_GLOBAL_EVENT'] = 'onAdminFilterInited'; // this allows js logic to be initialized after admin filter
			$parameters['GLOBAL_EVENT_SCOPE'] = 'window';
		}

		$GLOBALS['APPLICATION']->IncludeComponent(
			'bitrix:sale.location.selector.'.($filterMode || $isSearchLine ? 'search' : \Bitrix\Sale\Location\Admin\Helper::getWidgetAppearance()),
			'',
			$parameters,
			false
		);

		if($filterMode)
		{
			print('</div>');
		}

		$html = ob_get_contents();
		ob_end_clean();

		return $html;
	}

	public static function getErrorSingle(array $input, $value)
	{
		return \Bitrix\Sale\Location\LocationTable::getByCode($value)->fetch()
			? array()
			: array('INVALID' => Loc::getMessage('INPUT_INVALID_ERROR'));
	}
}

Manager::register('LOCATION', array(
	'CLASS' => __NAMESPACE__.'\Location',
	'NAME' => Loc::getMessage('INPUT_LOCATION'),
));

/**
 * Class Address
 * @package Bitrix\Sale\Internals\Input
 */
class Address extends Base
{
	/**
	 * @inheritdoc
	 */
	static function isMultiple($value)
	{
		return false;
	}

	/**
	 * @inheritdoc
	 */
	public static function hasMultipleValuesSupport()
	{
		return false;
	}

	/**
	 * @param array $input
	 * @param \Bitrix\Location\Entity\Address $value
	 * @return string
	 */
	public static function getViewHtml(array $input, $value = null)
	{
		if (!is_array($value) || !Loader::includeModule('location'))
		{
			return '';
		}

		$address = \Bitrix\Location\Entity\Address::fromArray($value);

		return $address->toString(
			FormatService::getInstance()->findDefault(LANGUAGE_ID)
		);
	}

	/**
	 * @inheritdoc
	 */
	public static function getFilterEditHtml($name, array $input, $value)
	{
		//not implemented
		return '';
	}

	/**
	 * @param array $input
	 * @param $value
	 * @return array
	 */
	public static function getErrorSingle(array $input, $value)
	{
		if ($input['REQUIRED'] == 'Y')
		{
			if (!(is_array($value) && !empty($value)))
			{
				return ['REQUIRED' => Loc::getMessage('INPUT_REQUIRED_ERROR')];
			}
		}

		return [];
	}

	/**
	 * @param array $input
	 * @param $value
	 * @return array
	 */
	public static function getRequiredError(array $input, $value)
	{
		return static::getErrorSingle($input, $value);
	}

	/**
	 * @inheritdoc
	 */
	public static function getEditHtmlSingle($name, array $input, $value)
	{
		if (!Loader::includeModule('location'))
		{
			return '';
		}

		\Bitrix\Main\UI\Extension::load('sale.address');

		ob_start();
		?>
		<script>
			if (BX.Sale.AddressControlConstructor)
			{
				new BX.Sale.AddressControlConstructor(
					{
						propsData: {
							name: '<?=$name?>',
							initValue: <?=($value) ? ("'" . \Bitrix\Location\Entity\Address::fromArray($value)->toJson() . "'") : Json::encode(null)?>,
							isLocked: <?=($input['DISABLED'] === 'Y') ? Json::encode(true) : Json::encode(false)?>,
							onChangeCallback: function () {
								<?if (isset($input['ONCHANGE'])):?>
								<?=$input['ONCHANGE']?>
								<?endif;?>
							}
						}
					}
				).$mount('#<?=$name?>');
			}
		</script>
		<?
		$script = ob_get_clean();

		return '
			<div id="' . $name . '"></div>
			' . $script . '
		';
	}
}

if (Loader::includeModule('location'))
{
	Manager::register('ADDRESS', array(
		'CLASS' => __NAMESPACE__.'\Address',
		'NAME' => Loc::getMessage('INPUT_ADDRESS'),
	));
}

class ProductCategories extends Base
{

    /**
     * Returns an HTML block with list of selected categories to restrict
     * @param array $input
     * @param null $values
     * @return string
     */
	public static function getViewHtml(array $input, $values = null) : string
	{
		if (!is_array($values))
        {
            return '';
        }

		$result = '<br><br>';
		$catList = self::getCategoriesList($values);

		foreach ($catList as $catName)
        {
			$result .= "<div> - {$catName}</div>";
		}

		return $result;
	}

    /**
     * Returns an HTML block for editing the type
     * @param $name
     * @param array $input
     * @param $values
     * @return string
     */
	public static function getEditHtml($name, array $input, $values = null) : string
	{
		if (!is_array($values))
        {
            $values = [];
        }

		$addInputTranslate = Loc::getMessage('SALE_PRODUCT_CATEGORY_INP_ADD');
		$deleteInputTranslate = Loc::getMessage('SALE_PRODUCT_CATEGORY_INP_DELETE');

		$openFilterButtonId = $input['ID'];

		$deprecatedSupport = isset($input['SCRIPT']) && isset($input['URL']);
		if ($deprecatedSupport)
        {
            $url = $input['URL'];
            $addCategoryScript = $input['SCRIPT'];
            $input['ID'] = 'sale-admin-delivery-restriction-cat';
        }
		else
        {
			$addCategoryScript = "window.InS".md5('SECTIONS_IDS')."=function(id, name){{$input['JS_HANDLER']}.addRestrictionProductSection(id, name, '{$input['ID']}', this);};";
			$url = 'cat_section_search.php?lang=ru&m=y&n=SECTIONS_IDS';
		}

		$editSection = "
            <br>
            <a 
                class='adm-s-restriction-open-dialog-link' 
                href='javascript:void(0);' 
                id='{$openFilterButtonId}' 
                onclick=\"window.open('{$url}','choose category', 'width=850, height=600');\"
            >
                {$addInputTranslate}
            </a>
            <br><br>
            <script type='text/javascript'>
                {$addCategoryScript}
                BX.message({SALE_PRODUCT_CATEGORY_INP_DELETE: '{$deleteInputTranslate}'});
            </script>
        ";

		$catList = self::getCategoriesList($values);
		$existCatHtml = "<table id='{$input['ID']}-content' width='100%'>";

		foreach ($catList as $catId => $catName)
        {
            if ($deprecatedSupport)
            {
                $deleteNodeScript = "BX.Sale.Delivery.deleteRestrictionProductSection('{$catId}');";
            }
            else
            {
                $deleteNodeScript = "{$input['JS_HANDLER']}.deleteRestrictionProductSection('{$catId}', '{$input['ID']}');";
            }

            $existCatHtml .= "
                <tr class='adm-s-product-category-restriction-delcat' id='{$input['ID']}-{$catId}'>
                    <td>
                        <span> - {$catName}</span>
                        <input type='hidden' name='RESTRICTION[CATEGORIES][]' value='{$catId}'>
                    </td>
                    <td align='right'>
                        &nbsp;
                        <a 
                            class='adm-s-bus-morelinkqhsw' 
                            href='javascript:void(0);' 
                            onclick=\"{$deleteNodeScript}\"
                        >
                            {$deleteInputTranslate}                        
                        </a>
                    </td>
                </tr>
            ";
        }

		$existCatHtml .= '</table>';

		return $existCatHtml.$editSection;
	}

    /**
     * Retrieves a list of categories that already selected in restriction
     * @param array $ids
     * @return array
     */
	protected static function getCategoriesList($ids) : array
	{
		if(!\Bitrix\Main\Loader::includeModule('iblock'))
			return [];

		$result = [];

		$res = \Bitrix\Iblock\SectionTable::getList([
			'filter' => [
				'ID' => $ids,
			],
			'select' => ['ID', 'NAME'],
		]);

		while($section = $res->fetch())
			$result[$section['ID']]  = htmlspecialcharsbx($section['NAME']);

		return $result;
	}

	public static function getValueSingle(array $input, $userValue)
	{
		return $userValue;
	}

	public static function getError(array $input, $values)
	{
		return self::getErrorSingle($input, $values);
	}

	public static function getErrorSingle(array $input, $values)
	{
		return [];
	}

	public static function getSettings(array $input, $reload)
	{
		return [];
	}
}

    Manager::register('PRODUCT_CATEGORIES', [
	'CLASS' => __NAMESPACE__.'\ProductCategories',
	'NAME' => Loc::getMessage('SALE_PRODUCT_CATEGORY_INP'),
]);

class ConcreteProduct extends Base
{
    /**
     * @param array $input
     * @param null $values
     * @return string
     */
    public static function getViewHtml(array $input, $values = null) : string
    {
        if (!is_array($values))
        {
            return '';
        }

        $result = '<br><br>';

        $productList = self::getProductsList($values);

        foreach ($productList as $productName)
        {
            $result .= "<div> - {$productName}</div>";
        }

        return $result;
    }

    /**
     * Return HTML section for edit concreteProduct type
     * @param $name
     * @param array $input
     * @param null $values
     * @return string
     */
    public static function getEditHtml($name, array $input, $values = null) : string
    {
        if (!is_array($values))
        {
            $values = [];
        }

        $nodeId = &$input['ID'];

        $input['FORM_NAME'] = md5($input['FORM_NAME']);
        $url = "cat_product_search.php?func_name={$input['FORM_NAME']}&new_value=Y";
        $addProductScript = "window.".$input['FORM_NAME']."=function(id, name, url){".$input["JS_HANDLER"].".addRestrictionByConcreteProduct('".$nodeId."', id, name, this);};";

        $addInputTranslate = Loc::getMessage('SALE_CONCRETE_PRODUCT_INP_ADD');
        $deleteInputTranslate = Loc::getMessage('SALE_CONCRETE_PRODUCT_INP_DELETE');

        $editSection = "
            <br>
            <a 
                class='adm-s-restriction-open-dialog-link' 
                href='javascript:void(0);' 
                id='{$input["ID"]}'
                onclick=\"window.open('{$url}', 'choose product', 'width=850,height=600');\"
            >
                {$addInputTranslate}
            </a>
            <br><br>
            <script type='text/javascript'>
                {$addProductScript}
                BX.message({SALE_CONCRETE_PRODUCT_INP_DELETE: '$deleteInputTranslate'});
            </script>";

        $productsList = self::getProductsList($values);
        $existProductsHtml = "<table id='{$nodeId}-content' width='100%'>";

        foreach ($productsList as $productId => $productName)
        {
            $existProductsHtml .= "
            <tr class='adm-s-concrete-product-restriction-delprod' id='{$nodeId}-{$productId}'>
                <td>
                    <span> - {$productName}</span>
                    <input type='hidden' name='RESTRICTION[PRODUCTS][]' value='{$productId}'>
                </td>
                <td align='right'>
                    &nbsp;
                    <a 
                        class='adm-s-bus-morelinkqhsw' href='javascript:void(0);' 
                        onclick=\"{$input["JS_HANDLER"]}.deleteRestrictionByConcreteProduct('{$nodeId}', '{$productId}');\"
                    >
                        {$deleteInputTranslate}
                    </a>
                </td>
            </tr>
            ";
        }

        $existProductsHtml .= "</table>";

        return $existProductsHtml.$editSection;
    }

    protected static function getProductsList($elementIds)
    {
        if (!\Bitrix\Main\Loader::includeModule('iblock'))
        {
            return [];
        }

        $productsList = [];

        $productsListSource = \Bitrix\Iblock\ElementTable::getList([
                'filter' => [
                        'ID' => $elementIds,
                ],
                'select' => ['ID', 'NAME'],
        ]);

        while ($productRow = $productsListSource->fetch())
        {
            $productsList[$productRow['ID']] = htmlspecialcharsbx($productRow['NAME']);
        }

        return $productsList;
    }

    public static function getValueSingle(array $input, $userValue)
    {
        return $userValue;
    }

    public static function getError(array $input, $value)
    {
        return self::getErrorSingle($input, $value);
    }

    public static function getErrorSingle(array $input, $value)
    {
        return [];
    }

    public static function getSettings(array $input, $reload)
    {
        return [];
    }
}

Manager::register(
    'CONCRETE_PRODUCT',
    [
        'CLASS' => __NAMESPACE__.'\\ConcreteProduct',
        'NAME' => Loc::getMessage('SALE_CONCRETE_PRODUCT_INP')
    ]
);

Youez - 2016 - github.com/yon3zu
LinuXploit