mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
Popover menu: Refactor to remove the necessity of coupling JS and PHP code to instantiate it correctly
This commit is contained in:
@@ -1123,24 +1123,9 @@ JS
|
||||
} else {
|
||||
$oToolbar = $oDashboard->GetToolbar();
|
||||
}
|
||||
$oActionButton = ButtonUIBlockFactory::MakeIconAction('fas fa-ellipsis-v', Dict::S($sName), $sName, '', false, $sMenuTogglerId);
|
||||
$oActionButton->AddCSSClasses(['ibo-top-bar--toolbar-dashboard-menu-toggler', 'ibo-action-button']);
|
||||
$oActionButton->SetJsCode(<<<JS
|
||||
$("#{$sPopoverMenuId}").popover_menu({toggler: "#{$sMenuTogglerId}"});
|
||||
$('#{$sMenuTogglerId}').on('click', function(oEvent) {
|
||||
var oEventTarget = $('#{$sMenuTogglerId}');
|
||||
var aEventTargetPos = oEventTarget.position();
|
||||
var popover = $("#{$sPopoverMenuId}");
|
||||
|
||||
popover.css({
|
||||
'top': (aEventTargetPos.top + oEventTarget.outerHeight(true)) + 'px',
|
||||
'left': (aEventTargetPos.left + oEventTarget.outerWidth(true) - popover.width()) + 'px',
|
||||
'z-index': 10060
|
||||
});
|
||||
popover.popover_menu("togglePopup");
|
||||
});
|
||||
JS
|
||||
);
|
||||
$oActionButton = ButtonUIBlockFactory::MakeIconAction('fas fa-ellipsis-v', Dict::S($sName), $sName, '', false, $sMenuTogglerId)
|
||||
->AddCSSClass('ibo-top-bar--toolbar-dashboard-menu-toggler')
|
||||
->AddCSSClass('ibo-action-button');
|
||||
|
||||
$oToolbar->AddSubBlock($oActionButton);
|
||||
|
||||
@@ -1161,7 +1146,11 @@ JS
|
||||
|
||||
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
|
||||
|
||||
$oToolbar->AddSubBlock($oPage->GetPopoverMenu($sPopoverMenuId, $aActions));
|
||||
$oActionsMenu = $oPage->GetPopoverMenu($sPopoverMenuId, $aActions)
|
||||
->SetTogglerJSSelector("#$sMenuTogglerId");
|
||||
|
||||
$oToolbar->AddSubBlock($oActionButton)
|
||||
->AddSubBlock($oActionsMenu);
|
||||
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
$oPage->add_script(
|
||||
|
||||
@@ -11,6 +11,7 @@ use Combodo\iTop\Application\UI\Base\Component\Dashlet\DashletFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Pill\PillFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenu;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Toolbar\Separator\ToolbarSeparatorUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\iUIBlock;
|
||||
@@ -1805,9 +1806,9 @@ class MenuBlock extends DisplayBlock
|
||||
$oSet = new CMDBObjectSet($this->m_oFilter);
|
||||
$sRefreshAction = $aExtraParams['sRefreshAction'] ?? '';
|
||||
|
||||
/** @var $aRegularActions Any action other than a transition */
|
||||
/** @var array $aRegularActions Any action other than a transition */
|
||||
$aRegularActions = [];
|
||||
/** @var $aTransitionActions Only transitions */
|
||||
/** @var array $aTransitionActions Only transitions */
|
||||
$aTransitionActions = [];
|
||||
if ((!isset($aExtraParams['selection_mode']) || $aExtraParams['selection_mode'] == "") && $this->m_sStyle != 'listInObject') {
|
||||
$oAppContext = new ApplicationContext();
|
||||
@@ -2201,27 +2202,14 @@ class MenuBlock extends DisplayBlock
|
||||
$sName = 'UI:Menu:Transitions';
|
||||
}
|
||||
$oActionButton = ButtonUIBlockFactory::MakeIconAction('fas fa-map-signs', Dict::S($sName), $sName, '', false, $sTransitionActionsMenuTogglerId)
|
||||
->AddCSSClasses(['ibo-action-button', 'ibo-transition-action-button'])
|
||||
->SetJsCode(<<<JS
|
||||
$("#{$sTransitionActionsPopoverMenuId}").popover_menu({toggler: "#{$sTransitionActionsMenuTogglerId}", add_visual_hint_to_toggler: true});
|
||||
$('#{$sTransitionActionsMenuTogglerId}').on('click', function(oEvent) {
|
||||
var oEventTarget = $('#{$sTransitionActionsMenuTogglerId}');
|
||||
var aEventTargetPos = oEventTarget.position();
|
||||
var popover = $("#{$sTransitionActionsPopoverMenuId}");
|
||||
|
||||
popover.css({
|
||||
'top': (aEventTargetPos.top + oEventTarget.outerHeight(true)) + 'px',
|
||||
'left': (aEventTargetPos.left + oEventTarget.outerWidth(true) - popover.width()) + 'px',
|
||||
'z-index': 10060
|
||||
});
|
||||
popover.popover_menu("togglePopup");
|
||||
});
|
||||
JS
|
||||
);
|
||||
->AddCSSClasses(['ibo-action-button', 'ibo-transition-action-button']);
|
||||
|
||||
$oTransitionActionsMenu = $oPage->GetPopoverMenu($sTransitionActionsPopoverMenuId, $aTransitionActions)
|
||||
->SetTogglerJSSelector("#$sTransitionActionsMenuTogglerId")
|
||||
->AddVisualHintToToggler();
|
||||
|
||||
// TODO 3.0.0: Try to handle the JS above in a nicer place or through block options
|
||||
$oActionsToolbar->AddSubBlock($oActionButton)
|
||||
->AddSubBlock($oPage->GetPopoverMenu($sTransitionActionsPopoverMenuId, $aTransitionActions));
|
||||
->AddSubBlock($oTransitionActionsMenu);
|
||||
}
|
||||
|
||||
// Separator between transitions and regulars
|
||||
@@ -2294,27 +2282,14 @@ JS
|
||||
$sName = 'UI:Menu:Actions';
|
||||
}
|
||||
$oActionButton = ButtonUIBlockFactory::MakeIconAction('fas fa-ellipsis-v', Dict::S($sName), $sName, '', false, $sRegularActionsMenuTogglerId)
|
||||
->AddCSSClasses(['ibo-action-button', 'ibo-regular-action-button'])
|
||||
->SetJsCode(<<<JS
|
||||
$("#{$sRegularActionsPopoverMenuId}").popover_menu({toggler: "#{$sRegularActionsMenuTogglerId}"});
|
||||
$('#{$sRegularActionsMenuTogglerId}').on('click', function(oEvent) {
|
||||
var oEventTarget = $('#{$sRegularActionsMenuTogglerId}');
|
||||
var aEventTargetPos = oEventTarget.position();
|
||||
var popover = $("#{$sRegularActionsPopoverMenuId}");
|
||||
|
||||
popover.css({
|
||||
'top': (aEventTargetPos.top + oEventTarget.outerHeight(true)) + 'px',
|
||||
'left': (aEventTargetPos.left + oEventTarget.outerWidth(true) - popover.width()) + 'px',
|
||||
'z-index': 10060
|
||||
});
|
||||
popover.popover_menu("togglePopup");
|
||||
});
|
||||
JS
|
||||
);
|
||||
->AddCSSClasses(['ibo-action-button', 'ibo-regular-action-button']);
|
||||
|
||||
$oRegularActionsMenu = $oPage->GetPopoverMenu($sRegularActionsPopoverMenuId, $aRegularActions)
|
||||
->SetTogglerJSSelector("#$sRegularActionsMenuTogglerId")
|
||||
->SetContainer(PopoverMenu::ENUM_CONTAINER_BODY);
|
||||
|
||||
// TODO 3.0.0: Try to handle the JS above in a nicer place or through block options
|
||||
$oActionsToolbar->AddSubBlock($oActionButton)
|
||||
->AddSubBlock($oPage->GetPopoverMenu($sRegularActionsPopoverMenuId, $aRegularActions));
|
||||
->AddSubBlock($oRegularActionsMenu);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,6 @@ img.ibo-navigation-menu--notifications--item--image:not([src=""]) ~ i.ibo-naviga
|
||||
}
|
||||
|
||||
.ibo-navigation-menu--notifications-show-all-multiple ~ .ibo-popover-menu{
|
||||
bottom: 0;
|
||||
.ibo-navigation-menu--notifications--item--new-message-indicator{
|
||||
display: inline-block;
|
||||
margin-right: $ibo-navigation-menu--notifications-show-all-multiple--ibo-popover-menu--indicator--margin-right;
|
||||
|
||||
@@ -40,19 +40,20 @@ $(function()
|
||||
_initializePopoverMenu: function()
|
||||
{
|
||||
var me = this;
|
||||
|
||||
// Important: For now, the popover menu is manually instantiated even though the PHP NewsroomMenu class inherits PopoverMenu because the jQuery widget doesn't. We might refactor this in the future.
|
||||
$(me.element).popover_menu({'toggler': this.js_selectors.menu_toggler});
|
||||
$(this.js_selectors.menu_toggler).on('click', function(oEvent) {
|
||||
$(this.js_selectors.menu_toggler).on('click', function (oEvent) {
|
||||
var oEventTarget = $(oEvent.target);
|
||||
var aEventTargetPos = oEventTarget.position();
|
||||
var aEventTargetOffset = oEventTarget.offset();
|
||||
|
||||
$iHeight = Math.abs(aEventTargetOffset.top - 100);
|
||||
$iHeight = Math.abs(aEventTargetOffset.top-100);
|
||||
$(me.element).css({
|
||||
'max-height': $iHeight + 'px',
|
||||
'top': (aEventTargetPos.top + parseInt(oEventTarget.css('marginTop'), 10) - Math.min($(me.element).height(), $iHeight)) + 'px',
|
||||
'left': (aEventTargetPos.left + parseInt(oEventTarget.css('marginLeft'), 10) + oEventTarget.width()) + 'px',
|
||||
'max-height': $iHeight+'px',
|
||||
'top': (aEventTargetPos.top+parseInt(oEventTarget.css('marginTop'), 10)-Math.min($(me.element).height(), $iHeight))+'px',
|
||||
'left': (aEventTargetPos.left+parseInt(oEventTarget.css('marginLeft'), 10)+oEventTarget.width())+'px',
|
||||
});
|
||||
$(me.element).popover_menu("togglePopup");
|
||||
});
|
||||
this.element.addClass(this.css_classes.newsroom_menu);
|
||||
$(this.js_selectors.menu_toggler).addClass('ibo-is-loaded');
|
||||
@@ -214,7 +215,7 @@ $(function()
|
||||
},
|
||||
_buildNoMessageItem: function()
|
||||
{
|
||||
return '<div class="ibo-popover-menu--item ibo-popover-menu--item--no-message">' + Dict.S(this.options.labels.no_notification) +
|
||||
return '<div class="ibo-popover-menu--item ibo-popover-menu--item--no-message">' + Dict.S(this.options.labels.no_notification) +
|
||||
'<div class="ibo-popover-menu--item--no-message--image ibo-svg-illustration--container">' + this.options.no_message_icon + '</div></div>';
|
||||
},
|
||||
_buildSingleShowAllMessagesItem: function()
|
||||
@@ -269,10 +270,10 @@ $(function()
|
||||
sMessageSection += sNoMessageItem;
|
||||
}
|
||||
sMessageSection += '<hr class="ibo-popover-menu--item ibo-popover-menu--separator"></div>';
|
||||
|
||||
|
||||
if (this.options.providers.length == 1)
|
||||
{
|
||||
var SingleShowAllMessagesItem = this._buildSingleShowAllMessagesItem();
|
||||
var SingleShowAllMessagesItem = this._buildSingleShowAllMessagesItem();
|
||||
sShowAllMessagesSection += SingleShowAllMessagesItem;
|
||||
sShowAllMessagesSection += '</div>'
|
||||
}
|
||||
@@ -303,19 +304,14 @@ $(function()
|
||||
// Add class to show there is no messages
|
||||
$(this.js_selectors.menu_toggler).addClass(this.css_classes.empty);
|
||||
}
|
||||
|
||||
if (this.options.providers.length != 1)
|
||||
{
|
||||
var oElem = $('[data-role="ibo-navigation-menu--notifications-show-all-multiple"]~[data-role="ibo-popover-menu"]');
|
||||
oElem.popover_menu({'toggler': '[data-role="ibo-navigation-menu--notifications-show-all-multiple"]'});
|
||||
|
||||
$('[data-role="ibo-navigation-menu--notifications-show-all-multiple"]').on('click', function(oEvent){
|
||||
var oEventTarget = $(oEvent.target);
|
||||
var aEventTargetPos = oEventTarget.position();
|
||||
oElem.css({
|
||||
'left': (aEventTargetPos.left + parseInt(oEventTarget.css('marginLeft'), 10) + oEventTarget.width()) + 'px'
|
||||
});
|
||||
oElem.popover_menu("togglePopup");
|
||||
if (this.options.providers.length != 1) {
|
||||
var oElem = $('[data-role="ibo-navigation-menu--notifications-show-all-multiple"]~[data-role="ibo-popover-menu"]');
|
||||
oElem.popover_menu({
|
||||
'toggler': '[data-role="ibo-navigation-menu--notifications-show-all-multiple"]',
|
||||
'position': {
|
||||
'horizontal': "(oTargetPos.left+parseInt(oTargetElem.css('marginLeft'), 10)+(oTargetElem.outerWidth() / 2)-(oElem.outerWidth() / 2))+'px'",
|
||||
},
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,26 @@ $(function()
|
||||
// default options
|
||||
options:
|
||||
{
|
||||
// Valid JS selector of the DOM element toggling the menu on click
|
||||
toggler: '',
|
||||
// Container element of the menu. Can be either 'parent' (default, better performance) or 'body' (use it if the menu gets cut by the hidden overflow of its parent).
|
||||
container: 'parent',
|
||||
// Position of the menu, relative to a DOM target element. Default target is 'toggler', but any valid JS selector is also accepted
|
||||
position: {
|
||||
// DOM element used to compute the menu relative position from. Value be 'toggler' to use the 'toggler' option or any valid JS selector.
|
||||
target: 'toggler',
|
||||
// Relative vertical position of the menu from the target. Value can be 'below' or 'above' for the menu to be strictly below/above the target,
|
||||
// or a JS expression to be evaluated that must return pixels (eg. (oTargetPos.top + oTarget.outerHeight(true)) + 'px')
|
||||
vertical: 'below',
|
||||
// Relative horizontal position of the menu from the target. Value can be 'align_inner_left' or 'align_inner_right' for the menu to be aligned with the target border,
|
||||
// or a JS expression to be evaluated that must return pixels (eg. (oTargetPos.left + oTarget.outerWidth(true) - popover.width()) + 'px')
|
||||
// JS vars that can be used in the expression:
|
||||
// - oElem
|
||||
// - oTargetElem
|
||||
// - oTargetPos
|
||||
horizontal: 'align_inner_right',
|
||||
},
|
||||
add_visual_hint_to_toggler: false
|
||||
},
|
||||
css_classes:
|
||||
{
|
||||
@@ -41,12 +60,22 @@ $(function()
|
||||
|
||||
// the constructor
|
||||
_create: function () {
|
||||
this._bindEvents();
|
||||
this._closePopup();
|
||||
// Consistency checks
|
||||
// - When target position set to 'toggler', ensure that a toggler is indeed set
|
||||
if (('toggler' === this.options.position.target) && (false === this._hasToggler())) {
|
||||
CombodoJSConsole.Error('Could not instantiate menu as the position target is set to "toggler" but no toggler set');
|
||||
}
|
||||
|
||||
// Build markup
|
||||
if (true === this.options.add_visual_hint_to_toggler) {
|
||||
this._addVisualHintToToggler();
|
||||
}
|
||||
if ('body' === this.options.container) {
|
||||
this.element.appendTo($('body'));
|
||||
}
|
||||
|
||||
this._bindEvents();
|
||||
this._closePopup();
|
||||
},
|
||||
// events bound via _bind are removed automatically
|
||||
// revert other modifications here
|
||||
@@ -56,6 +85,27 @@ $(function()
|
||||
const me = this;
|
||||
const oBodyElem = $('body');
|
||||
|
||||
// Toggler
|
||||
if (true === this._hasToggler()) {
|
||||
oBodyElem.find(this.options.toggler).on('click', function (oEvent) {
|
||||
me._onTogglerClick(oEvent);
|
||||
});
|
||||
}
|
||||
|
||||
// Force menu to close on scroll when it is positioned on the body, otherwise it will not follow it's target and it will look buggy.
|
||||
// Also, we decided not to update to position during scroll for to avoid performance drop.
|
||||
if ('body' === this.options.container) {
|
||||
// Important: This event is not bind using jQuery but the native method so we can set the "passive" option to minimize performance drops
|
||||
// as the 'scroll' event is extremely CPU consuming.
|
||||
// TODO 3.0.0: Make it work, event seems not to be triggered on user scroll
|
||||
// window.addEventListener('scroll', function () {
|
||||
// me._onBodyScroll();
|
||||
// }, {
|
||||
// passive: true
|
||||
// })
|
||||
}
|
||||
|
||||
// Menu items
|
||||
this.element.find(this.js_selectors.item).on('click', function (oEvent) {
|
||||
me._closePopup();
|
||||
});
|
||||
@@ -67,6 +117,61 @@ $(function()
|
||||
},
|
||||
|
||||
// Events callbacks
|
||||
_onTogglerClick: function (oEvent) {
|
||||
// Avoid anchor / link default behavior
|
||||
oEvent.preventDefault();
|
||||
|
||||
// Only recompute position when the menu is closed and about to be opened
|
||||
if (false === this._isOpened()) {
|
||||
const oTargetElem = ('toggler' === this.options.position.target) ? $(this.options.toggler) : $(this.options.position.target);
|
||||
const oTargetPos = ('parent' === this.options.container) ? oTargetElem.position() : oTargetElem.offset();
|
||||
|
||||
let oNextCSSPosition = {
|
||||
'z-index': 1,
|
||||
};
|
||||
const sVerticalPosExp = this.options.position.vertical;
|
||||
const sHorizontalPosExp = this.options.position.horizontal;
|
||||
|
||||
// Position referential
|
||||
if ('body' === this.options.container) {
|
||||
oNextCSSPosition['position'] = 'fixed';
|
||||
oNextCSSPosition['z-index'] = 30; // 30 to be above #ibo-page-container (10) and #ibo-navigation-menu (20)
|
||||
}
|
||||
|
||||
// Vertical
|
||||
if ('below' === sVerticalPosExp) {
|
||||
oNextCSSPosition['top'] = (oTargetPos.top+oTargetElem.outerHeight())+'px';
|
||||
} else if ('above' === sVerticalPosExp) {
|
||||
oNextCSSPosition['top'] = (oTargetPos.top-this.element.outerHeight())+'px';
|
||||
} else {
|
||||
let oTmpFunction = eval('(oElem, oTargetElem, oTargetPos) => '+sVerticalPosExp);
|
||||
oNextCSSPosition['top'] = oTmpFunction(this.element, oTargetElem, oTargetPos);
|
||||
}
|
||||
|
||||
// Horizontal
|
||||
if ('align_inner_left' === sHorizontalPosExp) {
|
||||
oNextCSSPosition['left'] = (oTargetPos.left)+'px';
|
||||
} else if ('align_outer_left' === sHorizontalPosExp) {
|
||||
oNextCSSPosition['left'] = (oTargetPos.left-this.element.width())+'px';
|
||||
} else if ('align_inner_right' === sHorizontalPosExp) {
|
||||
oNextCSSPosition['left'] = (oTargetPos.left+oTargetElem.outerWidth(true)-this.element.width())+'px';
|
||||
} else if ('align_outer_right' === sHorizontalPosExp) {
|
||||
oNextCSSPosition['left'] = (oTargetPos.left+oTargetElem.outerWidth(true))+'px';
|
||||
} else {
|
||||
let oTmpFunction = eval('(oElem, oTargetElem, oTargetPos) => '+sHorizontalPosExp);
|
||||
oNextCSSPosition['left'] = oTmpFunction(this.element, oTargetElem, oTargetPos);
|
||||
}
|
||||
|
||||
this.element.css(oNextCSSPosition);
|
||||
}
|
||||
|
||||
this.togglePopup();
|
||||
},
|
||||
_onBodyScroll: function () {
|
||||
if (true === this._isOpened()) {
|
||||
this._closePopup();
|
||||
}
|
||||
},
|
||||
_onBodyClick: function (oEvent) {
|
||||
if ($(oEvent.target.closest(this.js_selectors.menu)).length === 0 && $(oEvent.target.closest(this.options.toggler)).length === 0) {
|
||||
this._closePopup();
|
||||
@@ -74,6 +179,21 @@ $(function()
|
||||
},
|
||||
|
||||
// Methods
|
||||
/**
|
||||
* @return {boolean} True if there is a toggler selector for the popover menu
|
||||
* @private
|
||||
*/
|
||||
_hasToggler: function () {
|
||||
if (('' === this.options.toggler) || (null === this.options.toggler)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($(this.options.toggler).length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
/**
|
||||
* Add a visual hint (caret) on the toggler
|
||||
*
|
||||
@@ -81,40 +201,59 @@ $(function()
|
||||
* @private
|
||||
*/
|
||||
_addVisualHintToToggler: function () {
|
||||
if ('' === this.options.toggler) {
|
||||
if (false === this._hasToggler()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const oTogglerElem = $(this.options.toggler);
|
||||
if (oTogglerElem.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
oTogglerElem.append($(`<span class="ibo-popover-menu--toggler-visual-hint"><span class="fas fa-caret-down"></span></span>`));
|
||||
$(this.options.toggler).append($(`<span class="ibo-popover-menu--toggler-visual-hint"><span class="fas fa-caret-down"></span></span>`));
|
||||
|
||||
return true;
|
||||
},
|
||||
/**
|
||||
* @return {boolean} True if the menu is currently opened
|
||||
* @private
|
||||
*/
|
||||
_isOpened: function () {
|
||||
return this.element.hasClass(this.css_classes.opened);
|
||||
},
|
||||
/**
|
||||
* Open the menu
|
||||
* @return {void}
|
||||
* @private
|
||||
*/
|
||||
_openPopup: function () {
|
||||
this.element.addClass(this.css_classes.opened);
|
||||
},
|
||||
/**
|
||||
* Close the menu
|
||||
* @return {void}
|
||||
* @private
|
||||
*/
|
||||
_closePopup: function () {
|
||||
this.element.removeClass(this.css_classes.opened);
|
||||
},
|
||||
/**
|
||||
* @api
|
||||
* @return {void}
|
||||
*/
|
||||
openPopup: function () {
|
||||
this._openPopup();
|
||||
},
|
||||
closePopup: function()
|
||||
{
|
||||
/**
|
||||
* @api
|
||||
* @return {void}
|
||||
*/
|
||||
closePopup: function () {
|
||||
this._closePopup();
|
||||
},
|
||||
togglePopup: function()
|
||||
{
|
||||
if(this.element.hasClass(this.css_classes.opened))
|
||||
{
|
||||
/**
|
||||
* @api
|
||||
* @return {void}
|
||||
*/
|
||||
togglePopup: function () {
|
||||
if (this.element.hasClass(this.css_classes.opened)) {
|
||||
this._closePopup();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
this._openPopup();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -134,9 +134,6 @@ $(function()
|
||||
this._ReformatDateTimes();
|
||||
this._PrepareEntriesSubmitConfirmationDialog();
|
||||
|
||||
// TODO 3.0.0: Modify PopoverMenu so we can pass it the ID of the block triggering the open/close
|
||||
//$(this.element).find(this.js_selectors.send_choices_picker).popover_menu({toggler: this.js_selectors.send_button});
|
||||
|
||||
this.element.trigger('ready.activity_panel.itop');
|
||||
},
|
||||
// events bound via _bind are removed automatically
|
||||
|
||||
@@ -100,11 +100,6 @@ $(function()
|
||||
this.element.find(this.js_selectors.menu_filter_hint_close).on('click', function (oEvent) {
|
||||
me._onFilterHintCloseClick(oEvent);
|
||||
});
|
||||
|
||||
// User info
|
||||
this.element.find(this.js_selectors.user_menu_toggler).on('click', function (oEvent) {
|
||||
me._onUserMenuTogglerClick(oEvent);
|
||||
});
|
||||
},
|
||||
|
||||
// Events callbacks
|
||||
@@ -195,20 +190,6 @@ $(function()
|
||||
SetUserPreference('navigation_menu.show_filter_hint', false, true);
|
||||
},
|
||||
|
||||
_onUserMenuTogglerClick: function(oEvent)
|
||||
{
|
||||
// Avoid anchor glitch
|
||||
oEvent.preventDefault();
|
||||
var oEventTarget = $(oEvent.target);
|
||||
var aEventTargetPos = oEventTarget.position();
|
||||
|
||||
$(this.js_selectors.user_menu_container).css({
|
||||
'top': (aEventTargetPos.top + parseInt(oEventTarget.css('marginTop'), 10) - $(this.js_selectors.user_menu).height()) + 'px',
|
||||
'left': (aEventTargetPos.left + parseInt(oEventTarget.css('marginLeft'), 10) + oEventTarget.width()) + 'px'
|
||||
});
|
||||
$(this.js_selectors.user_menu).popover_menu('togglePopup');
|
||||
},
|
||||
|
||||
// Methods
|
||||
_checkIfClickShouldCloseDrawer: function(oEvent)
|
||||
{
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
namespace Combodo\iTop\Application\UI\Base\Component\PopoverMenu\NewsroomMenu;
|
||||
|
||||
use appUserPreferences;
|
||||
use Dict;
|
||||
use MetaModel;
|
||||
use UserRights;
|
||||
use utils;
|
||||
@@ -44,10 +43,10 @@ class NewsroomMenuFactory
|
||||
*/
|
||||
public static function MakeNewsroomMenuForNavigationMenu()
|
||||
{
|
||||
$oMenu = new NewsroomMenu('ibo-navigation-menu--notifications-menu');
|
||||
$oMenu->SetParams(static::PrepareParametersForNewsroomMenu());
|
||||
|
||||
return $oMenu;
|
||||
$oMenu = new NewsroomMenu('ibo-navigation-menu--notifications-menu');
|
||||
$oMenu->SetParams(static::PrepareParametersForNewsroomMenu());
|
||||
|
||||
return $oMenu;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,11 +42,103 @@ class PopoverMenu extends UIBlock
|
||||
'js/components/popover-menu.js',
|
||||
];
|
||||
|
||||
// Specific constants
|
||||
/** @see static::$sContainer */
|
||||
public const ENUM_CONTAINER_BODY = 'body';
|
||||
/** @see static::$sContainer */
|
||||
public const ENUM_CONTAINER_PARENT = 'parent';
|
||||
/** @see static::$sTargetForPositionJSSelector */
|
||||
public const ENUM_TARGET_FOR_POSITION_TOGGLER = 'toggler';
|
||||
/** @see static::$sVerticalPosition */
|
||||
public const ENUM_VERTICAL_POSITION_ABOVE = 'above';
|
||||
/** @see static::$sVerticalPosition */
|
||||
public const ENUM_VERTICAL_POSITION_BELOW = 'below';
|
||||
/**
|
||||
* @see static::$sHorizontalPosition
|
||||
*
|
||||
* +--------+
|
||||
* | Target |
|
||||
* +--------+-----------+
|
||||
* | |
|
||||
* | Menu |
|
||||
* | |
|
||||
* +--------------------+
|
||||
*/
|
||||
public const ENUM_HORIZONTAL_POSITION_ALIGN_INNER_LEFT = 'align_inner_left';
|
||||
/**
|
||||
* @see static::$sHorizontalPosition
|
||||
*
|
||||
* +--------+
|
||||
* | Target |
|
||||
* +--------------------+--------+
|
||||
* | |
|
||||
* | Menu |
|
||||
* | |
|
||||
* +--------------------+
|
||||
*/
|
||||
public const ENUM_HORIZONTAL_POSITION_ALIGN_OUTER_LEFT = 'align_outer_left';
|
||||
/**
|
||||
* @see static::$sHorizontalPosition
|
||||
*
|
||||
* +--------+
|
||||
* | Target |
|
||||
* +-----------+--------+
|
||||
* | |
|
||||
* | Menu |
|
||||
* | |
|
||||
* +--------------------+
|
||||
*/
|
||||
public const ENUM_HORIZONTAL_POSITION_ALIGN_INNER_RIGHT = 'align_inner_right';
|
||||
/**
|
||||
* @see static::$sHorizontalPosition
|
||||
*
|
||||
* +--------+
|
||||
* | Target |
|
||||
* +--------+--------------------+
|
||||
* | |
|
||||
* | Menu |
|
||||
* | |
|
||||
* +--------------------+
|
||||
*/
|
||||
public const ENUM_HORIZONTAL_POSITION_ALIGN_OUTER_RIGHT = 'align_outer_right';
|
||||
|
||||
/** @see static::$sContainer */
|
||||
public const DEFAULT_CONTAINER = self::ENUM_CONTAINER_PARENT;
|
||||
/** @see static::$sTargetForPositionJSSelector */
|
||||
public const DEFAULT_TARGET_FOR_POSITION = self::ENUM_TARGET_FOR_POSITION_TOGGLER;
|
||||
/** @see static::$sVerticalPosition */
|
||||
public const DEFAULT_VERTICAL_POSITION = self::ENUM_VERTICAL_POSITION_BELOW;
|
||||
/** @see static::$sHorizontalPosition */
|
||||
public const DEFAULT_HORIZONTAL_POSITION = self::ENUM_HORIZONTAL_POSITION_ALIGN_INNER_RIGHT;
|
||||
|
||||
/** @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 */
|
||||
/** @var string Container element of the menu. Can be either:
|
||||
* * static::ENUM_CONTAINER_PARENT (default, better performance)
|
||||
* * static::ENUM_CONTAINER_BODY (use it if the menu gets cut by the hidden overflow of its parent)
|
||||
*/
|
||||
protected $sContainer;
|
||||
/**
|
||||
* @var string JS selector for the DOM element the menu should be positioned relatively to.
|
||||
* * static::ENUM_TARGET_FOR_POSITION_TOGGLER (default, a shortcut pointing to the toggler)
|
||||
* * A JS selector
|
||||
*/
|
||||
protected $sTargetForPositionJSSelector;
|
||||
/** @var string Relative vertical position of the menu from the target. Value can be:
|
||||
* * static::ENUM_VERTICAL_POSITION_BELOW for the menu to be directly below the target
|
||||
* * static::ENUM_VERTICAL_POSITION_ABOVE for the menu to be directly above the target
|
||||
* * A JS expression to be evaluated that must return pixels (eg. (oTargetPos.top + oTarget.outerHeight(true)) + 'px')
|
||||
*/
|
||||
protected $sVerticalPosition;
|
||||
/** @var string Relative horizontal position of the menu from the target. Value can be:
|
||||
* * static::ENUM_HORIZONTAL_POSITION_ALIGN_INNER_LEFT for the menu to be aligned with the target's left side
|
||||
* * static::ENUM_HORIZONTAL_POSITION_ALIGN_INNER_RIGHT for the menu to be aligned with the target's right side
|
||||
* * A JS expression to be evaluated that must return pixels (eg. (oTargetPos.left + oTarget.outerWidth(true) - popover.width()) + 'px')
|
||||
*/
|
||||
protected $sHorizontalPosition;
|
||||
/** @var array */
|
||||
protected $aSections;
|
||||
|
||||
/**
|
||||
@@ -59,6 +151,10 @@ class PopoverMenu extends UIBlock
|
||||
parent::__construct($sId);
|
||||
$this->sTogglerJSSelector = '';
|
||||
$this->bAddVisualHintToToggler = false;
|
||||
$this->sContainer = static::DEFAULT_CONTAINER;
|
||||
$this->sTargetForPositionJSSelector = static::DEFAULT_TARGET_FOR_POSITION;
|
||||
$this->sVerticalPosition = static::DEFAULT_VERTICAL_POSITION;
|
||||
$this->sHorizontalPosition = static::DEFAULT_HORIZONTAL_POSITION;
|
||||
$this->aSections = [];
|
||||
}
|
||||
|
||||
@@ -113,6 +209,94 @@ class PopoverMenu extends UIBlock
|
||||
return $this->bAddVisualHintToToggler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sContainer
|
||||
*
|
||||
* @return $this
|
||||
* @uses static::$sContainer
|
||||
*/
|
||||
public function SetContainer(string $sContainer)
|
||||
{
|
||||
$this->sContainer = $sContainer;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @uses static::$sContainer
|
||||
*/
|
||||
public function GetContainer(): string
|
||||
{
|
||||
return $this->sContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sJSSelector
|
||||
*
|
||||
* @return $this
|
||||
* @uses static::$sTargetForPositionJSSelector
|
||||
*/
|
||||
public function SetTargetForPositionJSSelector(string $sJSSelector)
|
||||
{
|
||||
$this->sTargetForPositionJSSelector = $sJSSelector;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @uses static::$sTargetForPositionJSSelector
|
||||
*/
|
||||
public function GetTargetForPositionJSSelector(): string
|
||||
{
|
||||
return $this->sTargetForPositionJSSelector;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sPosition
|
||||
*
|
||||
* @return $this
|
||||
* @uses static::$sVerticalPosition
|
||||
*/
|
||||
public function SetVerticalPosition(string $sPosition)
|
||||
{
|
||||
$this->sVerticalPosition = $sPosition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @uses static::$sVerticalPosition
|
||||
*/
|
||||
public function GetVerticalPosition(): string
|
||||
{
|
||||
return $this->sVerticalPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sPosition
|
||||
*
|
||||
* @return $this
|
||||
* @uses static::$sHorizontalPosition
|
||||
*/
|
||||
public function SetHorizontalPosition(string $sPosition)
|
||||
{
|
||||
$this->sHorizontalPosition = $sPosition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @uses static::$sHorizontalPosition
|
||||
*/
|
||||
public function GetHorizontalPosition(): string
|
||||
{
|
||||
return $this->sHorizontalPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a section $sId if not already existing.
|
||||
* Important: It does not reset the section.
|
||||
|
||||
@@ -49,7 +49,10 @@ class PopoverMenuFactory
|
||||
public static function MakeUserMenuForNavigationMenu()
|
||||
{
|
||||
$oMenu = new PopoverMenu('ibo-navigation-menu--user-menu');
|
||||
$oMenu->SetTogglerJSSelector('[data-role="ibo-navigation-menu--user-menu--toggler"]');
|
||||
$oMenu->SetTogglerJSSelector('[data-role="ibo-navigation-menu--user-menu--toggler"]')
|
||||
->SetContainer(PopoverMenu::ENUM_CONTAINER_BODY)
|
||||
->SetHorizontalPosition(PopoverMenu::ENUM_HORIZONTAL_POSITION_ALIGN_OUTER_RIGHT)
|
||||
->SetVerticalPosition(PopoverMenu::ENUM_VERTICAL_POSITION_ABOVE);
|
||||
|
||||
// Allowed portals
|
||||
$aAllowedPortalsItems = static::PrepareAllowedPortalsItemsForUserMenu();
|
||||
|
||||
@@ -299,18 +299,18 @@ class CaseLogEntryForm extends UIContentBlock
|
||||
$aSubBlocks = [];
|
||||
$aSubBlocks[$this->GetTextInput()->GetId()] = $this->GetTextInput();
|
||||
|
||||
foreach ($this->GetExtraActionButtons() as $oExtraActionButton)
|
||||
{
|
||||
foreach ($this->GetExtraActionButtons() as $oExtraActionButton) {
|
||||
$aSubBlocks[$oExtraActionButton->GetId()] = $oExtraActionButton;
|
||||
}
|
||||
|
||||
foreach ($this->GetMainActionButtons() as $oMainActionButton)
|
||||
{
|
||||
foreach ($this->GetMainActionButtons() as $oMainActionButton) {
|
||||
$aSubBlocks[$oMainActionButton->GetId()] = $oMainActionButton;
|
||||
}
|
||||
|
||||
$aSubBlocks[$this->GetSendButtonPopoverMenu()->GetId()] = $this->GetSendButtonPopoverMenu();
|
||||
|
||||
if ($this->HasSendButtonPopoverMenu()) {
|
||||
$aSubBlocks[$this->GetSendButtonPopoverMenu()->GetId()] = $this->GetSendButtonPopoverMenu();
|
||||
}
|
||||
|
||||
return $aSubBlocks;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,8 +37,10 @@ class CaseLogEntryFormFactory
|
||||
$oCaseLogEntryForm = new CaseLogEntryForm($oObject, $sCaseLogAttCode);
|
||||
$oCaseLogEntryForm->SetSubmitModeFromHostObjectMode($sObjectMode)
|
||||
->AddMainActionButtons(static::PrepareCancelButton())
|
||||
->AddMainActionButtons(static::PrepareSaveButton())
|
||||
->SetSendButtonPopoverMenu(static::PrepareSendActionSelectionPopoverMenu($oObject, $sCaseLogAttCode));
|
||||
->AddMainActionButtons(static::PrepareSaveButton());
|
||||
|
||||
// TODO 3.0.0: Will be fixed by N°3649
|
||||
// ->SetSendButtonPopoverMenu(static::PrepareSendActionSelectionPopoverMenu($oObject, $sCaseLogAttCode));
|
||||
|
||||
return $oCaseLogEntryForm;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
$('#{{ oUIBlock.GetId() }}').popover_menu({
|
||||
toggler: {{ oUIBlock.GetTogglerJSSelector()|json_encode|raw }},
|
||||
container: {{ oUIBlock.GetContainer()|json_encode|raw }},
|
||||
position: {
|
||||
target: {{ oUIBlock.GetTargetForPositionJSSelector()|json_encode|raw }},
|
||||
vertical: {{ oUIBlock.GetVerticalPosition()|json_encode|raw }},
|
||||
horizontal: {{ oUIBlock.GetHorizontalPosition()|json_encode|raw }},
|
||||
},
|
||||
add_visual_hint_to_toggler: {{ oUIBlock.HasVisualHintToAddToToggler()|var_export }}
|
||||
});
|
||||
@@ -17,7 +17,9 @@
|
||||
{% for FormActionButton in oUIBlock.GetMainActionButtons() %}
|
||||
{{ render_block(FormActionButton, {aPage: aPage}) }}
|
||||
{% endfor %}
|
||||
{{ render_block(oUIBlock.GetSendButtonPopoverMenu(), {aPage: aPage}) }}
|
||||
{% if oUIBlock.HasSendButtonPopoverMenu() %}
|
||||
{{ render_block(oUIBlock.GetSendButtonPopoverMenu(), {aPage: aPage}) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibo-caselog-entry-form--text-input" data-role="ibo-caselog-entry-form--text-input">
|
||||
|
||||
Reference in New Issue
Block a user