Etemplate: Check dirty before closing, ask if there are changes

This commit is contained in:
nathangray 2020-06-19 13:27:41 -06:00
parent 73515cd412
commit 52714f0a63
14 changed files with 149 additions and 23 deletions

View File

@ -58,6 +58,14 @@ var et2_inputWidget = /** @class */ (function (_super) {
_super.prototype.destroy.call(this); _super.prototype.destroy.call(this);
this._labelContainer = null; this._labelContainer = null;
}; };
/**
* Make sure dirty flag is properly set
*/
et2_inputWidget.prototype.doLoadingFinished = function () {
var result = _super.prototype.doLoadingFinished.call(this);
this.resetDirty();
return result;
};
/** /**
* Load the validation errors from the server * Load the validation errors from the server
* *
@ -212,7 +220,25 @@ var et2_inputWidget = /** @class */ (function (_super) {
return this._oldValue; return this._oldValue;
}; };
et2_inputWidget.prototype.isDirty = function () { et2_inputWidget.prototype.isDirty = function () {
return this._oldValue != this.getValue(); var value = this.getValue();
if (typeof value !== typeof this._oldValue) {
return true;
}
if (this._oldValue === value) {
return false;
}
switch (typeof this._oldValue) {
case "object":
if (this._oldValue.length !== value.length)
return true;
for (var key in this._oldValue) {
if (this._oldValue[key] !== value[key])
return true;
}
return false;
default:
return this._oldValue != value;
}
}; };
et2_inputWidget.prototype.resetDirty = function () { et2_inputWidget.prototype.resetDirty = function () {
this._oldValue = this.getValue(); this._oldValue = this.getValue();

View File

@ -96,6 +96,18 @@ export class et2_inputWidget extends et2_valueWidget implements et2_IInput, et2_
this._labelContainer = null; this._labelContainer = null;
} }
/**
* Make sure dirty flag is properly set
*/
doLoadingFinished() : boolean | JQueryPromise<unknown>
{
let result = super.doLoadingFinished();
this.resetDirty();
return result;
}
/** /**
* Load the validation errors from the server * Load the validation errors from the server
* *
@ -300,7 +312,27 @@ export class et2_inputWidget extends et2_valueWidget implements et2_IInput, et2_
isDirty() isDirty()
{ {
return this._oldValue != this.getValue(); let value = this.getValue();
if(typeof value !== typeof this._oldValue)
{
return true;
}
if(this._oldValue === value)
{
return false;
}
switch(typeof this._oldValue)
{
case "object":
if(this._oldValue.length !== value.length) return true;
for(let key in this._oldValue)
{
if(this._oldValue[key] !== value[key]) return true;
}
return false;
default:
return this._oldValue != value;
}
} }
resetDirty() resetDirty()

View File

@ -316,10 +316,10 @@ var et2_customfields_list = /** @class */ (function (_super) {
return value; return value;
}; };
et2_customfields_list.prototype.isDirty = function () { et2_customfields_list.prototype.isDirty = function () {
var dirty = true; var dirty = false;
for (var field_name in this.widgets) { for (var field_name in this.widgets) {
if (this.widgets[field_name].isDirty) { if (this.widgets[field_name].isDirty) {
dirty = dirty && this.widgets[field_name].isDirty(); dirty = dirty || this.widgets[field_name].isDirty();
} }
} }
return dirty; return dirty;

View File

@ -430,12 +430,12 @@ export class et2_customfields_list extends et2_valueWidget implements et2_IDetac
isDirty( ) isDirty( )
{ {
let dirty = true; let dirty = false;
for(let field_name in this.widgets) for(let field_name in this.widgets)
{ {
if(this.widgets[field_name].isDirty) if(this.widgets[field_name].isDirty)
{ {
dirty = dirty && this.widgets[field_name].isDirty(); dirty = dirty || this.widgets[field_name].isDirty();
} }
} }
return dirty; return dirty;

View File

@ -344,8 +344,8 @@ var et2_selectbox = /** @class */ (function (_super) {
this.setDOMNode(node[0]); this.setDOMNode(node[0]);
}; };
et2_selectbox.prototype.doLoadingFinished = function () { et2_selectbox.prototype.doLoadingFinished = function () {
_super.prototype.doLoadingFinished.call(this);
this.set_tags(this.options.tags, this.options.width); this.set_tags(this.options.tags, this.options.width);
_super.prototype.doLoadingFinished.call(this);
return true; return true;
}; };
et2_selectbox.prototype.loadFromXML = function (_node) { et2_selectbox.prototype.loadFromXML = function (_node) {
@ -1366,6 +1366,12 @@ var et2_selectbox_ro = /** @class */ (function (_super) {
et2_selectbox_ro.prototype.getValue = function () { et2_selectbox_ro.prototype.getValue = function () {
return null; return null;
}; };
/**
* Readonly selectbox can't be dirty
*/
et2_selectbox_ro.prototype.isDirty = function () {
return false;
};
/** /**
* Functions for et2_IDetachedDOM * Functions for et2_IDetachedDOM
*/ */

View File

@ -484,10 +484,10 @@ export class et2_selectbox extends et2_inputWidget
doLoadingFinished() doLoadingFinished()
{ {
super.doLoadingFinished();
this.set_tags(this.options.tags, this.options.width); this.set_tags(this.options.tags, this.options.width);
super.doLoadingFinished();
return true; return true;
} }
@ -1679,6 +1679,14 @@ export class et2_selectbox_ro extends et2_selectbox implements et2_IDetachedDOM
return null; return null;
} }
/**
* Readonly selectbox can't be dirty
*/
isDirty()
{
return false;
}
/** /**
* Functions for et2_IDetachedDOM * Functions for et2_IDetachedDOM
*/ */

View File

@ -218,6 +218,7 @@ var et2_tabbox = /** @class */ (function (_super) {
} }
jQuery.when.apply(jQuery, promises).then(function () { jQuery.when.apply(jQuery, promises).then(function () {
tab_deferred.resolve(); tab_deferred.resolve();
tabs.resetDirty();
}); });
}, 0); }, 0);
return tab_deferred.promise(); return tab_deferred.promise();

View File

@ -274,6 +274,7 @@ class et2_tabbox extends et2_valueWidget implements et2_IInput,et2_IResizeable,e
} }
jQuery.when.apply(jQuery,promises).then(function() { jQuery.when.apply(jQuery,promises).then(function() {
tab_deferred.resolve(); tab_deferred.resolve();
tabs.resetDirty();
}); });
},0); },0);

