/** * EGroupware clientside API object * * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @package etemplate * @subpackage api * @link http://www.egroupware.org * @author Andreas Stöckel (as AT stylite.de) * @author Ralf Becker * @version $Id$ */ /** * This code setups the egw namespace and adds the "extend" function, which is * used by extension modules to inject their content into the egw object. */ (function() { "use strict"; var instanceUid = 0; // Some local functions for cloning and merging javascript objects function cloneObject(_obj) { var result = {}; for (var key in _obj) { result[key] = _obj[key]; } return result; } function mergeObjects(_to, _from) { // Extend the egw object for (var key in _from) { _to[key] = _from[key]; } } function deleteWhere(_arr, _cond) { for (var i = _arr.length - 1; i >= 0; i--) { if (_cond(_arr[i])) { _arr.splice(i, 1); } } } /** * The getAppModules function returns all application specific api modules * for the given application. If those application specific api instances * were not created yet, the functions creates them. * * @param _egw is a reference to the global _egw instance and is passed as * a context to the module instance. * @param _modules is the hash map which contains all module descriptors. * @param _moduleInstances is the the object which contains the application * and window specific module instances. * @param _app is the application for which the module instances should get * created. */ function getAppModules(_egw, _modules, _moduleInstances, _app) { // Check whether the application specific modules for that instance // already exists, if not, create it if (typeof _moduleInstances.app[_app] === 'undefined') { var modInsts = {}; _moduleInstances.app[_app] = modInsts; // Otherwise create the application specific instances for (var key in _modules) { var mod = _modules[key]; // Check whether the module is actually an application local // instance. As the module instance may already have been // created by another extension (when calling the egw.module // function) we're doing the second check. if (mod.flags === _egw.MODULE_APP_LOCAL && typeof modInsts[key] === 'undefined') { modInsts[key] = mod.code.call(_egw, _app, window); } } } return _moduleInstances.app[_app]; } function getExistingWndModules(_moduleInstances, _window) { // Search for the specific window instance for (var i = 0; i < _moduleInstances.wnd.length; i++) { if (_moduleInstances.wnd[i].window === _window) { return _moduleInstances.wnd[i].modules; } } return null; } /** * The getWndModules function returns all window specific api modules for * the given window. If those window specific api instances were not created * yet, the functions creates them. * * @param _egw is a reference to the global _egw instance and is passed as * a context to the module instance. * @param _modules is the hash map which contains all module descriptors. * @param _moduleInstances is the the object which contains the application * and window specific module instances. * @param _instances refers to all api instances. * @param _window is the window for which the module instances should get * created. */ function getWndModules(_egw, _modules, _moduleInstances, _instances, _window) { var mods = getExistingWndModules(_moduleInstances, _window); if (mods) { return mods; } // If none was found, create the slot mods = {}; _moduleInstances.wnd.push({ 'window': _window, 'modules': mods }); // Add an eventlistener for the "onunload" event -- if "onunload" gets // called, we have to delete the module slot created above var fnct = function() { cleanupEgwInstances(_instances, _moduleInstances, function(_w) { return _w.window === _window; }); }; if (_window.attachEvent) { _window.attachEvent('onbeforeunload', fnct); } else { _window.addEventListener('beforeunload', fnct, false); } // Otherwise create the window specific instances for (var key in _modules) { var mod = _modules[key]; // Check whether the module is actually a window local instance. As // the module instance may already have been created by another // extension (when calling the egw.module function) we're doing the // second check. if (mod.flags === _egw.MODULE_WND_LOCAL && typeof mods[key] === 'undefined') { mods[key] = mod.code.call(_egw, null, _window); } } return mods; } /** * Creates an api instance for the given application and the given window. * * @param {globalEgw} _egw is the global _egw instance which should be used. * @param {object} _modules is the hash map which contains references to all module * descriptors. * @param {object} _moduleInstances is the the object which contains the application * and window specific module instances. * @param {array} _list is the overall instances list, to which the module should be * added. * @param {object} _instances is the overall instances list, to which the module should be * added. * @param {string} _app is the application for which the instance should be created. * @param {DOMElement} _window is the window for which the instance should be created. * @return {egw} */ function createEgwInstance(_egw, _modules, _moduleInstances, _list, _instances, _app, _window) { // Clone the global object var instance = cloneObject(_egw); // Let "_window" and "_app" be exactly null, if it evaluates to false _window = _window ? _window : null; _app = _app ? _app : null; // Set the application name and the window the API instance belongs to instance.appName = _app; instance.window = _window; // Push the newly created instance onto the instance list _list.push({ 'instance': instance, 'window': _window, 'app': _app }); // Merge either the application specific and/or the window specific // module instances into the new instance if (_app) { var appModules = getAppModules(_egw, _modules, _moduleInstances, _app); for (var key in appModules) { mergeObjects(instance, appModules[key]); } } if (_window) { var wndModules = getWndModules(_egw, _modules, _moduleInstances, _instances, _window); for (var key in wndModules) { mergeObjects(instance, wndModules[key]); } } // Return the new api instance return instance; } /** * Returns a egw instance for the given application and the given window. If * the instance does not exist now, the instance will be created. * * @param {globalEgw} _egw is the global _egw instance which should be used. * @param {object} _modules is the hash map which contains references to all module * descriptors. * @param {object} _moduleInstances is the the object which contains the application * and window specific module instances. * @param {object} _instances is the overall instances list, to which the module should be * added. * @param {string} _app is the application for which the instance should be created. * @param {DOMElement} _window is the window for which the instance should be created. * @return {egw} */ function getEgwInstance(_egw, _modules, _moduleInstances, _instances, _app, _window) { // Generate the hash key for the instance descriptor object var hash = _app ? _app : '~global~'; // Let "_window" be exactly null, if it evaluates to false _window = _window ? _window : null; // Create a new entry if the calculated hash does not exist if (typeof _instances[hash] === 'undefined') { _instances[hash] = []; return createEgwInstance(_egw, _modules, _moduleInstances, _instances[hash], _instances, _app, _window); } else { // Otherwise search for the api instance corresponding to the given // window for (var i = 0; i < _instances[hash].length; i++) { if (_instances[hash][i].window === _window) { return _instances[hash][i].instance; } } } // If we're still here, no API instance for the given window has been // found -- create a new entry return createEgwInstance(_egw, _modules, _moduleInstances, _instances[hash], _instances, _app, _window); } function cleanupEgwInstances(_instances, _moduleInstances, _cond) { // Iterate over the instances for (var key in _instances) { // Delete all entries corresponding to closed windows deleteWhere(_instances[key], _cond); // Delete the complete instance key if the array is empty if (_instances[key].length === 0) { delete _instances[key]; } } // Delete all entries corresponding to non existing elements in the // module instances deleteWhere(_moduleInstances.wnd, _cond); } function mergeGlobalModule(_module, _code, _instances, _moduleInstances) { // Generate the global extension var globalExtension = _code.call(egw, null, window); // Store the global extension module _moduleInstances.glo[_module] = globalExtension; for (var key in _instances) { for (var i = 0; i < _instances[key].length; i++) { mergeObjects(_instances[key][i].instance, globalExtension); } } } function mergeAppLocalModule(_module, _code, _instances, _moduleInstances) { // Generate the global extension var globalExtension = _code.call(egw, null, window); // Store the global extension module _moduleInstances.glo[_module] = globalExtension; // Merge the extension into the global instances for (var i = 0; i < _instances['~global~'].length; i++) { mergeObjects(_instances['~global~'][i].instance, globalExtension); } for (var key in _moduleInstances.app) { // Create the application specific instance and // store it in the module instances var appExtension = _code.call(egw, key, window); _moduleInstances.app[key][_module] = appExtension; // Merge the extension into all instances for // the current application for (var i = 0; i < _instances[key].length; i++) { mergeObjects(_instances[key][i].instance, appExtension); } } } function mergeWndLocalModule(_module, _code, _instances, _moduleInstances) { // Iterate over all existing windows for (var i = 0; i < _moduleInstances.wnd.length; i++) { var wnd = _moduleInstances.wnd[i].window; // Create the window specific instance and // register it. var wndExtension = _code.call(egw, null, wnd); _moduleInstances.wnd[i].modules[_module] = wndExtension; // Extend all existing instances which are using // this window. for (var key in _instances) { for (var j = 0; j < _instances[key].length; j++) { if (_instances[key][j].window === wnd) { mergeObjects(_instances[key][j].instance, wndExtension); } } } } } /** * Creates the egw object --- if the egw object should be created, some data * has already been set inside the object by the Api\Framework::header * function and the instance has been marked as "prefsOnly". */ if (typeof window.egw != "undefined" && window.egw.prefsOnly) { // Rescue the old egw object var prefs = window.egw; delete prefs['prefsOnly']; /** * Modules contains all currently loaded egw extension modules. A module * is stored as an object of the following form: * { * name: , * code: , * flags: