PageRenderTime 24ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/modules/ui/lib/buttons/basebutton.php

https://gitlab.com/alexprowars/bitrix
PHP | 564 lines | 396 code | 103 blank | 65 comment | 34 complexity | f58bb4bfeeb4e8dc85497f684d353bfd MD5 | raw file
  1. <?php
  2. namespace Bitrix\UI\Buttons;
  3. use Bitrix\Main\ArgumentException;
  4. use Bitrix\Main\Localization\Loc;
  5. use Bitrix\Main\Security\Random;
  6. use Bitrix\Main\UI\Extension;
  7. use Bitrix\UI\Contract;
  8. //We know about lazy load. So, the code loads common messages for default buttons,
  9. //which implemented by subclasses of BaseButton.
  10. Loc::loadLanguageFile(__FILE__);
  11. class BaseButton implements Contract\Renderable
  12. {
  13. const UNIQ_ID_DATA_ATTR = 'btn-uniqid';
  14. const JSON_OPTIONS_DATA_ATTR = 'json-options';
  15. /** @var string */
  16. protected $id;
  17. /** @var string */
  18. protected $text;
  19. /** @var string */
  20. protected $tag = Tag::BUTTON;
  21. /** @var string */
  22. protected $baseClass = "ui-btn";
  23. /** @var string */
  24. protected $link;
  25. /** @var integer|string */
  26. protected $counter;
  27. /** @var array */
  28. protected $events = [];
  29. /** @var ButtonAttributes */
  30. private $attributes;
  31. final public function __construct(array $params = [])
  32. {
  33. $this->attributes = new ButtonAttributes();
  34. $this->attributes->addDataAttribute(self::UNIQ_ID_DATA_ATTR, $this->generateUniqid());
  35. $this->addClass($this->getBaseClass());
  36. $this->init($params);
  37. }
  38. /**
  39. * @return array
  40. */
  41. protected function getDefaultParameters()
  42. {
  43. return [];
  44. }
  45. protected function init(array $params = [])
  46. {
  47. $this->buildFromArray(array_merge(
  48. $this->getDefaultParameters(),
  49. $params
  50. ));
  51. }
  52. final public static function create(array $params = [])
  53. {
  54. return new static($params);
  55. }
  56. protected function buildFromArray($params)
  57. {
  58. if (isset($params['text']))
  59. {
  60. $this->setText($params['text']);
  61. }
  62. if (!empty($params['styles']))
  63. {
  64. $this->setStyles($params['styles']);
  65. }
  66. if (!empty($params['maxWidth']))
  67. {
  68. $this->setMaxWidth($params['maxWidth']);
  69. }
  70. if (!empty($params['className']) && is_string($params['className']))
  71. {
  72. $params['classList'] = array_filter(explode(' ', $params['className']));
  73. }
  74. if (empty($params['classList']))
  75. {
  76. $params['classList'] = [];
  77. }
  78. $params['classList'] = array_merge(
  79. [$this->getBaseClass()],
  80. $params['classList']
  81. );
  82. $this->getAttributeCollection()->setClassList($params['classList']);
  83. if (!empty($params['counter']))
  84. {
  85. $this->setCounter($params['counter']);
  86. }
  87. if (!empty($params['id']))
  88. {
  89. $this->setId($params['id']);
  90. }
  91. if (!empty($params['tag']))
  92. {
  93. $this->setTag($params['tag']);
  94. }
  95. if (!empty($params['link']))
  96. {
  97. $this->setLink($params['link']);
  98. }
  99. if (!empty($params['click']))
  100. {
  101. $this->bindEvent('click', $params['click']);
  102. }
  103. if (!empty($params['onclick']))
  104. {
  105. $this->bindEvent('click', $params['onclick']);
  106. }
  107. if (!empty($params['events']))
  108. {
  109. $this->bindEvents($params['events']);
  110. }
  111. if (isset($params['dataset']) && is_array($params['dataset']))
  112. {
  113. foreach ($params['dataset'] as $name => $value)
  114. {
  115. $this->addDataAttribute($name, $value);
  116. }
  117. }
  118. }
  119. protected function listExtensions()
  120. {
  121. return [];
  122. }
  123. public static function getJsClass()
  124. {
  125. return 'BX.UI.' . (new \ReflectionClass(get_called_class()))->getShortName();
  126. }
  127. protected function appendDefaultJsonOption(ButtonAttributes $attributes)
  128. {
  129. if (count($this->getEvents()) > 0)
  130. {
  131. $attributes->addJsonOption('events', $this->getEvents());
  132. }
  133. return $attributes;
  134. }
  135. public function render($jsInit = true)
  136. {
  137. Extension::load($this->listExtensions());
  138. $output = '';
  139. $tagName = $this->getTag();
  140. $attributes = clone $this->getAttributeCollection();
  141. $this->appendDefaultJsonOption($attributes);
  142. switch ($tagName)
  143. {
  144. case Tag::LINK:
  145. case Tag::BUTTON:
  146. if ($tagName === Tag::LINK && $this->getLink())
  147. {
  148. $attributes['href'] = $this->getLink();
  149. }
  150. $inner = $this->renderInner();
  151. $output = "<{$tagName} {$attributes}>{$inner}</{$tagName}>";
  152. break;
  153. case Tag::INPUT:
  154. case Tag::SUBMIT:
  155. $attributes['value'] = htmlspecialcharsbx($this->getText());
  156. $attributes['type'] = Tag::BUTTON;
  157. if ($tagName === Tag::SUBMIT)
  158. {
  159. $tagName = Tag::INPUT;
  160. $attributes['type'] = Tag::SUBMIT;
  161. }
  162. $output = "<{$tagName} {$attributes}/>";
  163. break;
  164. }
  165. if ($jsInit)
  166. {
  167. $js = $this->renderJavascript();
  168. if ($js)
  169. {
  170. $output .= "<script>BX.ready(function(){ {$js} });</script>";
  171. }
  172. }
  173. return $output;
  174. }
  175. protected function generateUniqid()
  176. {
  177. return 'uibtn-' . Random::getString(8);
  178. }
  179. public function isInputTag()
  180. {
  181. return $this->isInputType();
  182. }
  183. public function isInputType()
  184. {
  185. return in_array($this->tag, [
  186. Tag::INPUT,
  187. Tag::SUBMIT,
  188. ], true);
  189. }
  190. protected function renderInner()
  191. {
  192. $counter = $this->getCounter();
  193. return (
  194. (!empty($this->getText()) ? '<span class="ui-btn-text">'.htmlspecialcharsbx($this->getText()).'</span>' : '').
  195. ($counter !== null ? '<span class="ui-btn-counter">'.htmlspecialcharsbx($counter).'</span>' : '' )
  196. );
  197. }
  198. protected function renderJavascript()
  199. {
  200. $selector = $this->getQuerySelector();
  201. return "BX.UI.ButtonManager.createFromNode(document.querySelector('{$selector}'));";
  202. }
  203. protected function getQuerySelector()
  204. {
  205. $tag = $this->getTag();
  206. $uniqId = $this->getUniqId();
  207. $uniqIdName = "data-" . self::UNIQ_ID_DATA_ATTR;
  208. return "{$tag}[{$uniqIdName}=\"{$uniqId}\"]";
  209. }
  210. public function getUniqId()
  211. {
  212. return $this->getAttributeCollection()->getDataAttribute(self::UNIQ_ID_DATA_ATTR);
  213. }
  214. public function getId()
  215. {
  216. return $this->id;
  217. }
  218. public function setId($id)
  219. {
  220. $this->id = $id;
  221. return $this;
  222. }
  223. public function getMaxWidth()
  224. {
  225. return isset($this->getAttributeCollection()['style']['max-width'])?
  226. $this->getAttributeCollection()['style']['max-width'] : null;
  227. }
  228. public function setMaxWidth($width)
  229. {
  230. if (!isset($this->getAttributeCollection()['style']))
  231. {
  232. $this->getAttributeCollection()['style'] = [];
  233. }
  234. $this->getAttributeCollection()['style']['max-width'] = $width;
  235. return $this;
  236. }
  237. public function getLink()
  238. {
  239. return $this->link;
  240. }
  241. public function setLink($link)
  242. {
  243. if (is_string($link) && !empty($link))
  244. {
  245. $this->link = $link;
  246. $this->setTag(Tag::LINK);
  247. }
  248. return $this;
  249. }
  250. public function getCounter()
  251. {
  252. return $this->counter;
  253. }
  254. public function setCounter($counter)
  255. {
  256. if (in_array($counter, [0, '0', '', null, false], true))
  257. {
  258. $this->counter = null;
  259. }
  260. else if ((is_int($counter) && $counter > 0) || (is_string($counter) && mb_strlen($counter)))
  261. {
  262. $this->counter = $counter;
  263. }
  264. return $this;
  265. }
  266. public function addClass($className)
  267. {
  268. $this->getAttributeCollection()->addClass($className);
  269. return $this;
  270. }
  271. public function unsetClass($className)
  272. {
  273. $this->getAttributeCollection()->removeClass($className);
  274. return $this;
  275. }
  276. public function removeClass($className)
  277. {
  278. return $this->unsetClass($className);
  279. }
  280. public function hasClass($className)
  281. {
  282. return $this->getAttributeCollection()->hasClass($className);
  283. }
  284. public function getClassList()
  285. {
  286. return $this->getAttributeCollection()['class']?: [];
  287. }
  288. public function addAttribute($name, $value = null)
  289. {
  290. if (mb_strtolower($name) === 'class')
  291. {
  292. throw new ArgumentException('Could not add "class" attribute. You should use ::addClass()', 'class');
  293. }
  294. $this->getAttributeCollection()[$name] = $value;
  295. return $this;
  296. }
  297. public function unsetAttribute($name)
  298. {
  299. unset($this->getAttributeCollection()[$name]);
  300. return $this;
  301. }
  302. public function removeAttribute($name)
  303. {
  304. return $this->unsetAttribute($name);
  305. }
  306. public function getAttribute($name, $defaultValue = null)
  307. {
  308. return $this->getAttributeCollection()->getAttribute($name, $defaultValue);
  309. }
  310. public function addDataAttribute($name, $value = null)
  311. {
  312. $this->getAttributeCollection()->addDataAttribute($name, $value);
  313. return $this;
  314. }
  315. public function getDataAttribute($name, $defaultValue = null)
  316. {
  317. return $this->getAttributeCollection()->getDataAttribute($name, $defaultValue);
  318. }
  319. public function setDataRole($dataRole)
  320. {
  321. $this->addDataAttribute('role', $dataRole);
  322. return $this;
  323. }
  324. public function getDataRole()
  325. {
  326. return $this->getDataAttribute('role');
  327. }
  328. public function setStyles(array $styles)
  329. {
  330. $this->getAttributeCollection()['style'] = $styles;
  331. }
  332. public function getStyles()
  333. {
  334. return $this->getAttributeCollection()['style'];
  335. }
  336. /**
  337. * @return ButtonAttributes
  338. */
  339. public function getAttributeCollection()
  340. {
  341. return $this->attributes;
  342. }
  343. /**
  344. * @return string
  345. */
  346. public function getText()
  347. {
  348. return $this->text;
  349. }
  350. /**
  351. * @param string $text
  352. *
  353. * @return static
  354. */
  355. public function setText($text)
  356. {
  357. $this->text = $text;
  358. return $this;
  359. }
  360. /**
  361. * @return string
  362. */
  363. public function getTag()
  364. {
  365. return $this->tag;
  366. }
  367. /**
  368. * @param string $tag
  369. *
  370. * @return static
  371. */
  372. public function setTag($tag)
  373. {
  374. $this->tag = $tag;
  375. return $this;
  376. }
  377. /**
  378. * @return string
  379. */
  380. public function getBaseClass()
  381. {
  382. return $this->baseClass;
  383. }
  384. /**
  385. * @param bool $flag
  386. * @return static
  387. */
  388. public function setDisabled($flag = true)
  389. {
  390. if ($flag === false)
  391. {
  392. unset($this->getAttributeCollection()['disabled']);
  393. }
  394. else
  395. {
  396. $this->getAttributeCollection()['disabled'] = true;
  397. }
  398. return $this;
  399. }
  400. /**
  401. * @return bool
  402. */
  403. public function isDisabled()
  404. {
  405. return $this->getAttributeCollection()['disabled'] === true;
  406. }
  407. /**
  408. * @return array
  409. */
  410. public function getEvents()
  411. {
  412. return $this->events;
  413. }
  414. /**
  415. * @param string $eventName
  416. * @param string|JsHandler $fn Link to js function which will be invoked.
  417. * @see in js BX.UI.BaseButton.handleEvent to know order of arguments in event handler.
  418. *
  419. * @return $this
  420. */
  421. public function bindEvent($eventName, $fn)
  422. {
  423. if (is_string($fn))
  424. {
  425. $fn = new JsHandler($fn);
  426. }
  427. $this->events[$eventName] = $fn;
  428. return $this;
  429. }
  430. /**
  431. * @param array $events
  432. *
  433. * @return $this
  434. */
  435. public function bindEvents(array $events)
  436. {
  437. foreach ($events as $name => $fn)
  438. {
  439. $this->bindEvent($name, $fn);
  440. }
  441. return $this;
  442. }
  443. /**
  444. * @param string $eventName
  445. *
  446. * @return $this
  447. */
  448. public function unbindEvent($eventName)
  449. {
  450. unset($this->events[$eventName]);
  451. return $this;
  452. }
  453. /**
  454. * @return $this
  455. */
  456. public function unbindEvents()
  457. {
  458. unset($this->events);
  459. return $this;
  460. }
  461. }