View File

@ -279,6 +279,7 @@ var et2_taglist = /** @class */ (function (_super) {
this.div.on('blur', 'input', function () { this.div.on('blur', 'input', function () {
jQuery('.ms-ctn-focus', widget.div).removeClass('ms-ctn-focus'); jQuery('.ms-ctn-focus', widget.div).removeClass('ms-ctn-focus');
}); });
this.resetDirty();
return true; return true;
}; };
/** /**

View File

@ -430,6 +430,8 @@ export class et2_taglist extends et2_selectbox implements et2_IResizeable
this.div.on('blur', 'input', function() { this.div.on('blur', 'input', function() {
jQuery('.ms-ctn-focus', widget.div).removeClass('ms-ctn-focus'); jQuery('.ms-ctn-focus', widget.div).removeClass('ms-ctn-focus');
}); });
this.resetDirty();
return true; return true;
} }

View File

@ -274,20 +274,34 @@ var etemplate2 = /** @class */ (function () {
* calls, eg. via et2_dialog. * calls, eg. via et2_dialog.
*/ */
etemplate2.prototype.bind_unload = function () { etemplate2.prototype.bind_unload = function () {
// Prompt user to save for dirty popups
if (window !== egw_topWindow() && !this.close_prompt) {
this.close_prompt = this._close_changed_prompt.bind(this);
window.addEventListener("beforeunload", this.close_prompt);
}
if (this._etemplate_exec_id) { if (this._etemplate_exec_id) {
this.destroy_session = jQuery.proxy(function (ev) { this.destroy_session = jQuery.proxy(function (ev) {
// need to use async === "keepalive" to run via beforeunload // need to use async === "keepalive" to run via beforeunload
egw.json("EGroupware\\Api\\Etemplate::ajax_destroy_session", [this._etemplate_exec_id], null, null, "keepalive").sendRequest(); egw.json("EGroupware\\Api\\Etemplate::ajax_destroy_session", [this._etemplate_exec_id], null, null, "keepalive").sendRequest();
}, this); }, this);
if (!window.onbeforeunload) { window.addEventListener("beforeunload", this.destroy_session);
window.onbeforeunload = this.destroy_session;
} }
};
etemplate2.prototype._close_changed_prompt = function (e) {
if (!this.isDirty()) {
return;
} }
// Cancel the event
e.preventDefault(); // If you prevent default behavior in Mozilla Firefox prompt will always be shown
// Chrome requires returnValue to be set
e.returnValue = '';
}; };
/** /**
* Unbind our unload handler * Unbind our unload handler
*/ */
etemplate2.prototype.unbind_unload = function () { etemplate2.prototype.unbind_unload = function () {
window.removeEventListener("beforeunload", this.destroy_session);
window.removeEventListener("beforeunload", this.close_prompt);
if (window.onbeforeunload === this.destroy_session) { if (window.onbeforeunload === this.destroy_session) {
window.onbeforeunload = null; window.onbeforeunload = null;
} }

View File

@ -107,6 +107,7 @@ export class etemplate2
private resize_timeout: number | boolean; private resize_timeout: number | boolean;
private destroy_session: any; private destroy_session: any;
private close_prompt: any;
private app_obj: EgwApp; private app_obj: EgwApp;
app: string; app: string;
@ -344,6 +345,12 @@ export class etemplate2
*/ */
bind_unload() bind_unload()
{ {
// Prompt user to save for dirty popups
if(window !== egw_topWindow() && !this.close_prompt)
{
this.close_prompt = this._close_changed_prompt.bind(this);
window.addEventListener("beforeunload", this.close_prompt);
}
if (this._etemplate_exec_id) if (this._etemplate_exec_id)
{ {
this.destroy_session = jQuery.proxy(function (ev) this.destroy_session = jQuery.proxy(function (ev)
@ -353,11 +360,22 @@ export class etemplate2
[this._etemplate_exec_id], null, null, "keepalive").sendRequest(); [this._etemplate_exec_id], null, null, "keepalive").sendRequest();
}, this); }, this);
if (!window.onbeforeunload) window.addEventListener("beforeunload", this.destroy_session);
}
}
private _close_changed_prompt(e : BeforeUnloadEvent)
{ {
window.onbeforeunload = this.destroy_session; if(!this.isDirty())
} {
return;
} }
// Cancel the event
e.preventDefault(); // If you prevent default behavior in Mozilla Firefox prompt will always be shown
// Chrome requires returnValue to be set
e.returnValue = '';
} }
/** /**
@ -365,6 +383,8 @@ export class etemplate2
*/ */
unbind_unload() unbind_unload()
{ {
window.removeEventListener("beforeunload", this.destroy_session);
window.removeEventListener("beforeunload", this.close_prompt);
if (window.onbeforeunload === this.destroy_session) if (window.onbeforeunload === this.destroy_session)
{ {
window.onbeforeunload = null; window.onbeforeunload = null;

View File

@ -386,9 +386,7 @@ var CalendarApp = /** @class */ (function (_super) {
//send Syncronus ajax request to the server to unlock the on close entry //send Syncronus ajax request to the server to unlock the on close entry
//set onbeforeunload with json request to send request when the window gets close by X button //set onbeforeunload with json request to send request when the window gets close by X button
if (content.data.lock_token) { if (content.data.lock_token) {
window.onbeforeunload = function () { window.addEventListener("beforeunload", this._unlock.bind(this));
this.egw.json('calendar.calendar_uiforms.ajax_unlock', [content.data.id, content.data.lock_token], null, true, "keepalive", null).sendRequest();
};
} }
} }
this.alarm_custom_date(); this.alarm_custom_date();
@ -788,6 +786,15 @@ var CalendarApp = /** @class */ (function (_super) {
sortable.sortable('disable'); sortable.sortable('disable');
} }
}; };
/**
* Unlock the event before closing the popup
*
* @private
*/
CalendarApp.prototype._unlock = function () {
var content = this.et2.getArrayMgr('content');
this.egw.json('calendar.calendar_uiforms.ajax_unlock', [content.data.id, content.data.lock_token], null, this, "keepalive", null).sendRequest();
};
/** /**
* Bind scroll event * Bind scroll event
* When the user scrolls, we'll move enddate - startdate days * When the user scrolls, we'll move enddate - startdate days

View File

@ -286,10 +286,7 @@ class CalendarApp extends EgwApp
//set onbeforeunload with json request to send request when the window gets close by X button //set onbeforeunload with json request to send request when the window gets close by X button
if (content.data.lock_token) if (content.data.lock_token)
{ {
window.onbeforeunload = function () { window.addEventListener("beforeunload", this._unlock.bind(this));
this.egw.json('calendar.calendar_uiforms.ajax_unlock',
[content.data.id, content.data.lock_token],null,true,"keepalive",null).sendRequest();
};
} }
} }
this.alarm_custom_date(); this.alarm_custom_date();
@ -758,6 +755,17 @@ class CalendarApp extends EgwApp
} }
} }
/**
* Unlock the event before closing the popup
*
* @private
*/
private _unlock () {
const content = this.et2.getArrayMgr('content');
this.egw.json('calendar.calendar_uiforms.ajax_unlock',
[content.data.id, content.data.lock_token],null,this,"keepalive",null).sendRequest();
}
/** /**
* Bind scroll event * Bind scroll event
* When the user scrolls, we'll move enddate - startdate days * When the user scrolls, we'll move enddate - startdate days