Customer portal : Sticky form button when form is to long to be fully displayed in the screen

SVN:trunk[4077]
This commit is contained in:
Guillaume Lajarige
2016-05-13 10:31:15 +00:00
parent 58b571f08a
commit 2720f6e54b
6 changed files with 202 additions and 108 deletions

View File

@@ -2,6 +2,7 @@
{# Object brick create layout #}
{% set sFormId = (form.id is defined and form.id is not null) ? form.id : 'object_form' %}
{% set sFormIdSanitized = sFormId|replace({'-': ''}) %}
{% set tIsModal = (tIsModal is defined and tIsModal == true) ? true : false %}
<form id="{{ sFormId }}" method="POST" action="{{ form.renderer.GetEndpoint()|raw }}">
@@ -43,23 +44,65 @@
<script type="text/javascript">
$(document).ready(function(){
var oFieldSet = $('#{{ sFormId }} > .form_fields').field_set({{ form.fieldset|json_encode()|raw }});
// Form field set declaration
var oFieldSet_{{ sFormIdSanitized }} = $('#{{ sFormId }} > .form_fields').field_set({{ form.fieldset|json_encode()|raw }});
// Form handler declaration
$('#{{ sFormId }}').portal_form_handler({
formmanager_class: "{{ form.formmanager_class|escape('js') }}",
formmanager_data: {{ form.formmanager_data|json_encode()|raw }},
field_set: oFieldSet,
field_set: oFieldSet_{{ sFormIdSanitized }},
submit_btn_selector: $('#{{ sFormId }}').parent().find('.form_btn_submit, .form_btn_transition'),
cancel_btn_selector: $('#{{ sFormId }}').parent().find('.form_btn_cancel'),
submit_url: {% if form.submit_callback is not null %}"{{ form.submit_callback }}"{% else %}null{% endif %},
cancel_url: {% if form.cancel_callback is not null %}"{{ form.cancel_callback }}"{% else %}null{% endif %},
endpoint: "{{ form.renderer.GetEndpoint()|raw }}",
is_modal: {% if tIsModal is defined and tIsModal == true %}true{% else %}false{% endif %}
is_modal: {% if tIsModal == true %}true{% else %}false{% endif %}
});
{% if tIsModal is defined and tIsModal == true %}
// Sticky buttons handler
// 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 tIsModal == true %}
$('#{{ sFormId }}').closest('.modal').append(oStickyRegularButtons_{{ sFormIdSanitized }});
{% else %}
$('#{{ sFormId }}').closest('#main-content').append(oStickyRegularButtons_{{ sFormIdSanitized }});
{% endif %}
// - 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
$({% 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);
});
// - First time call
scrollHandler_{{ sFormIdSanitized }}();
{% if tIsModal == true %}
// Scroll top (because sometimes when several modals have been opened)
$('#{{ sFormId }}').closest('.modal').scrollTop(0);
$('#{{ sFormId }}').closest('.modal').find('.modal-footer').hide();
// Remove sticky button when closing modal
$('#{{ sFormId }}').closest('.modal').on('hidden.bs.modal', function () {
oStickyRegularButtons_{{ sFormIdSanitized }}.remove();
});
{% endif %}
});
</script>

View File

