WIP framework's popup storage/restore:

- Keep tracking of popup's window object and restore it when needed
- Implement a method to check an already opened popup and execute a method in the selected popup context
- Fix vcard import into opened compose windows not working
This commit is contained in:
Hadi Nategh 2018-03-09 17:48:09 +01:00
parent 50bfc960a8
commit a8e10cdc64
5 changed files with 221 additions and 138 deletions

View File

@ -769,72 +769,19 @@ app.classes.addressbook = AppJS.extend(
*/ */
adb_mail_vcard: function(_action, _elems) adb_mail_vcard: function(_action, _elems)
{ {
var app_registry = egw.link_get_registry('mail'); var link = '';
var link = egw().link("/index.php","menuaction="+app_registry['add']['menuaction']);
var content = {vcard:{file:[], type:[]}}; var content = {vcard:{file:[], type:[]}};
// Get open compose windows
var compose = egw.getOpenWindows("mail", "(^compose_)|(^mail.compose)");
for (var i = 0; i < _elems.length; i++) for (var i = 0; i < _elems.length; i++)
{ {
var idToUse = _elems[i].id; var idToUse = _elems[i].id;
var idToUseArray = idToUse.split('::'); var idToUseArray = idToUse.split('::');
idToUse = idToUseArray[1]; idToUse = idToUseArray[1];
link += "&preset[type][]="+encodeURIComponent("text/vcard; charset="+(egw.preference('vcard_charset', 'addressbook') || 'utf-8')); link += "preset[type][]="+"text/vcard; charset="+(egw.preference('vcard_charset', 'addressbook') || 'utf-8')+'&';
link += "&preset[file][]="+encodeURIComponent("vfs://default/apps/addressbook/"+idToUse+"/.entry"); link += "preset[file][]="+"vfs://default/apps/addressbook/"+idToUse+"/.entry"+'&';
content.vcard.file.push("vfs://default/apps/addressbook/"+idToUse+"/.entry"); content.vcard.file.push("vfs://default/apps/addressbook/"+idToUse+"/.entry");
content.vcard.type.push("text/vcard; charset="+(egw.preference('vcard_charset', 'addressbook') || 'utf-8')); content.vcard.type.push("text/vcard; charset="+(egw.preference('vcard_charset', 'addressbook') || 'utf-8'));
} }
egw.openWithinWindow("mail", "setCompose", content, link, /mail.mail_compose.compose/);
if(compose.length == 1)
{
var popup = egw.open_link('',compose[0],'100x100','mail');
popup.app.mail.setCompose(compose[0], content);
}
else if (compose.length > 1)
{
var buttons = [
{text: this.egw.lang("Add"), id: "add", "class": "ui-priority-primary", "default": true},
{text: this.egw.lang("Cancel"), id:"cancel"}
];
var c = [];
for(var i = 0; i < compose.length; i++)
{
var w = window.open('',compose[i],'100x100');
if(w.closed) continue;
w.blur();
c.push({label:w.document.title || egw.lang("compose"), compose:compose[i]});
}
et2_createWidget("dialog",
{
callback: function(_button_id, _value) {
if (_value && _value.grid)
{
switch (_button_id)
{
case "add":
var w = egw.open_link('', _value.grid.compose,'100x100','mail');
w.app.mail.setCompose(w.name, content);
return;
case "cancel":
}
}
},
title: this.egw.lang("Select an opened compose dialog"),
buttons: buttons,
value:{content:{grid:c}},
template: egw.webserverUrl+'/addressbook/templates/default/promptOpenedComposeDialog.xet?1',
resizable: false
}, et2_dialog._create_parent('addressbook'));
}
else if (typeof app_registry['view'] != 'undefined' && typeof app_registry['view_popup'] != 'undefined' )
{
var w_h =app_registry['view_popup'].split('x');
if (w_h[1] == 'egw_getWindowOuterHeight()') w_h[1] = (screen.availHeight>egw_getWindowOuterHeight()?screen.availHeight:egw_getWindowOuterHeight());
egw_openWindowCentered2(link, '_blank', w_h[0], w_h[1], 'yes');
}
}, },
/** /**

View File

@ -56,6 +56,9 @@ var fw_base = (function(){ "use strict"; return Class.extend(
// Override the egw_getAppName function // Override the egw_getAppName function
window.egw_getAppName = this.egw_getAppName; window.egw_getAppName = this.egw_getAppName;
// keep track of opened popups
this.popups = [];
}, },
/** /**
@ -133,6 +136,8 @@ var fw_base = (function(){ "use strict"; return Class.extend(
} }
this.applications[this.appData.appName] = this.appData; this.applications[this.appData.appName] = this.appData;
this.popups.concat(this.registerOpenedPopus(app.name));
} }
// else display the default application // else display the default application
@ -793,6 +798,7 @@ var fw_base = (function(){ "use strict"; return Class.extend(
var windowID = egw(parentWindow).openPopup(_url, _width, _height, _windowName, _app, true, _status, true); var windowID = egw(parentWindow).openPopup(_url, _width, _height, _windowName, _app, true, _status, true);
windowID.framework = this; windowID.framework = this;
this.popups.push(windowID);
if (navigate) if (navigate)
{ {
@ -802,6 +808,111 @@ var fw_base = (function(){ "use strict"; return Class.extend(
if (_returnID !== false) return windowID; if (_returnID !== false) return windowID;
}, },
registerOpenedPopus: function (_app)
{
var w = Object.keys(egw.getOpenWindows(_app));
var popups = [];
var popup;
for (var i=0; i < w.length; i++)
{
try{
popup = window.open('', w[i], '100x100');
if (popup.location.href == "about:blank")
{
popup.close();
egw(window).windowClosed(_app, popup);
}
if (popup && egw.is_popup(popup)) popups.push(popup);
}catch(e)
{
if (popup)
{
popup.close();
egw.windowClosed(_app, popup);
}
continue;
}
}
return popups;
},
/**
* Check if given window is a "popup" alike, returning integer or undefined if not
*
* @param {DOMWindow} _wnd
* @returns {Number|undefined}
*/
popup_idx: function(_wnd)
{
if (typeof window.framework.popups != 'undefined')
{
for (var i=0; i < window.framework.popups.length; i++)
{
if (window.framework.popups[i] === _wnd)
{
return i;
}
}
}
return undefined;
},
/**
* @param {window} _wnd window object which suppose to be closed
*/
popup_close:function (_wnd)
{
var i = this.popup_idx(_wnd);
if (i !== undefined)
{
// Close the matched popup
this.popups.splice(i,1);
}
_wnd.close();
},
/**
* Collect and close all already closed windowss
*/
popups_garbage_collector: function ()
{
for (var i=0; i < this.popups.length; i++)
{
if (this.popups[i].closed) this.popups.splice(i,1);
}
},
/**
* get popups based on application name and regexp
* @param {string} _app app name
* @param {regexp} regex regular expression to check against location.href url
*
* @returns {Array} returns array of windows object
*/
popups_get: function(_app, regex)
{
var popups = [];
for (var i=0; i < this.popups.length; i++)
{
if (!this.popups[i].closed && this.popups[i].egw_appName == _app) {
popups.push(this.popups[i]);
}
}
if (regex)
{
for (var j=0; j < popups.length; j++)
{
if (!popups[j].location.href.match(regex))
{
popups.splice(j,1);
}
}
}
return popups;
},
/** /**
* Get application window * Get application window
* @param {type} _app * @param {type} _app

View File

@ -55,9 +55,6 @@ egw.extend('open', egw.MODULE_WND_LOCAL, function(_egw, _wnd)
cc: match['cc'] || [], cc: match['cc'] || [],
bcc: match['bcc'] || [] bcc: match['bcc'] || []
}; };
var popup;
// Get open compose windows
var compose = egw.getOpenWindows("mail", /(^compose_)||(^mail.compose)/);
// Encode html entities in the URI, otheerwise server XSS protection wont // Encode html entities in the URI, otheerwise server XSS protection wont
// allow it to pass, because it may get mistaken for some forbiden tags, // allow it to pass, because it may get mistaken for some forbiden tags,
@ -65,82 +62,8 @@ egw.extend('open', egw.MODULE_WND_LOCAL, function(_egw, _wnd)
// including "<" would get mistaken for <math> tag, and server will cut it off. // including "<" would get mistaken for <math> tag, and server will cut it off.
uri = uri.replace(/</g,'&lt;').replace(/>/g,'&gt;'); uri = uri.replace(/</g,'&lt;').replace(/>/g,'&gt;');
if(compose.length == 0) egw.openWithinWindow ("mail", "setCompose", content, {'preset[mailto]':uri}, /mail_compose.compose/);
{
// No compose windows, might be no mail app.js
// We really want to use mail_compose() here
// Accoring to microsoft, IE 10/11 can only accept a url with 2083 caharacters
// therefore we need to send request to compose window with POST method
// instead of GET. We create a temporary <Form> and will post emails.
// ** WebServers and other browsers also have url length limit:
// Firefox:~ 65k, Safari:80k, Chrome: 2MB, Apache: 4k, Nginx: 4k
if (uri.length > 2083)
{
popup = egw.open('','mail','add','','compose__','mail');
var $tmpForm = jQuery(document.createElement('form')).appendTo('body');
var $tmpInput = jQuery(document.createElement('input')).attr({name:"preset[mailto]", type:"text", value: uri});
var $tmpSubmitInput = jQuery(document.createElement('input')).attr({type:"submit"});
// Set the temporary form's attributes
$tmpForm.attr({target:popup.name, action:"index.php?menuaction=mail.mail_compose.compose", method:"post"})
.append($tmpInput)
.append($tmpSubmitInput);
$tmpForm.submit();
// Remove the form after submit
$tmpForm.remove();
}
else // simple GET request
{
egw.open('','mail','add',{'preset[mailto]': uri},'compose__','mail');
}
}
if(compose.length == 1)
{
try {
popup = egw.open_link('',compose[0],'100x100','mail');
popup.app.mail.setCompose(compose[0], content);
} catch(e) {
// Looks like a leftover window that wasn't removed from the list
egw.debug("warn", e.message);
popup.close();
egw.windowClosed("mail",popup);
window.setTimeout(function() {
egw.open_link(uri);
console.debug("Trying again with ", uri);
}, 500);
}
}
else if(compose.length > 1)
{
// Need to prompt
var prompt = jQuery(document.createElement('ul'));
for(var i = 0; i < compose.length; i++)
{
var w = window.open('',compose[i],'100x100');
if(w.closed) continue;
w.blur();
var title = w.document.title || egw.lang("compose");
jQuery("<li data-window = '" + compose[i] + "'>"+ title + "</li>")
.click(function() {
var w = egw.open_link('',jQuery(this).attr("data-window"),'100x100','mail');
w.app.mail.setCompose(w.name, content);
prompt.dialog("close");
})
.appendTo(prompt);
}
_wnd.setTimeout(function() {
this.focus();
}, 200);
var _buttons = {};
_buttons[egw.lang("cancel")] = function() {
jQuery(this).dialog("close");
};
prompt.dialog({
buttons: _buttons
});
}
} }
return { return {
/** /**
* View an EGroupware entry: opens a popup of correct size or redirects window.location to requested url * View an EGroupware entry: opens a popup of correct size or redirects window.location to requested url
@ -509,6 +432,103 @@ egw.extend('open', egw.MODULE_WND_LOCAL, function(_egw, _wnd)
popup.close(); popup.close();
return false; return false;
} }
},
/**
* This function helps to append content/ run commands into an already
* opened popup window. Popup winodws now are getting stored in framework
* object and can be retrived/closed from framework.
*
* @param {string} _app name of application to be requested its popups
* @param {string} _method application method implemented in app.js
* @param {object} _content content to be passed to method
* @param {string|object} _extra url or object of extra
* @param {regex} _regexp regular expression to get specific popup with matched url
*/
openWithinWindow: function (_app, _method, _content, _extra, _regexp)
{
var popups = window.framework.popups_get(_app, _regexp);
for(var i = 0; i < popups.length; i++)
{
if(popups[i].closed)
{
window.framework.popups_grabage_collector();
}
}
if(popups.length == 1)
{
try {
popups[0].app[_app][_method](popups[0], _content);
}
catch(e) {
window.setTimeout(function() {
egw.open('', _app, 'add', _extra, _app, _app);
});
}
}
else if (popups.length > 1)
{
var buttons = [
{text: this.lang("Add"), id: "add", "class": "ui-priority-primary", "default": true},
{text: this.lang("Cancel"), id:"cancel"}
];
var c = [];
for(var i = 0; i < popups.length; i++)
{
c.push({label:popups[i].document.title || this.lang(_app), index:i});
}
et2_createWidget("dialog",
{
callback: function(_button_id, _value) {
if (_value && _value.grid)
{
switch (_button_id)
{
case "add":
popups[_value.grid.index].app[_app][_method](popups[_value.grid.index], _content);
return;
case "cancel":
}
}
},
title: this.lang("Select an opened dialog"),
buttons: buttons,
value:{content:{grid:c}},
template: this.webserverUrl+'/api/templates/default/promptOpenedDialog.xet?1',
resizable: false
}, et2_dialog._create_parent(this.app_name()));
}
else
{
// No compose windows, might be no mail app.js
// We really want to use mail_compose() here
// Accoring to microsoft, IE 10/11 can only accept a url with 2083 caharacters
// therefore we need to send request to compose window with POST method
// instead of GET. We create a temporary <Form> and will post emails.
// ** WebServers and other browsers also have url length limit:
// Firefox:~ 65k, Safari:80k, Chrome: 2MB, Apache: 4k, Nginx: 4k
if (_extra.length > 2083)
{
var popup = egw.open('', _app, 'add', '', '', _app);
var $tmpForm = jQuery(document.createElement('form')).appendTo('body');
var $tmpInput = jQuery(document.createElement('input')).attr({name:Object.keys(_extra)[0], type:"text", value: _extra});
var $tmpSubmitInput = jQuery(document.createElement('input')).attr({type:"submit"});
// Set the temporary form's attributes
$tmpForm.attr({target:popup.name, action:"index.php?menuaction=mail.mail_compose.compose", method:"post"})
.append($tmpInput)
.append($tmpSubmitInput);
$tmpForm.submit();
// Remove the form after submit
$tmpForm.remove();
}
else // simple GET request
{
egw.open('', _app, 'add', _extra, _app, _app);
}
}
} }
}; };
}); });

