BxBaseStudioFunctions.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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 BxBaseStudioFunctions extends BxBaseFunctions implements iBxDolSingleton
  11. {
  12. /**
  13. * Studio draws a block's title icon as an inline Lucide SVG (like its menus), whatever the site's default iconset is.
  14. */
  15. public function designBoxContent ($sTitle, $sContent, $iTemplateNum = BX_DB_DEF, $mixedMenu = false, $mixedButtons = [])
  16. {
  17. if(is_array($sTitle) && !empty($sTitle[2]) && preg_match('/^[a-z0-9-]+$/', $sTitle[2]) && ($oIconset = BxDolIconset::getObjectInstance('sys_lucide')) && ($sSvg = $oIconset->getIconHtml($sTitle[2])) !== false)
  18. $sTitle[2] = $sSvg;
  19. return parent::designBoxContent($sTitle, $sContent, $iTemplateNum, $mixedMenu, $mixedButtons);
  20. }
  21. /**
  22. * A Studio block may hand the caption ready-made markup (a segmented switcher, say) instead of a menu object.
  23. */
  24. public function designBoxMenu ($mixedMenu, $mixedButtons = [])
  25. {
  26. if(is_string($mixedMenu) && strncmp(ltrim($mixedMenu), '<', 1) === 0)
  27. return $mixedMenu;
  28. return parent::designBoxMenu($mixedMenu, $mixedButtons);
  29. }
  30. function __construct($oTemplate = false)
  31. {
  32. if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
  33. trigger_error ('Multiple instances are not allowed for the class: ' . get_class($this), E_USER_ERROR);
  34. parent::__construct($oTemplate ? $oTemplate : BxDolStudioTemplate::getInstance());
  35. }
  36. public static function getInstance()
  37. {
  38. if (!isset($GLOBALS['bxDolClasses']['BxBaseStudioFunctions']))
  39. $GLOBALS['bxDolClasses']['BxBaseStudioFunctions'] = new BxTemplStudioFunctions();
  40. return $GLOBALS['bxDolClasses']['BxBaseStudioFunctions'];
  41. }
  42. /**
  43. * Studio's favicon is the UNA logo on a coloured plate, which reads on light and dark tabs alike.
  44. */
  45. protected function getMetaIconDarkUrl()
  46. {
  47. return '';
  48. }
  49. public function getLogo()
  50. {
  51. return bx_idn_to_utf8(BX_DOL_URL_ROOT, true);
  52. }
  53. public function getLoginForm()
  54. {
  55. $oTemplate = BxDolStudioTemplate::getInstance();
  56. $sUrlRelocate = bx_get('relocate');
  57. if (empty($sUrlRelocate) || basename($sUrlRelocate) == 'index.php')
  58. $sUrlRelocate = '';
  59. $sHtml = $oTemplate->parseHtmlByName('login_form.html', array (
  60. 'role' => BX_DOL_ROLE_ADMIN,
  61. 'csrf_token' => BxDolForm::getCsrfToken(),
  62. 'relocate_url' => bx_html_attribute($sUrlRelocate),
  63. 'action_url' => BX_DOL_URL_ROOT . 'member.php',
  64. 'forgot_password_url' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=forgot-password')),
  65. ));
  66. $sHtml = $oTemplate->parseHtmlByName('login.html', array (
  67. 'form' => $this->transBox('bx-std-login-form-box', $sHtml, true),
  68. ));
  69. $oTemplate->setPageNameIndex(BX_PAGE_CLEAR);
  70. $oTemplate->setPageParams(array(
  71. 'css_name' => array('forms.css', 'login.css'),
  72. 'js_name' => array('jquery-ui/jquery-ui.min.js', 'jquery.form.min.js', 'jquery.dolPopup.js', 'login.js'),
  73. 'header' => _t('_adm_page_cpt_login'),
  74. ));
  75. $oTemplate->setPageContent ('page_main_code', $sHtml);
  76. $oTemplate->getPageCode();
  77. }
  78. public function getWidget($mixedWidget, $aParams = array())
  79. {
  80. $oTemplate = BxDolStudioTemplate::getInstance();
  81. $aNotices = array();
  82. if(!empty($aParams['notices']) && is_array($aParams['notices']))
  83. $aNotices = $aParams['notices'];
  84. $aMarkers = array(
  85. 'url_root' => BX_DOL_URL_ROOT,
  86. 'url_studio' => BX_DOL_URL_STUDIO,
  87. 'url_studio_icons' => BX_DOL_URL_STUDIO_BASE . 'images/icons/'
  88. );
  89. if(!is_array($mixedWidget))
  90. $mixedWidget = BxDolStudioWidgetsQuery::getInstance()->getWidgets(array('type' => 'by_id', 'value' => (int)$mixedWidget));
  91. if(!empty($mixedWidget['type']) && !BxDolStudioRolesUtils::getInstance()->isActionAllowed('use ' . $mixedWidget['type']))
  92. return '';
  93. $sCaption = _t($mixedWidget['caption']);
  94. $aTmplVarsActionsLeft = $aTmplVarsActionsRight = [];
  95. if(!empty($mixedWidget['cnt_actions'])) {
  96. $aService = unserialize($mixedWidget['cnt_actions']);
  97. $aActions = bx_srv_ii($aService['module'], $aService['method'], array_merge(array($mixedWidget), $aService['params']), $aService['class']);
  98. foreach($aActions as $iIndex => $aAction) {
  99. if(!empty($aAction['check_func'])) {
  100. $sCheckFunc = bx_gen_method_name($aAction['check_func']);
  101. if(method_exists($this, $sCheckFunc) && !$this->$sCheckFunc($mixedWidget))
  102. continue;
  103. }
  104. $sActionIcon = $aAction['icon'];
  105. $bActionIcon = strpos($sActionIcon, '.') === false;
  106. $bActionIconInline = !$bActionIcon;
  107. if($bActionIconInline && ($sActionIcon = $oTemplate->getIconContent($sActionIcon)) === false) {
  108. $sActionIcon = $oTemplate->getIconUrl($sActionIcon);
  109. $bActionIconInline = false;
  110. }
  111. if($bActionIcon)
  112. $sActionIconHtml = '<i class="sys-icon ' . $sActionIcon . '" aria-hidden="true"></i>';
  113. else if($bActionIconInline)
  114. $sActionIconHtml = $sActionIcon;
  115. else
  116. $sActionIconHtml = '<img src="' . $sActionIcon . '" alt="" />';
  117. /*
  118. * A control with a URL is a link, one that only runs a script is a button. Every widget has a control with the
  119. * same caption (Settings), so the accessible name adds the app it belongs to.
  120. */
  121. $sActionCaption = _t($aAction['caption']);
  122. $bActionLink = !empty($aAction['url']);
  123. $aTmplVarsControl = [
  124. 'name' => !empty($aAction['name']) ? $aAction['name'] : $mixedWidget['id'] . '-' . $iIndex,
  125. 'url' => $bActionLink ? bx_replace_markers($aAction['url'], $aMarkers) : '',
  126. 'onclick' => !empty($aAction['click']) ? 'onclick="' . bx_html_attribute($aAction['click']) . '"' : '',
  127. 'caption' => bx_html_attribute($sActionCaption),
  128. 'label' => bx_html_attribute(_t('_adm_txt_widget_action_label', $sActionCaption, $sCaption)),
  129. 'icon' => $sActionIconHtml,
  130. ];
  131. $aTmplVarsAction = [
  132. 'action' => $oTemplate->parseHtmlByName('widget_action.html', [
  133. 'bx_if:show_link' => ['condition' => $bActionLink, 'content' => $aTmplVarsControl],
  134. 'bx_if:show_button' => ['condition' => !$bActionLink, 'content' => $aTmplVarsControl],
  135. ]),
  136. ];
  137. if(in_array($aAction['name'], ['settings']))
  138. $aTmplVarsActionsLeft[] = $aTmplVarsAction;
  139. else
  140. $aTmplVarsActionsRight[] = $aTmplVarsAction;
  141. }
  142. }
  143. $sIcon = BxDolStudioUtils::getWidgetIcon($mixedWidget);
  144. $bIcon = strpos($sIcon, '.') === false && strcmp(substr($sIcon, 0, 10), 'data:image') != 0;
  145. $sNotices = !empty($aNotices[$mixedWidget['id']]) ? $aNotices[$mixedWidget['id']] : '';
  146. $aModule = BxDolModuleQuery::getInstance()->getModuleByName($mixedWidget['module']);
  147. $bEnabled = empty($aModule) || !is_array($aModule) || (int)$aModule['enabled'] == 1;
  148. $sStyles = 'animation-delay: -.' . rand(1 , 75) . 's; animation-duration: .' . rand(15 , 20) . 's';
  149. return $oTemplate->parseHtmlByName('widget.html', array(
  150. 'id' => $mixedWidget['id'],
  151. 'name' => strtolower($sCaption),
  152. 'url' => !empty($mixedWidget['url']) ? bx_replace_markers($mixedWidget['url'], $aMarkers) : 'javascript:void(0)',
  153. // opening an app is a route change that loads for a moment: the soft 'loading' cue (interface sounds); a tile
  154. // with its own click handler sounds through it
  155. 'bx_if:show_navigate_cue' => array(
  156. 'condition' => empty($mixedWidget['click']),
  157. 'content' => array()
  158. ),
  159. 'bx_if:show_click_icon' => array(
  160. 'condition' => !empty($mixedWidget['click']),
  161. 'content' => array(
  162. 'content' => 'javascript:' . $mixedWidget['click'],
  163. )
  164. ),
  165. // right-click (or a long press) on the tile opens the app's context menu, fetched from its page on first use
  166. 'bx_if:show_context_menu' => array(
  167. 'condition' => !empty($mixedWidget['page_name']),
  168. 'content' => array(
  169. 'page' => !empty($mixedWidget['page_name']) ? $mixedWidget['page_name'] : '',
  170. 'id' => (int)$mixedWidget['id'],
  171. )
  172. ),
  173. 'bx_if:show_notice' => array(
  174. 'condition' => !empty($sNotices),
  175. 'content' => array(
  176. 'content' => $sNotices
  177. )
  178. ),
  179. 'bx_if:show_actions_left' => array(
  180. 'condition' => !empty($aTmplVarsActionsLeft),
  181. 'content' => array(
  182. 'bx_repeat:actions' => $aTmplVarsActionsLeft,
  183. )
  184. ),
  185. 'bx_repeat:actions_right' => $aTmplVarsActionsRight,
  186. 'move_left' => bx_html_attribute(_t('_adm_txt_widget_move_left', $sCaption)),
  187. 'move_right' => bx_html_attribute(_t('_adm_txt_widget_move_right', $sCaption)),
  188. 'bx_if:icon' => array (
  189. 'condition' => $bIcon,
  190. 'content' => array('icon' => $sIcon),
  191. ),
  192. 'bx_if:image' => array (
  193. 'condition' => !$bIcon,
  194. 'content' => array('icon_url' => $sIcon),
  195. ),
  196. 'caption' => $sCaption,
  197. 'caption_attr' => bx_html_attribute($sCaption),
  198. 'widget_disabled_class' => !$bEnabled ? 'bx-std-widget-icon-disabled' : '',
  199. 'widget_styles' => $sStyles
  200. ));
  201. }
  202. /*
  203. * Note. For multi upload form field add [] at the end of the field name in $mParams parameter.
  204. */
  205. public function getDefaultGhostTemplate($mParams, $sTemplateName = 'form_ghost_template.html')
  206. {
  207. if (!is_array($mParams))
  208. $mParams = ['name' => $mParams];
  209. return BxDolStudioTemplate::getInstance()->parseHtmlByName($sTemplateName, $mParams);
  210. }
  211. protected function getInjHeadLiveUpdates()
  212. {
  213. return '';
  214. }
  215. protected function getSoundsPlatform()
  216. {
  217. return 'studio';
  218. }
  219. /**
  220. * Settings > Sounds plays each choice as it is made, even while Studio itself is silent.
  221. */
  222. protected function isSoundsPreview()
  223. {
  224. return true;
  225. }
  226. protected function getInjFooterPopupMenus()
  227. {
  228. $sResult = '';
  229. $oAccounMenu = BxDolMenu::getObjectInstance('sys_studio_account_popup');
  230. if($oAccounMenu)
  231. $sResult .= $this->transBox('bx-std-pcap-menu-popup-account', ['content' => $oAccounMenu->getCode(), 'wrapper_attrs' => 'aria-label="' . bx_html_attribute(_t('_adm_tmi_cpt_account')) . '"'], true);
  232. return $sResult;
  233. }
  234. }
  235. /** @} */