@@ -58,6 +58,8 @@
<script type="text/javascript" src="{{ app['combodo.absolute_url'] }}js/jquery.fileupload.js"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/latinise/latinise.min.js"></script>
{# Visible.js to check if an element is visible on screen #}
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/jquery-visible/js/jquery.visible.min.js"></script>
{# Moment.js #}
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/moment/js/moment.min.js"></script>
{# Datatables #}
@@ -209,7 +211,7 @@
<div class="logo">
{# This is a debug helper to know in which screen size we are #}
{% if app['debug'] %}
<div>Debug : Taille <span class="hidden-sm hidden-md hidden-lg">XS</span><span class="hidden-xs hidden-md hidden-lg">SM</span><span class="hidden-xs hidden-sm hidden-lg">MD</span><span class="hidden-xs hidden-sm hidden-md">LG</span></div>
<div style="position: fixed; bottom: 0px; left: 0px; z-index: 9999;">Debug : Taille <span class="hidden-sm hidden-md hidden-lg">XS</span><span class="hidden-xs hidden-md hidden-lg">SM</span><span class="hidden-xs hidden-sm hidden-lg">MD</span><span class="hidden-xs hidden-sm hidden-md">LG</span></div>
{% endif %}
<a href="{{ app.url_generator.generate('p_home') }}" title="{{ app['combodo.portal.instance.conf'].properties.name|dict_s }}">
<img src="{{ app['combodo.portal.instance.conf'].properties.logo }}" alt="{{ app['combodo.portal.instance.conf'].properties.name|dict_s }}" />
@@ -223,12 +225,12 @@
<div class="container-fluid" id="main-wrapper">
<div class="row">
<div class="col-xs-12 col-sm-9 col-md-10 col-sm-offset-3 col-md-offset-2">
<section class="row row-eq-height-sm" id="main-header">
<section class="row" id="main-header">
{% block pMainHeader %}
{% endblock %}
</section>
<section class="row row-eq-height-sm" id="main-content">
<section class="row" id="main-content">
{% block pMainContent %}
{% endblock %}
</section>

View File

@@ -638,18 +638,6 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{
bottom: 0px;
height: 0px;
}
#drag_overlay.drag_in{
animation: show-drop-zone 0.3s ease-out forwards;
-webkit-animation: show-drop-zone 0.3s ease-out forwards;
-moz-animation: show-drop-zone 0.3s ease-out forwards;
-ms-animation: show-drop-zone 0.3s ease-out forwards;
}
#drag_overlay.drag_out{
animation: hide-drop-zone 0.3s ease-out forwards;
-webkit-animation: hide-drop-zone 0.3s ease-out forwards;
-moz-animation: hide-drop-zone 0.3s ease-out forwards;
-ms-animation: hide-drop-zone 0.3s ease-out forwards;
}
#drag_overlay .overlay_content{
margin-top: 5em;
width: 100%;
@@ -661,57 +649,72 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{
#drag_overlay .overlay_content .message{
font-size: 1.5em;
}
@keyframes show-drop-zone{
/* Attachments drag & drop zone, only for none mobile devices */
@media (min-width: 768px){
#drag_overlay.drag_in{
animation: show-drop-zone 0.3s ease-out forwards;
-webkit-animation: show-drop-zone 0.3s ease-out forwards;
-moz-animation: show-drop-zone 0.3s ease-out forwards;
-ms-animation: show-drop-zone 0.3s ease-out forwards;
}
#drag_overlay.drag_out{
animation: hide-drop-zone 0.3s ease-out forwards;
-webkit-animation: hide-drop-zone 0.3s ease-out forwards;
-moz-animation: hide-drop-zone 0.3s ease-out forwards;
-ms-animation: hide-drop-zone 0.3s ease-out forwards;
}
@keyframes show-drop-zone{
100% {
height: 20%;
}
}
@-webkit-keyframes show-drop-zone{
}
@-webkit-keyframes show-drop-zone{
100% {
height: 20%;
}
}
@-moz-keyframes show-drop-zone{
}
@-moz-keyframes show-drop-zone{
100% {
height: 20%;
}
}
@-ms-keyframes show-drop-zone{
}
@-ms-keyframes show-drop-zone{
100% {
height: 20%;
}
}
@keyframes hide-drop-zone{
}
@keyframes hide-drop-zone{
0% {
height: 20%;
}
100% {
height: 0%;
}
}
@-webkit-keyframes hide-drop-zone{
}
@-webkit-keyframes hide-drop-zone{
0% {
height: 20%;
}
100% {
height: 0%;
}
}
@-moz-keyframes hide-drop-zone{
}
@-moz-keyframes hide-drop-zone{
0% {
height: 20%;
}
100% {
height: 0%;
}
}
@-ms-keyframes hide-drop-zone{
}
@-ms-keyframes hide-drop-zone{
0% {
height: 20%;
}
100% {
height: 0%;
}
}
}
.form_field .form-control-static img{
@@ -726,6 +729,9 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{
.form_buttons .form_btn_transitions{
margin-bottom: 20px;
}
.form_btn_regular.sticky{
display: none;
}
@media (min-width: 768px){
.form_buttons .form_btn_transitions{
float: left !important;
@@ -736,6 +742,40 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{
.form_buttons .form_btn_regular btn{
width: inherit;
}
/* Making regular button sticky */
.form_btn_regular.sticky{
display: block;
position: fixed;
bottom: 0px;
padding: 15px;
background-color: #FFF; /* TODO : SASS this to panel bg */
border: 1px solid #DDD; /* TODO : SASS this to panel border */
border-radius: 4px; /* TODO : SASS this to panel border */
transition: bottom 0.3s;
}
.form_btn_regular.sticky.closed{
bottom: -80px;
}
/* - For regular layout */
#main-content .form_btn_regular.sticky{
right: 15px; /* TODO : SASS this to col-xs-12 padding */
}
/* - For modal layout */
.modal.in .form_btn_regular.sticky{
margin-left: 61%;
}
}
@media (min-width: 992px) {
/* - For modal layout */
.modal.in .form_btn_regular.sticky{
margin-left: 70%;
}
}
@media (min-width: 1200px) {
/* - For modal layout */
.modal.in .form_btn_regular.sticky{
margin-left: 73%;
}
}
/* CKEditor : Adding BS error feedback */

View File

@@ -65,7 +65,7 @@ $oApp->register(new Silex\Provider\TwigServiceProvider(), array(
));
// Configuring Silex application
$oApp['debug'] = false;
$oApp['debug'] = true;
$oApp['combodo.absolute_url'] = utils::GetAbsoluteUrlAppRoot();
$oApp['combodo.portal.base.absolute_url'] = utils::GetAbsoluteUrlAppRoot() . 'env-' . utils::GetCurrentEnvironment() . '/itop-portal-base/portal/web/';
$oApp['combodo.portal.instance.absolute_url'] = utils::GetAbsoluteUrlAppRoot() . 'env-' . utils::GetCurrentEnvironment() . '/' . PORTAL_MODULE_ID . '/';

View File

@@ -125,7 +125,6 @@ $(function()
// Scrolling to top so the user can see messages
$('body').scrollTop(0);
}
// If everything is okay, we close the form and reload it.
if(oValidation.valid)
@@ -171,16 +170,25 @@ $(function()
}
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);
}
}
}
else if(me.options.submit_url !== null)
{
// 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);
}
}
}
}
)
.fail(function(oData){
me._onUpdateFailure(oData);

View File

@@ -0,0 +1 @@
!function(t){var i=t(window);t.fn.visible=function(t,e,o){if(!(this.length<1)){var r=this.length>1?this.eq(0):this,n=r.get(0),f=i.width(),h=i.height(),o=o?o:"both",l=e===!0?n.offsetWidth*n.offsetHeight:!0;if("function"==typeof n.getBoundingClientRect){var g=n.getBoundingClientRect(),u=g.top>=0&&g.top<h,s=g.bottom>0&&g.bottom<=h,c=g.left>=0&&g.left<f,a=g.right>0&&g.right<=f,v=t?u||s:u&&s,b=t?c||a:c&&a;if("both"===o)return l&&v&&b;if("vertical"===o)return l&&v;if("horizontal"===o)return l&&b}else{var d=i.scrollTop(),p=d+h,w=i.scrollLeft(),m=w+f,y=r.offset(),z=y.top,B=z+r.height(),C=y.left,R=C+r.width(),j=t===!0?B:z,q=t===!0?z:B,H=t===!0?R:C,L=t===!0?C:R;if("both"===o)return!!l&&p>=q&&j>=d&&m>=L&&H>=w;if("vertical"===o)return!!l&&p>=q&&j>=d;if("horizontal"===o)return!!l&&m>=L&&H>=w}}}}(jQuery);