N°1881 Portal: Show confirmation dialog when closing forms with unsaved data

This commit is contained in:
Stephen Abello
2019-10-24 10:50:03 +02:00
parent 3667f95b7c
commit 1851163cee
22 changed files with 219 additions and 1 deletions

View File

@@ -68,6 +68,7 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array(
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Open</a> / <a href="%4$s" class="file_download_link">Download</a>',
'Portal:Calendar-FirstDayOfWeek' => 'cs', //work with moment.js locales
'Portal:Form:Close:Warning' => 'Do you want to leave this form ? Data entered may be lost~~',
));
// UserProfile brick

View File

@@ -65,6 +65,7 @@ Dict::Add('DA DA', 'Danish', 'Dansk', array(
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>~~',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Open</a> / <a href="%4$s" class="file_download_link">Download</a>~~',
'Portal:Calendar-FirstDayOfWeek' => 'da', //work with moment.js locales
'Portal:Form:Close:Warning' => 'Do you want to leave this form ? Data entered may be lost~~',
));
// UserProfile brick

View File

@@ -65,6 +65,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Öffnen</a> / <a href="%4$s" class="file_download_link">Download</a>',
'Portal:Calendar-FirstDayOfWeek' => 'de', //work with moment.js locales
'Portal:Form:Close:Warning' => 'Do you want to leave this form ? Data entered may be lost~~',
));
// UserProfile brick

View File

@@ -66,6 +66,7 @@ Dict::Add('EN US', 'English', 'English', array(
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Open</a> / <a href="%4$s" class="file_download_link">Download</a>',
'Portal:Calendar-FirstDayOfWeek' => 'en-us', //work with moment.js locales
'Portal:Form:Close:Warning' => 'Do you want to leave this form ? Data entered may be lost',
));
// UserProfile brick

View File

@@ -64,6 +64,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', array(
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Abierto</a> / <a href="%4$s" class="file_download_link">Download</a>',
'Portal:Calendar-FirstDayOfWeek' => 'es', //work with moment.js locales
'Portal:Form:Close:Warning' => 'Do you want to leave this form ? Data entered may be lost~~',
));
// UserProfile brick

View File

@@ -64,6 +64,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Ouvrir</a> / <a href="%4$s" class="file_download_link">Télécharger</a>',
'Portal:Calendar-FirstDayOfWeek' => 'fr', //work with moment.js locales
'Portal:Form:Close:Warning' => 'Voulez-vous quitter ce formulaire ? Les données saisies seront perdues',
));
// UserProfile brick

View File

@@ -65,6 +65,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>~~',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Open</a> / <a href="%4$s" class="file_download_link">Download</a>~~',
'Portal:Calendar-FirstDayOfWeek' => 'hu', //work with moment.js locales
'Portal:Form:Close:Warning' => 'Do you want to leave this form ? Data entered may be lost~~',
));
// UserProfile brick

View File

@@ -65,6 +65,7 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>~~',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Open</a> / <a href="%4$s" class="file_download_link">Download</a>~~',
'Portal:Calendar-FirstDayOfWeek' => 'it', //work with moment.js locales
'Portal:Form:Close:Warning' => 'Do you want to leave this form ? Data entered may be lost~~',
));
// UserProfile brick

View File

@@ -65,6 +65,7 @@ Dict::Add('JA JP', 'Japanese', '日本語', array(
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>~~',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Open</a> / <a href="%4$s" class="file_download_link">Download</a>~~',
'Portal:Calendar-FirstDayOfWeek' => 'ja', //work with moment.js locales
'Portal:Form:Close:Warning' => 'Do you want to leave this form ? Data entered may be lost~~',
));
// UserProfile brick

View File

@@ -65,6 +65,7 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Open</a> / <a href="%4$s" class="file_download_link">Download</a>',
'Portal:Calendar-FirstDayOfWeek' => 'nl', //work with moment.js locales
'Portal:Form:Close:Warning' => 'Do you want to leave this form ? Data entered may be lost~~',
));
// UserProfile brick

View File

