N°2847 - Rework iTopWebPage layout (WIP Part VI)

- iTopWebPage: Restore "open search" feature
- iTopWebPage: Change all resources URL to absolute in order to benefit from the "duplicate removal" benefits
- iTopWebPage: Remove obsolete method IsMenuPaneVisible()
- Config: Add new parameters quick_create.enabled / global_search.enabled / breadcrumb.enabled
- utils: Add new GetAppRevisionNumber() method
- Introduce iUIBlock interface for UI layouts, components, ...
- Introduce BlockRenderer to properly render blocks
- Add "render_block" function to TwigHelper to render blocks directly from TWIG
- Refactor layouts and components into proper block classes to fit the new architecture
This commit is contained in:
Molkobain
2020-07-29 18:43:31 +02:00
parent b207ae1bb3
commit 1f0211b45a
43 changed files with 2537 additions and 335 deletions

View File

@@ -0,0 +1,259 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Renderer;
use Combodo\iTop\Application\TwigBase\Twig\TwigHelper;
use Combodo\iTop\Application\UI\iUIBlock;
use ReflectionClass;
/**
* Class BlockRenderer
*
* Used to render any block of the UI (layouts, components)
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Renderer\Component
* @since 2.8.0
*/
class BlockRenderer
{
/** @var \Twig_Environment $oTwigEnv Singleton used during rendering */
protected static $oTwigEnv;
/**
* Helper to use directly in TWIG to render a block and its sub blocks
*
* @param \Combodo\iTop\Application\UI\iUIBlock $oBlock
*
* @return string
* @throws \ReflectionException
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*/
public static function RenderBlockTemplates(iUIBlock $oBlock)
{
$oSelf = new static($oBlock);
return $oSelf->RenderTemplates();
}
/** @var \Combodo\iTop\Application\UI\iUIBlock $oBlock */
protected $oBlock;
/** @var \Combodo\iTop\Renderer\RenderingOutput $oRenderingOutput */
protected $oRenderingOutput;
/**
* BlockRenderer constructor.
*
* @param \Combodo\iTop\Application\UI\iUIBlock $oBlock
*/
public function __construct(iUIBlock $oBlock)
{
if(null === static::$oTwigEnv)
{
static::$oTwigEnv = TwigHelper::GetTwigEnvironment(APPROOT.'templates/');
}
$this->oBlock = $oBlock;
$this->ResetRenderingOutput();
}
/**
* Reset the rendering output so it can be computed again
*
* @return $this
*/
protected function ResetRenderingOutput()
{
$this->oRenderingOutput = new RenderingOutput();
return $this;
}
/**
* Return the processed rendering output.
*
* @return \Combodo\iTop\Renderer\RenderingOutput
* @throws \ReflectionException
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
* @throws \Exception
*/
public function GetRenderingOutput()
{
$this->ResetRenderingOutput();
$this->oRenderingOutput->AddHtml($this->RenderHtml())
->AddCss($this->RenderCssInline())
->AddJs($this->RenderJsInline())
->SetCssFiles($this->GetCssFiles())
->SetJsFiles($this->GetJsFiles());
return $this->oRenderingOutput;
}
/**
* Return the raw output of the HTML template
*
* @return string
* @throws \ReflectionException
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*/
public function RenderHtml()
{
$sOutput = '';
if(!empty($this->oBlock::GetHtmlTemplateRelPath()))
{
$sOutput = TwigHelper::RenderTemplate(
static::$oTwigEnv,
[$this->GetBlockParameterNameForTemplate() => $this->oBlock],
$this->oBlock::GetHtmlTemplateRelPath(),
TwigHelper::ENUM_FILE_TYPE_HTML
);
}
return $sOutput;
}
/**
* Return the raw output of the JS template
*
* @return string
* @throws \ReflectionException
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*/
public function RenderJsInline()
{
$sOutput = '';
if(!empty($this->oBlock::GetJsTemplateRelPath()))
{
$sOutput = TwigHelper::RenderTemplate(
static::$oTwigEnv,
[$this->GetBlockParameterNameForTemplate() => $this->oBlock],
$this->oBlock::GetJsTemplateRelPath(),
TwigHelper::ENUM_FILE_TYPE_JS
);
}
return $sOutput;
}
/**
* Return the raw output of the CSS template
*
* @return string
* @throws \ReflectionException
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*/
public function RenderCssInline()
{
$sOutput = '';
if(!empty($this->oBlock::GetCssTemplateRelPath()))
{
$sOutput = TwigHelper::RenderTemplate(
static::$oTwigEnv,
[$this->GetBlockParameterNameForTemplate() => $this->oBlock],
$this->oBlock::GetCssTemplateRelPath(),
TwigHelper::ENUM_FILE_TYPE_CSS
);
}
return $sOutput;
}
/**
* Return the cumulated HTML output of the CSS, HTML and JS templates
*
* @return string
* @throws \ReflectionException
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*/
public function RenderTemplates()
{
$sOutput = '';
// CSS first to avoid visual glitches
$sCssOutput = $this->RenderCssInline();
if(!empty($sCssOutput))
{
$sOutput .= <<<HTML
<style>
{$sCssOutput}
</style>
HTML;
}
$sOutput .= $this->RenderHtml();
// JS last so all markup is build and ready
$sJsOutput = $this->RenderJsInline();
if(!empty($sJsOutput))
{
$sOutput .= <<<HTML
<script type="text/javascript">
{$sJsOutput}
</script>
HTML;
}
return $sOutput;
}
/**
* Return an array of the absolute URL of the block JS files
*
* @return array
* @throws \Exception
*/
public function GetJsFiles()
{
return $this->oBlock->GetJsFilesUrlRecursively(true);
}
/**
* Return an array of the absolute URL of the block CSS files
*
* @return array
* @throws \Exception
*/
public function GetCssFiles()
{
return $this->oBlock->GetCssFilesUrlRecursively(true);
}
/**
* Return the name of the parameter used in the template to access the block object (class short name = without namespace)
*
* @return string
* @throws \ReflectionException
*/
protected function GetBlockParameterNameForTemplate()
{
return 'o'.(new ReflectionClass($this->oBlock))->getShortName();
}
}

