diff --git a/js/components/popover-menu.js b/js/components/popover-menu.js index 68f71b586..eb27230cd 100644 --- a/js/components/popover-menu.js +++ b/js/components/popover-menu.js @@ -172,8 +172,19 @@ $(function() this._closePopup(); } }, + /** + * @return {void} + * @param oEvent + * @private + */ _onBodyClick: function (oEvent) { - if ($(oEvent.target.closest(this.js_selectors.menu)).length === 0 && $(oEvent.target.closest(this.options.toggler)).length === 0) { + if (false === this._isOpened()) { + return; + } + + if ($(oEvent.target.closest(this.js_selectors.menu)).length === 0 && + // Menu without a toggler cannot be closed by an "outside" click, on programatically (same way it was opened in the first place) + ((true === this._hasToggler()) && ($(oEvent.target.closest(this.options.toggler)).length === 0))) { this._closePopup(); } }, diff --git a/js/layouts/activity-panel/activity-panel.js b/js/layouts/activity-panel/activity-panel.js index c57139cb2..273a6fd95 100644 --- a/js/layouts/activity-panel/activity-panel.js +++ b/js/layouts/activity-panel/activity-panel.js @@ -72,6 +72,8 @@ $(function() authors_count: '[data-role="ibo-activity-panel--tab-toolbar-info-authors-count"]', messages_count: '[data-role="ibo-activity-panel--tab-toolbar-info-messages-count"]', compose_button: '[data-role="ibo-activity-panel--add-caselog-entry-button"]', + compose_menu: '#ibo-activity-panel--compose-menu', + compose_menu_item: '#ibo-activity-panel--compose-menu [data-role="ibo-popover-menu--item"]', caselog_entry_form: '[data-role="ibo-caselog-entry-form"]', caselog_entry_forms_confirmation_dialog: '[data-role="ibo-activity-panel--entry-forms-confirmation-dialog"]', caselog_entry_forms_confirmation_preference_input: '[data-role="ibo-activity-panel--entry-forms-confirmation-preference-input"]', @@ -186,6 +188,10 @@ $(function() this.element.find(this.js_selectors.compose_button).on('click', function (oEvent) { me._onComposeButtonClick(oEvent); }); + // - Click on the compose menu items + this.element.find(this.js_selectors.compose_menu_item).on('click', function (oEvent) { + me._onComposeMenuItemClick(oEvent, $(this)); + }); // - Draft value ongoing this.element.on('draft.caselog_entry_form.itop', function (oEvent, oData) { me._onDraftEntryForm(oData.attribute_code); @@ -331,25 +337,37 @@ $(function() * @return {void} * @private */ - _onComposeButtonClick: function(oEvent) - { + _onComposeButtonClick: function (oEvent) { oEvent.preventDefault(); const oActiveTabData = this._GetActiveTabData(); // If on a caselog tab, open its form if it has one if ((this.enums.tab_types.caselog === oActiveTabData.type) && this._HasCaseLogEntryFormForTab(oActiveTabData.att_code)) { + // Note: Stop propogation to avoid the menu to be opened automatically by the popover handler, we will decide when it can opens below + oEvent.stopImmediatePropagation(); + this._ShowCaseLogTab(oActiveTabData.att_code); this._ShowCaseLogsEntryForms(); this._SetFocusInCaseLogEntryForm(oActiveTabData.att_code); } - // Else, check which *editable* case log tab to go to - else { - // TODO 3.0.0: Make a tab popover menu selection - console.log('TO IMPLEMENT'); + // Else, the compose menu will open automatically + }, + /** + * @param oEvent {Object} + * @param oItemElem {Object} jQuery object representing the clicked item + * @return {void} + * @private + */ + _onComposeMenuItemClick: function (oEvent, oItemElem) { + oEvent.preventDefault(); - // If only 1 editbale case log, open this one - // Else, open a popover menu to choose one - } + // Change tab + this.element.find(this.js_selectors.tab_toggler+'[data-tab-type="'+this.enums.tab_types.caselog+'"][data-caselog-attribute-code="'+oItemElem.attr('data-caselog-attribute-code')+'"]') + .find(this.js_selectors.tab_title) + .trigger('click'); + + // Then open editor + this.element.find(this.js_selectors.compose_button).trigger('click'); }, /** * @param oEvent {Object} diff --git a/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanel.php b/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanel.php index 4c738c061..6a0b58c08 100644 --- a/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanel.php +++ b/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanel.php @@ -23,6 +23,8 @@ namespace Combodo\iTop\Application\UI\Base\Layout\ActivityPanel; use appUserPreferences; use AttributeDateTime; use cmdbAbstractObject; +use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenu; +use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenuItem\PopoverMenuItemFactory; use Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry\ActivityEntry; use Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry\CaseLogEntry; use Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\CaseLogEntryForm\CaseLogEntryForm; @@ -30,6 +32,7 @@ use Combodo\iTop\Application\UI\Base\UIBlock; use DBObject; use Exception; use MetaModel; +use URLPopupMenuItem; use utils; /** @@ -82,6 +85,8 @@ class ActivityPanel extends UIBlock protected $bHasStates; /** @var \Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\CaseLogEntryForm\CaseLogEntryForm[] $aCaseLogTabsEntryForms */ protected $aCaseLogTabsEntryForms; + /** @var \Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenu Menu displaying the editable log entry forms the user can go to */ + protected $oComposeMenu; /** @var bool Whether a confirmation dialog should be prompt when multiple entries are about to be submitted at once */ protected $bShowMultipleEntriesSubmitConfirmation; @@ -101,6 +106,7 @@ class ActivityPanel extends UIBlock $this->InitializeCaseLogTabs(); $this->InitializeCaseLogTabsEntryForms(); + $this->InitializeComposeMenu(); $this->SetObjectMode(cmdbAbstractObject::DEFAULT_OBJECT_MODE); $this->SetObject($oObject); $this->SetEntries($aEntries); @@ -130,17 +136,19 @@ class ActivityPanel extends UIBlock // Initialize the case log tabs $this->InitializeCaseLogTabs(); $this->InitializeCaseLogTabsEntryForms(); + $this->InitializeComposeMenu(); // Get only case logs from the "details" zlist, but if none (2.7 and older) show them all $aCaseLogAttCodes = MetaModel::GetCaseLogs($sObjectClass, 'details'); if (empty($aCaseLogAttCodes)) { $aCaseLogAttCodes = MetaModel::GetCaseLogs($sObjectClass); } - + foreach ($aCaseLogAttCodes as $sCaseLogAttCode) { $this->AddCaseLogTab($sCaseLogAttCode); } + return $this; } @@ -545,9 +553,11 @@ class ActivityPanel extends UIBlock // Only if not hidden if (false === $bIsHidden) { + $sLogLabel = MetaModel::GetLabel(get_class($this->oObject), $sAttCode); + $this->aCaseLogs[$sAttCode] = [ 'rank' => count($this->aCaseLogs) + 1, - 'title' => MetaModel::GetLabel(get_class($this->oObject), $sAttCode), + 'title' => $sLogLabel, 'total_messages_count' => 0, 'authors' => [], 'is_read_only' => $bIsReadOnly, @@ -560,6 +570,16 @@ class ActivityPanel extends UIBlock if ((false === $bIsReadOnly) && (false === $this->HasTransactionId()) && (cmdbAbstractObject::ENUM_OBJECT_MODE_VIEW === $this->sObjectMode)) { $this->sTransactionId = (cmdbAbstractObject::ENUM_OBJECT_MODE_VIEW === $this->sObjectMode) ? utils::GetNewTransactionId() : null; } + + // Add log to compose button menu only if it is editable + if (false === $bIsReadOnly) { + $oItem = PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem( + new URLPopupMenuItem('log-'.$sAttCode, $sLogLabel, '#') + ) + ->AddDataAttribute('caselog-attribute-code', $sAttCode); + + $this->oComposeMenu->AddItem('editable-logs', $oItem); + } } } @@ -718,6 +738,46 @@ class ActivityPanel extends UIBlock return $iAutonomousSubmission > 0; } + /** + * @return bool Whether the "compose a new entry" button is enabled + * @throws \Exception + */ + public function IsComposeButtonEnabled(): bool + { + return $this->HasAnEditableCaseLogTab() && $this->IsCaseLogsSubmitAutonomous(); + } + + /** + * @return bool Whether there is a menu on the "compose" button to select which log entry form to open + * @uses static::$oComposeMenu + */ + public function HasComposeMenu(): bool + { + return $this->oComposeMenu->HasItems(); + } + + /** + * @return \Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenu + * @uses static::$oComposeMenu + */ + public function GetComposeMenu() + { + return $this->oComposeMenu; + } + + /** + * @return $this + * @uses static::$oComposeMenu + */ + protected function InitializeComposeMenu() + { + // Note: There is no toggler set on purpose, menu will be toggle depending on the active tab + $this->oComposeMenu = new PopoverMenu('ibo-activity-panel--compose-menu'); + $this->oComposeMenu->SetTogglerJSSelector('#ibo-activity-panel--add-caselog-entry-button'); + + return $this; + } + /** * @return bool True if the entry form shouldbe opened by default, false otherwise. Based on the user pref. or the config. param. by default. * @throws \CoreException @@ -796,6 +856,8 @@ class ActivityPanel extends UIBlock $aSubBlocks[$oCaseLogEntryForm->GetId()] = $oCaseLogEntryForm; } + $aSubBlocks[$this->GetComposeMenu()->GetId()] = $this->GetComposeMenu(); + return $aSubBlocks; } diff --git a/templates/base/layouts/activity-panel/layout.html.twig b/templates/base/layouts/activity-panel/layout.html.twig index 761fa4e1e..13cda207d 100644 --- a/templates/base/layouts/activity-panel/layout.html.twig +++ b/templates/base/layouts/activity-panel/layout.html.twig @@ -64,13 +64,17 @@ - {% if oUIBlock.HasAnEditableCaseLogTab() and oUIBlock.IsCaseLogsSubmitAutonomous() %} + {% if oUIBlock.IsComposeButtonEnabled() %} + {% if oUIBlock.HasComposeMenu() %} + {{ render_block(oUIBlock.GetComposeMenu()) }} + {% endif %} {% endif %}
{% if oUIBlock.GetGroupedEntries()|length > 0 %} @@ -101,4 +105,10 @@
- \ No newline at end of file + + + \ No newline at end of file