* @package Combodo\iTop\Application\UI\Base\Layout\NavigationMenu * @internal * @since 3.0.0 */ class NavigationMenu extends UIBlock implements iKeyboardShortcut { // Overloaded constants public const BLOCK_CODE = 'ibo-navigation-menu'; public const DEFAULT_HTML_TEMPLATE_REL_PATH = 'base/layouts/navigation-menu/layout'; public const DEFAULT_JS_TEMPLATE_REL_PATH = 'base/layouts/navigation-menu/layout'; public const DEFAULT_JS_FILES_REL_PATH = [ 'js/layouts/navigation-menu.js', 'js/extkeywidget.js', 'js/forms-json-utils.js', ]; // Specific constants /** @var bool DEFAULT_SHOW_MENU_FILTER_HINT */ public const DEFAULT_SHOW_MENU_FILTER_HINT = true; /** @var string $sAppRevisionNumber */ protected $sAppRevisionNumber; /** @var string Logo to display when the menu is collapsed */ protected $sAppSquareIconUrl; /** @var string Logo to display when the menu is expanded */ protected $sAppFullIconUrl; /** @var string URL of the link on both $AppXXXIconUrl */ protected $sAppIconLink; /** @var array Data to render the silo selection area */ protected $aSiloSelection; /** @var bool Whether a silo is currently selected or not */ protected $bHasSiloSelected; /** @var string|null Current silo label */ protected $sSiloLabel; /** @var array $aMenuGroups */ protected $aMenuGroups; /** @var array $aUserData */ protected $aUserData; /** @var \Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenu $oUserMenu */ private $oUserMenu; /** @var \Combodo\iTop\Application\UI\Base\Component\PopoverMenu\NewsroomMenu\NewsroomMenu $oNewsroomMenu */ private $oNewsroomMenu; /** @var bool $bIsExpanded */ protected $bIsExpanded; /** @var bool Whether the hint on how the menu filter works shoudl be displayed or not */ protected $bShowMenuFilterHint; /** @var bool */ protected $bShowMenusCount; /** * NavigationMenu constructor. * * @param \ApplicationContext $oAppContext * @param \Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenu $oUserMenu * @param \Combodo\iTop\Application\UI\Base\Component\PopoverMenu\NewsroomMenu\NewsroomMenu|null $oNewsroomMenu * @param string|null $sId * * @throws \CoreException * @throws \CoreUnexpectedValue * @throws \DictExceptionMissingString * @throws \MySQLException * @throws \Exception */ public function __construct( ApplicationContext $oAppContext, PopoverMenu $oUserMenu, NewsroomMenu $oNewsroomMenu = null, ?string $sId = null ) { parent::__construct($sId); $oConfig = MetaModel::GetConfig(); $this->sAppRevisionNumber = utils::GetAppRevisionNumber(); $this->sAppSquareIconUrl = Branding::GetCompactMainLogoAbsoluteUrl(); $this->sAppFullIconUrl = Branding::GetFullMainLogoAbsoluteUrl(); $this->sAppIconLink = $oConfig->Get('app_icon_url'); $this->SetShowMenusCount($oConfig->Get('navigation_menu.show_menus_count')); $this->aSiloSelection = array(); $this->aMenuGroups = ApplicationMenu::GetMenuGroups($oAppContext->GetAsHash()); $this->oUserMenu = $oUserMenu; $this->oNewsroomMenu = $oNewsroomMenu; $this->ComputeAppIconLink(); $this->ComputeExpandedState(); $this->ComputeMenuFilterHintState(); $this->ComputeUserData(); $this->ComputeSiloSelection(); } /** * @return string */ public function GetAppRevisionNumber(): string { return $this->sAppRevisionNumber; } /** * @uses $sAppSquareIconUrl * @return string */ public function GetAppSquareIconUrl(): string { return $this->sAppSquareIconUrl; } /** * @uses $sAppFullIconUrl * @return string */ public function GetAppFullIconUrl(): string { return $this->sAppFullIconUrl; } /** * @uses $sAppIconLink * @return string */ public function GetAppIconLink(): string { return $this->sAppIconLink; } /** * @return array */ public function GetSiloSelection() { return $this->aSiloSelection; } /** * @uses $bHasSiloSelected * @return bool */ public function HasSiloSelected(): bool { return $this->bHasSiloSelected; } /** * @uses $sSiloLabel * @return string|null */ public function GetSiloLabel() { return $this->sSiloLabel; } /** * @return string The current organization ID of the app. context */ public function GetOrgId(): string { $oAppContext = new ApplicationContext(); $sCurrentOrganization = $oAppContext->GetCurrentValue('org_id'); if(!empty($sCurrentOrganization)) { return $sCurrentOrganization; } return ''; } /** * @return array */ public function GetMenuGroups(): array { return $this->aMenuGroups; } /** * @return array */ public function GetUserData(): array { return $this->aUserData; } /** * @return \Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenu */ public function GetUserMenu() { return $this->oUserMenu; } /** * @return \Combodo\iTop\Application\UI\Base\Component\PopoverMenu\NewsroomMenu\NewsroomMenu */ public function GetNewsroomMenu() { return $this->oNewsroomMenu; } /** * Return true if the menu is expanded * * @return bool */ public function IsExpanded(): bool { return $this->bIsExpanded; } /** * @uses $bShowMenuFilterHint * @return bool */ public function HasMenuFilterHint(): bool { return $this->bShowMenuFilterHint; } /** * @inheritDoc */ public function GetSubBlocks(): array { $aSubBlocks = [ $this->oUserMenu->GetId() => $this->oUserMenu, ]; if ($this->IsNewsroomEnabled()) { $aSubBlocks[$this->GetNewsroomMenu()->GetId()] = $this->GetNewsroomMenu(); } return $aSubBlocks; } /** * @return boolean */ public function IsNewsroomEnabled(): bool { return MetaModel::GetConfig()->Get('newsroom_enabled'); } /** * @uses $sAppIconLink * @return void */ public function ComputeAppIconLink(): void { $sPropCode = 'app_icon_url'; // Try if a custom URL was set in the configuration file if(MetaModel::GetConfig()->IsCustomValue($sPropCode)) { $this->sAppIconLink = MetaModel::GetConfig()->Get($sPropCode); } // Otherwise use the home page else { $this->sAppIconLink = utils::GetAbsoluteUrlAppRoot(); } } /** * @return True if the silo selection is enabled, false otherwise * @since 3.1.0 */ public function IsSiloSelectionEnabled() : bool { return MetaModel::GetConfig()->Get('navigation_menu.show_organization_filter'); } /** * @return void * @throws \CoreException * @throws \CoreUnexpectedValue * @throws \MySQLException */ public function ComputeSiloSelection() { $this->bHasSiloSelected = false; $this->sSiloLabel = null; if (! $this->IsSiloSelectionEnabled()){ return; } //TODO 3.0 Use components if we have the time to build select/autocomplete components before release // List of visible Organizations $iCount = 0; $oSet = null; if (MetaModel::IsValidClass('Organization')) { // Display the list of *favorite* organizations... but keeping in mind what is the real number of organizations $aFavoriteOrgs = appUserPreferences::GetPref('favorite_orgs', null); $oSearchFilter = new DBObjectSearch('Organization'); $oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true); $oSet = new CMDBObjectSet($oSearchFilter); $iCount = $oSet->Count(); // total number of existing Orgs // Now get the list of Orgs to be displayed in the menu $oSearchFilter = DBObjectSearch::FromOQL(ApplicationMenu::GetFavoriteSiloQuery()); $oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true); if (!empty($aFavoriteOrgs)) { $oSearchFilter->AddCondition('id', $aFavoriteOrgs, 'IN'); } $oSet = new CMDBObjectSet($oSearchFilter); // List of favorite orgs } switch ($iCount) { case 0: case 1: // No such dimension/silo or only one possible choice => nothing to select break; default: $oAppContext = new ApplicationContext(); $iCurrentOrganization = $oAppContext->GetCurrentValue('org_id'); if(!empty($iCurrentOrganization)) { $oCurrentOrganization = MetaModel::GetObject('Organization', $iCurrentOrganization, true, true); $this->bHasSiloSelected = true; $this->sSiloLabel = $oCurrentOrganization->GetRawName(); } $this->aSiloSelection['html'] = '
'; $sAddClearButton = ""; if ($this->bHasSiloSelected ){ $sAddClearButton = "$('#mini_clear_org_id').removeClass('ibo-is-hidden');"; } $sPageJS = $oPage->GetJS(); $oPage->add_ready_script('$(\'[data-role="ibo-navigation-menu--silo-selection--form"] #org_id\').on(\'extkeychange\', function() { $(\'[data-role="ibo-navigation-menu--silo-selection--form"]\').submit(); } );'); $oPage->add_ready_script('$(\'[data-role="ibo-navigation-menu--silo-selection--form"] #label_org_id\').on(\'click\', function() { if ($(\'[data-role="ibo-navigation-menu--silo-selection--form"] #org_id\').val() == \'\') { $(this).val(\'\'); } } );'); $sPageReadyJS = $oPage->GetReadyJS(); $this->aSiloSelection['js'] = <<