View File

@@ -165,6 +165,20 @@ class RenderingOutput
return $this;
}
/**
* Set the JS files (absolute URLs) and replace any existing ones.
*
* @param array $aFiles Array of absolute URLs
*
* @return $this
* @since 2.8.0
*/
public function SetJsFiles($aFiles)
{
$this->aJsFiles = $aFiles;
return $this;
}
/**
*
* @param string $sFile
@@ -204,6 +218,20 @@ class RenderingOutput
return $this;
}
/**
* Set the CSS files (absolute URLs) and replace any existing ones.
*
* @param array $aFiles Array of absolute URLs
*
* @return $this
* @since 2.8.0
*/
public function SetCssFiles($aFiles)
{
$this->aCssFiles = $aFiles;
return $this;
}
/**
*
* @param string $sFile

View File

@@ -8,6 +8,8 @@ namespace Combodo\iTop\Application\TwigBase\Twig;
use AttributeDateTime;
use Combodo\iTop\Application\UI\iUIBlock;
use Combodo\iTop\Renderer\BlockRenderer;
use Dict;
use Exception;
use MetaModel;
@@ -144,6 +146,13 @@ class Extension
$oTwigEnv->addFunction(new Twig_SimpleFunction('get_absolute_url_modules_root', function () {
return utils::GetAbsoluteUrlModulesRoot();
}));
// Function to render a UI block (HTML, inline CSS, inline JS) and its sub blocks directly in the TWIG
// Usage in twig: {{ render_block(oBlock) }}
/** @since 2.8.0 */
$oTwigEnv->addFunction(new Twig_SimpleFunction('render_block', function(iUIBlock $oBlock){
return BlockRenderer::RenderBlockTemplates($oBlock);
}, ['is_safe' => ['html']]));
}
}

View File

@@ -0,0 +1,106 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI\Component\Breadcrumbs;
use Combodo\iTop\Application\UI\UIBlock;
use MetaModel;
use utils;
/**
* Class Breadcrumbs
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\UI\Component\Breadcrumbs
* @internal
* @since 2.8.0
*/
class Breadcrumbs extends UIBlock
{
const BLOCK_CODE = 'ibo-breadcrumbs';
const HTML_TEMPLATE_REL_PATH = 'components/breadcrumbs/layout';
const JS_TEMPLATE_REL_PATH = 'components/breadcrumbs/layout';
const JS_FILES_REL_PATH = [
'js/components/breadcrumbs.js',
];
/** @var array|null $aNewEntry */
protected $aNewEntry;
/**
* QuickCreate constructor.
*
* @param string $sId
* @param array|null $aNewEntry
*/
public function __construct($sId = null, $aNewEntry = null)
{
parent::__construct($sId);
$this->SetNewEntry($aNewEntry);
}
/**
* The new breadcrumbs entry
*
* @param array|null $aNewEntry
*
* @return $this
*/
public function SetNewEntry($aNewEntry)
{
$this->aNewEntry = $aNewEntry;
return $this;
}
/**
* @return array|null
*/
public function GetNewEntry()
{
return $this->aNewEntry;
}
/**
* @return array
* @throws \ConfigException
* @throws \CoreException
* @throws \Exception
*/
public function GetJsWidgetOptions()
{
$aJsWidgetOptions = [];
$iBreadCrumbMaxCount = utils::GetConfig()->Get('breadcrumb.max_count');
if ($iBreadCrumbMaxCount > 1)
{
$oConfig = MetaModel::GetConfig();
$siTopInstanceId = $oConfig->GetItopInstanceid();
$aJsWidgetOptions = [
'itop_instance_id' => $siTopInstanceId,
'max_count' => $iBreadCrumbMaxCount,
'new_entry' => $this->GetNewEntry(),
];
}
return $aJsWidgetOptions;
}
}

View File

@@ -0,0 +1,115 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI\Component\GlobalSearch;
use Combodo\iTop\Application\UI\UIBlock;
use utils;
/**
* Class GlobalSearch
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\UI\Component\GlobalSearch
* @internal
* @since 2.8.0
*/
class GlobalSearch extends UIBlock
{
const BLOCK_CODE = 'ibo-global-search';
const HTML_TEMPLATE_REL_PATH = 'components/global-search/layout';
const JS_TEMPLATE_REL_PATH = 'components/global-search/layout';
const JS_FILES_REL_PATH = [
'js/components/global-search.js',
];
const DEFAULT_ENDPOINT_REL_URL = 'pages/UI.php?operation=full_text';
/** @var string $sEndpoint Absolute endpoint URL of the search form */
protected $sEndpoint;
/** @var array $aLastQueries */
protected $aLastQueries;
/**
* GlobalSearch constructor.
*
* @param string $sId
* @param array $aLastClasses
*
* @throws \Exception
*/
public function __construct($sId = null, $aLastClasses = [])
{
parent::__construct($sId);
$this->SetEndpoint(static::DEFAULT_ENDPOINT_REL_URL);
$this->SetLastQueries($aLastClasses);
}
/**
* Set the search form endpoint URL.
* If $bRelativeUrl is true, then $sEndpoint will be complete with the app_root_url
*
* @param string $sEndpoint URL to the endpoint
* @param bool $bRelativeUrl Whether or not the $sEndpoint parameter is a relative URL
*
* @return $this
* @throws \Exception
*/
public function SetEndpoint($sEndpoint, $bRelativeUrl = true)
{
$this->sEndpoint = (($bRelativeUrl) ? utils::GetAbsoluteUrlAppRoot() : '') . $sEndpoint;
return $this;
}
/**
* Return the absolute URL of the search form
*
* @return $this
* @throws \Exception
*/
public function GetEndpoint()
{
return $this->sEndpoint;
}
/**
* Set all the last queries at once
*
* @param array $aLastQueries
*
* @return $this
*/
public function SetLastQueries($aLastQueries)
{
$this->aLastQueries = $aLastQueries;
return $this;
}
/**
* Return the last queries (query itself, label as HTML)
*
* @return array
*/
public function GetLastQueries()
{
return $this->aLastQueries;
}
}

