AntonLV 5 лет назад
Родитель
Сommit
b8ee7c8191
63 измененных файлов с 2256 добавлено и 0 удалено
  1. 15 0
      modules/boonex/accounts/template/set_role_popup.html
  2. 18 0
      modules/boonex/decorous/data/template/studio/scripts/BxTemplStudioMenuAccountPopup.php
  3. 18 0
      modules/boonex/decorous/data/template/studio/scripts/BxTemplStudioRoles.php
  4. 18 0
      modules/boonex/decorous/data/template/studio/scripts/BxTemplStudioRolesActions.php
  5. 18 0
      modules/boonex/decorous/data/template/studio/scripts/BxTemplStudioRolesLevels.php
  6. 19 0
      modules/boonex/decorous/data/template/studio/scripts/BxTemplStudioWidget.php
  7. 18 0
      modules/boonex/lucid/data/template/studio/scripts/BxTemplStudioMenuAccountPopup.php
  8. 18 0
      modules/boonex/lucid/data/template/studio/scripts/BxTemplStudioRoles.php
  9. 18 0
      modules/boonex/lucid/data/template/studio/scripts/BxTemplStudioRolesActions.php
  10. 18 0
      modules/boonex/lucid/data/template/studio/scripts/BxTemplStudioRolesLevels.php
  11. 19 0
      modules/boonex/lucid/data/template/studio/scripts/BxTemplStudioWidget.php
  12. 18 0
      modules/boonex/ocean/data/template/studio/scripts/BxTemplStudioMenuAccountPopup.php
  13. 18 0
      modules/boonex/ocean/data/template/studio/scripts/BxTemplStudioRoles.php
  14. 18 0
      modules/boonex/ocean/data/template/studio/scripts/BxTemplStudioRolesActions.php
  15. 18 0
      modules/boonex/ocean/data/template/studio/scripts/BxTemplStudioRolesLevels.php
  16. 19 0
      modules/boonex/ocean/data/template/studio/scripts/BxTemplStudioWidget.php
  17. 18 0
      modules/boonex/protean/data/template/studio/scripts/BxTemplStudioMenuAccountPopup.php
  18. 18 0
      modules/boonex/protean/data/template/studio/scripts/BxTemplStudioRoles.php
  19. 18 0
      modules/boonex/protean/data/template/studio/scripts/BxTemplStudioRolesActions.php
  20. 18 0
      modules/boonex/protean/data/template/studio/scripts/BxTemplStudioRolesLevels.php
  21. 19 0
      modules/boonex/protean/data/template/studio/scripts/BxTemplStudioWidget.php
  22. 43 0
      studio/builder_roles.php
  23. 50 0
      studio/classes/BxDolStudioMenuAccountPopup.php
  24. 53 0
      studio/classes/BxDolStudioRoles.php
  25. 47 0
      studio/classes/BxDolStudioRolesActions.php
  26. 56 0
      studio/classes/BxDolStudioRolesLevels.php
  27. 283 0
      studio/classes/BxDolStudioRolesQuery.php
  28. 88 0
      studio/classes/BxDolStudioRolesUtils.php
  29. 101 0
      studio/classes/BxDolStudioWidget.php
  30. 15 0
      studio/js/roles.js
  31. 27 0
      studio/js/roles_actions.js
  32. 19 0
      studio/js/roles_levels.js
  33. 18 0
      studio/template/css/roles.css
  34. 3 0
      studio/template/images/icons/bc-arrow.svg
  35. 6 0
      studio/template/images/icons/bc-home.svg
  36. 5 0
      studio/template/images/icons/lmi-appearance.svg
  37. 2 0
      studio/template/images/icons/lmi-configuration.svg
  38. 8 0
      studio/template/images/icons/lmi-content.svg
  39. 8 0
      studio/template/images/icons/lmi-extensions.svg
  40. 6 0
      studio/template/images/icons/lmi-favorites.svg
  41. 7 0
      studio/template/images/icons/lmi-integrations.svg
  42. 8 0
      studio/template/images/icons/lmi-library.svg
  43. 7 0
      studio/template/images/icons/lmi-structure.svg
  44. 7 0
      studio/template/images/icons/lmi-users.svg
  45. 7 0
      studio/template/images/icons/tmi-account.svg
  46. 2 0
      studio/template/images/icons/tmi-actions.svg
  47. 8 0
      studio/template/images/icons/tmi-help.svg
  48. 10 0
      studio/template/images/icons/tmi-site.svg
  49. 37 0
      studio/template/images/icons/wi-bld-roles.svg
  50. 18 0
      studio/template/launcher_browser.html
  51. 14 0
      studio/template/menu_launcher_browser.html
  52. 5 0
      studio/template/mod_popup_settings.html
  53. 12 0
      studio/template/page_breadcrumb.html
  54. 20 0
      studio/template/rl_role.html
  55. 10 0
      studio/template/rl_roles_actions.html
  56. 10 0
      studio/template/rl_roles_levels.html
  57. 6 0
      studio/template/roles.html
  58. 25 0
      studio/template/scripts/BxBaseStudioMenuAccountPopup.php
  59. 92 0
      studio/template/scripts/BxBaseStudioRoles.php
  60. 125 0
      studio/template/scripts/BxBaseStudioRolesActions.php
  61. 294 0
      studio/template/scripts/BxBaseStudioRolesLevels.php
  62. 271 0
      studio/template/scripts/BxBaseStudioWidget.php
  63. 44 0
      studio/template/widget.html

+ 15 - 0
modules/boonex/accounts/template/set_role_popup.html

@@ -0,0 +1,15 @@
+<div class="bx-accnt-set-role">
+    <div class="bx-accnt-sr-roles">
+        <bx_repeat:roles>
+            <div class="bx-accnt-sr-role bx-def-round-corners bx-def-color-bg-hl-hover">
+                <div class="bx-accnt-sr-role-cnt bx-def-padding-leftright bx-def-padding-sec-topbottom">
+                    <input type="checkbox" id="__id__" name="role[]" value="__value__" onclick="__onclick__"<bx_if:show_checked> checked="checked"</bx_if:show_checked> />
+                    <label class="bx-def-margin-sec-left" for="__id__">__title__</label>
+                </div>
+            </div>
+        </bx_repeat:roles>
+    </div>
+    <div class="bx-accnt-sr-done bx-def-margin-sec-topbottom bx-def-font-align-center">
+        <a class="bx-btn" href="javascript:void(0)" onclick="javascript:$('.bx-popup-applied:visible').dolPopupHide();"><bx_text:_sys_done /></a>
+    </div>
+</div>

+ 18 - 0
modules/boonex/decorous/data/template/studio/scripts/BxTemplStudioMenuAccountPopup.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxTemplStudioMenuAccountPopup extends BxBaseStudioMenuAccountPopup
+{
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+    }
+}
+/** @} */

+ 18 - 0
modules/boonex/decorous/data/template/studio/scripts/BxTemplStudioRoles.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxTemplStudioRoles extends BxBaseStudioRoles
+{
+    function __construct($sPage = '')
+    {
+        parent::__construct($sPage);
+    }
+}
+/** @} */

+ 18 - 0
modules/boonex/decorous/data/template/studio/scripts/BxTemplStudioRolesActions.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxTemplStudioRolesActions extends BxBaseStudioRolesActions
+{
+    function __construct($aOptions, $oTemplate = false)
+    {
+        parent::__construct($aOptions, $oTemplate);
+    }
+}
+/** @} */

+ 18 - 0
modules/boonex/decorous/data/template/studio/scripts/BxTemplStudioRolesLevels.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxTemplStudioRolesLevels extends BxBaseStudioRolesLevels
+{
+    function __construct($aOptions, $oTemplate = false)
+    {
+        parent::__construct($aOptions, $oTemplate);
+    }
+}
+/** @} */

+ 19 - 0
modules/boonex/decorous/data/template/studio/scripts/BxTemplStudioWidget.php

@@ -0,0 +1,19 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+defined('BX_DOL') or die('hack attempt');
+
+class BxTemplStudioWidget extends BxBaseStudioWidget
+{
+    function __construct($mixedPageName)
+    {
+        parent::__construct($mixedPageName);
+    }
+}
+/** @} */

+ 18 - 0
modules/boonex/lucid/data/template/studio/scripts/BxTemplStudioMenuAccountPopup.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxTemplStudioMenuAccountPopup extends BxBaseStudioMenuAccountPopup
+{
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+    }
+}
+/** @} */

+ 18 - 0
modules/boonex/lucid/data/template/studio/scripts/BxTemplStudioRoles.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxTemplStudioRoles extends BxBaseStudioRoles
+{
+    function __construct($sPage = '')
+    {
+        parent::__construct($sPage);
+    }
+}
+/** @} */

+ 18 - 0
modules/boonex/lucid/data/template/studio/scripts/BxTemplStudioRolesActions.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxTemplStudioRolesActions extends BxBaseStudioRolesActions
+{
+    function __construct($aOptions, $oTemplate = false)
+    {
+        parent::__construct($aOptions, $oTemplate);
+    }
+}
+/** @} */

+ 18 - 0
modules/boonex/lucid/data/template/studio/scripts/BxTemplStudioRolesLevels.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxTemplStudioRolesLevels extends BxBaseStudioRolesLevels
+{
+    function __construct($aOptions, $oTemplate = false)
+    {
+        parent::__construct($aOptions, $oTemplate);
+    }
+}
+/** @} */

+ 19 - 0
modules/boonex/lucid/data/template/studio/scripts/BxTemplStudioWidget.php

@@ -0,0 +1,19 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+defined('BX_DOL') or die('hack attempt');
+
+class BxTemplStudioWidget extends BxBaseStudioWidget
+{
+    function __construct($mixedPageName)
+    {
+        parent::__construct($mixedPageName);
+    }
+}
+/** @} */

+ 18 - 0
modules/boonex/ocean/data/template/studio/scripts/BxTemplStudioMenuAccountPopup.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxTemplStudioMenuAccountPopup extends BxBaseStudioMenuAccountPopup
+{
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+    }
+}
+/** @} */

+ 18 - 0
modules/boonex/ocean/data/template/studio/scripts/BxTemplStudioRoles.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxTemplStudioRoles extends BxBaseStudioRoles
+{
+    function __construct($sPage = '')
+    {
+        parent::__construct($sPage);
+    }
+}
+/** @} */

+ 18 - 0
modules/boonex/ocean/data/template/studio/scripts/BxTemplStudioRolesActions.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxTemplStudioRolesActions extends BxBaseStudioRolesActions
+{
+    function __construct($aOptions, $oTemplate = false)
+    {
+        parent::__construct($aOptions, $oTemplate);
+    }
+}
+/** @} */

+ 18 - 0
modules/boonex/ocean/data/template/studio/scripts/BxTemplStudioRolesLevels.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxTemplStudioRolesLevels extends BxBaseStudioRolesLevels
+{
+    function __construct($aOptions, $oTemplate = false)
+    {
+        parent::__construct($aOptions, $oTemplate);
+    }
+}
+/** @} */

+ 19 - 0
modules/boonex/ocean/data/template/studio/scripts/BxTemplStudioWidget.php

