浏览代码

#1284: Fixed portal issue when trying to re-open a ticket as a portal user. Cause was that the destination state had "must prompt" attributes that were all "read only" for the current user, making the entire form "read only" and therefore removing "submit" button. The user was the not able to complete the transition. Fix consists of skipping the form when all attributes are "read only" for the user.

Also :
- Refactored a portion of TWIG (Loader is now in an helper TWIG)
- Placed transition buttons to the right with the submit one as it was confusing

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@4332 a333f486-631f-4898-b8df-5754b55c2be0
glajarige 8 年之前
父节点
当前提交
b9d323e246

+ 29 - 1
datamodels/2.x/itop-portal-base/portal/src/controllers/objectcontroller.class.inc.php

@@ -335,6 +335,9 @@ class ObjectController extends AbstractController
 			$oApp->abort(404, Dict::S('UI:ObjectDoesNotExist'));
 		}
 
+		// Retrieving request parameters
+		$sOperation = $oRequest->request->get('operation');
+		
 		// Preparing a dedicated form for the stimulus application
 		$aFormProperties = array(
 			'id' => 'apply-stimulus',
@@ -372,14 +375,39 @@ class ObjectController extends AbstractController
 			'url' => $oApp['url_generator']->generate('p_object_edit', array('sObjectClass' => $sObjectClass, 'sObjectId' => $sObjectId))
 		);
 
+		// TODO : This is a ugly patch to avoid showing a modal with a readonly form to the user as it would prevent user from finishing the transition.
+		// Instead, we apply the stimulus directly here and then go to the edited object.
+		if ($sOperation === null)
+		{
+			if (isset($aData['form']['editable_fields_count']) && $aData['form']['editable_fields_count'] === 0)
+			{
+				$sOperation = 'redirect';
+
+				$oSubRequest = $oRequest;
+				$oSubRequest->request->set('operation', 'submit');
+				$oSubRequest->request->set('stimulus_code', null);
+				
+				$aData = array('sMode' => 'apply_stimulus');
+				$aData['form'] = $this->HandleForm($oSubRequest, $oApp, $aData['sMode'], $sObjectClass, $sObjectId, $aFormProperties);
+				// Redefining the array to be as simple as possible :
+				$aData = array('redirection' =>
+					array('url' => $oApp['url_generator']->generate('p_object_edit', array('sObjectClass' => $sObjectClass, 'sObjectId' => $sObjectId)))
+				);
+			}
+		}
+
 		// Preparing response
 		if ($oRequest->isXmlHttpRequest())
 		{
 			// We have to check whether the 'operation' parameter is defined or not in order to know if the form is required via ajax (to be displayed as a modal dialog) or if it's a lifecycle call from a existing form.
-			if ($oRequest->request->get('operation') === null)
+			if ($sOperation === null)
 			{
 				$oResponse = $oApp['twig']->render('itop-portal-base/portal/src/views/bricks/object/modal.html.twig', $aData);
 			}
+			elseif ($sOperation === 'redirect')
+			{
+				$oResponse = $oApp['twig']->render('itop-portal-base/portal/src/views/modal/mode_loader.html.twig', $aData);
+			}
 			else
 			{
 				$oResponse = $oApp->json($aData);

+ 53 - 50
datamodels/2.x/itop-portal-base/portal/src/views/bricks/object/mode_create.html.twig

@@ -24,7 +24,7 @@
 			{% if form.buttons is defined and form.buttons.transitions is defined and form.buttons.transitions|length > 0 %}
 				<div class="form_btn_transitions">
 				{% for sStimulusCode, sStimulusLabel in form.buttons.transitions %}
-					<button class="btn btn-default form_btn_transition" type="submit" name="stimulus_code" value="{{ sStimulusCode }}">{{ sStimulusLabel }}</button>
+					<button class="btn btn-primary form_btn_transition" type="submit" name="stimulus_code" value="{{ sStimulusCode }}">{{ sStimulusLabel }}</button>
 				{% endfor %}
 				</div>
 			{% endif %}
@@ -67,60 +67,63 @@
 		
 		// Sticky buttons handler
 		{% if sMode != 'view' %}
-			// Note : This pattern if to prevent performance issues
-			// - Cloning buttons
-			var oNormalRegularButtons_{{ sFormIdSanitized }} = $('#{{ sFormId }} .form_btn_regular');
-			var oStickyRegularButtons_{{ sFormIdSanitized }} = oNormalRegularButtons_{{ sFormIdSanitized }}.clone(true, true);
-			oStickyRegularButtons_{{ sFormIdSanitized }}.addClass('sticky');
-			if(oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_submit span.glyphicon').length > 0)
+			if( $('#{{ sFormId }} .form_btn_regular button').length > 0 )
 			{
-				oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_submit').html( oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_submit span.glyphicon')[0].outerHTML );
-			}
-			if(oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_cancel span.glyphicon').length > 0)
-			{
-				oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_cancel').html( oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_cancel span.glyphicon')[0].outerHTML );
-			}
-			
-			$('#{{ sFormId }}').closest({% if tIsModal == true %}'.modal'{% else %}'#main-content'{% endif %}).append(oStickyRegularButtons_{{ sFormIdSanitized }});
-			
-			// - Global timeout for any
-			var oScrollTimeout;
-			// - Scroll handler
-			scrollHandler_{{ sFormIdSanitized }} = function () {
-				if($('#{{ sFormId }} .form_buttons').visible())
+				// Note : This pattern if to prevent performance issues
+				// - Cloning buttons
+				var oNormalRegularButtons_{{ sFormIdSanitized }} = $('#{{ sFormId }} .form_btn_regular');
+				var oStickyRegularButtons_{{ sFormIdSanitized }} = oNormalRegularButtons_{{ sFormIdSanitized }}.clone(true, true);
+				oStickyRegularButtons_{{ sFormIdSanitized }}.addClass('sticky');
+				if(oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_submit span.glyphicon').length > 0)
 				{
-					oStickyRegularButtons_{{ sFormIdSanitized }}.addClass('closed');
+					oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_submit').html( oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_submit span.glyphicon')[0].outerHTML );
 				}
