Skip to content

Commit

Permalink
N°1192 Introduce navigation_rules in the end-users portal
Browse files Browse the repository at this point in the history
  • Loading branch information
Molkobain committed Nov 22, 2019
1 parent ff88453 commit b1b6c9f
Show file tree
Hide file tree
Showing 10 changed files with 887 additions and 118 deletions.
3 changes: 3 additions & 0 deletions datamodels/2.x/itop-portal-base/portal/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ services:
context_manipulator:
alias: Combodo\iTop\Portal\Helper\ContextManipulatorHelper
public: true
navigation_rule_helper:
alias: Combodo\iTop\Portal\Helper\NavigationRuleHelper
public: true
lifecycle_validator:
alias: Combodo\iTop\Portal\Helper\LifecycleValidatorHelper
public: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,35 @@ $(function()
$.widget( 'itop.portal_form_handler', $.itop.form_handler,
{
options: {
submit_url: null,
cancel_url: null
submit_url: null, // Deprecated. We kept those properties to preserve compatibility with extensions
cancel_url: null, // but you should start using xxx_rule.url as soon as possible.
submit_rule: {
category: 'redirect',
url: null,
modal: false,
},
cancel_rule: {
category: 'close',
url: null,
modal: false,
},
},

// the constructor
_create: function()
{
this.element
.addClass('portal_form_handler');
this.element.addClass('portal_form_handler');

// Safe check for options
if(this.options.submit_url === "")
this.options.submit_url = null;
if(this.options.cancel_url === "")
this.options.cancel_url = null;
if(this.options.submit_rule.url === '')
this.options.submit_rule.url = null;
if(this.options.cancel_rule.url === '')
this.options.cancel_rule.url = null;
// Deprecated, see this.options.submit_url
if((this.options.submit_url !== null) && (this.options.submit_url !== ''))
this.options.submit_rule.url = this.options.submit_url;
if((this.options.cancel_url !== null) && (this.options.cancel_url !== ''))
this.options.cancel_rule.url = this.options.cancel_url;

this._super();
},
Expand Down Expand Up @@ -160,69 +174,34 @@ $(function()
// If everything is okay, we close the form and reload it.
if(oValidation.valid)
{

var bRedirectInModal = me.options.submit_rule.modal;
var sRedirectUrl = me.options.submit_rule.url;

$('body').trigger('unregister_blocker.portal.itop', {'sBlockerId': me.element.attr('id')});

if(me.options.is_modal)
{
me.element.closest('.modal').modal('hide');
}

// Checking if we have to redirect to another page
// Typically this happens when applying a stimulus, we redirect to transition form
if(oValidation.redirection !== undefined)
{
var oRedirection = oValidation.redirection;
var bRedirectionAjax = (oRedirection.ajax !== undefined) ? oRedirection.ajax : false;
var sUrl = null;

// URL priority order :
// redirection.url > me.option.submit_url > redirection.alternative_url
if(oRedirection.url !== undefined)
if(oRedirection.modal !== undefined)
{
sUrl = oRedirection.url;
bRedirectInModal = oRedirection.modal;
}
else if(me.options.submit_url !== null)
{
sUrl = me.options.submit_url;
}
else if(oRedirection.alternative_url !== undefined)
{
sUrl = oRedirection.alternative_url;
}

if(sUrl !== null)
if(oRedirection.url !== undefined)
{
if(bRedirectionAjax)
{
// Creating a new modal
CombodoPortalToolbox.OpenModal({
content: {
endpoint: sUrl,
data: {
// Passing form manager data to the next page, just in case it needs it (eg. when applying stimulus)
formmanager_class: me.options.formmanager_class,
formmanager_data: JSON.stringify(me.options.formmanager_data)
},
},
});
}
else
{
// Showing loader while redirecting, otherwise user tend to click somewhere in the page.
// Note : We use a timeout because .always() is called right after here and will hide the loader
setTimeout(function(){ me._disableFormBeforeLoading(); }, 50);
// Redirecting after a few ms so the user can see what happend
setTimeout(function() { location.href = sUrl; }, 400);
}
sRedirectUrl = oRedirection.url;
}
me._applyRedirectRule(sRedirectUrl, bRedirectInModal);
}
else if(me.options.submit_url !== null)
else if(me.options.submit_rule.category === 'redirect')
{
// Showing loader while redirecting, otherwise user tend to click somewhere in the page.
// Note : We use a timeout because .always() is called right after here and will hide the loader
setTimeout(function(){ me._disableFormBeforeLoading(); }, 50);
// Redirecting after a few ms so the user can see what happend
setTimeout(function() { location.href = me.options.submit_url; }, 400);
me._applyRedirectRule(sRedirectUrl, bRedirectInModal);
}
// Close rule only needs to be applied to non modal forms (modal is always closed on submit)
else if(me.options.submit_rule.category === 'close')
{
me._applyCloseRule();
}
}
}
Expand Down Expand Up @@ -269,38 +248,31 @@ $(function()
},
function(oData)
{
if(me.options.cancel_url !== null)
if(me.options.cancel_rule.category === 'redirect')
{
me._applyRedirectRule(me.options.cancel_rule.url, me.options.cancel_rule.modal);
}
else if(me.options.cancel_rule.category === 'close')
{
location.href = me.options.cancel_url;
me._applyCloseRule();
}
}
)
.always(function(){
// Close the modal only if fields had to be cancelled
if(me.options.is_modal)
{
me.element.closest('.modal').modal('hide');
}
.always(function()
{
me._enableFormAfterLoading();
});
}
// Otherwise we can close the modal immediately
else
{
if(me.options.cancel_url !== null)
if(me.options.cancel_rule.category === 'redirect')
{
location.href = me.options.cancel_url;
me._applyRedirectRule(me.options.cancel_rule.url, me.options.cancel_rule.modal);
}
else
else if(me.options.cancel_rule.category === 'close')
{
if(me.options.is_modal)
{
me.element.closest('.modal').modal('hide');
}
else
{
location.reload();
}
me._applyCloseRule();
}
}
},
Expand Down Expand Up @@ -343,6 +315,53 @@ $(function()
{
$('#page_overlay').fadeOut(200);
},
_applyRedirectRule: function(sRedirectUrl, bRedirectInModal)
{
var me = this;

// Always close current modal
if(this.options.is_modal)
{
this.element.closest('.modal').modal('hide');
}

if(sRedirectUrl !== null)
{
if(bRedirectInModal === true)
{
// Creating a new modal
CombodoPortalToolbox.OpenModal({
content: {
endpoint: sRedirectUrl,
data: {
// Passing form manager data to the next page, just in case it needs it (eg. when applying stimulus)
formmanager_class: this.options.formmanager_class,
formmanager_data: JSON.stringify(this.options.formmanager_data)
},
},
});
}
else
{
// Showing loader while redirecting, otherwise user tend to click somewhere in the page.
// Note: We use a timeout because .always() is called right after here and will hide the loader
setTimeout(function(){ me._disableFormBeforeLoading(); }, 50);
// Redirecting after a few ms so the user can see what happend
setTimeout(function() { location.href = sRedirectUrl; }, 400);
}
}
},
_applyCloseRule: function()
{
if(this.options.is_modal)
{
this.element.closest('.modal').modal('hide');
}
else
{
window.close();
}
},
submit: function(oEvent)
{
this._onSubmitClick(oEvent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,11 @@
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/

namespace Combodo\iTop\Portal\DependencyInjection\SilexCompatBootstrap\PortalXmlConfiguration;

use Combodo\iTop\Portal\Helper\NavigationRuleHelper;
use Symfony\Component\DependencyInjection\Container;
use DOMFormatException;
use Exception;
Expand Down Expand Up @@ -66,7 +65,19 @@ public function Process(Container $oContainer)
$aFormProperties = array(
'display_mode' => ApplicationHelper::FORM_DEFAULT_DISPLAY_MODE,
'always_show_submit' => ApplicationHelper::FORM_DEFAULT_ALWAYS_SHOW_SUBMIT,
'navigation_rules' => array(
'submit' => array(
NavigationRuleHelper::ENUM_ORIGIN_PAGE => null,
NavigationRuleHelper::ENUM_ORIGIN_MODAL => null,
),
'cancel' => array(
NavigationRuleHelper::ENUM_ORIGIN_PAGE => null,
NavigationRuleHelper::ENUM_ORIGIN_MODAL => null,
),
),
);

$aAllowedNavRulesButtonCodes = array_keys($aFormProperties['navigation_rules']);
if ($oFormNode->GetOptionalElement('properties') !== null)
{
/** @var \MFElement $oPropertyNode */
Expand All @@ -77,9 +88,48 @@ public function Process(Container $oContainer)
case 'display_mode':
$aFormProperties['display_mode'] = $oPropertyNode->GetText(ApplicationHelper::FORM_DEFAULT_DISPLAY_MODE);
break;

case 'always_show_submit':
$aFormProperties['always_show_submit'] = ($oPropertyNode->GetText('false') === 'true') ? true : false;
break;

case 'navigation_rules':
/** @var \MFElement $oNavRuleButtonNode */
foreach($oPropertyNode->childNodes as $oNavRuleButtonNode)
{
$sNavRuleButtonCode = $oNavRuleButtonNode->nodeName;
if(!in_array($sNavRuleButtonCode, $aAllowedNavRulesButtonCodes))
{
throw new DOMFormatException('navigation_rules tag must only contain '.implode('|', $aAllowedNavRulesButtonCodes).' tags, "'.$sNavRuleButtonCode.'" given.', null, null, $oPropertyNode);
}

/** @var \MFElement $oNavRuleOriginNode */
foreach($oNavRuleButtonNode->childNodes as $oNavRuleOriginNode)
{
$sNavRuleOrigin = $oNavRuleOriginNode->nodeName;
if(!in_array($sNavRuleOrigin, NavigationRuleHelper::GetAllowedOrigins()))
{
throw new DOMFormatException($sNavRuleButtonCode. ' tag must only contain '.implode('|', NavigationRuleHelper::GetAllowedOrigins()).' tags, "'.$sNavRuleOrigin.'" given.', null, null, $oPropertyNode);
}

$sNavRuleId = $oNavRuleOriginNode->GetText();
// Note: We don't check is rule exists as it would introduce a dependency to the NavigationRuleHelper service.
// Maybe we will consider it later.
if(empty($sNavRuleId))
{
throw new DOMFormatException($sNavRuleButtonCode.' tag cannot be empty.', null, null, $oPropertyNode);
}

$aFormProperties['navigation_rules'][$sNavRuleButtonCode][$sNavRuleOrigin] = $sNavRuleId;
}

// Set modal rule as the same as default is not present.
// We preset it so we don't have to make checks elsewhere in the code when using it.
if(empty($aFormProperties['navigation_rules'][$sNavRuleButtonCode][NavigationRuleHelper::ENUM_ORIGIN_MODAL]))
{
$aFormProperties['navigation_rules'][$sNavRuleButtonCode][NavigationRuleHelper::ENUM_ORIGIN_MODAL] = $aFormProperties['navigation_rules'][$sNavRuleButtonCode][NavigationRuleHelper::ENUM_ORIGIN_PAGE];
}
}
}
}
}
Expand All @@ -98,7 +148,7 @@ public function Process(Container $oContainer)
}
else
{
throw new DOMFormatException('Mode tag must have an id attribute', null, null,
throw new DOMFormatException('mode tag must have an id attribute', null, null,
$oFormNode);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/

namespace Combodo\iTop\Portal\Helper;
Expand Down Expand Up @@ -374,6 +372,10 @@ protected static function GenerateDefaultFormForClass($sClass, $bAddLinksets = f
'properties' => array(
'display_mode' => static::FORM_DEFAULT_DISPLAY_MODE,
'always_show_submit' => static::FORM_DEFAULT_ALWAYS_SHOW_SUBMIT,
'navigation_rules' => array(
'submit' => null,
'cancel' => null,
),
),
'fields' => array(),
'layout' => array(
Expand Down
Loading

0 comments on commit b1b6c9f

Please sign in to comment.