Files
iTop/sources/application/UI/Base/Component/PopoverMenu/PopoverMenu.php
Molkobain 8334b68285 Popover menu: Introduce option to add a visual hint on the menu toggler
This adds a visual hint (caret down) on the toggler to help the user understand that clicking on the toggler won't do something right away, but will open a menu instead
2021-03-19 19:50:50 +01:00

281 lines
6.4 KiB
PHP

<?php
/**
* Copyright (C) 2013-2021 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\Base\Component\PopoverMenu;
use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenuItem\PopoverMenuItem;
use Combodo\iTop\Application\UI\Base\UIBlock;
use Exception;
/**
* Class PopoverMenu
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Application\UI\Base\Component\PopoverMenu
* @internal
* @since 3.0.0
*/
class PopoverMenu extends UIBlock
{
// Overloaded constants
public const BLOCK_CODE = 'ibo-popover-menu';
public const DEFAULT_HTML_TEMPLATE_REL_PATH = 'base/components/popover-menu/layout';
public const DEFAULT_JS_TEMPLATE_REL_PATH = 'base/components/popover-menu/layout';
public const DEFAULT_JS_FILES_REL_PATH = [
'js/components/popover-menu.js',
];
/** @var string JS selector for the DOM element that should trigger the menu open/close */
protected $sTogglerJSSelector;
/** @var bool Whether the menu should add a visual hint (caret down) on the toggler to help the user understand that clicking on the toggler won't do something right away, but will open a menu instead */
protected $bAddVisualHintToToggler;
/** @var array $aSections */
protected $aSections;
/**
* PopoverMenu constructor.
*
* @param string|null $sId
*/
public function __construct(?string $sId = null)
{
parent::__construct($sId);
$this->sTogglerJSSelector = '';
$this->bAddVisualHintToToggler = false;
$this->aSections = [];
}
/**
* @param string $sSelector
*
* @return $this
* @uses static::$sTogglerJSSelector
*/
public function SetTogglerJSSelector(string $sSelector)
{
$this->sTogglerJSSelector = $sSelector;
return $this;
}
/**
* @return string
* @uses static::$sTogglerJSSelector
*/
public function GetTogglerJSSelector(): string
{
return $this->sTogglerJSSelector;
}
/**
* @return bool
* @uses static::$sTogglerJSSelector
*/
public function HasToggler(): bool
{
return !empty($this->sTogglerJSSelector);
}
/**
* @return $this
* @uses static::$bAddVisualHintToToggler
*/
public function AddVisualHintToToggler()
{
$this->bAddVisualHintToToggler = true;
return $this;
}
/**
* @return bool
* @uses static::$bAddVisualHintToToggler
*/
public function HasVisualHintToAddToToggler(): bool
{
return $this->bAddVisualHintToToggler;
}
/**
* Add a section $sId if not already existing.
* Important: It does not reset the section.
*
* @param string $sId
*
* @return $this
*/
public function AddSection(string $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(string $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(string $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(string $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\Base\Component\PopoverMenu\PopoverMenuItem\PopoverMenuItem $oItem
*
* @return $this
* @throws \Exception
*/
public function AddItem(string $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(string $sSectionId, string $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(string $sSectionId, array $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;
}
}