-				else
+				if(oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_cancel span.glyphicon').length > 0)
 				{
-					oStickyRegularButtons_{{ sFormIdSanitized }}.removeClass('closed');
-				}
-			};
-			// - Event binding for scroll
-			$({% if tIsModal == true %}'.modal.in'{% else %}window{% endif %}).off('scroll').on('scroll', function () {
-				if (oScrollTimeout) {
-					// Clear the timeout, if one is pending
-					clearTimeout(oScrollTimeout);
-					oScrollTimeout = null;
+					oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_cancel').html( oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_cancel span.glyphicon')[0].outerHTML );
 				}
-				oScrollTimeout = setTimeout(scrollHandler_{{ sFormIdSanitized }}, 50);
-			});
-			// - Event binding for linkedset collapse
-			$({% if tIsModal == true %}'.modal.in'{% else %}window{% endif %}).off('shown.bs.collapse hidden.bs.collapse').on('shown.bs.collapse hidden.bs.collapse', function () {
-				scrollHandler_{{ sFormIdSanitized }}();
-			});
-			// - Event binding for form building / updating
-			// Note : We do not want to 'off' the event or it will remove listeners from the widget
-			oFieldSet_{{ sFormIdSanitized }}.on('form_built', function(oEvent){
-				scrollHandler_{{ sFormIdSanitized }}();
-			});
-			// - Initial test
-			setTimeout(function(){ scrollHandler_{{ sFormIdSanitized }}(); }, 400);
-			
-			// Remove sticky button when closing modal
-			$('#{{ sFormId }}').closest('.modal').on('hide.bs.modal', function () {
-				oStickyRegularButtons_{{ sFormIdSanitized }}.remove();
-			});
+
+				$('#{{ sFormId }}').closest({% if tIsModal == true %}'.modal'{% else %}'#main-content'{% endif %}).append(oStickyRegularButtons_{{ sFormIdSanitized }});
+
+				// - Global timeout for any
+				var oScrollTimeout;
+				// - Scroll handler
+				scrollHandler_{{ sFormIdSanitized }} = function () {
+					if($('#{{ sFormId }} .form_buttons').visible())
+					{
+						oStickyRegularButtons_{{ sFormIdSanitized }}.addClass('closed');
+					}
+					else
+					{
+						oStickyRegularButtons_{{ sFormIdSanitized }}.removeClass('closed');
+					}
+				};
+				// - Event binding for scroll
+				$({% if tIsModal == true %}'.modal.in'{% else %}window{% endif %}).off('scroll').on('scroll', function () {
+					if (oScrollTimeout) {
+						// Clear the timeout, if one is pending
+						clearTimeout(oScrollTimeout);
+						oScrollTimeout = null;
+					}
+					oScrollTimeout = setTimeout(scrollHandler_{{ sFormIdSanitized }}, 50);
+				});
+				// - Event binding for linkedset collapse
+				$({% if tIsModal == true %}'.modal.in'{% else %}window{% endif %}).off('shown.bs.collapse hidden.bs.collapse').on('shown.bs.collapse hidden.bs.collapse', function () {
+					scrollHandler_{{ sFormIdSanitized }}();
+				});
+				// - Event binding for form building / updating
+				// Note : We do not want to 'off' the event or it will remove listeners from the widget
+				oFieldSet_{{ sFormIdSanitized }}.on('form_built', function(oEvent){
+					scrollHandler_{{ sFormIdSanitized }}();
+				});
+				// - Initial test
+				setTimeout(function(){ scrollHandler_{{ sFormIdSanitized }}(); }, 400);
+
+				// Remove sticky button when closing modal
+				$('#{{ sFormId }}').closest('.modal').on('hide.bs.modal', function () {
+					oStickyRegularButtons_{{ sFormIdSanitized }}.remove();
+				});
+			}
 		{% endif %}
 		
 		{% if tIsModal == true %}

