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 // 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 // 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 parts = _val.split('.');
var func = parts.pop(); var func = parts.pop();

View File

@ -28,8 +28,8 @@
* - window.open() replaces it with egw_openWindowCentered2() * - window.open() replaces it with egw_openWindowCentered2()
* - xajax_doXMLHTTP('etemplate. replace ajax calls in widgets with special handler not requiring etemplate run rights * - xajax_doXMLHTTP('etemplate. replace ajax calls in widgets with special handler not requiring etemplate run rights
* *
* @param string _val onclick, onchange, ... action * @param {string} _val onclick, onchange, ... action
* @param string _cname name-prefix / name-space * @param {et2_widget} widget
* @ToDo replace xajax_doXMLHTTP with egw.json() * @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 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 * @ToDo template::styles(name) inserts the styles of a named template
@ -131,6 +131,9 @@
{ {
_code += '(ev,widget)'; _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); var func = new Function('ev', 'widget', _code);
} catch(e) { } catch(e) {
_widget.egw().debug('error', 'Error while compiling JS code ', _code); _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 // Highlight matching favorite in sidebox
if(this.getInstanceManager().app) if(this.getInstanceManager().app)
{ {
var app = this.getInstanceManager().app; var appname = this.getInstanceManager().app;
if(window.app[app] && window.app[app].highlight_favorite) 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); egw().debug("info", "Loaded data", _data);
var currentapp = this.app = _data.currentapp || egw().app_name(); 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 // extract $content['msg'] and call egw.message() with it
var msg = _data.content.msg; 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 = []; if (!$j.isArray(_data.langRequire)) _data.langRequire = [];
egw(currentapp, window).langRequire(window, _data.langRequire, function() 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 // Initialize application js
var app_callback = null; var app_callback = null;
// Only initialize once // Only initialize once
@ -407,7 +409,7 @@ etemplate2.prototype.load = function(_name, _url, _data, _callback, _app)
{ {
(function() { new app[appname]();}).call(); (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); 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); 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? // Loaded a template from a different application?
// Let the application that loaded it know too // 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); $j(this.DOMContainer).trigger('load', this);

View File

@ -75,7 +75,7 @@ app.classes.infolog = AppJS.extend(
} }
else 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(); this.infolog_print_preview_onload();
} }
break; break;
@ -766,6 +766,9 @@ app.classes.infolog = AppJS.extend(
*/ */
_get_stylite: function(callback,attrs) _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) if (!app.stylite)
{ {
var self = this; var self = this;

View File

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

View File

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

View File

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

View File

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

View File

@ -227,9 +227,9 @@
// instanciate app object // instanciate app object
var appname = window.egw_appName; 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 // set sidebox for tabed templates
@ -392,9 +392,9 @@ function et2_call(_func)
parent = parent[parts[i]]; parent = parent[parts[i]];
} }
// check if we need a not yet instanciated app.js object --> instanciate it now // 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') if (typeof parent[func] == 'function')