@@ -1,3 +1,23 @@
/*
*
* * Copyright (C) 2013-2019 Combodo SARL
* *
* * This file is part of iTop.
* *
* * iTop is free software; you can redistribute it and/or modify
* * it under the terms of the GNU Affero General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * iTop is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU Affero General Public License for more details.
* *
* * You should have received a copy of the GNU Affero General Public License
*
*/
//iTop Portal Form field
;
$(function()

View File

@@ -1,3 +1,23 @@
/*
*
* * Copyright (C) 2013-2019 Combodo SARL
* *
* * This file is part of iTop.
* *
* * iTop is free software; you can redistribute it and/or modify
* * it under the terms of the GNU Affero General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * iTop is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU Affero General Public License for more details.
* *
* * You should have received a copy of the GNU Affero General Public License
*
*/
//iTop Portal Form field HTML
//Used for field containing html data such as rich editors, html blocks, ...
;

View File

@@ -1,3 +1,23 @@
/*
*
* * Copyright (C) 2013-2019 Combodo SARL
* *
* * This file is part of iTop.
* *
* * iTop is free software; you can redistribute it and/or modify
* * it under the terms of the GNU Affero General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * iTop is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU Affero General Public License for more details.
* *
* * You should have received a copy of the GNU Affero General Public License
*
*/
//iTop Portal Form field Set
//Used for field containing tagset ...
;

View File

@@ -63,6 +63,13 @@ $(function()
{
this._super( key, value );
},
// - Callback when some fields have been touched
_onFieldsTouched: function(oEvent)
{
this._super(oEvent);
$('body').trigger('register_blocker.portal.itop', {'sBlockerId': this.element.attr('id'), 'sTargetElemSelector': '#' + this.element.closest('.modal').attr('id'), 'oTargetElemSelector': '#' + this.element.closest('.modal').attr('id'), 'sEventName': 'hide.bs.modal'});
$('body').trigger('register_blocker.portal.itop', {'sBlockerId': this.element.attr('id'), 'sTargetElemSelector': 'document', 'oTargetElemSelector': document, 'sEventName': 'beforeunload'});
},
// Overload from parent class
_onSubmitClick: function(oEvent)
{
@@ -153,6 +160,9 @@ $(function()
// If everything is okay, we close the form and reload it.
if(oValidation.valid)
{
$('body').trigger('unregister_blocker.portal.itop', {'sBlockerId': me.element.attr('id')});
if(me.options.is_modal)
{
me.element.closest('.modal').modal('hide');
@@ -248,6 +258,7 @@ $(function()
if(me.options.field_set.field_set('option', 'touched_fields').length > 0)
{
me._disableFormBeforeLoading();
$('body').trigger('unregister_blocker.portal.itop', {'sBlockerId': me.element.attr('id')});
$.post(
me.options.endpoint,
{

View File

@@ -0,0 +1,124 @@
/*
*
* * Copyright (C) 2013-2019 Combodo SARL
* *
* * This file is part of iTop.
* *
* * iTop is free software; you can redistribute it and/or modify
* * it under the terms of the GNU Affero General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * iTop is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU Affero General Public License for more details.
* *
* * You should have received a copy of the GNU Affero General Public License
*
*/
;
$(function()
{
// the widget definition, where 'itop' is the namespace,
// 'portal_leave_handler' the widget name
$.widget( 'itop.portal_leave_handler',
{
// default options
options:
{
'message': 'allo la',
},
events: ['hide.bs.modal', 'beforeunload'],
//[event]
registered_blockers: {},
// {id : {target : 'event1', target : 'event2'}}
// the constructor
_create: function()
{
var me =this;
this.element
.addClass('portal_leave_handler');
this.element.on('register_blocker.portal.itop', function(oEvent, oData){
me._onRegisterBlocker(oData.sBlockerId, oData.sTargetElemSelector, oData.oTargetElemSelector, oData.sEventName);
});
this.element.on('unregister_blocker.portal.itop', function(oEvent, oData){
me._onUnregisterBlocker(oData.sBlockerId);
});
this.element.on('hide.bs.modal', function(oEvent) {return me._onLeaveHandler(oEvent);});
window.addEventListener('beforeunload', function(oEvent) {return me._onLeaveHandler(oEvent);});
this._super();
},
_onRegisterBlocker: function(sBlockerId, sTargetElemSelector, oTargetElemSelector, sEventName)
{
var aRegisteredBlock = {};
aRegisteredBlock[sTargetElemSelector] = {'eventName': sEventName, 'selector': oTargetElemSelector};
$.extend(
aRegisteredBlock,
this.registered_blockers[sBlockerId]
);
this.registered_blockers[sBlockerId] = aRegisteredBlock;
},
_onUnregisterBlocker: function(sBlockerId)
{
delete this.registered_blockers[sBlockerId];
},
_onLeaveHandler: function(oEvent)
{
var me = this;
for(var aRegisteredBlocker in me.registered_blockers)
{
for(var sBlockerTarget in me.registered_blockers[aRegisteredBlocker])
{
if($(me.registered_blockers[aRegisteredBlocker][sBlockerTarget]['selector'])[0] === oEvent.target && me.registered_blockers[aRegisteredBlocker][sBlockerTarget]['eventName'].split('.')[0] === oEvent.type)
{
if(oEvent.type === 'beforeunload')
{
oEvent.returnValue = me.options.message;
return;
}
else
{
var $bReturnValue = confirm(me.options.message);
if ($bReturnValue)
{
$('body').trigger('unregister_blocker.portal.itop', {'sBlockerId': aRegisteredBlocker});
}
return $bReturnValue;
}
}
}
}
},
// events bound via _bind are removed automatically
// revert other modifications here
_destroy: function()
{
this.element
.removeClass('portal_leave_handler');
this._super();
},
// _setOptions is called with a hash of all options that are changing
// always refresh when changing options
_setOptions: function()
{
this._superApply(arguments);
},
// _setOption is called for each individual option that is changing
_setOption: function( key, value )
{
this._super( key, value );
},
showOptions: function()
{
return this.options;
}
});
});

View File

@@ -123,6 +123,9 @@
{# Typeahead files for autocomplete #}
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/typeahead/js/typeahead.bundle.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/handlebars/js/handlebars.min-768ddbd.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'js/portal_leave_handler.js'|add_itop_version }}"></script>
{# Selectize for sets #}
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/selectize.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery.itop-set-widget.js'|add_itop_version }}"></script>
@@ -489,6 +492,9 @@
ShowErrorDialog();
}
});
// Initialize confirmation message handler when a form with touched fields is closed
$('body').portal_leave_handler({'message': '{{ 'Portal:Form:Close:Warning'|dict_s }}'});
{% endblock %}
});
</script>

View File

@@ -64,6 +64,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Abrir</a> / <a href="%4$s" class="file_download_link">Download</a>',
'Portal:Calendar-FirstDayOfWeek' => 'pt-br', //work with moment.js locales
'Portal:Form:Close:Warning' => 'Do you want to leave this form ? Data entered may be lost~~',
));
// UserProfile brick

View File

@@ -53,6 +53,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>~~',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Открыть</a> / <a href="%4$s" class="file_download_link">Скачать</a>',
'Portal:Calendar-FirstDayOfWeek' => 'ru', //work with moment.js locales
'Portal:Form:Close:Warning' => 'Do you want to leave this form ? Data entered may be lost~~',
));
// UserProfile brick

View File

@@ -65,6 +65,7 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', array(
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>~~',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Open</a> / <a href="%4$s" class="file_download_link">Download</a>~~',
'Portal:Calendar-FirstDayOfWeek' => 'en-us~~', //work with moment.js locales
'Portal:Form:Close:Warning' => 'Do you want to leave this form ? Data entered may be lost~~',
));
// UserProfile brick