+ 1 - 1
datamodels/2.x/itop-portal-base/portal/src/views/bricks/object/mode_view.html.twig

@@ -8,7 +8,7 @@
 	{% if form.buttons is defined and form.buttons.links is defined %}
 		<div class="form_btn_transitions">
 			{% for aLink in form.buttons.links %}
-				<a class="btn btn-default" href="{{ aLink.url }}">{{ aLink.label }}</a>
+				<a class="btn btn-primary" href="{{ aLink.url }}">{{ aLink.label }}</a>
 			{% endfor %}
 		</div>
 	{% endif %}

+ 6 - 0
datamodels/2.x/itop-portal-base/portal/src/views/helpers/loader.html.twig

@@ -0,0 +1,6 @@
+<div class="content_loader">
+	<div class="icon glyphicon glyphicon-refresh"></div>
+	<div class="message">
+		{{ 'Page:PleaseWait'|dict_s }}
+	</div>
+</div>

+ 3 - 13
datamodels/2.x/itop-portal-base/portal/src/views/layout.html.twig

@@ -22,7 +22,7 @@
 	{# This block can be used to add your own meta tags by extending the default template #}
 	{% block pPageExtraMetas %}
 	{% endblock %}
-	<title>{% block pPageTitle %}{% if sPageTitle is defined and sPageTitle is not null %}{{ sPageTitle }} - iTop{% else %}{{ 'Page:DefaultTitle'|dict_s }}{% endif %}{% endblock %}</title>
+	<title>{% block pPageTitle %}{% if sPageTitle is defined and sPageTitle is not null %}{{ sPageTitle }} - {{ constant('ITOP_APPLICATION') }}{% else %}{{ 'Page:DefaultTitle'|dict_s }}{% endif %}{% endblock %}</title>
 	<link rel="shortcut icon" href="{{ app['combodo.absolute_url'] }}images/favicon.ico?itopversion=$ITOP_VERSION$" />
 	{% block pPageStylesheets %}
 		{# First bootstrap core, lib themes, then bootstrap theme, portal adjustements #}
@@ -260,12 +260,7 @@
 		<div class="modal fade" id="modal-for-all" role="dialog">
 			<div class="modal-dialog modal-lg" role="document">
 				<div class="modal-content">
-					<div class="content_loader">
-						<div class="icon glyphicon glyphicon-refresh"></div>
-						<div class="message">
-							{{ 'Page:PleaseWait'|dict_s }}
-						</div>
-					</div>
+					{% include 'itop-portal-base/portal/src/views/helpers/loader.html.twig' %}
 				</div>
 			</div>
 		</div>					
@@ -289,12 +284,7 @@
 
 		<div id="page_overlay" class="global_overlay">
 			<div class="overlay_content">
-				<div class="content_loader">
-					<div class="icon glyphicon glyphicon-refresh"></div>
-					<div class="message">
-						{{ 'Page:PleaseWait'|dict_s }}
-					</div>
-				</div>
+				{% include 'itop-portal-base/portal/src/views/helpers/loader.html.twig' %}
 			</div>
 		</div>
 	{% endblock %}

+ 12 - 10
datamodels/2.x/itop-portal-base/portal/src/views/modal/layout.html.twig

@@ -1,12 +1,14 @@
 {# modal/layout.html.twig #}
 {# Base modal layout, used to fill Bootstrap .modal-content #}
-<div class="modal-header">
-	<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
-	<h4 class="modal-title">{% block pModalTitle %}{% endblock %}</h4>
-</div>
-<div class="modal-body">{% block pModalBody %}{% endblock %}</div>
-<div class="modal-footer">
-	{% block pModalFooter %}
-		<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'Portal:ButtonClose'|dict_s }}</button>
-	{% endblock %}
-</div>
+{% block pModalContent %}
+	<div class="modal-header">
+		<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+		<h4 class="modal-title">{% block pModalTitle %}{% endblock %}</h4>
+	</div>
+	<div class="modal-body">{% block pModalBody %}{% endblock %}</div>
+	<div class="modal-footer">
+		{% block pModalFooter %}
+			<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'Portal:ButtonClose'|dict_s }}</button>
+		{% endblock %}
+	</div>
+{% endblock %}