View File

@@ -0,0 +1,48 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI\Component\GlobalSearch;
/**
* Class GlobalSearchFactory
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\UI\Component\GlobalSearch
* @internal
* @since 2.8.0
*/
class GlobalSearchFactory
{
/**
* Make a GlobalSearch component with the history entries from the current user
*
* @return \Combodo\iTop\Application\UI\Component\GlobalSearch\GlobalSearch
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
* @throws \Exception
*/
public static function MakeFromUserHistory()
{
$aLastClasses = GlobalSearchHelper::GetLastQueries();
return new GlobalSearch(GlobalSearch::BLOCK_CODE, $aLastClasses);
}
}

View File

@@ -17,7 +17,7 @@
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\GlobalSearch;
namespace Combodo\iTop\Application\UI\Component\GlobalSearch;
use appUserPreferences;
@@ -27,7 +27,8 @@ use utils;
* Class GlobalSearchHelper
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\GlobalSearch
* @package Combodo\iTop\Application\UI\Component\GlobalSearch
* @internal
* @since 2.8.0
*/
class GlobalSearchHelper

View File

@@ -0,0 +1,224 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI\Component\PopoverMenu;
use Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuItem\PopoverMenuItem;
use Combodo\iTop\Application\UI\UIBlock;
use Exception;
/**
* Class PopoverMenu
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\UI\Component\PopoverMenu
* @internal
* @since 2.8.0
*/
class PopoverMenu extends UIBlock
{
const BLOCK_CODE = 'ibo-popover-menu';
const HTML_TEMPLATE_REL_PATH = 'components/popover-menu/layout';
//const JS_TEMPLATE_REl_PATH = 'components/popover-menu/layout';
const JS_FILES_REL_PATH = [
'js/components/popover-menu.js',
];
/** @var array $aSections */
protected $aSections;
/**
* PopoverMenu constructor.
*
* @param string|null $sId
*/
public function __construct($sId = null)
{
parent::__construct($sId);
$this->aSections = [];
}
/**
* Add a section $sId if not already existing.
* Important: It does not reset the section.
*
* @param string $sId
*
* @return $this
*/
public function AddSection($sId)
{
if (false === $this->HasSection($sId))
{
$this->aSections[$sId] = [
'aItems' => [],
];
}
return $this;
}
/**
* Remove the $sId section.
* Note: If the section does not exist, we silently proceed anyway.
*
* @param string $sId
*
* @return $this
* @throws \Exception
*/
public function RemoveSection($sId)
{
if (true === $this->HasSection($sId))
{
unset($this->aSections[$sId]);
}
return $this;
}
/**
* Return true if the $sId section exists
*
* @param string $sId
*
* @return bool
*/
public function HasSection($sId)
{
return array_key_exists($sId, $this->aSections);
}
/**
* Clear the $sId section from all its items.
*
* @param string $sId
*
* @return $this
* @throws \Exception
*/
public function ClearSection($sId)
{
if (false === $this->HasSection($sId))
{
throw new Exception('Could not clear section "'.$sId.'" as it does not exist in the "'.$this->GetId().'" menu');
}
$this->aSections[$sId]['aItems'] = [];
return $this;
}
/**
* Return the sections
*
* @return array
*/
public function GetSections()
{
return $this->aSections;
}
/**
* Add the $oItem in the $sSectionId. If an item with the same ID already exists it will be overwritten.
*
* @param string $sSectionId
* @param \Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuItem\PopoverMenuItem $oItem
*
* @return $this
* @throws \Exception
*/
public function AddItem($sSectionId, PopoverMenuItem $oItem)
{
if(false === $this->HasSection($sSectionId))
{
throw new Exception('Could not add an item to the "'.$sSectionId.'" section has it does not seem to exist in the "'.$this->GetId().'" menu.');
}
$this->aSections[$sSectionId]['aItems'][$oItem->GetId()] = $oItem;
return $this;
}
/**
* Remove the $sItemId from the $sSectionId.
* Note: If the item is not in the section, we proceed silently.
*
* @param string $sSectionId
* @param string $sItemId
*
* @return $this
* @throws \Exception
*/
public function RemoveItem($sSectionId, $sItemId)
{
if(false === $this->HasSection($sSectionId))
{
throw new Exception('Could not remove en item from the "'.$sSectionId.'" as it does not seem to exist in the "'.$this->GetId().'" menu.');
}
if(array_key_exists($sItemId, $this->aSections[$sSectionId]['aItems']))
{
unset($this->aSections[$sSectionId]['aItems'][$sItemId]);
}
return $this;
}
/**
* Set all $aItems at once in the $sSectionId, overwriting all existing.
*
* @param string $sSectionId
* @param PopoverMenuItem[] $aItems
*
* @return $this
* @throws \Exception
*/
public function SetItems($sSectionId, $aItems)
{
if(false === $this->HasSection($sSectionId))
{
throw new Exception('Could not set items to the "'.$sSectionId.'" section has it does not seem to exist in the "'.$this->GetId().'" menu.');
}
$this->aSections[$sSectionId]['aItems'] = $aItems;
return $this;
}
/**
* @inheritDoc
*/
public function GetSubBlocks()
{
$aSubBlocks = [];
foreach($this->aSections as $sSectionId => $aSectionData)
{
foreach($aSectionData['aItems'] as $sItemId => $oItem)
{
$aSubBlocks[$sItemId] = $oItem;
}
}
return $aSubBlocks;
}
}

View File