View File

@@ -65,6 +65,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>~~',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Open</a> / <a href="%4$s" class="file_download_link">Download</a>~~',
'Portal:Calendar-FirstDayOfWeek' => 'tr', //work with moment.js locales
'Portal:Form:Close:Warning' => 'Do you want to leave this form ? Data entered may be lost~~',
));
// UserProfile brick

View File

@@ -65,6 +65,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Open</a> / <a href="%4$s" class="file_download_link">Download</a>',
'Portal:Calendar-FirstDayOfWeek' => 'en-us~~', //work with moment.js locales
'Portal:Form:Close:Warning' => 'Do you want to leave this form ? Data entered may be lost~~',
));
// UserProfile brick

View File

@@ -168,7 +168,9 @@ EOF
$oOutput->AddJs(
<<<EOF
$('#{$this->oField->GetGlobalId()}').addClass('htmlEditor');
$('#{$this->oField->GetGlobalId()}').ckeditor(function(){}, {language: '$sEditorLanguage', contentsLanguage: '$sEditorLanguage', extraPlugins: 'codesnippet'});
$('#{$this->oField->GetGlobalId()}').ckeditor(function(){}, {language: '$sEditorLanguage', contentsLanguage: '$sEditorLanguage', extraPlugins: 'codesnippet'}).editor.on("change", function(){
$('#{$this->oField->GetGlobalId()}').trigger("change");
});
EOF
);
if (($this->oField->GetObject() !== null) && ($this->oField->GetTransactionId() !== null))