@@ -0,0 +1,19 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+defined('BX_DOL') or die('hack attempt');
+
+class BxTemplStudioWidget extends BxBaseStudioWidget
+{
+    function __construct($mixedPageName)
+    {
+        parent::__construct($mixedPageName);
+    }
+}
+/** @} */

+ 18 - 0
modules/boonex/protean/data/template/studio/scripts/BxTemplStudioMenuAccountPopup.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxTemplStudioMenuAccountPopup extends BxBaseStudioMenuAccountPopup
+{
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+    }
+}
+/** @} */

+ 18 - 0
modules/boonex/protean/data/template/studio/scripts/BxTemplStudioRoles.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxTemplStudioRoles extends BxBaseStudioRoles
+{
+    function __construct($sPage = '')
+    {
+        parent::__construct($sPage);
+    }
+}
+/** @} */

+ 18 - 0
modules/boonex/protean/data/template/studio/scripts/BxTemplStudioRolesActions.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxTemplStudioRolesActions extends BxBaseStudioRolesActions
+{
+    function __construct($aOptions, $oTemplate = false)
+    {
+        parent::__construct($aOptions, $oTemplate);
+    }
+}
+/** @} */

+ 18 - 0
modules/boonex/protean/data/template/studio/scripts/BxTemplStudioRolesLevels.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxTemplStudioRolesLevels extends BxBaseStudioRolesLevels
+{
+    function __construct($aOptions, $oTemplate = false)
+    {
+        parent::__construct($aOptions, $oTemplate);
+    }
+}
+/** @} */

+ 19 - 0
modules/boonex/protean/data/template/studio/scripts/BxTemplStudioWidget.php

@@ -0,0 +1,19 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudioView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+defined('BX_DOL') or die('hack attempt');
+
+class BxTemplStudioWidget extends BxBaseStudioWidget
+{
+    function __construct($mixedPageName)
+    {
+        parent::__construct($mixedPageName);
+    }
+}
+/** @} */

+ 43 - 0
studio/builder_roles.php

@@ -0,0 +1,43 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaEndAdmin UNA Studio End Admin Pages
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+require_once('./../inc/header.inc.php');
+require_once(BX_DIRECTORY_PATH_INC . 'design.inc.php');
+
+bx_import('BxDolLanguages');
+
+bx_require_authentication(true);
+
+$sPage = bx_get('page');
+$sPage = $sPage !== false ? bx_process_input($sPage) : '';
+
+$oPage = new BxTemplStudioRoles($sPage);
+
+if(($mixedResult = $oPage->checkAction()) !== false) {
+    echoJson($mixedResult);
+    exit;
+}
+
+$oTemplate = BxDolStudioTemplate::getInstance();
+
+$sPageCode = $oPage->getPageCode();
+if($sPageCode === false)
+    $oTemplate->displayMsg(($sError = $oPage->getError(false)) !== false ? $sError : '_sys_txt_error_occured', true);
+
+$oTemplate->setPageNameIndex($oPage->getPageIndex());
+$oTemplate->setPageHeader($oPage->getPageHeader());
+$oTemplate->setPageContent('page_caption_code', $oPage->getPageCaption());
+$oTemplate->setPageContent('page_attributes', $oPage->getPageAttributes());
+$oTemplate->setPageContent('page_menu_code', $oPage->getPageMenu());
+$oTemplate->setPageContent('page_main_code', $sPageCode);
+$oTemplate->addCss($oPage->getPageCss());
+$oTemplate->addJs($oPage->getPageJs());
+$oTemplate->getPageCode();
+/** @} */

+ 50 - 0
studio/classes/BxDolStudioMenuAccountPopup.php