@@ -0,0 +1,197 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI\Component\PopoverMenu;
use Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuItem\PopupMenuItemFactory;
use Dict;
use JSPopupMenuItem;
use MetaModel;
use URLPopupMenuItem;
use UserRights;
use utils;
/**
* Class PopoverMenuFactory
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\UI\Component\PopoverMenu
* @internal
* @since 2.8.0
*/
class PopoverMenuFactory
{
/**
* Make a standard NavigationMenu layout for backoffice pages
*
* @return \Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenu
* @throws \CoreException
* @throws \Exception
*/
public static function MakeUserMenuForNavigationMenu()
{
$oMenu = new PopoverMenu('ibo-navigation-menu--user-menu');
// Allowed portals
$aAllowedPortalsItems = static::PrepareAllowedPortalsItemsForUserMenu();
if(!empty($aAllowedPortalsItems))
{
$oMenu->AddSection('allowed_portals')
->SetItems('allowed_portals', $aAllowedPortalsItems);
}
// User related pages
$oMenu->AddSection('user_related')
->SetItems('user_related', static::PrepareUserRelatedItemsForUserMenu());
// Misc links
$oMenu->AddSection('misc')
->SetItems('misc', static::PrepareMiscItemsForUserMenu());
return $oMenu;
}
/**
* Return the allowed portals items for the current user
*
* @return \Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuItem\PopoverMenuItem[]
*/
protected static function PrepareAllowedPortalsItemsForUserMenu()
{
$aItems = [];
foreach (UserRights::GetAllowedPortals() as $aAllowedPortal)
{
if ($aAllowedPortal['id'] !== 'backoffice')
{
$oPopupMenuItem = new URLPopupMenuItem(
'portal:'.$aAllowedPortal['id'],
Dict::S($aAllowedPortal['label']),
$aAllowedPortal['url'],
'_blank'
);
$aItems[] = PopupMenuItemFactory::MakeFromApplicationPopupMenuItem($oPopupMenuItem);
}
}
return $aItems;
}
/**
* Return the user related items (preferences, change password, log off, ...)
*
* @return \Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuItem\PopoverMenuItem[]
* @throws \CoreException
*/
protected static function PrepareUserRelatedItemsForUserMenu()
{
$aItems = [];
// Preferences
$aItems[] = PopupMenuItemFactory::MakeFromApplicationPopupMenuItem(
new URLPopupMenuItem(
'UI:Preferences',
Dict::S('UI:Preferences'),
utils::GetAbsoluteUrlAppRoot().'pages/preferences.php'
)
);
// Archive mode
if(true === utils::IsArchiveMode())
{
$aItems[] = PopupMenuItemFactory::MakeFromApplicationPopupMenuItem(
new JSPopupMenuItem(
'UI:ArchiveModeOff',
Dict::S('UI:ArchiveModeOff'),
'return ArchiveMode(false);'
)
);
}
elseif(UserRights::CanBrowseArchive())
{
$aItems[] = PopupMenuItemFactory::MakeFromApplicationPopupMenuItem(
new JSPopupMenuItem(
'UI:ArchiveModeOn',
Dict::S('UI:ArchiveModeOn'),
'return ArchiveMode(true);'
)
);
}
// Logoff
if(utils::CanLogOff())
{
$aItems[] = PopupMenuItemFactory::MakeFromApplicationPopupMenuItem(
new URLPopupMenuItem(
'UI:LogOffMenu',
Dict::S('UI:LogOffMenu'),
utils::GetAbsoluteUrlAppRoot().'pages/logoff.php?operation=do_logoff'
)
);
}
// Change password
if (UserRights::CanChangePassword())
{
$aItems[] = PopupMenuItemFactory::MakeFromApplicationPopupMenuItem(
new URLPopupMenuItem(
'UI:ChangePwdMenu',
Dict::S('UI:ChangePwdMenu'),
utils::GetAbsoluteUrlAppRoot().'pages/UI.php?loginop=change_pwd'
)
);
}
// TODO: iPopupMenuExtension::MENU_USER_ACTIONS
return $aItems;
}
/**
* Return the misc. items for the user menu (online doc., about box)
*
* @return \Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuItem\PopoverMenuItem[]
*/
protected static function PrepareMiscItemsForUserMenu()
{
$aItems = [];
// Online documentation
$aItems[] = PopupMenuItemFactory::MakeFromApplicationPopupMenuItem(
new URLPopupMenuItem(
'UI:Help',
Dict::S('UI:Help'),
MetaModel::GetConfig()->Get('online_help'),
'_blank'
)
);
// About box
$aItems[] = PopupMenuItemFactory::MakeFromApplicationPopupMenuItem(
new JSPopupMenuItem(
'UI:AboutBox',
Dict::S('UI:AboutBox'),
'return ShowAboutBox();'
)
);
return $aItems;
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuItem;
/**
* Class JsPopoverMenuItem
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuItem
* @since 2.8.0
*/
class JsPopoverMenuItem extends PopoverMenuItem
{
const HTML_TEMPLATE_REL_PATH = 'components/popover-menu/item/mode_js';
}

View File

@@ -0,0 +1,103 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuItem;
use ApplicationPopupMenuItem;
use Combodo\iTop\Application\UI\UIBlock;
/**
* Class PopoverMenuItem
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuItem
* @internal
* @since 2.8.0
*/
class PopoverMenuItem extends UIBlock
{
const BLOCK_CODE = 'ibo-popover-menu--item';
const HTML_TEMPLATE_REL_PATH = 'components/popover-menu/item/layout';
/** @var \ApplicationPopupMenuItem $oPopupMenuItem We decorate the class with the original \ApplicationPopupMenuItem as it is used among the application (backoffice, portal, extensions) and cannot be refactored without BC breaks */
protected $oPopupMenuItem;
/**
* PopoverMenuItem constructor.
*
* @param \ApplicationPopupMenuItem $oPopupMenuItem
*/
public function __construct(ApplicationPopupMenuItem $oPopupMenuItem)
{
$this->oPopupMenuItem = $oPopupMenuItem;
parent::__construct(/* ID will be generated from $oPopupMenuItem */);
}
/**
* @inheritDoc
*/
protected function GenerateId()
{
return static::BLOCK_CODE.'-'.$this->oPopupMenuItem->GetUID();
}
/**
* @see \ApplicationPopupMenuItem::GetLabel()
* @return string
*/
public function GetLabel()
{
return $this->oPopupMenuItem->GetLabel();
}
/**
* @see \ApplicationPopupMenuItem::SetCssClasses()
* @param array $aCssClasses
*
* @return $this
*/
public function SetCssClasses($aCssClasses)
{
$this->oPopupMenuItem->SetCssClasses($aCssClasses);
return $this;
}
/**
* @see \ApplicationPopupMenuItem::AddCssClass()
* @param string $sCssClass
*
* @return $this
*/
public function AddCssClass($sCssClass)
{
$this->oPopupMenuItem->AddCssClass($sCssClass);
return $this;
}
/**
* @see \ApplicationPopupMenuItem::GetCssClasses()
* @return array
*/
public function GetCssClasses()
{
return $this->oPopupMenuItem->GetCssClasses();
}
}

View File

@@ -0,0 +1,64 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuItem;
use ApplicationPopupMenuItem;
use JSPopupMenuItem;
use URLPopupMenuItem;
/**
* Class PopupMenuItemFactory
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuItem
* @internal
* @since 2.8.0
*/
class PopupMenuItemFactory
{
/**
* Make a standard NavigationMenu layout for backoffice pages
*
* @param \ApplicationPopupMenuItem $oItem
*
* @return \Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuItem\PopoverMenuItem
*/
public static function MakeFromApplicationPopupMenuItem(ApplicationPopupMenuItem $oItem)
{
$sNamespace = 'Combodo\\iTop\\Application\\UI\\Component\\PopoverMenu\\PopoverMenuItem\\';
switch(true)
{
case $oItem instanceof URLPopupMenuItem:
$sTargetClass = 'UrlPopoverMenuItem';
break;
case $oItem instanceof JSPopupMenuItem:
$sTargetClass = 'JsPopoverMenuItem';
break;
default:
$sTargetClass = 'PopoverMenuItem';
break;
}
$sTargetClass = $sNamespace.$sTargetClass;
return new $sTargetClass($oItem);
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuItem;
/**
* Class UrlPopoverMenuItem
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuItem
* @since 2.8.0
*/
class UrlPopoverMenuItem extends PopoverMenuItem
{
const HTML_TEMPLATE_REL_PATH = 'components/popover-menu/item/mode_url';
}

View File

@@ -0,0 +1,103 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI\Component\QuickCreate;
use Combodo\iTop\Application\UI\UIBlock;
use UserRights;
/**
* Class QuickCreate
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\UI\Component\QuickCreate
* @internal
* @since 2.8.0
*/
class QuickCreate extends UIBlock
{
const BLOCK_CODE = 'ibo-quick-create';
const HTML_TEMPLATE_REL_PATH = 'components/quick-create/layout';
const JS_TEMPLATE_REL_PATH = 'components/quick-create/layout';
const JS_FILES_REL_PATH = [
'js/selectize.min.js',
'js/components/quick-create.js',
];
const CSS_FILES_REL_PATH = [
'css/selectize.default.css',
];
const DEFAULT_ENDPOINT_REL_URL = 'pages/UI.php';
/** @var array $aAvailableClasses */
protected $aAvailableClasses;
/** @var array $aLastClasses */
protected $aLastClasses;
/**
* QuickCreate constructor.
*
* @param string $sId
* @param array $aLastClasses
*
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
public function __construct($sId = null, $aLastClasses = [])
{
parent::__construct($sId);
$this->aAvailableClasses = UserRights::GetAllowedClasses(UR_ACTION_CREATE, array('bizmodel'), true);
$this->aLastClasses = $aLastClasses;
}
/**
* Return the available classes (to create) for the current user
*
* @return array
*/
public function GetAvailableClasses()
{
return $this->aAvailableClasses;
}
/**
* Set all the last classes at once
*
* @param array $aLastClasses
*
* @return $this
*/
public function SetLastClasses($aLastClasses)
{
$this->aLastClasses = $aLastClasses;
return $this;
}
/**
* Return the last classes (class name, label as HTML, icon URL, ...)
*
* @return array
*/
public function GetLastClasses()
{
return $this->aLastClasses;
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI\Component\QuickCreate;
/**
* Class QuickCreateFactory
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\UI\Component\QuickCreate
* @internal
* @since 2.8.0
*/
class QuickCreateFactory
{
/**
* Make a QuickCreate component with the last classes from the current user
*
* @return \Combodo\iTop\Application\UI\Component\QuickCreate\QuickCreate
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
public static function MakeFromUserHistory()
{
$aLastClasses = QuickCreateHelper::GetLastClasses();
return new QuickCreate(QuickCreate::BLOCK_CODE,$aLastClasses);
}
}

View File

@@ -17,7 +17,7 @@
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\QuickCreate;
namespace Combodo\iTop\Application\UI\Component\QuickCreate;
use appUserPreferences;
@@ -29,7 +29,8 @@ use utils;
* Class QuickCreateHelper
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\QuickCreate
* @package Combodo\iTop\Application\UI\Component\QuickCreate
* @internal
* @since 2.8.0
*/
class QuickCreateHelper

View File

@@ -0,0 +1,222 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI\Layout\NavigationMenu;
use ApplicationContext;
use ApplicationMenu;
use appUserPreferences;
use Combodo\iTop\Application\Branding;
use Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenu;
use Combodo\iTop\Application\UI\UIBlock;
use Dict;
use MetaModel;
use UserRights;
use utils;
/**
* Class NavigationMenu
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\UI\Layout\NavigationMenu
* @internal
* @since 2.8.0
*/
class NavigationMenu extends UIBlock
{
const BLOCK_CODE = 'ibo-navigation-menu';
const HTML_TEMPLATE_REL_PATH = 'layouts/navigation-menu/layout';
const JS_TEMPLATE_REL_PATH = 'layouts/navigation-menu/layout';
const JS_FILES_REL_PATH = [
'js/layouts/navigation-menu.js',
];
/** @var string $sAppRevisionNumber */
protected $sAppRevisionNumber;
/** @var string $sAppSquareIconUrl */
protected $sAppSquareIconUrl;
/** @var string $sAppFullIconUrl */
protected $sAppFullIconUrl;
/** @var string $sAppIconLink */
protected $sAppIconLink;
/** @var array $aMenuGroups */
protected $aMenuGroups;
/** @var array $aUserData */
protected $aUserData;
/** @var \Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenu $oUserMenu */
private $oUserMenu;
/** @var bool $bIsExpanded */
protected $bIsExpanded;
/**
* NavigationMenu constructor.
*
* @param string|null $sId
* @param \ApplicationContext $oAppContext
* @param \Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenu $oUserMenu
*
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DictExceptionMissingString
* @throws \MySQLException
* @throws \Exception
*/
public function __construct($sId, ApplicationContext $oAppContext, PopoverMenu $oUserMenu)
{
parent::__construct($sId);
$this->sAppRevisionNumber = utils::GetAppRevisionNumber();
$this->sAppSquareIconUrl = Branding::GetSquareMainLogoAbsoluteUrl();
$this->sAppFullIconUrl = Branding::GetFullMainLogoAbsoluteUrl();
$this->sAppIconLink = MetaModel::GetConfig()->Get('app_icon_url');
$this->aMenuGroups = ApplicationMenu::GetMenuGroups($oAppContext->GetAsHash());
$this->oUserMenu = $oUserMenu;
$this->ComputeExpandedState();
$this->ComputeUserData();
}
/**
* @return string
*/
public function GetAppRevisionNumber()
{
return $this->sAppRevisionNumber;
}
/**
* @return string
*/
public function GetAppSquareIconUrl()
{
return $this->sAppSquareIconUrl;
}
/**
* @return string
*/
public function GetAppFullIconUrl()
{
return $this->sAppFullIconUrl;
}
/**
* @return string
*/
public function GetAppIconLink()
{
return $this->sAppIconLink;
}
/**
* @return array
*/
public function GetMenuGroups()
{
return $this->aMenuGroups;
}
/**
* @return array
*/
public function GetUserData()
{
return $this->aUserData;
}
/**
* @return \Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenu
*/
public function GetUserMenu()
{
return $this->oUserMenu;
}
/**
* Return true if the menu is expanded
*
* @return bool
*/
public function IsExpanded()
{
return $this->bIsExpanded;
}
/**
* @inheritDoc
*/
public function GetSubBlocks()
{
return [$this->oUserMenu->GetId() => $this->oUserMenu];
}
/**
* Compute if the menu is expanded or collapsed
*
* @return $this
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
protected function ComputeExpandedState()
{
$bIsExpanded = false;
// Check if menu should be opened only if we re not in demo mode
if (false === MetaModel::GetConfig()->Get('demo_mode'))
{
if (utils::ReadParam('force_menu_pane', null) === 0)
{
$bIsExpanded = false;
}
elseif (appUserPreferences::GetPref('menu_pane', 'closed') === 'opened')
{
$bIsExpanded = true;
}
}
$this->bIsExpanded = $bIsExpanded;
return $this;
}
/**
* Compute the user data displayed in the menu (organization, name, picture, ...)
*
* @return $this
* @throws \Exception
*/
protected function ComputeUserData()
{
$aData = [
'sOrganization' => UserRights::GetContactOrganizationFriendlyname(),
'sFirstname' => UserRights::GetContactFirstname(),
'sPictureUrl' => UserRights::GetContactPicture(),
];
// Logon message
$sLogonMessageDictCode = (UserRights::IsAdministrator()) ? 'UI:LoggedAsMessage+Admin' : 'UI:LoggedAsMessage';
$aData['sLogonMessage'] = Dict::Format($sLogonMessageDictCode, UserRights::GetUser());
$this->aUserData = $aData;
return $this;
}
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI\Layout\NavigationMenu;
use ApplicationContext;
use Combodo\iTop\Application\UI\Component\PopoverMenu\PopoverMenuFactory;
/**
* Class NavigationMenuFactory
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\UI\Layout\NavigationMenu
* @internal
* @since 2.8.0
*/
class NavigationMenuFactory
{
/**
* Make a standard NavigationMenu layout for backoffice pages
*
* @return \Combodo\iTop\Application\UI\Layout\NavigationMenu\NavigationMenu
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DictExceptionMissingString
* @throws \MySQLException
*/
public static function MakeStandard()
{
return new NavigationMenu(
NavigationMenu::BLOCK_CODE,
new ApplicationContext(),
PopoverMenuFactory::MakeUserMenuForNavigationMenu()
);
}
}

View File

@@ -0,0 +1,185 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI\Layout\TopBar;
use Combodo\iTop\Application\UI\Component\Breadcrumbs\Breadcrumbs;
use Combodo\iTop\Application\UI\Component\GlobalSearch\GlobalSearch;
use Combodo\iTop\Application\UI\Component\QuickCreate\QuickCreate;
use Combodo\iTop\Application\UI\UIBlock;
/**
* Class TopBar
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\UI\Layout\TopBar
* @internal
* @since 2.8.0
*/
class TopBar extends UIBlock
{
const BLOCK_CODE = 'ibo-top-bar';
const HTML_TEMPLATE_REL_PATH = 'layouts/top-bar/layout';
/** @var QuickCreate|null $oQuickCreate */
protected $oQuickCreate;
/** @var GlobalSearch|null $oGlobalSearch */
protected $oGlobalSearch;
/** @var Breadcrumbs|null $oBreadcrumbs */
protected $oBreadcrumbs;
/**
* TopBar constructor.
*
* @param string $sId
* @param \Combodo\iTop\Application\UI\Component\QuickCreate\QuickCreate $oQuickCreate
* @param \Combodo\iTop\Application\UI\Component\GlobalSearch\GlobalSearch $oGlobalSearch
* @param \Combodo\iTop\Application\UI\Component\Breadcrumbs\Breadcrumbs $oBreadcrumbs
*/
public function __construct($sId = null, QuickCreate $oQuickCreate = null, GlobalSearch $oGlobalSearch = null, Breadcrumbs $oBreadcrumbs = null)
{
parent::__construct($sId);
$this->oQuickCreate = $oQuickCreate;
$this->oGlobalSearch = $oGlobalSearch;
$this->oBreadcrumbs = $oBreadcrumbs;
}
/**
* Set the quick create component
*
* @param \Combodo\iTop\Application\UI\Component\QuickCreate\QuickCreate $oQuickCreate
*
* @return $this
*/
public function SetQuickCreate(QuickCreate $oQuickCreate)
{
$this->oQuickCreate = $oQuickCreate;
return $this;
}
/**
* Return the global search component
*
* @return \Combodo\iTop\Application\UI\Component\QuickCreate\QuickCreate|null
*/
public function GetQuickCreate()
{
return $this->oQuickCreate;
}
/**
* Return true if the quick create has been set
*
* @return bool
*/
public function HasQuickCreate()
{
return ($this->oQuickCreate !== null);
}
/**
* Set the global search component
*
* @param \Combodo\iTop\Application\UI\Component\GlobalSearch\GlobalSearch $oGlobalSearch
*
* @return $this
*/
public function SetGlobalSearch(GlobalSearch $oGlobalSearch)
{
$this->oGlobalSearch = $oGlobalSearch;
return $this;
}
/**
* Return the global search component
*
* @return \Combodo\iTop\Application\UI\Component\GlobalSearch\GlobalSearch|null
*/
public function GetGlobalSearch()
{
return $this->oGlobalSearch;
}
/**
* Return true if the global search has been set
*
* @return bool
*/
public function HasGlobalSearch()
{
return ($this->oGlobalSearch !== null);
}
/**
* Set the breadcrumbs component
*
* @param \Combodo\iTop\Application\UI\Component\Breadcrumbs\Breadcrumbs $oBreadcrumbs
*
* @return $this
*/
public function SetBreadcrumbs(Breadcrumbs $oBreadcrumbs)
{
$this->oBreadcrumbs = $oBreadcrumbs;
return $this;
}
/**
* Return the breadcrumbs component
*
* @return \Combodo\iTop\Application\UI\Component\Breadcrumbs\Breadcrumbs|null
*/
public function GetBreadcrumbs()
{
return $this->oBreadcrumbs;
}
/**
* Return true if the breadcrumb has been set
*
* @return bool
*/
public function HasBreadcrumbs()
{
return ($this->oBreadcrumbs !== null);
}
/**
* @inheritDoc
*/
public function GetSubBlocks()
{
$aSubBlocks = [];
$aSubBlocksNames = ['QuickCreate', 'GlobalSearch', 'Breadcrumbs'];
foreach($aSubBlocksNames as $sSubBlockName)
{
$sHasMethodName = 'Has'.$sSubBlockName;
if(true === call_user_func_array([$this, $sHasMethodName], []))
{
$sPropertyName = 'o'.$sSubBlockName;
$aSubBlocks[$this->$sPropertyName->GetId()] = $this->$sPropertyName;
}
}
return $aSubBlocks;
}
}

View File

@@ -0,0 +1,71 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI\Layout\TopBar;
use Combodo\iTop\Application\UI\Component\Breadcrumbs\Breadcrumbs;
use Combodo\iTop\Application\UI\Component\GlobalSearch\GlobalSearchFactory;
use Combodo\iTop\Application\UI\Component\QuickCreate\QuickCreateFactory;
use utils;
/**
* Class TopBarFactory
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\UI\Layout\TopBar
* @internal
* @since 2.8.0
*/
class TopBarFactory
{
/**
* Make a standard TopBar layout for backoffice pages
*
* @param array|null $aBreadcrumbsEntry Current breadcrumbs entry to add
*
* @return \Combodo\iTop\Application\UI\Layout\TopBar\TopBar
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
public static function MakeStandard($aBreadcrumbsEntry = null)
{
$oTopBar = new TopBar();
if(utils::GetConfig()->Get('quick_create.enabled') === true)
{
$oTopBar->SetQuickCreate(QuickCreateFactory::MakeFromUserHistory());
}
if(utils::GetConfig()->Get('global_search.enabled') === true)
{
$oTopBar->SetGlobalSearch(GlobalSearchFactory::MakeFromUserHistory());
}
if(utils::GetConfig()->Get('breadcrumb.enabled') === true)
{
$oBreadcrumbs = new Breadcrumbs(Breadcrumbs::BLOCK_CODE, $aBreadcrumbsEntry);
$oTopBar->SetBreadcrumbs($oBreadcrumbs);
}
return $oTopBar;
}
}

View File

@@ -0,0 +1,196 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI;
use utils;
/**
* Class UIBlock
*
* @package Combodo\iTop\Application\UI
* @internal
* @since 2.8.0
*/
abstract class UIBlock implements iUIBlock
{
/** @var string BLOCK_CODE The block code to use to generate the identifier, the CSS/JS prefixes, ... */
const BLOCK_CODE = 'ibo-block';
/** @var string|null GLOBAL_TEMPLATE_REL_PATH Relative path (from <ITOP>/templates/) to the "global" TWIG template which contains HTML, JS inline, JS files, CSS inline, CSS files. Should not be used to often as JS/CSS files would be duplicated making browser parsing time way longer. */
const GLOBAL_TEMPLATE_REL_PATH = null;
/** @var string|null HTML_TEMPLATE_REL_PATH Relative path (from <ITOP>/templates/) to the HTML template */
const HTML_TEMPLATE_REL_PATH = null;
/** @var array JS_FILES_REL_PATH Relative paths (from <ITOP>/) to the JS files */
const JS_FILES_REL_PATH = [];
/** @var string|null JS_TEMPLATE_REL_PATH Relative path (from <ITOP>/templates/) to the JS template */
const JS_TEMPLATE_REL_PATH = null;
/** @var array CSS_FILES_REL_PATH Relative paths (from <ITOP>/) to the CSS files */
const CSS_FILES_REL_PATH = [];
/** @var string|null CSS_TEMPLATE_REL_PATH Relative path (from <ITOP>/templates/) to the CSS template */
const CSS_TEMPLATE_REL_PATH = null;
/** @var string ENUM_BLOCK_FILES_TYPE_JS */
const ENUM_BLOCK_FILES_TYPE_JS = 'js';
/** @var string ENUM_BLOCK_FILES_TYPE_CSS */
const ENUM_BLOCK_FILES_TYPE_CSS = 'css';
/**
* @inheritDoc
*/
public static function GetGlobalTemplateRelPath()
{
return static::GLOBAL_TEMPLATE_REL_PATH;
}
/**
* @inheritDoc
*/
public static function GetHtmlTemplateRelPath()
{
return static::HTML_TEMPLATE_REL_PATH;
}
/**
* @inheritDoc
*/
public static function GetJsTemplateRelPath()
{
return static::JS_TEMPLATE_REL_PATH;
}
/**
* @inheritDoc
*/
public static function GetJsFilesRelPaths()
{
return static::JS_FILES_REL_PATH;
}
/**
* @inheritDoc
*/
public static function GetCssTemplateRelPath()
{
return static::CSS_TEMPLATE_REL_PATH;
}
/**
* @inheritDoc
*/
public static function GetCssFilesRelPaths()
{
return static::CSS_FILES_REL_PATH;
}
/** @var string $sId */
protected $sId;
/**
* UIBlock constructor.
*
* @param string|null $sId
*/
public function __construct($sId = null)
{
$this->sId = ($sId !== null) ? $sId : $this->GenerateId();
}
/**
* Return a unique ID for the block
*
* @return string
*/
protected function GenerateId()
{
return uniqid(static::BLOCK_CODE.'-');
}
/**
* @inheritDoc
*/
public function GetId()
{
return $this->sId;
}
/**
* @inheritDoc
* @return \Combodo\iTop\Application\UI\UIBlock[]
*/
public function GetSubBlocks()
{
return [];
}
/**
* @inheritDoc
* @throws \Exception
*/
public function GetJsFilesUrlRecursively($bAbsoluteUrl = false)
{
return $this->GetFilesUrlRecursively(static::ENUM_BLOCK_FILES_TYPE_JS, $bAbsoluteUrl);
}
/**
* @inheritDoc
* @throws \Exception
*/
public function GetCssFilesUrlRecursively($bAbsoluteUrl = false)
{
return $this->GetFilesUrlRecursively(static::ENUM_BLOCK_FILES_TYPE_CSS, $bAbsoluteUrl);
}
/**
* Return an array of the URL of the block $sFilesType and its sub blocks.
* URL is relative unless the $bAbsoluteUrl is set to true.
*
* @param string $sFilesType (see static::ENUM_BLOCK_FILES_TYPE_JS, static::ENUM_BLOCK_FILES_TYPE_CSS)
* @param bool $bAbsoluteUrl
*
* @return array
* @throws \Exception
*/
protected function GetFilesUrlRecursively($sFilesType, $bAbsoluteUrl = false)
{
$aFiles = [];
$sFilesRelPathMethodName = 'Get'.ucfirst($sFilesType).'FilesRelPaths';
$sFilesAbsUrlMethodName = 'Get'.ucfirst($sFilesType).'FilesUrlRecursively';
// Files from the block itself
foreach($this::$sFilesRelPathMethodName() as $sFilePath)
{
$aFiles[] = (($bAbsoluteUrl === true) ? utils::GetAbsoluteUrlAppRoot() : '').$sFilePath;
}
// Files from its sub blocks
foreach($this->GetSubBlocks() as $sSubBlockName => $oSubBlock)
{
$aFiles = array_merge(
$aFiles,
call_user_func_array([$oSubBlock, $sFilesAbsUrlMethodName], [$bAbsoluteUrl])
);
}
return $aFiles;
}
}

View File

@@ -0,0 +1,108 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
namespace Combodo\iTop\Application\UI;
/**
* Interface iUIBlock
*
* @package Combodo\iTop\Application\UI
* @internal
* @since 2.8.0
*/
interface iUIBlock
{
/**
* Return the relative path (from <ITOP>/templates/) of the global template (HTML, JS, CSS) to use or null if it's not provided. Should not be used to often as JS/CSS files would be duplicated making the browser parsing time way longer.
*
* @return string|null
*/
public static function GetGlobalTemplateRelPath();
/**
* Return the relative path (from <ITOP>/templates/) of the HTML template to use or null if no HTML to render
*
* @return string|null
*/
public static function GetHtmlTemplateRelPath();
/**
* Return the relative path (from <ITOP>/templates/) of the JS template to use or null if there is no inline JS to render
*
* @return string|null
*/
public static function GetJsTemplateRelPath();
/**
* Return an array of the relative paths (from <ITOP>/) of the JS files to use
*
* @return array
*/
public static function GetJsFilesRelPaths();
/**
* Return the relative path (from <ITOP>/templates/) of the CSS template to use or null if there is no inline CSS to render
*
* @return string|null
*/
public static function GetCssTemplateRelPath();
/**
* Return an array of the relative paths (from <ITOP>/) of the CSS files to use
*
* @return array
*/
public static function GetCssFilesRelPaths();
/**
* Return the ID of the block
*
* @return string
*/
public function GetId();
/**
* Return an array iUIBlock embedded in this iUIBlock
*
* @return \Combodo\iTop\Application\UI\iUIBlock[]
*/
public function GetSubBlocks();
/**
* Return an array of the JS files URL of the block and its sub blocks.
* URL is relative unless the $bAbsolutePath is set to true.
*
* @param bool $bAbsoluteUrl
*
* @return array
*/
public function GetJsFilesUrlRecursively($bAbsoluteUrl = false);
/**
* Return an array of the CSS files URL of the block and its sub blocks.
* URL is relative unless the $bAbsolutePath is set to true.
*
* @param bool $bAbsoluteUrl
*
* @return array
* @throws \Exception
*/
public function GetCssFilesUrlRecursively($bAbsoluteUrl = false);
}