View File

@ -270,6 +270,12 @@ egw.extend('utils', egw.MODULE_GLOBAL, function()
*/ */
storeWindow: function(appname, popup) storeWindow: function(appname, popup)
{ {
if (popup.opener) popup.opener.framework.popups_garbage_collector();
if (popup.opener && popup.opener.framework && egw.is_popup(popup)
&& typeof popup.opener.framework.popup_idx(popup) == 'undefined')
{
popup.opener.framework.popups.push(popup);
}
// Don't store if it has no name // Don't store if it has no name
if(!popup.name || ['_blank'].indexOf(popup.name) >= 0) if(!popup.name || ['_blank'].indexOf(popup.name) >= 0)
{ {

View File

@ -656,7 +656,7 @@ app.classes.mail = AppJS.extend(
* @function * @function
* @memberOf mail * @memberOf mail
* *
* @param {String} window_name The name of an open content window. * @param {window object} compose compose window object
* @param {object} content * @param {object} content
* *
* @description content Data to set into the window's fields * @description content Data to set into the window's fields
@ -666,10 +666,9 @@ app.classes.mail = AppJS.extend(
* *
* @return {boolean} Success * @return {boolean} Success
*/ */
setCompose: function(window_name, content) setCompose: function(compose, content)
{ {
// Get window // Get window
var compose = window.open('', window_name);
if(!compose || compose.closed) return false; if(!compose || compose.closed) return false;
// Get etemplate of popup // Get etemplate of popup