@@ -0,0 +1,50 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudio UNA Studio
+ * @{
+ */
+
+class BxDolStudioMenuAccountPopup extends BxTemplStudioMenu
+{
+    public function __construct ($aObject, $oTemplate)
+    {
+        parent::__construct ($aObject, $oTemplate);
+    }
+
+    protected function _isVisible ($a)
+    {
+        if(!parent::_isVisible($a))
+            return false;
+
+        $bResult = false;
+        switch ($a['name']) {
+            case 'edit':
+            case 'featured':
+                if(!BxDolStudioRolesUtils::getInstance()->isActionAllowed(BX_SRA_MANAGE_APPS))
+                    break;
+
+                list($sPageLink) = bx_get_base_url_popup();
+                $sLauncherLink = BxTemplStudioLauncher::getInstance()->getPageUrl();
+                if(strcmp($sPageLink, $sLauncherLink) != 0)
+                    break;
+
+                $bResult = true;
+                break;
+
+            case 'language':
+                $aLanguages = BxDolLanguagesQuery::getInstance()->getLanguages(false, true);
+                $bResult = count($aLanguages) > 1;
+                break;
+
+            default:
+                $bResult = true;
+        }
+
+        return $bResult;
+    }
+}
+
+/** @} */

+ 53 - 0
studio/classes/BxDolStudioRoles.php

@@ -0,0 +1,53 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudio UNA Studio
+ * @{
+ */
+
+define('BX_DOL_STUDIO_RL_TYPE_LEVELS', 'rlevels');
+define('BX_DOL_STUDIO_RL_TYPE_ACTIONS', 'ractions');
+define('BX_DOL_STUDIO_RL_TYPE_DEFAULT', BX_DOL_STUDIO_RL_TYPE_LEVELS);
+
+class BxDolStudioRoles extends BxTemplStudioWidget
+{
+    protected $sPage;
+
+    function __construct($sPage = "")
+    {
+        parent::__construct('builder_roles');
+
+        $this->oDb = BxDolStudioRolesQuery::getInstance();
+
+        $this->sPage = BX_DOL_STUDIO_RL_TYPE_DEFAULT;
+        if(is_string($sPage) && !empty($sPage))
+            $this->sPage = $sPage;
+    }
+
+    public function checkAction()
+    {
+        $sAction = bx_get('rl_action');
+    	if($sAction === false)
+            return false;
+
+        $sAction = bx_process_input($sAction);
+
+        $aResult = array('code' => 1, 'message' => _t('_adm_rl_err_cannot_process_action'));
+        switch($sAction) {
+            case 'get-page-by-type':
+                $sValue = bx_process_input(bx_get('rl_value'));
+                if(empty($sValue))
+                    break;
+
+                $this->sPage = $sValue;
+                $aResult = array('code' => 0, 'content' => $this->getPageCode());
+                break;
+        }
+
+        return $aResult;
+    }
+}
+
+/** @} */

+ 47 - 0
studio/classes/BxDolStudioRolesActions.php

@@ -0,0 +1,47 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudio UNA Studio
+ * @{
+ */
+
+class BxDolStudioRolesActions extends BxTemplStudioGrid
+{
+    protected $iRole = 0;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->oDb = BxDolStudioRolesQuery::getInstance();
+
+        $iLevel = (int)bx_get('role');
+        if($iLevel > 0)
+            $this->iRole = $iLevel;
+
+        $this->_aQueryAppend['role'] = $this->iRole;
+    }
+
+    protected function _isRowDisabled($aRow)
+    {
+        return $aRow['active'] == 0;
+    }
+
+    protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        if(empty($this->iRole))
+            return array();
+
+        $aActions = parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+        $aActionsActive = $this->oDb->getActions(array('type' => 'by_role_id_key_id', 'role_id' => $this->iRole));
+
+        foreach($aActions as $iKey => $aAction)
+            $aActions[$iKey]['active'] = array_key_exists($aAction['id'], $aActionsActive) ? 1 : 0;
+
+        return $aActions;
+    }
+}
+
+/** @} */

+ 56 - 0
studio/classes/BxDolStudioRolesLevels.php

@@ -0,0 +1,56 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudio UNA Studio
+ * @{
+ */
+
+define('BX_DOL_STUDIO_ROLES_ROLE_ID_INT_MAX', round(log(BX_DOL_INT_MAX, 2)));
+
+class BxDolStudioRolesLevels extends BxTemplStudioGrid
+{
+    protected $aNonDeletable;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->oDb = BxDolStudioRolesQuery::getInstance();
+
+        $this->aNonDeletable = array(
+            BX_DOL_STUDIO_ROLE_MASTER, 
+            BX_DOL_STUDIO_ROLE_OPERATOR
+        );
+    }
+
+    protected function _delete($mixedId)
+    {
+        $iId = (int)$mixedId;
+        $aRole = $this->oDb->getRoles(array('type' => 'by_id', 'id' => $iId));
+        if(empty($aRole) || !is_array($aRole))
+            return false;
+
+        if(in_array($iId, $this->aNonDeletable) || $this->oDb->isRoleUsed($iId))
+            return false;
+
+        $isStopDeletion = false;
+        bx_alert('roles', 'before_delete', $iId, 0, array('role' => $aRole, 'stop_deletion' => &$isStopDeletion));
+        if($isStopDeletion)
+            return false;
+
+        $oLanguage = BxDolStudioLanguagesUtils::getInstance();
+        $oLanguage->deleteLanguageString($aRole['title']);
+        $oLanguage->deleteLanguageString($aRole['description']);
+
+        if(!parent::_delete($mixedId)) 
+            return false;
+
+        bx_alert('roles', 'deleted', $iId, 0, array('role' => $aRole));
+
+        return true;
+    }
+}
+
+/** @} */

+ 283 - 0
studio/classes/BxDolStudioRolesQuery.php

@@ -0,0 +1,283 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudio UNA Studio
+ * @{
+ */
+
+class BxDolStudioRolesQuery extends BxDolDb implements iBxDolSingleton
+{
+    public function __construct()
+    {
+        if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
+            trigger_error ('Multiple instances are not allowed for the class: ' . get_class($this), E_USER_ERROR);
+
+        parent::__construct();
+    }
+
+    public function __clone()
+    {
+        if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
+            trigger_error('Clone is not allowed for the class: ' . get_class($this), E_USER_ERROR);
+    }
+
+    static function getInstance()
+    {
+        if(!isset($GLOBALS['bxDolClasses'][__CLASS__]))
+            $GLOBALS['bxDolClasses'][__CLASS__] = new BxDolStudioRolesQuery();
+
+        return $GLOBALS['bxDolClasses'][__CLASS__];
+    }
+
+    public function setRole ($iAccountId, $iRole)
+    {
+        $sBindings = array(
+            'account_id' => $iAccountId,
+            'role' => $iRole
+        );
+        if(!$this->query("REPLACE INTO `sys_std_roles_members` SET `account_id`=:account_id, `role`=:role", $sBindings))
+            return false;
+
+        $this->query("UPDATE `sys_accounts` SET `role`=:role WHERE `id`=:id", array(
+            'id' => $iAccountId,
+            'role' => $iRole == 0 ? 1 : 3
+        ));
+
+        return true;
+    }
+
+    public function getRoles($aParams)
+    {
+        $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+        $sSelectClause = $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+
+        if(!isset($aParams['order']) || empty($aParams['order']))
+           $sOrderClause = "ORDER BY `tr`.`Order` ASC";
+
+        switch($aParams['type']) {
+            case 'by_id':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = array(
+                    'id' => $aParams['id']
+                );
+
+                $sWhereClause .= "AND `tr`.`id`=:id";
+                $sLimitClause .= "LIMIT 1";
+                break;               
+
+            case 'all_active':
+                $sWhereClause .= "AND `tr`.`active`=1";
+                break;
+
+            case 'all_active_pair':
+                $aMethod['name'] = "getPairs";
+                $aMethod['params'][1] = 'id';
+                $aMethod['params'][2] = 'name';
+                $sWhereClause .= "AND `tr`.`active`=1";
+                break;
+
+            case 'all_pair':
+                $aMethod['name'] = "getPairs";
+                $aMethod['params'][1] = 'id';
+                $aMethod['params'][2] = 'title';
+                break;
+
+            case 'all_order_id':
+                $sOrderClause = "ORDER BY `tr`.`id` ASC";
+                break;
+
+            case 'all':
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT 
+                `tr`.`id` AS `id`,
+                `tr`.`name` AS `name`,
+                `tr`.`title` AS `title`,
+                `tr`.`description` AS `description`,
+                `tr`.`active` AS `active`,
+                `tr`.`order` AS `order`" . $sSelectClause . "
+            FROM `sys_std_roles` AS `tr` " . $sJoinClause . "
+            WHERE 1 " . $sWhereClause . " " . $sOrderClause . " " . $sLimitClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function isRoleUsed($iId)
+    {
+        return (int)$this->getOne("SELECT `id` FROM `sys_std_roles_members` WHERE `role` & :role_id <> 0", array(
+            'role_id' => $iId
+        )) > 0;
+    }
+
+    public function getRoleOrderMax()
+    {
+        return (int)$this->getOne("SELECT MAX(`order`) FROM `sys_std_roles` WHERE 1");
+    }
+
+    public function updateRoles($aSet, $aWhere)
+    {
+        if(empty($aSet) || empty($aWhere))
+            return false;
+
+        return (int)$this->query("UPDATE `sys_std_roles` SET " . $this->arrayToSQL($aSet) . " WHERE " . $this->arrayToSQL($aWhere)) > 0;
+    }
+
+    public function deleteRoles($aParams)
+    {
+    	$aBindings = array();
+        $sWhereClause = $sLimitClause = "";
+
+        switch($aParams['type']) {
+            case 'by_id':
+            	$aBindings = array(
+                    'id' => $aParams['id']
+                );
+
+                $sWhereClause .= "AND `id`=:id";
+                break;
+        }
+
+        $sSql = "DELETE FROM `sys_std_roles` WHERE 1 " . $sWhereClause . " " . $sLimitClause;
+
+        return (int)$this->query($sSql, $aBindings) > 0;
+    }
+
+    public function getActions($aParams)
+    {
+        $sMemoryKey = '';
+        $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+        $sSelectClause = $sJoinClause = $sWhereClause = $sGroupClause = $sOrderClause = $sLimitClause = "";
+
+        if(!isset($aParams['order']) || empty($aParams['order']))
+           $sOrderClause = "ORDER BY `tra`.`name` ASC";
+           
+        switch($aParams['type']) {
+            case 'by_name':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = array(
+                    'name' => $aParams['name'],
+                );
+
+                $sWhereClause .= "AND `tra`.`name`=:name ";
+                break;
+
+            case 'by_names':
+            	$aMethod['params'][1] = array();
+
+                $sWhereClause .= "AND `tra`.`name` IN(" . $this->implode_escape($aParams['value']) . ") ";
+                $sMemoryKey = 'BxDolStudioRolesQuery::getActions' . $aParams['type'] . $sWhereClause;
+                break;
+
+            case 'by_role_id':
+            	$aMethod['params'][1] = array(
+                    'role_id' => $aParams['role_id']
+                );
+
+                $sJoinClause .= "LEFT JOIN `sys_std_roles_actions2roles` AS `trar` ON `tra`.`id`=`trar`.`action_id` ";
+                $sWhereClause .= "AND `trar`.`role_id`=:role_id ";
+                break;
+
+            case 'by_role_id_key_id':
+                $aMethod['name'] = 'getAllWithKey';
+                $aMethod['params'][1] = 'id';
+                $aMethod['params'][2] = array(
+                    'role_id' => $aParams['role_id']
+                );
+
+                $sJoinClause .= "LEFT JOIN `sys_std_roles_actions2roles` AS `trar` ON `tra`.`id`=`trar`.`action_id` ";
+                $sWhereClause .= "AND `trar`.`role_id`=:role_id";
+                break;
+
+            case 'counter_by_roles':
+                $aMethod['name'] = 'getPairs';
+                $aMethod['params'][1] = 'role_id';
+                $aMethod['params'][2] = 'counter';
+                $sSelectClause = ", `trar`.`role_id` AS `role_id`, COUNT(`trar`.`action_id`) AS `counter`";
+                $sJoinClause = "LEFT JOIN `sys_std_roles_actions2roles` AS `trar` ON `tra`.`id`=`trar`.`action_id` ";
+                $sGroupClause = "GROUP BY `trar`.`role_id`";
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT 
+                `tra`.`id` AS `id`,
+                `tra`.`name` AS `name`,
+                `tra`.`title` AS `title`,
+                `tra`.`description` AS `description`" . $sSelectClause . "
+            FROM `sys_std_roles_actions` AS `tra` " . $sJoinClause . "
+            WHERE 1 " . $sWhereClause . " " . $sGroupClause . " " . $sOrderClause . " " . $sLimitClause;
+
+        if ($sMemoryKey) {
+            array_unshift($aMethod['params'], $sMemoryKey, $aMethod['name']);
+            return call_user_func_array(array($this, 'fromMemory'), $aMethod['params']);
+        }
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function switchAction($iRoleId, $iActionId, $bEnable)
+    {
+        $aBindings = array(
+            'role_id' => $iRoleId,
+            'action_id' => $iActionId
+        );
+
+        if($bEnable)
+            $sSql = "INSERT INTO `sys_std_roles_actions2roles` SET `role_id`=:role_id, `action_id`=:action_id";
+        else
+            $sSql = "DELETE FROM `sys_std_roles_actions2roles` WHERE `role_id`=:role_id AND `action_id`=:action_id";
+
+        return (int)$this->query($sSql, $aBindings) > 0;
+    }
+
+    public function isActionAllowed($iRole, $iActionId)
+    {
+        $aResult = $this->getRow("SELECT * FROM `sys_std_roles_actions2roles` WHERE :role & POW(2, (`role_id` - 1)) != 0 AND `action_id`=:action_id", array(
+            'role' => $iRole,
+            'action_id' => $iActionId
+        ));
+
+        return !empty($aResult) && is_array($aResult);
+    }
+
+    public function getMembers($aParams)
+    {
+        $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+        $sSelectClause = $sJoinClause = $sWhereClause = $sGroupClause = $sOrderClause = $sLimitClause = "";
+
+        if(!isset($aParams['order']) || empty($aParams['order']))
+           $sOrderClause = "ORDER BY `trm`.`id` ASC";
+
+        switch($aParams['type']) {
+            case 'by_account_id':
+                $aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = array(
+                    'account_id' => $aParams['account_id']
+                );
+
+                $sWhereClause .= "AND `trm`.`account_id`=:account_id ";
+                break;
+
+            case 'by_role_id':
+            	$aMethod['params'][1] = array(
+                    'role_id' => $aParams['role_id']
+                );
+
+                $sWhereClause .= "AND `trm`.`role_id`=:role_id ";
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT 
+                `trm`.`id` AS `id`,
+                `trm`.`account_id` AS `account_id`,
+                `trm`.`role` AS `role`" . $sSelectClause . "
+            FROM `sys_std_roles_members` AS `trm` " . $sJoinClause . "
+            WHERE 1 " . $sWhereClause . " " . $sGroupClause . " " . $sOrderClause . " " . $sLimitClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+}
+
+/** @} */

+ 88 - 0
studio/classes/BxDolStudioRolesUtils.php

@@ -0,0 +1,88 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudio UNA Studio
+ * @{
+ */
+
+/**
+ * Default Studio roles actions.
+ */
+define('BX_SRA_MANAGE_ROLES', 'manage roles');
+define('BX_SRA_MANAGE_APPS', 'manage apps');
+
+class BxDolStudioRolesUtils extends BxDol implements iBxDolSingleton
+{
+    function __construct()
+    {
+        if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
+            trigger_error ('Multiple instances are not allowed for the class: ' . get_class($this), E_USER_ERROR);
+
+        parent::__construct();
+
+        $this->oDb = BxDolStudioRolesQuery::getInstance();
+    }
+    
+    public function __clone()
+    {
+        if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
+            trigger_error('Clone is not allowed for the class: ' . get_class($this), E_USER_ERROR);
+    }
+
+    static function getInstance()
+    {
+        if(!isset($GLOBALS['bxDolClasses'][__CLASS__]))
+            $GLOBALS['bxDolClasses'][__CLASS__] = new BxDolStudioRolesUtils();
+
+        return $GLOBALS['bxDolClasses'][__CLASS__];
+    }
+
+    public function getRoles($bActive = true)
+    {
+        return $this->oDb->getRoles(array('type' => 'all' . ($bActive ? '_active' : '')));
+    }
+    
+    public function getRole($iAccountId)
+    {
+        $aMember = $this->oDb->getMembers(array('type' => 'by_account_id', 'account_id' => $iAccountId));
+        if(empty($aMember) || !is_array($aMember))
+            return 0;
+
+        return (int)$aMember['role'];
+    }
+
+    public function setRole($iAccountId, $mixedRole)
+    {
+        if(is_array($mixedRole)) {
+            if(count($mixedRole) != 1 || current($mixedRole) != 0) {
+                $iAccountRole = 0;
+
+                foreach($mixedRole as $iRole)
+                    $iAccountRole = $iAccountRole | pow(2, ($iRole - 1));
+
+                $mixedRole = $iAccountRole;
+            }
+            else 
+                $mixedRole = 0;
+        }
+
+        return $this->oDb->setRole($iAccountId, $mixedRole);
+    }
+
+    public function isActionAllowed($sAction, $iAccountId = 0)
+    {
+        if(empty($iAccountId))
+            $iAccountId = getLoggedId();
+
+        $aAction = $this->oDb->getActions(array('type' => 'by_name', 'name' => $sAction));
+        if(empty($aAction) || !is_array($aAction))
+            return true;
+
+        $iRole = $this->getRole($iAccountId);
+        return $this->oDb->isActionAllowed($iRole, (int)$aAction['id']);
+    }
+}
+
+/** @} */

+ 101 - 0
studio/classes/BxDolStudioWidget.php

@@ -0,0 +1,101 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudio UNA Studio
+ * @{
+ */
+
+class BxDolStudioWidget extends BxTemplStudioPage
+{
+    protected $aActions;
+
+    public function __construct($mixedPageName)
+    {
+        parent::__construct($mixedPageName);
+
+        $this->aActions = array();
+
+        if(!$this->bPageMultiple) {
+            $this->sPageRssHelpId = $this->aPage['name'];
+
+            $this->aPage['featured'] = $this->oDb->isFeatured($this->aPage);
+            $this->aPage['bookmark'] = $this->oDb->isBookmarked($this->aPage, bx_get_logged_profile_id());
+
+            $sJsObjectLauncher = BxTemplStudioLauncher::getInstance()->getPageJsObject();
+
+            if(BxDolStudioRolesUtils::getInstance()->isActionAllowed(BX_SRA_MANAGE_APPS))
+                $this->addAction(array(
+                    'type' => 'switcher',
+                    'name' => 'featured',
+                    'caption' => '_adm_txt_pca_featured',
+                    'checked' => $this->aPage['featured'],
+                    'onchange' => "javascript:" . $sJsObjectLauncher . ".featured('" . $this->aPage['name'] . "', this)"
+                ));
+
+            $this->addAction(array(
+                'type' => 'switcher',
+                'name' => 'bookmark',
+                'caption' => '_adm_txt_pca_bookmark',
+                'checked' => $this->aPage['bookmark'],
+                'onchange' => "javascript:" . $sJsObjectLauncher . ".bookmark('" . $this->aPage['name'] . "', this)"
+            ));
+
+            $this->addAction(array(
+                'type' => 'select',
+                'name' => 'rearrange',
+                'caption' => '_adm_txt_pca_rearrange',
+                'value' => '{widget_type}',
+                'values' => BxDolFormQuery::getDataItems($this->_sTypesPreList),
+                'onchange' => "javascript:" . $sJsObjectLauncher . ".rearrange({widget_id}, this)"
+            ));
+
+            $this->aMarkers['page_name'] = $this->aPage['name'];
+        }
+        else
+            foreach($this->aPage as $sName => $aPage) 
+                $this->aPage[$sName]['featured'] = $this->oDb->isFeatured($aPage);
+    }
+
+    public function addAction($aAction, $bOnRight = true)
+    {
+        if($bOnRight)
+            $this->aActions[] = $aAction;
+        else
+            $this->aActions = array_merge(array($aAction), $this->aActions);
+    }
+
+    public function removeActions()
+    {
+        $this->aActions = array();
+    }
+
+    public function featured()
+    {
+        $bResult = $this->oDb->featured($this->aPage);
+        if(!$bResult)
+            return array('code' => 1, 'message' => _t('_adm_err_operation_failed'));
+
+        $iWidgetId = (int)$this->aPage['wid_id'];
+        return array(
+            'code' => 0, 
+            'message' => _t('_adm_scs_operation_done'),
+            'widget_id' => $iWidgetId,
+            'widget' => !empty($this->aPage['wid_id']) ? BxTemplStudioFunctions::getInstance()->getWidget($iWidgetId) : ''
+        );
+    }
+    
+    public function bookmark()
+    {
+        $iProfileId = bx_get_logged_profile_id();
+
+        $bResult = $this->oDb->bookmark($this->aPage, $iProfileId);
+        if(!$bResult)
+            return array('code' => 1, 'message' => _t('_adm_err_operation_failed'));
+
+        return array('code' => 0, 'message' => _t('_adm_scs_operation_done'));
+    }
+}
+
+/** @} */

+ 15 - 0
studio/js/roles.js

@@ -0,0 +1,15 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudio UNA Studio
+ * @{
+ */
+function BxDolStudioRoles(oOptions) {
+    this.sActionsUrl = oOptions.sActionUrl;
+    this.sObjName = oOptions.sObjName == undefined ? 'oBxDolStudioRoles' : oOptions.sObjName;
+    this.sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'fade' : oOptions.sAnimationEffect;
+    this.iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+    this.sPage = oOptions.sPage == undefined ? 'general' : oOptions.sPage;
+}
+/** @} */

+ 27 - 0
studio/js/roles_actions.js

@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudio UNA Studio
+ * @{
+ */
+
+function BxDolStudioRolesActions(oOptions) {
+    this._iSearchTimeoutId = false;
+    this.sActionsUrl = oOptions.sActionUrl;
+    this.sPageUrl = oOptions.sPageUrl;
+    this.sObjNameGrid = oOptions.sObjNameGrid;
+    this.sObjName = oOptions.sObjName == undefined ? 'oBxDolStudioRolesActions' : oOptions.sObjName;
+    this.sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'fade' : oOptions.sAnimationEffect;
+    this.iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+    this.sParamsDivider = oOptions.sParamsDivider == undefined ? '#-#' : oOptions.sParamsDivider;
+
+    this.sTextSearchInput = oOptions.sTextSearchInput == undefined ? '' : oOptions.sTextSearchInput;
+}
+
+BxDolStudioRolesActions.prototype.onChangeRole = function() {
+    var iRole = parseInt($('#bx-grid-role-' + this.sObjNameGrid).val().replace('id-', ''));
+    document.location.href = this.sPageUrl + (iRole > 0 ? '&role=' + iRole : ''); 
+};
+
+/** @} */

+ 19 - 0
studio/js/roles_levels.js

@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudio UNA Studio
+ * @{
+ */
+
+function BxDolStudioRolesLevels(oOptions) {
+    this.sActionsUrl = oOptions.sActionUrl;
+    this.sPageUrl = oOptions.sPageUrl;
+    this.sObjNameGrid = oOptions.sObjNameGrid;
+    this.sObjName = oOptions.sObjName == undefined ? 'oBxDolStudioRolesLevels' : oOptions.sObjName;
+    this.sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'fade' : oOptions.sAnimationEffect;
+    this.iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+    this.sParamsDivider = oOptions.sParamsDivider == undefined ? '#-#' : oOptions.sParamsDivider;
+}
+
+/** @} */

+ 18 - 0
studio/template/css/roles.css

@@ -0,0 +1,18 @@
+/*--- General ---*/
+div.bx-grid-header div.bx-form-element-wrapper {
+    position: relative;
+    float: left;
+    width: 165px;
+}
+
+/*--- Levels page -> Add/Edit Level block ---*/
+div.bx-rl-role {}
+div.bx-rl-role-cnt {}
+
+/*--- Actions page -> Panel Top style ---*/
+div.bx-grid-header div#bx-form-element-role {
+    margin-right: 20px;
+}
+div.bx-grid-header div#bx-form-element-keyword {
+    margin-top: 0px;
+}

+ 3 - 0
studio/template/images/icons/bc-arrow.svg

@@ -0,0 +1,3 @@
+<svg width="24" height="22" viewBox="0 0 24 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M10 14.6667L14 11L10 7.33337" stroke="#595959" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

+ 6 - 0
studio/template/images/icons/bc-home.svg

@@ -0,0 +1,6 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.75 9.75H5C3.895 9.75 3 8.855 3 7.75V5C3 3.895 3.895 3 5 3H7.75C8.855 3 9.75 3.895 9.75 5V7.75C9.75 8.855 8.855 9.75 7.75 9.75Z" stroke="#FAFAFA" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M19 9.75H16.25C15.145 9.75 14.25 8.855 14.25 7.75V5C14.25 3.895 15.145 3 16.25 3H19C20.105 3 21 3.895 21 5V7.75C21 8.855 20.105 9.75 19 9.75Z" stroke="#FAFAFA" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.75 21H5C3.895 21 3 20.105 3 19V16.25C3 15.145 3.895 14.25 5 14.25H7.75C8.855 14.25 9.75 15.145 9.75 16.25V19C9.75 20.105 8.855 21 7.75 21Z" stroke="#FAFAFA" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M19 21H16.25C15.145 21 14.25 20.105 14.25 19V16.25C14.25 15.145 15.145 14.25 16.25 14.25H19C20.105 14.25 21 15.145 21 16.25V19C21 20.105 20.105 21 19 21Z" stroke="#FAFAFA" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

+ 5 - 0
studio/template/images/icons/lmi-appearance.svg

@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M18.718 5.28199C22.428 8.99199 22.428 15.007 18.718 18.717C15.008 22.427 8.99299 22.427 5.28299 18.717C1.57299 15.007 1.57299 8.99199 5.28299 5.28199C8.99199 1.57299 15.008 1.57299 18.718 5.28199" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M8 20.619V15.63C8 15.16 8.11 14.696 8.323 14.277L12 7L15.677 14.277C15.89 14.696 16 15.16 16 15.63V20.619" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M15.9229 14.973L14.0259 16.396L11.9999 14.876L9.9739 16.396L8.0769 14.973" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

Разница между файлами не показана из-за своего большого размера
+ 2 - 0
studio/template/images/icons/lmi-configuration.svg


+ 8 - 0
studio/template/images/icons/lmi-content.svg

@@ -0,0 +1,8 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g opacity="0.7">
+<path d="M16.502 13.1255H7.49829" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M15.0014 16.5019H8.99892C8.60092 16.5019 8.21921 16.3438 7.93779 16.0624C7.65636 15.781 7.49829 15.3993 7.49829 15.0013V8.99879C7.49829 8.6008 7.65636 8.21909 7.93779 7.93767C8.21921 7.65624 8.60092 7.49817 8.99892 7.49817H15.0014C15.3994 7.49817 15.7811 7.65624 16.0625 7.93767C16.344 8.21909 16.502 8.6008 16.502 8.99879V15.0013C16.502 15.3993 16.344 15.781 16.0625 16.0624C15.7811 16.3438 15.3994 16.5019 15.0014 16.5019Z" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<circle cx="12.0001" cy="12" r="9.00375" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M9.99927 10.4994H14.0009" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>

+ 8 - 0
studio/template/images/icons/lmi-extensions.svg

@@ -0,0 +1,8 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g opacity="0.7">
+<path d="M18.3667 5.63339C21.8829 9.14959 21.8829 14.8504 18.3667 18.3666C14.8505 21.8828 9.14967 21.8828 5.63349 18.3666C2.11731 14.8504 2.11728 9.14959 5.63344 5.63339C7.32197 3.94484 9.61213 2.99622 12.0001 2.99622C14.388 2.99622 16.6782 3.94484 18.3667 5.63339" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<rect x="7.3252" y="12.6853" width="3.27636" height="3.27636" rx="1" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<circle cx="14.9782" cy="14.3249" r="1.83176" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M11.8631 6.80583L10.0713 9.90712C10.0266 9.98458 10.0267 10.08 10.0715 10.1574C10.1163 10.2349 10.199 10.2825 10.2884 10.2823H13.8699C13.9594 10.2825 14.0421 10.2349 14.0869 10.1574C14.1317 10.08 14.1317 9.98458 14.087 9.90712L12.2963 6.80583C12.2516 6.72845 12.169 6.68079 12.0797 6.68079C11.9903 6.68079 11.9078 6.72845 11.8631 6.80583Z" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>

+ 6 - 0
studio/template/images/icons/lmi-favorites.svg

@@ -0,0 +1,6 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g opacity="0.7">
+<path d="M11.9982 14.8412L14.0821 15.9356C14.4883 16.1497 14.9615 15.8036 14.8844 15.3524L14.4863 13.0324L16.172 11.3907C16.5011 11.0716 16.319 10.5134 15.8658 10.4483L13.5359 10.1102L12.4944 7.99832C12.2913 7.58715 11.7051 7.58715 11.503 7.99832L10.4616 10.1102L8.13162 10.4483C7.67843 10.5144 7.49635 11.0716 7.82549 11.3907L9.51119 13.0324L9.11202 15.3534C9.03499 15.8046 9.50819 16.1487 9.91436 15.9366L11.9982 14.8422" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M18.3668 5.65139C21.9433 9.22788 21.8822 15.0633 18.1837 18.5628C14.7693 21.7931 9.23096 21.7931 5.81654 18.5628C2.118 15.0633 2.05697 9.22788 5.63346 5.65139C9.14992 2.13492 14.8503 2.13492 18.3668 5.65139" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>

+ 7 - 0
studio/template/images/icons/lmi-integrations.svg

@@ -0,0 +1,7 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g opacity="0.7">
+<path d="M14.2189 15.2194C13.5509 15.7241 12.7372 15.9987 11.9 16.0017C9.74491 15.9984 7.99715 14.2551 7.98835 12.1001L7.99835 10.4994L6.66479 11.8339" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M12.0001 21.0037C7.02745 21.0037 2.99634 16.9726 2.99634 12C2.99634 7.02733 7.02745 2.99622 12.0001 2.99622C16.9727 2.99622 21.0038 7.02733 21.0038 12C21.0038 16.9726 16.9727 21.0037 12.0001 21.0037" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M17.3354 12.166L16.0019 13.5006L16.0159 11.8999C16.0065 9.74353 14.2567 7.99992 12.1003 7.99829C11.2624 8.00132 10.448 8.27581 9.7793 8.78062" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>

+ 8 - 0
studio/template/images/icons/lmi-library.svg

@@ -0,0 +1,8 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g opacity="0.7">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.75 9.75H5C3.895 9.75 3 8.855 3 7.75V5C3 3.895 3.895 3 5 3H7.75C8.855 3 9.75 3.895 9.75 5V7.75C9.75 8.855 8.855 9.75 7.75 9.75Z" stroke="#FAFAFA" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M19 9.75H16.25C15.145 9.75 14.25 8.855 14.25 7.75V5C14.25 3.895 15.145 3 16.25 3H19C20.105 3 21 3.895 21 5V7.75C21 8.855 20.105 9.75 19 9.75Z" stroke="#FAFAFA" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.75 21H5C3.895 21 3 20.105 3 19V16.25C3 15.145 3.895 14.25 5 14.25H7.75C8.855 14.25 9.75 15.145 9.75 16.25V19C9.75 20.105 8.855 21 7.75 21Z" stroke="#FAFAFA" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M19 21H16.25C15.145 21 14.25 20.105 14.25 19V16.25C14.25 15.145 15.145 14.25 16.25 14.25H19C20.105 14.25 21 15.145 21 16.25V19C21 20.105 20.105 21 19 21Z" stroke="#FAFAFA" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>

+ 7 - 0
studio/template/images/icons/lmi-structure.svg

@@ -0,0 +1,7 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g opacity="0.7">
+<path d="M18.3639 5.63604C21.8787 9.15076 21.8787 14.8492 18.3639 18.3639C14.8492 21.8787 9.15074 21.8787 5.63604 18.3639C2.12132 14.8492 2.12132 9.15074 5.63604 5.63604C9.15076 2.12132 14.8492 2.12132 18.3639 5.63604" stroke="white" stroke-width="1.5"/>
+<path d="M12 21V3" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M12 12H21" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>

+ 7 - 0
studio/template/images/icons/lmi-users.svg

@@ -0,0 +1,7 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g opacity="0.7">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6 18.584C7.569 17.059 9.692 16.121 12.023 16.121C14.331 16.121 16.431 17.04 18 18.537C16.431 20.062 14.308 21 11.977 21C9.669 21 7.569 20.081 6 18.584Z" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M3.975 16.025C3.365 14.811 3 13.452 3 12C3 7.026 7.026 3 12 3C16.974 3 21 7.026 21 12C21 13.45 20.637 14.81 20.023 16.023" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M14.1213 7.87868C15.2929 9.05025 15.2929 10.9497 14.1213 12.1213C12.9497 13.2929 11.0502 13.2929 9.87868 12.1213C8.70711 10.9497 8.70711 9.05025 9.87868 7.87868C11.0502 6.70711 12.9497 6.70711 14.1213 7.87868" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>

+ 7 - 0
studio/template/images/icons/tmi-account.svg

@@ -0,0 +1,7 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g opacity="0.7">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6 18.584C7.569 17.059 9.692 16.121 12.023 16.121C14.331 16.121 16.431 17.04 18 18.537C16.431 20.062 14.308 21 11.977 21C9.669 21 7.569 20.081 6 18.584Z" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M3.975 16.025C3.365 14.811 3 13.452 3 12C3 7.026 7.026 3 12 3C16.974 3 21 7.026 21 12C21 13.45 20.637 14.81 20.023 16.023" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M14.1213 7.87868C15.2929 9.05025 15.2929 10.9497 14.1213 12.1213C12.9497 13.2929 11.0502 13.2929 9.87868 12.1213C8.70711 10.9497 8.70711 9.05025 9.87868 7.87868C11.0502 6.70711 12.9497 6.70711 14.1213 7.87868" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>

Разница между файлами не показана из-за своего большого размера
+ 2 - 0
studio/template/images/icons/tmi-actions.svg


+ 8 - 0
studio/template/images/icons/tmi-help.svg

@@ -0,0 +1,8 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g opacity="0.7">
+<circle cx="12.0003" cy="12" r="9.00375" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M9.68506 9.6847C9.92208 8.66314 10.8525 7.95484 11.9003 7.99832C13.073 7.93337 14.0783 8.82697 14.1512 9.99916C14.1512 11.5037 12.0004 12 12.0004 13.0004" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M12.1253 15.7516C12.1253 15.8206 12.0693 15.8766 12.0002 15.8766C11.9311 15.8766 11.8752 15.8206 11.8752 15.7516C11.8752 15.6825 11.9311 15.6265 12.0002 15.6265" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M12.0002 15.6265C12.0692 15.6265 12.1252 15.6825 12.1252 15.7516" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>

+ 10 - 0
studio/template/images/icons/tmi-site.svg

@@ -0,0 +1,10 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g opacity="0.7">
+<path d="M8 20.064V11C8 9.895 8.895 9 10 9H20.487" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M8 14H20.776" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M11.0049 11.49C11.0019 11.49 10.9999 11.492 10.9999 11.495C10.9999 11.498 11.0019 11.5 11.0049 11.5C11.0079 11.5 11.0099 11.498 11.0099 11.495C11.0099 11.492 11.0079 11.49 11.0049 11.49" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M13.5479 11.49C13.5449 11.49 13.5429 11.492 13.5429 11.495C13.5429 11.498 13.5449 11.5 13.5479 11.5C13.5509 11.5 13.5529 11.498 13.5529 11.495C13.5529 11.492 13.5509 11.49 13.5479 11.49" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12 21V21C16.971 21 21 16.971 21 12V12C21 7.029 16.971 3 12 3V3C7.029 3 3 7.029 3 12V12C3 16.971 7.029 21 12 21Z" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M16.0879 11.49C16.0849 11.49 16.0829 11.492 16.0829 11.495C16.0829 11.498 16.0849 11.5 16.0879 11.5C16.0909 11.5 16.0929 11.498 16.0929 11.495C16.0929 11.492 16.0899 11.49 16.0879 11.49" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>

+ 37 - 0
studio/template/images/icons/wi-bld-roles.svg

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="64px" height="64px" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 54.1 (76490) - https://sketchapp.com -->
+    <title>permissions</title>
+    <desc>Created with Sketch.</desc>
+    <defs>
+        <path d="M32,64 C46.0222222,64 53.8173667,64 58.9086889,58.9086889 C64,53.8173667 64,46.0222222 64,32 C64,17.9777778 64,10.1826333 58.9086889,5.09131111 C53.8173667,0 46.0222222,0 32,0 C17.9777778,0 10.1826333,0 5.09131111,5.09131111 C0,10.1826333 0,17.9777778 0,32 C0,46.0222222 0,53.8173667 5.09131111,58.9086889 C10.1826333,64 17.9777778,64 32,64 Z" id="path-1"></path>
+        <linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-3">
+            <stop stop-color="#FDFEFF" offset="0%"></stop>
+            <stop stop-color="#FBFCFD" stop-opacity="0.9" offset="100%"></stop>
+        </linearGradient>
+        <path d="M36.6666667,4.3902439 L26.6666667,4.3902439 L26.6666667,10.9756098 L13.3333333,10.9756098 L13.3333333,4.3902439 L3.33333333,4.3902439 C1.49305556,4.3902439 0,5.86509146 0,7.68292683 L0,31.8292683 C0,33.6471037 1.49305556,35.1219512 3.33333333,35.1219512 L36.6666667,35.1219512 C38.5069444,35.1219512 40,33.6471037 40,31.8292683 L40,7.68292683 C40,5.86509146 38.5069444,4.3902439 36.6666667,4.3902439 Z M20,15.3658537 C22.4513889,15.3658537 24.4444444,17.3346037 24.4444444,19.7560976 C24.4444444,22.1775915 22.4513889,24.1463415 20,24.1463415 C17.5486111,24.1463415 15.5555556,22.1775915 15.5555556,19.7560976 C15.5555556,17.3346037 17.5486111,15.3658537 20,15.3658537 Z M26.4791667,30.7317073 L13.5208333,30.7317073 C12.7986111,30.7317073 12.2152778,30.0457317 12.4375,29.3734756 C13.0138889,27.617378 14.6875,26.3414634 16.6666667,26.3414634 L17.2361111,26.3414634 C18.0902778,26.691311 19.0208333,26.8902439 20,26.8902439 C20.9791667,26.8902439 21.9166667,26.691311 22.7638889,26.3414634 L23.3333333,26.3414634 C25.3055556,26.3414634 26.9791667,27.6105183 27.5625,29.3734756 C27.7847222,30.0457317 27.2013889,30.7317073 26.4791667,30.7317073 L26.4791667,30.7317073 Z M24.4444444,2.19512195 C24.4444444,0.980945122 23.4513889,0 22.2222222,0 L17.7777778,0 C16.5486111,0 15.5555556,0.980945122 15.5555556,2.19512195 L15.5555556,8.7804878 L24.4444444,8.7804878 L24.4444444,2.19512195 Z" id="path-4"></path>
+        <filter x="-5.0%" y="-2.8%" width="110.0%" height="111.4%" filterUnits="objectBoundingBox" id="filter-5">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
+        </filter>
+    </defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="Artboard" transform="translate(-583.000000, -512.000000)">
+            <g id="permissions" transform="translate(583.000000, 512.000000)">
+                <mask id="mask-2" fill="white">
+                    <use xlink:href="#path-1"></use>
+                </mask>
+                <use id="Path" fill="#2085FD" xlink:href="#path-1"></use>
+                <g id="id-card-alt" mask="url(#mask-2)" fill-rule="nonzero">
+                    <g transform="translate(12.000000, 14.000000)" id="Shape">
+                        <g>
+                            <use fill="black" fill-opacity="1" filter="url(#filter-5)" xlink:href="#path-4"></use>
+                            <use fill="url(#linearGradient-3)" xlink:href="#path-4"></use>
+                        </g>
+                    </g>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 18 - 0
studio/template/launcher_browser.html

@@ -0,0 +1,18 @@
+<div class="bx-std-launcher-browser">
+    <div class="bx-std-lb-cnt">
+        <div class="bx-std-lb-menu">
+            <div class="bx-std-lb-logo bx-def-font-h3">__logo__</div>
+            <div class="bx-std-lb-menu-cnt">__menu__</div>
+        </div>
+        <div class="bx-std-lb-content">
+            <div class="bx-std-lb-content-cnt">
+                <bx_repeat:types>
+                    <div id="bx-std-lbw-__type__" class="bx-std-lb-widgets bx-std-lbw-__type__ __class__">
+                        __widgets__
+                        <div class="bx-std-cb"></div>
+                    </div>
+                </bx_repeat:types>
+            </div>
+        </div>
+    </div>
+</div>

+ 14 - 0
studio/template/menu_launcher_browser.html

@@ -0,0 +1,14 @@
+<bx_repeat:menu_items>
+    <div id="bx-std-lb-mi-__name__" class="bx-std-pmen-item bx-std-pmen-item-__name__ __class_add__">
+        <a href="__link__" onclick="__onclick__" title="__title_attr__"__attrs__>
+            <div class="bx-std-pmen-item-cnt">
+                <bx_if:icon>
+                    <i class="sys-icon __icon__ bx-def-margin-sec-right"></i>
+                </bx_if:icon>
+                <bx_if:image><img src="__icon_url__" /></bx_if:image>
+                __title__
+            </div>
+        </a>                
+    </div>                
+</bx_repeat:menu_items>
+<div class="bx-clear"></div>

+ 5 - 0
studio/template/mod_popup_settings.html

@@ -0,0 +1,5 @@
+<div class="bx-mod-popup-settings bx-def-popup-width bx-def-color-bg-block">
+    <div class="bx-mod-popup-settings-cnt bx-def-padding">
+        __content__
+    </div>
+</div>

+ 12 - 0
studio/template/page_breadcrumb.html

@@ -0,0 +1,12 @@
+<div class="bx-std-pcap-bx-std-pcap">
+    <ul class="bx-menu-hor bx-menu-breadcrumb">
+        <bx_repeat:menu_items>
+            <li class="bx-menu-bc-div">
+                <img src="<bx_icon_url:bc-arrow.svg />" />
+            </li>
+            <li class="bx-menu-bc-__name__  __class_add__">
+                <a href="__link__" onclick="__onclick__" class="bx-def-margin-sec-left bx-def-font-contrasted" title="__title_attr__"__attrs__><bx_if:icon><i class="sys-icon __icon__ bx-def-round-corners bx-def-font-contrasted"></i></bx_if:icon><bx_if:image><img src="__icon_url__" /></bx_if:image><bx_if:title><span class="bx-def-padding-thd-left">__title__</span></bx_if:title></a>
+            </li>
+        </bx_repeat:menu_items>
+    </ul>
+</div>

+ 20 - 0
studio/template/rl_role.html

@@ -0,0 +1,20 @@
+<div class="bx-rl-role bx-def-color-bg-block">
+    <div class="bx-rl-role-cnt">
+        __form__
+        <script language="javascript">
+            $(document).ready(function () {
+                $("#__form_id__").ajaxForm({ 
+                    dataType: "json",
+                    beforeSubmit: function (formData, jqForm, options) {
+                        bx_loading($("#__form_id__"), true);
+                    },
+                    success: function (data) {
+                        $(".bx-popup-applied:visible").dolPopupHide();
+
+                        glGrids.__object__.processJson(data, '__action__');
+                    }
+                });
+            });
+        </script>
+    </div>
+</div>

+ 10 - 0
studio/template/rl_roles_actions.html

@@ -0,0 +1,10 @@
+__content__
+<script language="javascript">
+    var __js_object__ = new BxDolStudioRolesActions({
+        sActionUrl: '<bx_url_root />grid.php',
+        sPageUrl: '__page_url__',
+        sObjNameGrid: '__grid_object__',
+        sParamsDivider: '__params_divider__',
+        sTextSearchInput: '<bx_text_js:_sys_grid_search />'
+    });
+</script>

+ 10 - 0
studio/template/rl_roles_levels.html

@@ -0,0 +1,10 @@
+__content__
+<script language="javascript">
+    var __js_object__ = new BxDolStudioRolesLevels({
+        sActionUrl: '<bx_url_root />grid.php',
+        sPageUrl: '__page_url__',
+        sObjNameGrid: '__grid_object__',
+        sParamsDivider: '__params_divider__',
+        sTextSearchInput: '<bx_text_js:_sys_grid_search />'
+    });
+</script>

+ 6 - 0
studio/template/roles.html

@@ -0,0 +1,6 @@
+__content__
+<script defer language="javascript">
+    var __js_object__ = new BxDolStudioRoles({
+        sActionUrl: '<bx_url_studio />builder_roles.php'
+    });
+</script>

+ 25 - 0
studio/template/scripts/BxBaseStudioMenuAccountPopup.php

@@ -0,0 +1,25 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxBaseStudioMenuAccountPopup extends BxDolStudioMenuAccountPopup
+{
+    public function __construct ($aObject, $oTemplate)
+    {
+        parent::__construct ($aObject, $oTemplate);
+
+        $this->addMarkers(array(
+            'js_object' => BxTemplStudioMenuTop::getInstance()->getJsObject(),
+            'url_root' => BX_DOL_URL_ROOT,
+            'url_studio' => BX_DOL_URL_STUDIO
+        ));
+    }
+}
+
+/** @} */

+ 92 - 0
studio/template/scripts/BxBaseStudioRoles.php

@@ -0,0 +1,92 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxBaseStudioRoles extends BxDolStudioRoles
+{
+    protected $sSubpageUrl;
+
+    function __construct($sPage = '')
+    {
+        parent::__construct($sPage);
+
+        $this->sSubpageUrl = BX_DOL_URL_STUDIO . 'builder_roles.php?page=';
+    }
+    function getPageCss()
+    {
+        return array_merge(parent::getPageCss(), array('forms.css', 'paginate.css', 'roles.css'));
+    }
+    function getPageJs()
+    {
+        return array_merge(parent::getPageJs(), array('roles.js'));
+    }
+    function getPageJsObject()
+    {
+        return 'oBxDolStudioRoles';
+    }
+    function getPageMenu($aMenu = array(), $aMarkers = array())
+    {
+        $sJsObject = $this->getPageJsObject();
+
+        $aMenu = array();
+        $aMenuItems = array(
+            BX_DOL_STUDIO_RL_TYPE_LEVELS => array('icon' => 'sliders-h'),
+            BX_DOL_STUDIO_RL_TYPE_ACTIONS => array('icon' => 'exchange-alt')
+        );
+
+        foreach($aMenuItems as $sMenuItem => $aItem)
+            $aMenu[] = array(
+                'name' => $sMenuItem,
+                'icon' => $aItem['icon'],
+                'link' => $this->sSubpageUrl . $sMenuItem,
+                'title' => _t('_adm_lmi_cpt_' . $sMenuItem),
+                'selected' => $sMenuItem == $this->sPage
+            );
+
+        return parent::getPageMenu($aMenu);
+    }
+    function getPageCode()
+    {
+        $sResult = parent::getPageCode();
+        if($sResult === false)
+            return false;
+
+        $sMethod = 'get' . ucfirst($this->sPage);
+        if(!method_exists($this, $sMethod))
+            return '';
+
+        return $sResult . $this->$sMethod();
+    }
+
+    protected function getRlevels()
+    {
+        return $this->getGrid('sys_studio_roles');
+    }
+
+    protected function getRactions()
+    {
+        return $this->getGrid('sys_studio_roles_actions');
+    }
+
+    protected function getGrid($sObjectName)
+    {
+        $oGrid = BxDolGrid::getObjectInstance($sObjectName);
+        if(!$oGrid)
+            return '';
+
+        return BxDolStudioTemplate::getInstance()->parseHtmlByName('roles.html', array(
+            'js_object' => $this->getPageJsObject(),
+            'content' => $this->getBlockCode(array(
+                'items' => $oGrid->getCode()
+            ))
+        ));
+    }
+}
+
+/** @} */

+ 125 - 0
studio/template/scripts/BxBaseStudioRolesActions.php

@@ -0,0 +1,125 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxBaseStudioRolesActions extends BxDolStudioRolesActions
+{
+    protected $sUrlPage;
+
+    function __construct($aOptions, $oTemplate = false)
+    {
+        parent::__construct($aOptions, $oTemplate);
+
+        $this->sUrlPage = BX_DOL_URL_STUDIO . 'builder_roles.php?page=ractions';
+    }
+
+    public function performActionEnable($mixedChecked = null)
+    {
+        $aIds = bx_get('ids');
+        $bEnable = (int)bx_get('checked');
+
+        if(!$aIds || !is_array($aIds))
+            return echoJson(array());
+
+        $aResultIds = array();
+        foreach($aIds as $mixedId) {
+            if(strpos($mixedId, $this->sParamsDivider) !== false)
+                list($this->iRole, $iId) = explode($this->sParamsDivider, urldecode($mixedId));
+
+            if($this->oDb->switchAction($this->iRole, $iId, $bEnable))
+                $aResultIds[] = $iId;
+        }
+
+        $sAction = $bEnable ? 'enable' : 'disable';
+        return echoJson(array(
+            $sAction => $aResultIds,
+        ));
+    }
+
+    function getJsObject()
+    {
+        return 'oBxDolStudioRolesActions';
+    }
+
+    function getCode($isDisplayHeader = true)
+    {
+        return $this->_oTemplate->parseHtmlByName('rl_roles_actions.html', array(
+            'content' => parent::getCode($isDisplayHeader),
+            'js_object' => $this->getJsObject(),
+            'page_url' => $this->sUrlPage,
+            'grid_object' => $this->_sObject,
+            'params_divider' => $this->sParamsDivider
+        ));
+    }
+
+    protected function _addJsCss()
+    {
+        parent::_addJsCss();
+        $this->_oTemplate->addJs(array('jquery.form.min.js', 'roles_actions.js'));
+
+        $oForm = new BxTemplStudioFormView(array());
+        $oForm->addCssJs();
+    }
+
+    protected function _getCellSwitcher($mixedValue, $sKey, $aField, $aRow)
+    {
+        if($this->iRole == 0)
+            return parent::_getCellDefault('', $sKey, $aField, $aRow);
+
+        $aRow[$this->_aOptions['field_id']] = urlencode($this->iRole . $this->sParamsDivider . $aRow[$this->_aOptions['field_id']]);
+        return parent::_getCellSwitcher($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getFilterControls ()
+    {
+        parent::_getFilterControls();
+
+        $sContent = "";
+
+        $sJsObject = $this->getJsObject();
+        $oForm = new BxTemplStudioFormView(array());
+
+        $aInputRoles = array(
+            'type' => 'select',
+            'name' => 'role',
+            'attrs' => array(
+                'id' => 'bx-grid-role-' . $this->_sObject,
+                'onChange' => 'javascript:' . $this->getJsObject() . '.onChangeRole()'
+            ),
+            'value' => 'id-' . $this->iRole,
+            'values' => array()
+        );
+
+        $aRoles = $this->oDb->getRoles(array('type' => 'all'));
+        $aCounter = $this->oDb->getActions(array('type' => 'counter_by_roles'));
+        foreach($aRoles as $aRole)
+            $aInputRoles['values']['id-' . $aRole['id']] = _t($aRole['title']) . " (" . (isset($aCounter[$aRole['id']]) ? $aCounter[$aRole['id']] : "0") . ")";
+
+        asort($aInputRoles['values']);
+        $aInputRoles['values'] = array_merge(array('id-0' => _t('_adm_rl_txt_select_role')), $aInputRoles['values']);
+
+        $sContent .= $oForm->genRow($aInputRoles);
+        if($this->iRole == 0)
+            return $sContent;
+
+        $aInputSearch = array(
+            'type' => 'text',
+            'name' => 'keyword',
+            'attrs' => array(
+                'id' => 'bx-grid-search-' . $this->_sObject,
+                'onKeyup' => 'javascript:$(this).off(\'keyup\'); ' . $this->getJsObject() . '.onChangeFilter()'
+            )
+        );
+        $sContent .= $oForm->genRow($aInputSearch);
+
+        return  $sContent;
+    }
+}
+
+/** @} */

+ 294 - 0
studio/template/scripts/BxBaseStudioRolesLevels.php

@@ -0,0 +1,294 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxBaseStudioRolesLevels extends BxDolStudioRolesLevels
+{
+    public static $iBinMB = 1048576;
+
+    protected $sUrlPage;
+
+    public function __construct($aOptions, $oTemplate = false)
+    {
+        parent::__construct($aOptions, $oTemplate);
+
+        $this->sUrlPage = BX_DOL_URL_STUDIO . 'builder_roles.php?page=rlevels';
+    }
+
+    public function performActionAdd()
+    {
+        $sAction = 'add';
+
+        $oForm = $this->_getFormObject($sAction);
+        $oForm->initChecker();
+
+        if($oForm->isSubmittedAndValid()) {
+            if(($iId = $this->_getAvailableId()) === false)
+                return echoJson(array('msg' => _t('_adm_prm_err_role_id')));
+
+            $sLanguage = BxDolStudioLanguagesUtils::getInstance()->getCurrentLangName(false);
+
+            $sName = BxDolForm::getSubmittedValue('title-' . $sLanguage, $oForm->aFormAttrs['method']);
+            $sName = uriGenerate(strtolower($sName), 'sys_std_roles', 'name', 'role');
+
+            $iId = (int)$oForm->insert(array('id' => $iId, 'name' => $sName, 'active' => 1, 'order' => $this->oDb->getRoleOrderMax() + 1));
+            if($iId != 0) {
+                $aRole = $this->oDb->getRoles(array('type' => 'by_id', 'id' => (int)$iId));
+
+            	if(($iActionsFrom = (int)$oForm->getCleanValue('actions')) > 0) {
+                    $aActions = $this->oDb->getActions(array('type' => 'by_role_id', 'role_id' => $iActionsFrom));
+                    foreach($aActions as $aAction)
+                        $this->oDb->switchAction($iId, $aAction['id'], true);
+            	}
+
+                // create system event
+                bx_alert('roles', 'added', $iId, 0, array('role' => $aRole));
+
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            }
+            else
+                $aRes = array('msg' => _t('_adm_rl_err_role_create'));
+
+            return echoJson($aRes);
+        }
+
+        $sContent = BxTemplStudioFunctions::getInstance()->popupBox('adm-rl-role-add-popup', _t('_adm_rl_txt_role_create_popup'), $this->_oTemplate->parseHtmlByName('rl_role.html', array(
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true),
+            'object' => $this->_sObject,
+            'action' => $sAction
+        )));
+
+        echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+    }
+
+    public function performActionEdit()
+    {
+        $sAction = 'edit';
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) {
+            $iId = (int)bx_get('id');
+            if(!$iId) {
+                echoJson(array());
+                exit;
+            }
+
+            $aIds = array($iId);
+        }
+
+        $iId = $aIds[0];
+
+        $aRole = $this->oDb->getRoles(array('type' => 'by_id', 'id' => $iId));
+        if(empty($aRole) || !is_array($aRole))
+            return echoJson(array());
+
+        $oForm = $this->_getFormObject($sAction, $aRole);
+        $oForm->initChecker();
+
+        if($oForm->isSubmittedAndValid()) {
+            if($oForm->update($iId) !== false) {
+                $aRole = $this->oDb->getRoles(array('type' => 'by_id', 'id' => (int)$iId));
+
+                // create system event
+                bx_alert('roles', 'edited', $iId, 0, array('role' => $aRole));
+
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            }
+            else
+                $aRes = array('msg' => _t('_adm_rl_err_role_edit'));
+
+            return echoJson($aRes);
+        }
+
+        $sContent = BxTemplStudioFunctions::getInstance()->popupBox('adm-rl-role-edit-popup', _t('_adm_rl_txt_role_edit_popup', _t($aRole['title'])), $this->_oTemplate->parseHtmlByName('rl_role.html', array(
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true),
+            'object' => $this->_sObject,
+            'action' => $sAction
+        )));
+
+        echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+    }
+
+    public function getJsObject()
+    {
+        return 'oBxDolStudioRolesLevels';
+    }
+
+    public function getCode($isDisplayHeader = true)
+    {
+        return $this->_oTemplate->parseHtmlByName('rl_roles_levels.html', array(
+            'content' => parent::getCode($isDisplayHeader),
+            'js_object' => $this->getJsObject(),
+            'page_url' => $this->sUrlPage,
+            'grid_object' => $this->_sObject,
+            'params_divider' => $this->sParamsDivider
+        ));
+    }
+
+    protected function _addJsCss()
+    {
+        parent::_addJsCss();
+        $this->_oTemplate->addJs(array('jquery.form.min.js', 'roles_levels.js'));
+
+        $oForm = new BxTemplStudioFormView(array());
+        $oForm->addCssJs();
+    }
+
+    protected function _getCellSwitcher ($mixedValue, $sKey, $aField, $aRow)
+    {
+        if(in_array($aRow['id'], array(BX_DOL_STUDIO_ROLE_MASTER)))
+            return parent::_getCellDefault('', $sKey, $aField, $aRow);
+
+        return parent::_getCellSwitcher($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellActionsList ($mixedValue, $sKey, $aField, $aRow)
+    {
+        $aActions = $this->oDb->getActions(array('type' => 'by_role_id', 'role_id' => $aRow['id']));
+
+        $sLink = BX_DOL_URL_STUDIO . 'builder_roles.php?page=ractions&role=' . $aRow['id'];
+        $mixedValue = $this->_oTemplate->parseLink($sLink, _t('_adm_rl_txt_n_actions', count($aActions)), array(
+            'title' => _t('_adm_rl_txt_manage_actions')
+        ));
+
+        return parent::_getCellDefault ($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getActionDelete ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if(in_array($aRow['id'], array($this->aNonDeletable)))
+            return '';
+
+        return  parent::_getActionDefault($sType, $sKey, $a, false, $isDisabled, $aRow);
+    }
+
+    protected function _getFormObject($sAction, $aRole = array())
+    {
+    	bx_import('BxTemplStudioFormView');
+
+        $aForm = array(
+            'form_attrs' => array(
+                'id' => 'adm-rl-role-',
+                'action' => BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction,
+                'method' => BX_DOL_STUDIO_METHOD_DEFAULT,
+                'enctype' => 'multipart/form-data',
+            ),
+            'params' => array (
+                'db' => array(
+                    'table' => 'sys_std_roles',
+                    'key' => 'id',
+                    'uri' => '',
+                    'uri_title' => '',
+                    'submit_name' => 'do_submit'
+                ),
+            ),
+            'inputs' => array (
+                'id' => array(
+                    'type' => 'hidden',
+                    'name' => 'id',
+                    'value' => isset($aRole['id']) ? (int)$aRole['id'] : 0,
+                    'db' => array (
+                        'pass' => 'Int',
+                    ),
+                ),
+                'title' => array(
+                    'type' => 'text_translatable',
+                    'name' => 'title',
+                    'caption' => _t('_adm_rl_txt_role_title'),
+                    'value' => isset($aRole['title']) ? $aRole['title'] : '_adm_rl_txt_role',
+                    'required' => '1',
+                    'db' => array (
+                        'pass' => 'Xss',
+                    ),
+                    'checker' => array (
+                        'func' => 'LengthTranslatable',
+                        'params' => array(3, 100, 'title'),
+                        'error' => _t('_adm_rl_err_role_title'),
+                    ),
+                ),
+                'description' => array(
+                    'type' => 'textarea_translatable',
+                    'name' => 'description',
+                    'caption' => _t('_adm_rl_txt_role_description'),
+                    'value' => isset($aRole['description']) ? $aRole['description'] : '_adm_rl_txt_role',
+                    'code' => 1,
+                    'db' => array (
+                        'pass' => 'XssHtml',
+                    )
+                ),
+                'actions' => array(
+                    'type' => 'select',
+                    'name' => 'actions',
+                    'caption' => _t('_adm_rl_txt_role_actions_copy'),
+                    'values' => array(
+                        array('key' => 0, 'value' => _t('_sys_txt_empty'))
+                    ),
+                ),
+                'controls' => array(
+                    'name' => 'controls',
+                    'type' => 'input_set',
+                    array(
+                        'type' => 'submit',
+                        'name' => 'do_submit',
+                        'value' => _t('_adm_rl_btn_role_create'),
+                    ),
+                    array (
+                        'type' => 'reset',
+                        'name' => 'close',
+                        'value' => _t('_adm_rl_btn_role_cancel'),
+                        'attrs' => array(
+                            'onclick' => "$('.bx-popup-applied:visible').dolPopupHide()",
+                            'class' => 'bx-def-margin-sec-left',
+                        ),
+                    )
+                )
+            )
+        );
+
+        $aRoles = $this->oDb->getRoles(array('type' => 'all_pair'));
+        foreach($aRoles as $iId => $sTitle)
+            $aForm['inputs']['actions']['values'][] = array('key' => $iId, 'value' => _t($sTitle));
+
+        switch($sAction) {
+            case 'add':
+                unset($aForm['inputs']['id']);
+
+                $aForm['form_attrs']['id'] .= 'create';
+                break;
+
+            case 'edit':
+                unset($aForm['inputs']['actions']);
+
+                $aForm['form_attrs']['id'] .= 'edit';
+                $aForm['inputs']['controls'][0]['value'] = _t('_adm_rl_btn_role_save');
+                break;
+        }
+
+        return new BxTemplStudioFormView($aForm);
+    }
+
+    protected function _getAvailableId()
+    {
+        $aRoles = $this->oDb->getRoles(array('type' =>'all_order_id'));
+
+        $iId = 1;
+        foreach($aRoles as $aRole) {
+            if($iId != (int)$aRole['id'])
+                break;
+
+            $iId++;
+        }
+
+        return $iId <= BX_DOL_STUDIO_ROLES_ROLE_ID_INT_MAX ? $iId : false;
+    }
+}
+
+/** @} */

+ 271 - 0
studio/template/scripts/BxBaseStudioWidget.php

@@ -0,0 +1,271 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaView UNA Studio Representation classes
+ * @ingroup     UnaStudio
+ * @{
+ */
+
+class BxBaseStudioWidget extends BxDolStudioWidget
+{
+    public function __construct($mixedPageName)
+    {
+        parent::__construct($mixedPageName);
+    }
+
+    public function getPageCss()
+    {
+        return array_merge(parent::getPageCss(), array(
+            'launcher.css'
+        ));
+    }
+
+    public function getPageJs()
+    {
+        return array_merge(parent::getPageJs(), array(
+            'launcher.js'
+        ));
+    }
+
+    public function getPageCaption()
+    {
+        if(empty($this->aPage) || !is_array($this->aPage))
+            return '';
+
+        $this->updateHistory();
+
+        $oTemplate = BxDolStudioTemplate::getInstance();
+        $oFunctions = BxTemplStudioFunctions::getInstance();
+
+        $bActions = false;
+        $sActions = $this->getPageCaptionActions();
+        if(($bActions = strlen($sActions)) > 0)
+            $sActions = $oFunctions->transBox('bx-std-pcap-menu-popup-actions', $sActions, true);
+
+        $bHelp = false;
+        $sHelp = $this->getPageCaptionHelp();
+        if(($bHelp = strlen($sHelp)) > 0)
+            $sHelp = $oFunctions->transBox('bx-std-pcap-menu-popup-help', $sHelp, true);
+
+        $oTemplate->addInjection('injection_header', 'text', $sActions . $sHelp);
+
+        //--- Menu Right ---//
+        $aItemsRight = array(
+            'site' => array(
+                'name' => 'site',
+                'icon' => 'tmi-site.svg',
+                'link' => '{url_root}',
+                'title' => '_adm_tmi_cpt_site'
+            ),
+        );
+
+        if($bHelp)
+            $aItemsRight['help'] = array(
+                'name' => 'help',
+                'icon' => 'tmi-help.svg',
+                'onclick' => BX_DOL_STUDIO_PAGE_JS_OBJECT . ".togglePopup('help', this)",
+                'title' => '_adm_txt_show_help'
+            );
+
+        if($bActions)
+            $aItemsRight['actions'] = array(
+                'name' => 'actions',
+                'icon' => 'tmi-actions.svg',
+                'onclick' => BX_DOL_STUDIO_PAGE_JS_OBJECT . ".togglePopup('actions', this)",
+                'title' => '_adm_txt_show_actions'
+            );
+
+        $aItemsRight['account'] = array(
+            'name' => 'account',
+            'icon' => 'tmi-account.svg',
+            'link' => 'javascript:void(0);',
+            'onclick' => 'bx_menu_popup(\'sys_studio_account_popup\', this);',
+            'title' => '_adm_tmi_cpt_account'
+        );
+
+        $oTopMenu = BxTemplStudioMenuTop::getInstance();
+        $oTopMenu->setContent(BX_DOL_STUDIO_MT_LEFT, $this->getPageBreadcrumb());
+        $oTopMenu->setSelected(BX_DOL_STUDIO_MT_CENTER, $this->aPage['name']);
+        $oTopMenu->setContent(BX_DOL_STUDIO_MT_RIGHT, array(
+            'template' => 'menu_top_toolbar.html', 
+            'menu_items' => $aItemsRight
+        ));
+
+        return '';
+    }
+
+    public function getPageCode()
+    {
+        $sResult = parent::getPageCode();
+        if($sResult === false)
+            return false;
+
+        if(!empty($this->aPage['wid_type']) && !BxDolStudioRolesUtils::getInstance()->isActionAllowed('use ' . $this->aPage['wid_type'])) {
+            $this->setError('_Access denied');
+            return false;
+        }
+
+        return $sResult . BxTemplStudioLauncher::getInstance()->getPageJsCode(array(
+            'bInit' => false
+        ));
+    }
+    
+
+    /**
+     * Block related methods
+     */
+    public function getBlocksLine($aBlocks)
+    {
+        $aTmplVarsBlocks = array();
+        foreach ($aBlocks as $aBlock) {
+            $aTmplVarsBlocks[] = array(
+                'content' => $this->getBlockCode($aBlock)
+            ); 
+        }
+
+    	return BxDolStudioTemplate::getInstance()->parseHtmlByName('page_blocks_line.html', array(
+    	    'count' => count($aTmplVarsBlocks),
+            'bx_repeat:blocks' => $aTmplVarsBlocks
+    	));
+    }
+    public function getBlockCode($aBlock)
+    {
+    	return BxDolStudioTemplate::getInstance()->parseHtmlByName('page_block.html', array(
+            'caption' => $this->getBlockCaption($aBlock),
+            'panel_top' => $this->getBlockPanelTop($aBlock),
+            'items' => !empty($aBlock['items']) ? $aBlock['items'] : '',
+            'panel_bottom' => $this->getBlockPanelBottom($aBlock)
+    	));
+    }
+
+    public function getBlockCaption($aBlock)
+    {
+        if(empty($aBlock) || !is_array($aBlock) || (empty($aBlock['caption']) && empty($aBlock['actions'])))
+            return '';
+
+        $aTmplActions = array();
+        if(!empty($aBlock['actions']) && is_array($aBlock['actions']))
+            foreach($aBlock['actions'] as $aAction) {
+                $sCaption = is_array($aAction['caption']) ? call_user_func_array('_t', $aAction['caption']) : _t($aAction['caption']);
+
+                $bOnClick = !empty($aAction['onclick']);
+                $aOnClick = $bOnClick ? array('onclick' => $aAction['onclick']) : array();
+
+                $aTmplActions[] = array(
+                    'name' => $aAction['name'],
+                    'url' => $aAction['url'],
+                    'title' => $sCaption,
+                    'bx_if:show_onclick' => array(
+                        'condition' => $bOnClick,
+                        'content' => $aOnClick
+                    ),
+                    'caption' => $sCaption
+                );
+            }
+
+        return BxDolStudioTemplate::getInstance()->parseHtmlByName('block_caption.html', array(
+            'caption' => is_array($aBlock['caption']) ? call_user_func_array('_t', $aBlock['caption']) : _t($aBlock['caption']),
+            'bx_if:show_actions' => array(
+                'condition' => !empty($aTmplActions),
+                'content' => array(
+                    'bx_repeat:actions' => $aTmplActions
+                )
+            ),
+        ));
+    }
+
+    public function getBlockPanelTop($aBlock)
+    {
+        if(empty($aBlock) || !is_array($aBlock) || empty($aBlock['panel_top']))
+            return '';
+
+        return BxDolStudioTemplate::getInstance()->parseHtmlByName('block_panel_top.html', array(
+            'content' => $aBlock['panel_top']
+        ));
+    }
+
+    public function getBlockPanelBottom($aBlock)
+    {
+        if(empty($aBlock) || !is_array($aBlock) || empty($aBlock['panel_bottom']))
+            return '';
+
+        return BxDolStudioTemplate::getInstance()->parseHtmlByName('block_panel_bottom.html', array(
+            'content' => $aBlock['panel_bottom']
+        ));
+    }
+
+
+    /**
+     * Internal methods.
+     */
+    protected function getPageCaptionActions()
+    {
+        $sActions = $this->getPageActions();
+        if(empty($sActions))
+            return "";
+
+        return BxDolStudioTemplate::getInstance()->parseHtmlByName('page_caption_actions.html', array(
+            'content' => $sActions
+        ));
+    }
+
+    protected function getPageActions($iWidgetId = 0)
+    {
+        if(empty($this->aActions))
+            return "";
+
+        $aMarkers = array(
+            'widget_id' => $iWidgetId,
+        );
+
+        if(!empty($iWidgetId)) {
+            $aWidget = BxDolStudioWidgetsQuery::getInstance()->getWidgets(array('type' => 'by_id', 'value' => $iWidgetId));
+            if(!empty($aWidget) && is_array($aWidget))
+                $aMarkers['widget_type'] = $aWidget['type'];            
+        }
+
+        $aForm = array(
+            'form_attrs' => array(
+                'id' => 'adm-page-actions',
+                'name' => 'adm-page-actions',
+                'action' => '',
+                'method' => 'post',
+            ),
+            'params' => array(),
+            'inputs' => array()
+        );
+
+        foreach($this->aActions as $aAction) {
+            if($aAction['name'] == 'rearrange' && empty($iWidgetId))
+                continue;
+
+            $aInput = array(
+                'type' => $aAction['type'],
+                'name' => $aAction['name'],
+                'caption' => _t($aAction['caption'])
+            );
+
+            switch($aAction['type']) {
+                case 'switcher':
+                    $aInput['checked'] = $aAction['checked'];
+                    $aInput['attrs']['onchange'] = bx_replace_markers($aAction['onchange'], $aMarkers);
+                    break;
+
+                case 'select':
+                    $aInput['value'] = bx_replace_markers($aAction['value'], $aMarkers);
+                    $aInput['values'] = $aAction['values'];
+                    $aInput['attrs']['onchange'] = bx_replace_markers($aAction['onchange'], $aMarkers);
+                    break;
+            }
+
+            $aForm['inputs'][$aInput['name']] = $aInput;
+        }
+
+        $oForm = new BxTemplStudioFormView($aForm);
+        return $oForm->getCode();
+    }
+}
+
+/** @} */

+ 44 - 0
studio/template/widget.html

@@ -0,0 +1,44 @@
+<div id="bx-std-widget-__id__" class="bx-std-widget __widget_disabled_class__ __widget_featured_class__" style="__widget_styles__">
+    <div class="bx-std-widget-cont">
+        <div class="bx-std-widget-icon bx-std-widget-icon-trans">
+            <a class="bx-std-widget-link" href="__url__" <bx_if:show_click_icon>onClick="__content__"</bx_if:show_click_icon>>
+                <bx_if:icon>
+                    <img src="<bx_icon_url:wi-empty.png />" />
+                    <i class="sys-icon __icon__"></i>
+                </bx_if:icon>
+                <bx_if:image><img src="__icon_url__" /></bx_if:image>
+            </a>
+        </div>
+        <bx_if:show_notice>
+           <div class="bx-std-widget-notices bx-def-box-sizing">
+               __content__
+           </div>
+        </bx_if:show_notice>
+
+        <bx_if:show_actions>
+            <div class="bx-std-widget-actions">
+                <div class="bx-std-widget-actions-cnt">
+                    <bx_repeat:actions>
+                        <div class="bx-std-widget-action bx-def-box-sizing">
+                            <a class="bx-std-widget-action bx-std-wa-__name__" href="__url__" <bx_if:show_click>onClick="__content__"</bx_if:show_click> title="__caption__">
+                                <bx_if:action_icon><i class="sys-icon __icon__" alt="__caption__"></i></bx_if:action_icon>
+                                <bx_if:action_image><img src="__icon_url__"  alt="__caption__" /></bx_if:action_image>
+                            </a>
+                        </div>
+                    </bx_repeat:actions>
+                </div>
+            </div>
+        </bx_if:show_actions>
+
+        <div class="bx-std-widget-icon-jitter" style="display:none">
+            <img class="bx-def-round-corners" src="<bx_image_url:bx-std-spacer.gif />" />
+        </div>
+
+        <div class="bx-std-widget-loading"></div>
+
+        <div class="bx-std-widget-caption">
+            <a class="bx-std-widget-link" href="__url__" <bx_if:show_click_link>onClick="__content__"</bx_if:show_click_link>>__caption__</a>
+            <div class="bx-std-widget-caption-jitter" style="display:none"></div>
+        </div>
+    </div>
+</div>

Некоторые файлы не были показаны из-за большого количества измененных файлов