fix situation where multiple app.js objects are used, eg. InfoLog and CRM view in Addressbook:

- etemplate2 creates a private app object instead of using window.app with just prototypes, if template is not from current app
- fixed all cases where window.app was used to use just app, to use evtl. private object
- app_base no longer assigns itself to window.app (window.app[this.appname] = this), as that breaks private app objects
- et2_compileLegacyJS replaces app.appname with widget.getInstanceManager().app_obj.appname
- etemplate2 stores either private or global app object in app_obj attribute
This commit is contained in:
Ralf Becker 2016-03-17 18:12:36 +00:00
parent 6fd841ebee
commit d49f8bc45f
10 changed files with 70 additions and 63 deletions

View File

@ -237,7 +237,7 @@ function et2_checkType(_val, _type, _attr, _widget)
// Check to see if it's a string in app.appname.function format, and wrap it in
// a closure to make sure context is preserved
if(typeof _val == "string" && _val.substr(0,4) == "app." && window.app)
if(typeof _val == "string" && _val.substr(0,4) == "app." && app)
{
var parts = _val.split('.');
var func = parts.pop();

View File

@ -28,8 +28,8 @@
* - window.open() replaces it with egw_openWindowCentered2()
* - xajax_doXMLHTTP('etemplate. replace ajax calls in widgets with special handler not requiring etemplate run rights
*
* @param string _val onclick, onchange, ... action
* @param string _cname name-prefix / name-space
* @param {string} _val onclick, onchange, ... action
* @param {et2_widget} widget
* @ToDo replace xajax_doXMLHTTP with egw.json()
* @ToDo replace (common) cases of confirm with new dialog, idea: calling function supplys function to call after confirm
* @ToDo template::styles(name) inserts the styles of a named template
@ -131,6 +131,9 @@
{
_code += '(ev,widget)';
}
// use app object from etemplate2, which might be private and not just window.app
_code = _code.replace(/(window\.)?app\./, 'widget.getInstanceManager().app_obj.');
var func = new Function('ev', 'widget', _code);
} catch(e) {
_widget.egw().debug('error', 'Error while compiling JS code ', _code);

View File

@ -544,10 +544,10 @@ var et2_nextmatch = (function(){ "use strict"; return et2_DOMWidget.extend([et2_
// Highlight matching favorite in sidebox
if(this.getInstanceManager().app)
{
var app = this.getInstanceManager().app;
if(window.app[app] && window.app[app].highlight_favorite)
var appname = this.getInstanceManager().app;
if(app[appname] && app[appname].highlight_favorite)
{
window.app[app].highlight_favorite();
app[appname].highlight_favorite();
}
}
}

View File

@ -353,6 +353,12 @@ etemplate2.prototype.load = function(_name, _url, _data, _callback, _app)
egw().debug("info", "Loaded data", _data);
var currentapp = this.app = _data.currentapp || egw().app_name();
var appname = _name.split('.')[0];
// if no app object provided and template app is not currentapp (eg. infolog CRM view)
// create private app object / closure with just classes / prototypes
if (!_app && appname && appname != currentapp) app = { classes: window.app.classes };
// remember used app object, to eg. use: onchange="widget.getInstanceMgr().app_object[app].callback()"
this.app_obj = app;
// extract $content['msg'] and call egw.message() with it
var msg = _data.content.msg;
@ -390,10 +396,6 @@ etemplate2.prototype.load = function(_name, _url, _data, _callback, _app)
if (!$j.isArray(_data.langRequire)) _data.langRequire = [];
egw(currentapp, window).langRequire(window, _data.langRequire, function()
{
// Appname should be first part of the template name
var split = _name.split('.');
var appname = split[0];
// Initialize application js
var app_callback = null;
// Only initialize once
@ -407,7 +409,7 @@ etemplate2.prototype.load = function(_name, _url, _data, _callback, _app)
{
(function() { new app[appname]();}).call();
}
else if (typeof app[appname] !== "object")
else if (appname && typeof app[appname] !== "object")
{
egw.debug("warn", "Did not load '%s' JS object",appname);
}
@ -531,11 +533,11 @@ etemplate2.prototype.load = function(_name, _url, _data, _callback, _app)
{
app_callback.call(window,this,_name);
}
if(appname != this.app && typeof window.app[this.app] == "object")
if(appname && appname != this.app && typeof app[this.app] == "object")
{
// Loaded a template from a different application?
// Let the application that loaded it know too
window.app[this.app].et2_ready(this, this.name);
app[this.app].et2_ready(this, this.name);
}
$j(this.DOMContainer).trigger('load', this);

View File

@ -75,7 +75,7 @@ app.classes.infolog = AppJS.extend(
}
else
{
// Trigger print command if the infolog oppend for printing porpuse
// Trigger print command if the infolog oppend for printing purpose
this.infolog_print_preview_onload();
}
break;
@ -766,6 +766,9 @@ app.classes.infolog = AppJS.extend(
*/
_get_stylite: function(callback,attrs)
{
// use app object from etemplate2, which might be private and not just window.app
var app = this.et2.getInstanceManager().app_obj;
if (!app.stylite)
{
var self = this;

View File

@ -236,7 +236,7 @@ egwEventQueue.prototype.queue = function(_proc, _context, _args, _id)
var key = "";
// _id must be a string and evaluate to true - if this is not
// _id must be a string and evaluate to true - if this is not
// generate an unique key.
if (typeof _id != "string" || !_id)
{
@ -366,10 +366,10 @@ egwFnct.prototype.setValue = function(_value)
{
this.fnct = _value;
}
// Global function (on window)
else if (typeof _value == "string" &&
_value.substr(0,11) == "javaScript:" &&
_value.substr(0,11) == "javaScript:" &&
typeof window[_value.substr(11)] == "function")
{
this.fnct = window[_value.substr(11)];
@ -379,20 +379,20 @@ egwFnct.prototype.setValue = function(_value)
{
this.value = _value;
}
// egw application specific function
else if (typeof _value == "string" &&
_value.substr(0,15) == "javaScript:app." && window.app)
_value.substr(0,15) == "javaScript:app." && app)
{
var parts = _value.split(".");
if(parts.length == 3 && typeof window.app[parts[1]] == "object" &&
typeof window.app[parts[1]][parts[2]] == "function")
if(parts.length == 3 && typeof app[parts[1]] == "object" &&
typeof app[parts[1]][parts[2]] == "function")
{
this.fnct = window.app[parts[1]][parts[2]];
this.context = window.app[parts[1]];
this.fnct = app[parts[1]][parts[2]];
this.context = app[parts[1]];
}
}
// Something, but could not figure it out
else if (_value)
{

View File

@ -481,22 +481,22 @@ egw_json_request.prototype.handleResponse = function(data, textStatus, XMLHttpRe
}
hasResponse = true;
} else if (typeof res.data.func == "string" &&
res.data.func.substr(0,4) == "app." && window.app)
res.data.func.substr(0,4) == "app." && app)
{
var parts = res.data.func.split(".");
// check if we need a not yet instanciated app.js object --> instanciate it now
if (parts.length == 3 && typeof window.app[parts[1]] == 'undefined' &&
typeof window.app.classes[parts[1]] == 'function')
if (parts.length == 3 && typeof app[parts[1]] == 'undefined' &&
typeof app.classes[parts[1]] == 'function')
{
window.app[parts[1]] = new window.app.classes[parts[1]]();
app[parts[1]] = new app.classes[parts[1]]();
}
if(parts.length == 3 && typeof window.app[parts[1]] == "object" &&
typeof window.app[parts[1]][parts[2]] == "function")
if(parts.length == 3 && typeof app[parts[1]] == "object" &&
typeof app[parts[1]][parts[2]] == "function")
{
try
{
this.context = window.app[parts[1]][parts[2]].apply(window.app[parts[1]], res.data.parms);
this.context = app[parts[1]][parts[2]].apply(app[parts[1]], res.data.parms);
}
catch (e)
{

View File

@ -130,10 +130,10 @@ var fw_browser = (function(){ "use strict"; return Class.extend(
browse: function(_url)
{
// check if app has its own linkHandler and it accepts the link (returns true), or returns different url instead
if (typeof window.app == 'object' && typeof window.app[this.app.appName] == 'object' &&
typeof window.app[this.app.appName].linkHandler == 'function')
if (typeof app == 'object' && typeof app[this.app.appName] == 'object' &&
typeof app[this.app.appName].linkHandler == 'function')
{
var ret = window.app[this.app.appName].linkHandler.call(window.app[this.app.appName], _url);
var ret = app[this.app.appName].linkHandler.call(app[this.app.appName], _url);
{
if (ret === true) return this.loadingDeferred.promise();
if (typeof ret === 'string')
@ -195,9 +195,9 @@ var fw_browser = (function(){ "use strict"; return Class.extend(
}
// Destroy application js
if(window.app[this.app.appName] && window.app[this.app.appName].destroy)
if(app[this.app.appName] && app[this.app.appName].destroy)
{
window.app[this.app.appName].destroy();
app[this.app.appName].destroy();
}
// Unload etemplate2, if there

View File

@ -117,8 +117,6 @@ var AppJS = (function(){ "use strict"; return Class.extend(
* is not yet ready.
*/
init: function() {
window.app[this.appname] = this;
this.egw = egw(this.appname, window);
// Initialize sidebox for non-popups.
@ -132,7 +130,7 @@ var AppJS = (function(){ "use strict"; return Class.extend(
sidebox= $j('#favorite_sidebox_'+this.appname,egw_fw.sidemenuDiv);
}
// Make sure we're running in the top window when we init sidebox
if(window.top.app[this.appname] !== this && window.top.app[this.appname])
if(window.app[this.appname] === this && window.top.app[this.appname] !== this && window.top.app[this.appname])
{
window.top.app[this.appname]._init_sidebox(sidebox);
}
@ -145,14 +143,14 @@ var AppJS = (function(){ "use strict"; return Class.extend(
/**
* Clean up any created objects & references
* @param {pbject} _app local app object
* @param {object} _app local app object
*/
destroy: function(_app) {
delete this.et2;
if (this.sidebox)
this.sidebox.off();
delete this.sidebox;
if (!_app) delete window.app[this.appname];
if (!_app) delete app[this.appname];
},
/**
@ -389,7 +387,7 @@ var AppJS = (function(){ "use strict"; return Class.extend(
* @param {object} _action
* @param {object} _senders
* @param {boolean} _noEdit defines whether to set edit button or not default is false
* @param {function} callback function to run after et2 is loaded
* @param {function} et2_callback function to run after et2 is loaded
*/
viewEntry: function(_action, _senders, _noEdit, et2_callback)
{
@ -1156,6 +1154,8 @@ var AppJS = (function(){ "use strict"; return Class.extend(
* ]
* }
* }
*
* @param {DOMNode} div
*/
egwTutorial_init: function(div)
{
@ -1536,23 +1536,22 @@ var AppJS = (function(){ "use strict"; return Class.extend(
var dialog = function(_content, _callback)
{
return et2_createWidget("dialog", {
callback: function(_button_id, _value) {
if (typeof _callback == "function")
{
_callback.call(this, _button_id, _value.value);
}
},
title: egw.lang('PGP Encryption Installation'),
buttons: buttons,
dialog_type: 'info',
value: {
content: _content
},
template: egw.webserverUrl+'/etemplate/templates/default/pgp_installation.xet',
class: "pgp_installation",
modal: true,
//resizable:false,
callback: function(_button_id, _value) {
if (typeof _callback == "function")
{
_callback.call(this, _button_id, _value.value);
}
},
title: egw.lang('PGP Encryption Installation'),
buttons: buttons,
dialog_type: 'info',
value: {
content: _content
},
template: egw.webserverUrl+'/etemplate/templates/default/pgp_installation.xet',
class: "pgp_installation",
modal: true
//resizable:false,
});
};
var content = [

View File

@ -227,9 +227,9 @@
// instanciate app object
var appname = window.egw_appName;
if (window.app && typeof window.app[appname] != 'object' && typeof window.app.classes[appname] == 'function')
if (app && typeof app[appname] != 'object' && typeof app.classes[appname] == 'function')
{
window.app[appname] = new window.app.classes[appname]();
app[appname] = new app.classes[appname]();
}
// set sidebox for tabed templates
@ -392,9 +392,9 @@ function et2_call(_func)
parent = parent[parts[i]];
}
// check if we need a not yet instanciated app.js object --> instanciate it now
else if (i == 1 && parts[0] == 'app' && typeof window.app.classes[parts[1]] == 'function')
else if (i == 1 && parts[0] == 'app' && typeof app.classes[parts[1]] == 'function')
{
parent = parent[parts[1]] = new window.app.classes[parts[1]]();
parent = parent[parts[1]] = new app.classes[parts[1]]();
}
}
if (typeof parent[func] == 'function')