+ 15 - 0
datamodels/2.x/itop-portal-base/portal/src/views/modal/mode_loader.html.twig

@@ -0,0 +1,15 @@
+{# itop-portal-base/portal/src/views/bricks/object/mode_loader.html.twig #}
+{# Modal loader layout #}
+{% extends 'itop-portal-base/portal/src/views/modal/layout.html.twig' %}
+
+{% block pModalContent %}
+	{% include 'itop-portal-base/portal/src/views/helpers/loader.html.twig' %}
+	
+	{% if redirection is defined and redirection.url is defined %}
+		<script type="text/javascript">
+			$(document).ready( function(){
+				window.location = '{{ redirection.url|raw }}';
+			});
+		</script>
+	{% endif %}
+{% endblock %}

+ 2 - 1
datamodels/2.x/itop-portal-base/portal/web/css/portal.css

@@ -816,7 +816,8 @@ table .group-actions {
 @media (min-width: 768px) {
   /* Making regular button sticky */
   .form_buttons .form_btn_transitions {
-    float: left !important;
+    float: right !important;
+    margin-left: 3px;
   }
   .form_buttons .form_btn_regular {
     text-align: right;

+ 2 - 1
datamodels/2.x/itop-portal-base/portal/web/css/portal.scss

@@ -857,7 +857,8 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{
 }
 @media (min-width: 768px){
 	.form_buttons .form_btn_transitions{
-		float: left !important;
+		float: right !important;
+		margin-left: 3px;
 	}
 	.form_buttons .form_btn_regular{
 		text-align: right;

+ 7 - 1
datamodels/2.x/itop-portal-base/portal/web/js/portal_form_handler.js

@@ -171,7 +171,13 @@ $(function()
 											oModalElem.attr('id', '').appendTo('body');
 											// Loading content
 											oModalElem.find('.modal-content').html($('#page_overlay .overlay_content').html());
-											oModalElem.find('.modal-content').load(sUrl);
+											oModalElem.find('.modal-content').load(sUrl, {
+													// Passing formmanager 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)
+												}
+											);
+											
 											oModalElem.modal('show');
 										}
 										else