1
0

BxBaseStudioWidget.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup UnaView UNA Studio Representation classes
  7. * @ingroup UnaStudio
  8. * @{
  9. */
  10. class BxBaseStudioWidget extends BxDolStudioWidget
  11. {
  12. protected $bPageMenuTitle;
  13. protected $bPageMenuIconsInline;
  14. protected $aPageCodeNoWrap;
  15. public function __construct($mixedPageName)
  16. {
  17. parent::__construct($mixedPageName);
  18. $this->bPageMenuTitle = !$this->_bShowHeaderBreadcrumb;
  19. $this->bPageMenuIconsInline = true;
  20. $this->aPageCodeNoWrap = [];
  21. }
  22. public function getPageCss()
  23. {
  24. return array_merge(parent::getPageCss(), array(
  25. 'launcher.css'
  26. ));
  27. }
  28. public function getPageJs()
  29. {
  30. return array_merge(parent::getPageJs(), array(
  31. 'launcher.js'
  32. ));
  33. }
  34. public function getPageCaption()
  35. {
  36. if(empty($this->aPage) || !is_array($this->aPage))
  37. return '';
  38. $sResult = parent::getPageCaption();
  39. $this->updateHistory();
  40. $oTemplate = BxDolStudioTemplate::getInstance();
  41. $oFunctions = BxTemplStudioFunctions::getInstance();
  42. $sActions = '';
  43. $bActions = false;
  44. if(false && ($sActions = $this->getPageCaptionActions()) && ($bActions = strlen($sActions)) > 0) //--- Hidden for now.
  45. $sActions = $oFunctions->transBox('bx-std-pcap-menu-popup-actions', $sActions, true);
  46. $sHelp = '';
  47. $bHelp = false;
  48. if(false && ($sHelp = $this->getPageCaptionHelp()) && ($bHelp = strlen($sHelp)) > 0) //--- Hidden for now.
  49. $sHelp = $oFunctions->transBox('bx-std-pcap-menu-popup-help', $sHelp, true);
  50. if($bActions || $bHelp)
  51. $oTemplate->addInjection('injection_header', 'text', $sActions . $sHelp);
  52. //--- Menu Right ---//
  53. $aItemsRight = [];
  54. if($bHelp)
  55. $aItemsRight['help'] = [
  56. 'name' => 'help',
  57. 'icon' => 'tmi-help.svg',
  58. 'onclick' => BX_DOL_STUDIO_PAGE_JS_OBJECT . ".togglePopup('help', this)",
  59. 'title' => '_adm_txt_show_help'
  60. ];
  61. if($this->_bShowHeaderRightAssistant)
  62. $aItemsRight['assistant'] = [
  63. 'name' => 'assistant',
  64. 'icon' => 'tmi-assistant.svg',
  65. 'link' => 'javascript:void(0);',
  66. 'onclick' => BX_DOL_STUDIO_PAGE_JS_OBJECT . ".togglePopup('assistant', this)",
  67. 'title' => '_adm_tmi_cpt_assistant'
  68. ];
  69. if($bActions)
  70. $aItemsRight['actions'] = [
  71. 'name' => 'actions',
  72. 'icon' => 'tmi-actions.svg',
  73. 'onclick' => BX_DOL_STUDIO_PAGE_JS_OBJECT . ".togglePopup('actions', this)",
  74. 'title' => '_adm_txt_show_actions'
  75. ];
  76. if($this->_bShowHeaderRightSite)
  77. $aItemsRight['site'] = [
  78. 'name' => 'site',
  79. 'icon' => 'tmi-site.svg',
  80. 'link' => '{url_root}',
  81. 'title' => '_adm_tmi_cpt_site'
  82. ];
  83. $aItemsRight['account'] = [
  84. 'name' => 'account',
  85. 'icon' => 'tmi-account.svg',
  86. 'link' => 'javascript:void(0);',
  87. 'onclick' => 'bx_menu_popup_inline(\'#bx-std-pcap-menu-popup-account\', this);',
  88. 'attrs_add' => 'aria-haspopup="true" aria-expanded="false" aria-controls="bx-std-pcap-menu-popup-account"',
  89. 'title' => '_adm_tmi_cpt_account'
  90. ];
  91. $oTopMenu = BxTemplStudioMenuTop::getInstance();
  92. $oTopMenu->setPageName($this->aPage['name']);
  93. $oTopMenu->setContent(BX_DOL_STUDIO_MT_LEFT, $this->getPageBreadcrumb());
  94. $oTopMenu->setSelected(BX_DOL_STUDIO_MT_CENTER, $this->aPage['name']);
  95. $oTopMenu->setContent(BX_DOL_STUDIO_MT_RIGHT, array(
  96. 'template' => 'menu_top_toolbar.html',
  97. 'menu_items' => $aItemsRight
  98. ));
  99. return $sResult;
  100. }
  101. public function getPageMenu($aMenu = [], $aMarkers = [])
  102. {
  103. if(!$this->bPageMenuTitle && $aMenu === false)
  104. return '';
  105. $sActions = $this->bPageMenuTitle ? $this->getPageCaptionActions() : '';
  106. return BxDolStudioTemplate::getInstance()->parseHtmlByName('page_menu.html', [
  107. 'bx_if:show_title' => [
  108. 'condition' => $this->bPageMenuTitle,
  109. 'content' => [
  110. 'title' => _t($this->aPage['caption']),
  111. 'bx_if:show_actions' => [
  112. 'condition' => (bool)$sActions,
  113. 'content' => [
  114. 'attrs' => $sActions,
  115. ]
  116. ],
  117. ]
  118. ],
  119. 'menu' => parent::getPageMenu($aMenu, $aMarkers)
  120. ]);
  121. }
  122. public function getPageCode($sPage = '', $bWrap = true)
  123. {
  124. $sResult = parent::getPageCode($sPage, $bWrap);
  125. if($sResult === false)
  126. return false;
  127. if(!empty($this->aPage['wid_type']) && !BxDolStudioRolesUtils::getInstance()->isActionAllowed('use ' . $this->aPage['wid_type'])) {
  128. $this->setError('_Access denied');
  129. return false;
  130. }
  131. if(empty($sPage))
  132. $sPage = $this->sPage;
  133. $sMethod = 'get' . bx_gen_method_name($sPage);
  134. if(method_exists($this, $sMethod)) {
  135. $mixedContent = $this->$sMethod();
  136. if(!$bWrap || in_array($sPage, $this->aPageCodeNoWrap))
  137. $sResult .= $mixedContent;
  138. else if(is_string($mixedContent))
  139. $sResult .= $this->getBlockCode([
  140. 'content' => $mixedContent
  141. ]);
  142. else if(is_array($mixedContent)) {
  143. if(isset($mixedContent['content']))
  144. $sResult .= $this->getBlockCode($mixedContent);
  145. else
  146. foreach($mixedContent as $mixedBlock)
  147. $sResult .= $this->getBlockCode(is_array($mixedBlock) ? $mixedBlock : [
  148. 'content' => $mixedBlock
  149. ]);
  150. }
  151. else if(is_a($mixedContent, 'BxDolPage'))
  152. $sResult .= $mixedContent->getCode();
  153. }
  154. return $sResult . BxTemplStudioLauncher::getInstance()->getPageJsCode(array(
  155. 'bInit' => false
  156. ));
  157. }
  158. /**
  159. * Block related methods
  160. */
  161. public function getBlocksLine($aBlocks)
  162. {
  163. $aTmplVarsBlocks = array();
  164. foreach ($aBlocks as $aBlock) {
  165. $aTmplVarsBlocks[] = array(
  166. 'content' => $this->getBlockCode($aBlock)
  167. );
  168. }
  169. return BxDolStudioTemplate::getInstance()->parseHtmlByName('page_blocks_line.html', array(
  170. 'count' => count($aTmplVarsBlocks),
  171. 'bx_repeat:blocks' => $aTmplVarsBlocks
  172. ));
  173. }
  174. public function getBlockCode($aBlock)
  175. {
  176. $aTypeI2S = [
  177. BX_DB_CONTENT_ONLY => 'cnt',
  178. BX_DB_DEF => 'cnt-ttl-bg',
  179. BX_DB_NO_CAPTION => 'cnt-bg'
  180. ];
  181. $iType = isset($aBlock['type'], $aTypeI2S[$aBlock['type']]) ? $aBlock['type'] : BX_DB_DEF;
  182. $sContent = '';
  183. if(!empty($aBlock['content']))
  184. $sContent = $aBlock['content'];
  185. else if(!empty($aBlock['items']))
  186. $sContent = $aBlock['items'];
  187. return BxDolStudioTemplate::getInstance()->parseHtmlByName('page_block.html', array(
  188. 'type' => $aTypeI2S[$iType],
  189. 'caption' => !in_array($iType, [BX_DB_CONTENT_ONLY, BX_DB_NO_CAPTION]) ? $this->getBlockCaption($aBlock) : '',
  190. 'panel_top' => $this->getBlockPanelTop($aBlock),
  191. 'items' => $sContent,
  192. 'panel_bottom' => $this->getBlockPanelBottom($aBlock)
  193. ));
  194. }
  195. public function getBlockCaption($aBlock)
  196. {
  197. if(($sK = 'caption') && empty($aBlock[$sK])) {
  198. if(($sPageCaption = $this->aPage['subcaption'] ?? false))
  199. $aBlock[$sK] = $sPageCaption;
  200. else if(($sPageCaption = $this->aPage['caption'] ?? false)) {
  201. $_sPageCaption = _t($sPageCaption);
  202. if(strcmp($sPageCaption, $_sPageCaption) !== 0)
  203. $aBlock[$sK] = $_sPageCaption;
  204. }
  205. }
  206. if(empty($aBlock) || !is_array($aBlock) || (empty($aBlock['caption']) && empty($aBlock['actions'])))
  207. return '';
  208. $oTemplate = BxDolStudioTemplate::getInstance();
  209. $aTmplActions = array();
  210. if(!empty($aBlock['actions']) && is_array($aBlock['actions']))
  211. foreach($aBlock['actions'] as $aAction) {
  212. $aTmplVarsIcon = $aTmplVarsIconUrl = $aTmplVarsIconHtml = [];
  213. if(($sIcon = $aAction['icon'] ?? false)) {
  214. list($sIcon, $sIconUrl, $sIconA, $sIconHtml) = $oTemplate->getTemplateFunctions()->getIcon($sIcon);
  215. if($sIcon)
  216. $aTmplVarsIcon = [
  217. 'icon' => BxDolIconset::getObjectInstance()->getIcon($sIcon)
  218. ];
  219. else if($sIconUrl)
  220. $aTmplVarsIconUrl = [
  221. 'icon_url' => $sIconUrl,
  222. ];
  223. else if($sIconHtml)
  224. $aTmplVarsIconHtml = [
  225. 'icon_html' => $sIconHtml
  226. ];
  227. }
  228. $sCaption = is_array($aAction['caption']) ? call_user_func_array('_t', $aAction['caption']) : _t($aAction['caption']);
  229. $bTitleOnly = $aAction['title_only'] ?? false;
  230. $bOnClick = !empty($aAction['onclick']);
  231. $aOnClick = $bOnClick ? array('onclick' => $aAction['onclick']) : array();
  232. $aTmplActions[] = [
  233. 'name' => $aAction['name'],
  234. 'url' => $aAction['url'],
  235. 'title' => bx_html_attribute($sCaption),
  236. 'bx_if:show_onclick' => [
  237. 'condition' => $bOnClick,
  238. 'content' => $aOnClick
  239. ],
  240. 'bx_if:show_bc_icon' => [
  241. 'condition' => !empty($aTmplVarsIcon),
  242. 'content' => $aTmplVarsIcon
  243. ],
  244. 'bx_if:show_bc_icon_url' => [
  245. 'condition' => !empty($aTmplVarsIconUrl),
  246. 'content' => $aTmplVarsIconUrl
  247. ],
  248. 'bx_if:show_bc_icon_html' => [
  249. 'condition' => !empty($aTmplVarsIconHtml),
  250. 'content' => $aTmplVarsIconHtml
  251. ],
  252. 'bx_if:show_bc_text' => [
  253. 'condition' => (bool)$sCaption && !$bTitleOnly,
  254. 'content' => [
  255. 'caption' => $sCaption
  256. ]
  257. ],
  258. ];
  259. }
  260. return $oTemplate->parseHtmlByName('block_caption.html', [
  261. 'caption' => is_array($aBlock['caption']) ? call_user_func_array('_t', $aBlock['caption']) : _t($aBlock['caption']),
  262. 'bx_if:show_actions' => [
  263. 'condition' => !empty($aTmplActions),
  264. 'content' => [
  265. 'bx_repeat:actions' => $aTmplActions
  266. ]
  267. ],
  268. ]);
  269. }
  270. public function getBlockPanelTop($aBlock)
  271. {
  272. if(empty($aBlock) || !is_array($aBlock) || empty($aBlock['panel_top']))
  273. return '';
  274. return BxDolStudioTemplate::getInstance()->parseHtmlByName('block_panel_top.html', array(
  275. 'content' => $aBlock['panel_top']
  276. ));
  277. }
  278. public function getBlockPanelBottom($aBlock)
  279. {
  280. if(empty($aBlock) || !is_array($aBlock) || empty($aBlock['panel_bottom']))
  281. return '';
  282. return BxDolStudioTemplate::getInstance()->parseHtmlByName('block_panel_bottom.html', array(
  283. 'content' => $aBlock['panel_bottom']
  284. ));
  285. }
  286. /**
  287. * Internal methods.
  288. */
  289. protected function getPageActions($iWidgetId = 0)
  290. {
  291. if(empty($this->aActions))
  292. return "";
  293. $aMarkers = array(
  294. 'widget_id' => $iWidgetId,
  295. );
  296. if(!empty($iWidgetId)) {
  297. $aWidget = BxDolStudioWidgetsQuery::getInstance()->getWidgets(array('type' => 'by_id', 'value' => $iWidgetId));
  298. if(!empty($aWidget) && is_array($aWidget))
  299. $aMarkers['widget_type'] = $aWidget['type'];
  300. }
  301. $aForm = array(
  302. 'form_attrs' => array(
  303. 'id' => 'adm-page-actions',
  304. 'name' => 'adm-page-actions',
  305. 'action' => '',
  306. 'method' => 'post',
  307. ),
  308. 'params' => array(),
  309. 'inputs' => array()
  310. );
  311. foreach($this->aActions as $aAction) {
  312. if($aAction['name'] == 'rearrange' && (empty($iWidgetId) || getParam('sys_std_show_launcher_left') != 'on'))
  313. continue;
  314. if(!empty($aAction['context_only'])) // only in the context menu (see getPageContextMenu)
  315. continue;
  316. $aInput = array(
  317. 'type' => $aAction['type'],
  318. 'name' => $aAction['name'],
  319. 'caption' => _t($aAction['caption'])
  320. );
  321. switch($aAction['type']) {
  322. case 'switcher':
  323. $aInput['checked'] = $aAction['checked'];
  324. $aInput['attrs']['onchange'] = bx_replace_markers($aAction['onchange'], $aMarkers);
  325. break;
  326. case 'select':
  327. $aInput['value'] = bx_replace_markers($aAction['value'], $aMarkers);
  328. $aInput['values'] = $aAction['values'];
  329. $aInput['attrs']['onchange'] = bx_replace_markers($aAction['onchange'], $aMarkers);
  330. break;
  331. }
  332. $aForm['inputs'][$aInput['name']] = $aInput;
  333. }
  334. $oForm = new BxTemplStudioFormView($aForm);
  335. return $oForm->getCode();
  336. }
  337. /**
  338. * The same actions as a context menu (studio/template/menu_context.html, studio/js/context_menu.js): a switch is a
  339. * checkbox item with a switch drawn after its label, the "move to" select a group of radio items with a tick, a button
  340. * a plain item, each running the JS the form control ran. Destructive items are set off by a separator and drawn in red.
  341. */
  342. protected function getPageContextMenu($iWidgetId = 0)
  343. {
  344. if(empty($this->aActions))
  345. return '';
  346. $aMarkers = array(
  347. 'widget_id' => $iWidgetId,
  348. );
  349. if(!empty($iWidgetId)) {
  350. $aWidget = BxDolStudioWidgetsQuery::getInstance()->getWidgets(array('type' => 'by_id', 'value' => $iWidgetId));
  351. if(!empty($aWidget) && is_array($aWidget))
  352. $aMarkers['widget_type'] = $aWidget['type'];
  353. }
  354. $oIconset = BxDolIconset::getObjectInstance('sys_lucide');
  355. $fIcon = function($sIcon) use ($oIconset) {
  356. return $oIconset && !empty($sIcon) && ($sSvg = $oIconset->getIconHtml($sIcon)) !== false ? $sSvg : '';
  357. };
  358. $fJs = function($sJs) use ($aMarkers) {
  359. return bx_html_attribute(bx_replace_markers(preg_replace('/^javascript:/', '', $sJs), $aMarkers));
  360. };
  361. $aItems = [];
  362. $fItem = function($aItem) use (&$aItems) {
  363. $aItems[] = [
  364. 'bx_if:show_separator' => ['condition' => !empty($aItem['separator']), 'content' => []],
  365. 'bx_if:show_label' => ['condition' => !empty($aItem['label']), 'content' => ['title' => !empty($aItem['label']) ? $aItem['label'] : '']],
  366. 'bx_if:show_item' => ['condition' => !empty($aItem['role']), 'content' => [
  367. 'role' => !empty($aItem['role']) ? $aItem['role'] : '',
  368. 'class' => !empty($aItem['class']) ? $aItem['class'] : '',
  369. 'attrs' => !empty($aItem['attrs']) ? $aItem['attrs'] : '',
  370. 'onclick' => !empty($aItem['onclick']) ? $aItem['onclick'] : '',
  371. 'icon' => !empty($aItem['icon']) ? $aItem['icon'] : '',
  372. 'title' => !empty($aItem['title']) ? $aItem['title'] : '',
  373. // a radio item is marked by a tick before it, an on/off item by a switch after it (the same look as the form switch)
  374. 'bx_if:show_check' => ['condition' => !empty($aItem['role']) && $aItem['role'] == 'menuitemradio', 'content' => ['check' => !empty($aItem['check']) ? $aItem['check'] : '']],
  375. 'bx_if:show_switch' => ['condition' => !empty($aItem['role']) && $aItem['role'] == 'menuitemcheckbox', 'content' => []],
  376. ]],
  377. ];
  378. };
  379. $sCheck = $fIcon('check');
  380. foreach($this->aActions as $aAction) {
  381. if($aAction['name'] == 'rearrange' && (empty($iWidgetId) || getParam('sys_std_show_launcher_left') != 'on'))
  382. continue;
  383. $sIcon = $fIcon(!empty($aAction['icon']) ? $aAction['icon'] : '');
  384. $sTitle = _t($aAction['caption']);
  385. switch($aAction['type']) {
  386. case 'switcher':
  387. $fItem([
  388. 'role' => 'menuitemcheckbox',
  389. 'attrs' => ' aria-checked="' . (!empty($aAction['checked']) ? 'true' : 'false') . '"',
  390. 'onclick' => $fJs($aAction['onchange']),
  391. 'check' => $sCheck,
  392. 'icon' => $sIcon,
  393. 'title' => $sTitle,
  394. ]);
  395. break;
  396. case 'select':
  397. $sValue = bx_replace_markers($aAction['value'], $aMarkers);
  398. $fItem(['separator' => true]);
  399. $fItem(['label' => $sTitle]);
  400. foreach($aAction['values'] as $mixedKey => $mixedValue) {
  401. $sKey = is_array($mixedValue) ? $mixedValue['key'] : $mixedKey;
  402. $fItem([
  403. 'role' => 'menuitemradio',
  404. 'attrs' => ' aria-checked="' . ($sKey == $sValue ? 'true' : 'false') . '" value="' . bx_html_attribute($sKey) . '"',
  405. 'onclick' => $fJs($aAction['onchange']), // reads the item's value like the select's
  406. 'check' => $sCheck,
  407. 'icon' => $sIcon,
  408. 'title' => is_array($mixedValue) ? $mixedValue['value'] : $mixedValue,
  409. ]);
  410. }
  411. break;
  412. case 'button':
  413. if(!empty($aAction['danger']))
  414. $fItem(['separator' => true]);
  415. $fItem([
  416. 'role' => 'menuitem',
  417. 'class' => !empty($aAction['danger']) ? 'bx-std-cm-danger' : '',
  418. 'onclick' => $fJs($aAction['onclick']),
  419. 'check' => $sCheck,
  420. 'icon' => $sIcon,
  421. 'title' => $sTitle,
  422. ]);
  423. break;
  424. }
  425. }
  426. if(empty($aItems))
  427. return '';
  428. return BxDolStudioTemplate::getInstance()->parseHtmlByName('menu_context.html', [
  429. 'label' => bx_html_attribute(_t('_adm_txt_show_actions')),
  430. 'bx_repeat:items' => $aItems,
  431. ]);
  432. }
  433. protected function getPageMenuObject($aMenu = array(), $aMarkers = array())
  434. {
  435. $oMenu = parent::getPageMenuObject($aMenu, $aMarkers);
  436. $oMenu->setInlineIcons($this->bPageMenuIconsInline);
  437. return $oMenu;
  438. }
  439. }
  440. /** @} */