Client side API now supports modules which are instanciated per application or per window; removed et2_debug function from et2_core_common, now using corresponding API function.

This commit is contained in:
Andreas Stöckel 2012-03-05 13:07:38 +00:00
parent a5be6a5016
commit d310b14ecf
30 changed files with 1087 additions and 278 deletions

View File

@ -35,7 +35,7 @@ var et2_arrayMgr = Class.extend({
// Hold a reference to the data
if (typeof _data == "undefined" || !_data)
{
et2_debug("error", "Invalid data passed to content array manager!");
egw.debug("error", "Invalid data passed to content array manager!");
_data = {};
}
@ -224,7 +224,7 @@ var et2_arrayMgr = Class.extend({
catch(e)
{
proto.compiledExpressions[_ident] = null;
et2_debug("error", "Error while compiling PHP->JS ", e);
egw.debug("error", "Error while compiling PHP->JS ", e);
}
}
@ -239,7 +239,7 @@ var et2_arrayMgr = Class.extend({
}
catch(e)
{
et2_debug("error", e);
egw.debug("error", e);
}
}
}

View File

@ -27,49 +27,6 @@ if (typeof Array.prototype.indexOf == "undefined")
};
}
/**
* ET2_DEBUGLEVEL specifies which messages are printed to the console. Decrease
* the value of ET2_DEBUGLEVEL to get less messages.
*/
var ET2_DEBUGLEVEL = 4;
function et2_debug(_level)
{
if (typeof console != "undefined")
{
// Get the passed parameters and remove the first entry
var args = [];
for (var i = 1; i < arguments.length; i++)
{
args.push(arguments[i]);
}
if (_level == "log" && ET2_DEBUGLEVEL >= 4 &&
typeof console.log == "function")
{
console.log.apply(console, args);
}
if (_level == "info" && ET2_DEBUGLEVEL >= 3 &&
typeof console.info == "function")
{
console.info.apply(console, args);
}
if (_level == "warn" && ET2_DEBUGLEVEL >= 2 &&
typeof console.warn == "function")
{
console.warn.apply(console, args);
}
if (_level == "error" && ET2_DEBUGLEVEL >= 1 &&
typeof console.error == "function")
{
console.error.apply(console, args);
}
}
}
/**
* Array with all types supported by the et2_checkType function.
*/
@ -202,7 +159,7 @@ function et2_checkType(_val, _type, _attr, _cname)
function _err() {
var res = et2_typeDefaults[_type];
et2_debug("warn", "'" + _val + "' was not of specified _type '" +
egw.debug("warn", "'" + _val + "' was not of specified _type '" +
_type + (_attr != null ? "' for attribute '" + _attr + "' " : "") +
"and is now '" + res + "'");
@ -270,7 +227,7 @@ function et2_checkType(_val, _type, _attr, _cname)
}
catch(e)
{
et2_debug("error", "Error while parsing JS event handler code", e,_val);
egw.debug("error", "Error while parsing JS event handler code", e,_val);
}
}
@ -380,7 +337,7 @@ function et2_validateAttrib(_id, _attrib)
if (typeof _attrib["name"] == "undefined")
{
_attrib["name"] = _id;
et2_debug("log", "Human name ('name'-Field) for attribute '" +
egw.debug("log", "Human name ('name'-Field) for attribute '" +
_id + "' has not been supplied, set to '" + _id + "'");
console.debug(_attrib);
}
@ -388,7 +345,7 @@ console.debug(_attrib);
if (typeof _attrib["description"] == "undefined")
{
_attrib["description"] = "";
et2_debug("log", "Description for attribute '" +
egw.debug("log", "Description for attribute '" +
_id + "' has not been supplied");
}
@ -400,7 +357,7 @@ console.debug(_attrib);
{
if (et2_validTypes.indexOf(_attrib["type"]) < 0)
{
et2_debug("error", "Invalid type for attribute '" + _id +
egw.debug("error", "Invalid type for attribute '" + _id +
"' supplied.");
}
}
@ -655,7 +612,7 @@ function et2_insertLinkText(_text, _node, _target)
{
if(!_node)
{
et2_debug("warn", "et2_insertLinkText called without node", _text, _node, _target);
egw.debug("warn", "et2_insertLinkText called without node", _text, _node, _target);
return;
}
@ -677,7 +634,7 @@ function et2_insertLinkText(_text, _node, _target)
{
if(!s.href)
{
et2_debug("warn", "et2_activateLinks gave bad data", s, _node, _target);
egw.debug("warn", "et2_activateLinks gave bad data", s, _node, _target);
s.href = "";
}
var a = $j(document.createElement("a"))

View File

@ -273,7 +273,7 @@
"created": new Date().getTime(),
"class": className
}
et2_debug("log", "*" + this.__OBJ_UID + " (" + className + ")");
egw.debug("log", "*" + this.__OBJ_UID + " (" + className + ")");
}
if (this.init)
@ -323,7 +323,7 @@
if (getMem_freeMem_trace)
{
delete(tracedObjects[this.__OBJ_UID]);
et2_debug("log", "-" + this.__OBJ_UID);
egw.debug("log", "-" + this.__OBJ_UID);
}
// Delete every object entry
@ -382,7 +382,7 @@
}
else
{
et2_debug("error", this, "Attribute '" + _name + "' does not exist!");
egw.debug("error", this, "Attribute '" + _name + "' does not exist!");
}
};
@ -417,7 +417,7 @@
}
else
{
et2_debug("warn", this, "Attribute '" + _name + "' does not exist!");
egw.debug("warn", this, "Attribute '" + _name + "' does not exist!");
}
};
@ -445,7 +445,7 @@
{
// Key does not exist - delete it and issue a warning
delete(_attrs[key]);
et2_debug("warn", this, "Attribute '" + key +
egw.debug("warn", this, "Attribute '" + key +
"' does not exist in " + _attrs.type+"!");
}
}

View File

@ -403,7 +403,7 @@
var js = _php_compileJSCode(_vars, syntaxTree);
// Log the successfull compiling
et2_debug("log", "Compiled PHP " + _expr + " --> " + js);
egw.debug("log", "Compiled PHP " + _expr + " --> " + js);
// Prepate the attributes for the function constuctor
var attrs = [];

View File

@ -41,7 +41,7 @@ function et2_register_widget(_constructor, _types)
// types.
if (et2_registry[type])
{
et2_debug("warn", "Widget class registered for " + type +
egw.debug("warn", "Widget class registered for " + type +
" will be overwritten.");
}
@ -272,7 +272,7 @@ var et2_widget = Class.extend({
assign: function(_obj) {
if (typeof _obj._children == "undefined")
{
et2_debug("log", "Foo!");
this.egw().debug("log", "Foo!");
}
// Create a clone of all child elements of the given object
@ -345,7 +345,7 @@ var et2_widget = Class.extend({
}
else
{
et2_debug("error", this, "Widget is not supported by this widget class", _node);
this.egw().debug("error", this, "Widget is not supported by this widget class", _node);
// throw("Widget is not supported by this widget class!");
}
},
@ -537,7 +537,7 @@ var et2_widget = Class.extend({
}
else
{
et2_debug("warn", "Attributes cannot be objects", this, key, data[key]);
this.egw().debug("warn", "Attributes cannot be objects", this, key, data[key]);
}
}
}
@ -579,7 +579,7 @@ var et2_widget = Class.extend({
// Try again, but skip the fancy stuff
// TODO: Figure out why the getEntry() call doesn't always work
var entry = modifications.data[_node.getAttribute("id")];
if(entry) et2_debug("warn", "getEntry("+_node.getAttribute("id")+") failed, but the data is there.", modifications, entry);
if(entry) this.egw().debug("warn", "getEntry("+_node.getAttribute("id")+") failed, but the data is there.", modifications, entry);
}
if(entry && entry.type)
{
@ -687,8 +687,16 @@ var et2_widget = Class.extend({
return this._parent.egw();
}
// Return the global egw instance if none is given
return egw('phpgwapi');
// Get the window this object belongs to
var wnd = null;
if (this.implements(et2_IDOMNode))
{
var node = this.getDOMNode();
wnd = node.ownerDocument.parentNode || node.ownerDocument.defaultView;
}
// If we're the root object, return the phpgwapi API instance
return egw('phpgwapi', wnd);
}
return this._egw;
@ -831,4 +839,3 @@ var et2_widget = Class.extend({
}
});

View File

@ -121,7 +121,7 @@ var et2_dataview_column = Class.extend({
}
else
{
et2_debug("warn", "Invalid visibility option for column: ", _value);
this.egw().debug("warn", "Invalid visibility option for column: ", _value);
}
}
});

View File

@ -96,7 +96,7 @@ var et2_dataview_dataProvider = Class.extend(et2_IDataProvider, {
if (typeof this._registeredRows[_idx] != "undefined")
{
et2_debug("warn", "Overriding data row for index " + _idx);
this.egw().debug("warn", "Overriding data row for index " + _idx);
}
// Associate the given data row with that index

View File

@ -214,9 +214,9 @@ var et2_dataview_grid = Class.extend(et2_dataview_IViewRange, {
// regarding to the count of elements managed in it
if (count < Math.pow(ET2_PARTITION_TREE_WIDTH, depth - 1))
{
et2_debug("info", "Rebuilding dataview partition tree");
this.egw().debug("info", "Rebuilding dataview partition tree");
this._partitionTree.rebuild();
et2_debug("info", "Done.");
this.egw().debug("info", "Done.");
}
// Reset the "treeChanged" function.

View File

@ -144,7 +144,7 @@ var et2_dataview_partitionNode = Class.extend([et2_dataview_IPartitionHeight,
// complete tree!
if (isNaN(this._height))
{
et2_debug("error", "calculateHeight returned a NaN value!");
this.egw().debug("error", "calculateHeight returned a NaN value!");
this._height = 0;
}

View File

@ -506,7 +506,7 @@ var et2_dataview_partitionOrganizationNode = et2_dataview_partitionNode.extend(
if (Math.abs(actualTop - calculatedTop) > 1)
{
et2_debug("warn", i, "Position missmatch at idx ", idx,
egw.debug("warn", i, "Position missmatch at idx ", idx,
actualTop, calculatedTop, node);
}
@ -515,7 +515,7 @@ var et2_dataview_partitionOrganizationNode = et2_dataview_partitionNode.extend(
if (Math.abs(actualHeight - calculateHeight) > 1)
{
et2_debug("warn", i, "Height missmatch at idx ", idx,
egw.debug("warn", i, "Height missmatch at idx ", idx,
actualHeight, calculateHeight, node);
}
}

View File

@ -37,7 +37,7 @@ var et2_dataview_partitionTree = et2_dataview_partitionOrganizationNode.extend({
this._dataProvider = _dataProvider;
this._rowProvider = _rowProvider;
et2_debug("Creating partition tree with ", this._count,
egw.debug("Creating partition tree with ", this._count,
" elements of avgHeight ", this._avgHeight);
// Append a spacer node to the children

View File

@ -166,7 +166,7 @@ var et2_dataview_rowProvider = Class.extend({
if (!supportsAttr)
{
et2_debug("warn", "et2_IDetachedDOM widget " +
egw.debug("warn", "et2_IDetachedDOM widget " +
widget._type + " does not support " + data.attribute);
}
@ -203,7 +203,7 @@ var et2_dataview_rowProvider = Class.extend({
// Issue a warning - widgets which do not implement et2_IDOMNode
// are very slow
et2_debug("warn", "Non-clonable widget '"+ entry.widget._type + "' in dataview row - this " +
egw.debug("warn", "Non-clonable widget '"+ entry.widget._type + "' in dataview row - this " +
"might be slow", entry);
// Set the placeholder for the entry to null
@ -399,7 +399,7 @@ var et2_dataview_rowProvider = Class.extend({
nodes[j] = entry.nodeFuncs[j](_row[0]);
}
if(typeof nodes[0] == "undefined")
et2_debug("warn", "Missing node", entry.widget.id,nodes, entry );
egw.debug("warn", "Missing node", entry.widget.id,nodes, entry );
// Set the array managers first
entry.widget._mgrs = mgrs;

View File

@ -247,7 +247,7 @@ var et2_nextmatch = et2_DOMWidget.extend(et2_IResizeable, {
},
applyFilters: function() {
et2_debug("info", "Changing nextmatch filters to ", this.activeFilters);
this.egw().debug("info", "Changing nextmatch filters to ", this.activeFilters);
// Clear the dataprovider and the dataview container - this will cause
// the grid to reload.
@ -295,7 +295,7 @@ var et2_nextmatch = et2_DOMWidget.extend(et2_IResizeable, {
var colName = name + (name != "" && child_names.length > 0 ? "_" : "") + child_names.join("_");
if(colName == "") {
et2_debug("info", "Unable to generate nm column name for ", _widget);
this.egw().debug("info", "Unable to generate nm column name for ", _widget);
}
return colName;
},
@ -417,7 +417,7 @@ var et2_nextmatch = et2_DOMWidget.extend(et2_IResizeable, {
}
}
} else if (colMgr.columns[i].fixedWidth) {
et2_debug("info", "Could not save column width - no name", colMgr.columns[i].id);
this.egw().debug("info", "Could not save column width - no name", colMgr.columns[i].id);
}
}
@ -663,7 +663,7 @@ var et2_nextmatch = et2_DOMWidget.extend(et2_IResizeable, {
if (!template.proxiedTemplate)
{
et2_debug("error", "Error while loading definition template for" +
this.egw().debug("error", "Error while loading definition template for" +
"nextmatch widget.");
return;
}
@ -676,7 +676,7 @@ var et2_nextmatch = et2_DOMWidget.extend(et2_IResizeable, {
}
else
{
et2_debug("error", "Nextmatch widget expects a grid to be the " +
this.egw().debug("error", "Nextmatch widget expects a grid to be the " +
"first child of the defined template.");
return;
}

View File

@ -177,7 +177,7 @@ var et2_grid = et2_DOMWidget.extend([et2_IDetachedDOM], {
function _readColNode(node, nodeName) {
if (y >= h)
{
et2_debug("warn", "Skipped grid cell in column, '" +
this.egw().debug("warn", "Skipped grid cell in column, '" +
nodeName + "'");
return;
}
@ -234,7 +234,7 @@ var et2_grid = et2_DOMWidget.extend([et2_IDetachedDOM], {
function _readRowNode(node, nodeName) {
if (x >= w)
{
et2_debug("warn", "Skipped grid cell in row, '" +
this.egw().debug("warn", "Skipped grid cell in row, '" +
nodeName + "'");
return;
}

View File

@ -190,7 +190,7 @@ var et2_selectbox = et2_inputWidget.extend({
{
if(jQuery("option[value='"+_value+"']", this.input).attr("selected", true).length == 0)
{
et2_debug("warning", "Tried to set value that isn't an option", this, _value);
this.egw().debug("warning", "Tried to set value that isn't an option", this, _value);
//console.trace();
}
}

View File

@ -67,10 +67,14 @@ var et2_template = et2_DOMWidget.extend({
if (this.id != "")
{
// Get the window this object belongs to
var node = this.getDOMNode();
var wnd = node.ownerDocument.parentNode || node.ownerDocument.defaultView;
// Set the api instance to the first part of the name of the
// template
var splitted = this.id.split('.');
this.setApiInstance(egw(splitted[0]));
this.setApiInstance(egw(splitted[0], wnd));
this.createProxy();
}

View File

@ -119,7 +119,7 @@ etemplate2.prototype._createArrayManagers = function(_data)
{
if (typeof _data[neededEntries[i]] == "undefined" || !_data[neededEntries[i]])
{
et2_debug("log", "Created not passed entry '" + neededEntries[i] +
egw.debug("log", "Created not passed entry '" + neededEntries[i] +
"' in data array.");
_data[neededEntries[i]] = {};
}
@ -257,7 +257,7 @@ etemplate2.prototype.submit = function(button)
}
else
{
et2_debug("info", "Form got submitted with values: ", values);
egw.debug("info", "Form got submitted with values: ", values);
}
}
}
@ -316,7 +316,7 @@ etemplate2.prototype.getValues = function(_root)
}
else
{
et2_debug("error", "ID collision while writing at path " +
egw.debug("error", "ID collision while writing at path " +
"node '" + path[i] + "'");
}
}
@ -324,7 +324,7 @@ etemplate2.prototype.getValues = function(_root)
// Check whether the entry is really undefined
if (typeof _target[id] != "undefined")
{
et2_debug("error", _widget, "Overwriting value of '" + _widget.id +
egw.debug("error", _widget, "Overwriting value of '" + _widget.id +
"', id exists twice!");
}
@ -374,6 +374,6 @@ if (typeof egw_json_register_plugin != "undefined")
}
else
{
et2_debug("info", "EGW JSON Plugin could not be registered, running ET2 standalone.");
egw.debug("info", "EGW JSON Plugin could not be registered, running ET2 standalone.");
}

View File

@ -21,5 +21,6 @@
egw_config;
egw_images;
egw_jsonq;
egw_files;
*/

View File

@ -16,7 +16,7 @@
egw_core;
*/
egw().extend('config', function() {
egw.extend('config', egw.MODULE_GLOBAL, function() {
/**
* Clientside config

View File

@ -14,21 +14,6 @@
var egw;
/**
* IE Fix for array.indexOf
*/
if (typeof Array.prototype.indexOf == "undefined")
{
Array.prototype.indexOf = function(_elem) {
for (var i = 0; i < this.length; i++)
{
if (this[i] === _elem)
return i;
}
return -1;
};
}
/**
* 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.
@ -50,12 +35,114 @@ if (typeof Array.prototype.indexOf == "undefined")
function mergeObjects(_to, _from) {
// Extend the egw object
for (var key in _from)
{
if (typeof _to[key] === 'undefined')
{
_to[key] = _from[key];
}
}
function createEgwInstance(_egw, _modules, _list, _app, _window)
{
// Clone the global object
var instance = cloneObject(_egw);
// Let "_window" be exactly null, if it evaluates to false
_window = _window ? _window : null;
// Set the application name and the window the API instance belongs to
instance.appName = _app ? _app : null;
instance.window = _window;
// Insert the newly created instance into the instances list
_list.push({
'window': _window,
'app': _app,
'instance': instance
});
// Re-instanciate all modules which are marked as "local"
for (var key in _modules)
{
// Get the module object
var mod = _modules[key];
if (mod.flags !== _egw.MODULE_GLOBAL)
{
// If the module is marked as application local and an
// application instance is given or if the module is marked as
// window local and a window instance is given, re-instanciate
// this module.
if (((mod.flags & _egw.MODULE_APP_LOCAL) && (_app)) ||
((mod.flags & _egw.MODULE_WND_LOCAL) && (_window)))
{
var extension = mod.code.call(instance, instance,
_window ? _window : window);
mergeObjects(instance, extension);
}
}
}
return instance;
}
function getEgwInstance(_egw, _modules, _instances, _app, _window)
{
// Generate the hash key for the instance descriptor object
var hash = _window ? _app + "_" + _window.location : _app;
// 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, _instances[hash], _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, _instances[hash], _app, _window);
}
function cleanupEgwInstances(_instances)
{
// Iterate over the egw instances and check whether the window they
// correspond to is still open.
for (var key in _instances)
{
for (var i = _instances[key].length - 1; i >= 0; i--)
{
// Get the instance descriptor
var instDescr = _instances[key][i];
// Check whether the window this API instance belongs to is
// still opened. If not, remove the API instance.
if (instDescr.window && instDescr.window.closed)
{
_instances[key].splice(i, 1)
}
}
// If all instances for the current hash have been deleted, delete
// the hash entry itself
if (_instances[key].length === 0)
{
delete _instances[key];
}
}
}
if (window.opener && typeof window.opener.egw !== 'undefined')
@ -69,67 +156,112 @@ if (typeof Array.prototype.indexOf == "undefined")
else
{
/**
* EGW_DEBUGLEVEL specifies which messages are printed to the console.
* Decrease the value of EGW_DEBUGLEVEL to get less messages.
* Modules contains all currently loaded egw extension modules. A module
* is stored as an object of the following form:
* {
* name: <NAME OF THE OBJECT>,
* code: <REFERENCE TO THE MODULE FUNCTION>,
* flags: <MODULE FLAGS (local, global, etc.)
* }
*/
var EGW_DEBUGLEVEL = 4;
var modules = {};
/**
* Modules contains all currently loaded egw extension modules.
* instances contains all api instances. These are organized as a hash
* of the form _app + _window.location. For each of these hashes a list
* of instances is stored, where the instance itself is an entry of the
* form
* {
* instance: <EGW_API_OBJECT>,
* app: <APPLICATION NAME>,
* window: <WINDOW REFERENCE>
* }
*/
var modules = [];
var instances = {};
var localEgw = {};
/**
* Set a interval which is used to cleanup unused API instances all 10
* seconds.
*/
window.setInterval(function() {cleanupEgwInstances(instances);}, 10000);
/**
* The egw function returns an instance of the client side api. If no
* parameter is given, an egw istance, which is not bound to a certain
* application is returned.
* You may pass either an application name (as string) to the egw
* function and/or a window object. If you specify both, the app name
* has to preceed the window object reference. If no window object is
* given, the root window will be used.
*/
egw = function(_app) {
egw = function() {
// If no argument is given, simply return the global egw object, or
// check whether 'window.egw_appName' is set correctly.
if (typeof _app === 'undefined')
{
// TODO: Remove this code, window.egw_appName will be removed
// in the future.
if (typeof window.egw_appName == 'string')
{
_app = window.egw_appName;
}
else
// Get the window/app reference
var _app = "";
var _window = window;
switch (arguments.length)
{
case 0:
// Return the global instance
return egw;
}
}
if (typeof _app == 'string')
case 1:
if (typeof arguments[0] === 'string')
{
// If a argument is given, this represents the current application
// name. Check whether we already have a copy of the egw object for
// that application. If yes, return it.
if (typeof localEgw[_app] === 'undefined')
_app = arguments[0];
}
else if (typeof arguments[0] === 'object')
{
// Otherwise clone the global egw object, set the application
// name and return it
localEgw[_app] = cloneObject(egw);
localEgw[_app].appName = _app;
_window = arguments[0];
}
break;
case 2:
_app = arguments[0];
_window = arguments[1];
break;
default:
throw "Invalid count of parameters";
}
return localEgw[_app];
}
this.debug("error", "Non-string argument given to the egw function.");
// Generate an API instance
return getEgwInstance(egw, modules, instances, _app, _window);
}
var globalEgw = {
/**
* The MODULE_GLOBAL flag describes a module as global. A global
* module always works on the same data.
*/
MODULE_GLOBAL: 0x00,
/**
* The MODULE_APP_LOCAL flag is used to describe a module as local
* for each application. Each time an api object is requested for
* another application, the complete module gets recreated.
*/
MODULE_APP_LOCAL: 0x01,
/**
* The MODULE_WND_LOCAL flag is used to describe a module as local
* for each window. Each time an api object is requested for another
* window, the complete module gets recreated.
*/
MODULE_WND_LOCAL: 0x02,
/**
* Name of the application the egw object belongs to.
*/
appName: null,
/**
* Reference to the window this egw object belongs to.
*/
window: window,
/**
* Returns the current application name. The current application
* name equals the name, which was given when calling the egw
@ -159,74 +291,65 @@ if (typeof Array.prototype.indexOf == "undefined")
*
* @param _module should be a string containing the name of the new
* module.
* @param _flags specifies whether the extension should be treated
* as a local or a global module.
* @param _code should be a function, which returns an object that
* should extend the egw object.
*/
extend: function(_module, _code) {
extend: function(_module, _flags, _code) {
// Check whether the given module has already been loaded.
if (modules.indexOf(_module) < 0) {
// Check whether that module is already registered
if (typeof modules[_module] === 'undefined')
{
// Create a new module entry
modules[_module] = {
'code': _code,
'flags': _flags,
'name': _module
};
// Call the function specified by "_code" which returns
// nothing but an object containing the extension.
var content = _code.call(this);
// Generate the global extension
var globalExtension = _code.call(egw, egw, window);
// Merge the extension into the egw function
mergeObjects(egw, content);
// Merge the global extension into the egw function
mergeObjects(egw, globalExtension);
// Merge the extension into the local egw object
for (var key in localEgw) {
mergeObjects(localEgw[key], content);
// Iterate over the instances and merge the modules into
// them
for (var key in instances)
{
for (var i = 0; i < instances[key].length; i++)
{
// Get the instance descriptor
var instDescr = instances[key][i];
// Merge the module into the instance
if (_flags !== egw.MODULE_GLOBAL)
{
mergeObjects(instDescr.instance, _code.call(
instDescr.instance, instDescr.instance,
instDescr.window ? instDescr.window : window));
}
else
{
mergeObjects(instDescr.instance, globalExtension);
}
}
}
// Register the module as loaded
modules.push(_module);
}
},
/**
* The debug function can be used to send a debug message to the
* java script console. The first parameter specifies the debug
* level, all other parameters are passed to the corresponding
* console function.
*/
debug: function(_level) {
if (typeof console != "undefined")
{
// Get the passed parameters and remove the first entry
var args = [];
for (var i = 1; i < arguments.length; i++)
{
args.push(arguments[i]);
dumpModules: function() {
return modules;
},
dumpInstances: function() {
return instances;
}
if (_level == "log" && EGW_DEBUGLEVEL >= 4 &&
typeof console.log == "function")
{
console.log.apply(console, args);
}
if (_level == "info" && EGW_DEBUGLEVEL >= 3 &&
typeof console.info == "function")
{
console.info.apply(console, args);
}
if (_level == "warn" && EGW_DEBUGLEVEL >= 2 &&
typeof console.warn == "function")
{
console.warn.apply(console, args);
}
if (_level == "error" && EGW_DEBUGLEVEL >= 1 &&
typeof console.error == "function")
{
console.error.apply(console, args);
}
}
}
};
// Merge the globalEgw functions into the egw object.
mergeObjects(egw, globalEgw);
}
})();

View File

@ -0,0 +1,70 @@
/**
* 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 <RalfBecker@outdoor-training.de>
* @version $Id$
*/
"use strict";
/*egw:uses
egw_core;
*/
egw.extend('debug', egw.MODULE_WND_LOCAL, function(_egw, _wnd) {
/**
* DEBUGLEVEL specifies which messages are printed to the console.
* Decrease the value of EGW_DEBUGLEVEL to get less messages.
*/
var DEBUGLEVEL = 4;
/**
* The debug function can be used to send a debug message to the
* java script console. The first parameter specifies the debug
* level, all other parameters are passed to the corresponding
* console function.
*/
return {
debug: function(_level) {
if (typeof _wnd.console != "undefined")
{
// Get the passed parameters and remove the first entry
var args = [];
for (var i = 1; i < arguments.length; i++)
{
args.push(arguments[i]);
}
if (_level == "log" && DEBUGLEVEL >= 4 &&
typeof _wnd.console.log == "function")
{
_wnd.console.log.apply(_wnd.console, args);
}
if (_level == "info" && DEBUGLEVEL >= 3 &&
typeof _wnd.console.info == "function")
{
_wnd.console.info.apply(_wnd.console, args);
}
if (_level == "warn" && DEBUGLEVEL >= 2 &&
typeof _wnd.console.warn == "function")
{
_wnd.console.warn.apply(_wnd.console, args);
}
if (_level == "error" && DEBUGLEVEL >= 1 &&
typeof _wnd.console.error == "function")
{
_wnd.console.error.apply(_wnd.console, args);
}
}
}
}
});

View File

@ -0,0 +1,153 @@
/**
* 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 <RalfBecker@outdoor-training.de>
* @version $Id$
*/
"use strict";
/*egw:uses
jquery.jquery; // Used for traversing the DOM
egw_core;
egw_debug;
*/
egw.extend('files', egw.MODULE_GLOBAL, function() {
/**
* Array which contains all currently bound in javascript and css files.
*/
var files = {};
/**
* Gather all already loaded JavaScript and CSS files on document load.
*
* TODO: Currently this can only contain the JS files present in the main
* window.
*/
$j(document).ready(function() {
$j("script, link").each(function() {
var elem = $j(this);
if (elem.attr("src"))
{
files[elem.attr("src")] = true;
}
if (elem.attr("href"))
{
files[elem.attr("href")] = true;
}
});
});
function includeJSFile(_jsFile, _callback, _context)
{
var alreadyLoaded = false;
if (typeof files[_jsFile] === 'undefined')
{
// Create the script node which contains the new file
var scriptnode = document.createElement('script');
scriptnode.type = "text/javascript";
scriptnode.src = _jsFile;
scriptnode._originalSrc = _jsFile;
// Setup the 'onload' handler for FF, Opera, Chrome
scriptnode.onload = function(e) {
this.debug('info', 'Retrieved JS file "%s" from server', _jsFile);
_callback.call(_context, _jsFile);
};
// IE
if (typeof scriptnode.readyState != 'undefined')
{
if (scriptnode.readyState != 'complete' &&
scriptnode.readyState != 'loaded')
{
scriptnode.onreadystatechange = function() {
var node = window.event.srcElement;
if (node.readyState == 'complete' || node.readyState == 'loaded')
{
this.debug('info', 'Retrieved JS file "%s" from server', _jsFile);
_callback.call(_context, _jsFile);
}
};
}
else
{
alreadyLoaded = true;
}
}
// Append the newly create script node to the head
var head = document.getElementsByTagName('head')[0];
head.appendChild(scriptnode);
// Request the given javascript file
this.debug('info', 'Requested JS file "%s" from server', _jsFile);
}
// If the file is already loaded, call the callback
if (alreadyLoaded)
{
window.setTimeout(
function() {
_callback.call(_context, _jsFile);
}, 0);
}
}
return {
includeJS: function(_jsFiles, _callback, _context) {
// Also allow including a single javascript file
if (typeof _jsFiles === 'string')
{
_jsFiles = [_jsFiles];
}
var loaded = 0;
// Include all given JS files, if all are successfully loaded, call
// the context function
for (var i = 0; i < _jsFiles.length; i++)
{
includeJSFile.call(this, _jsFiles[i], function(_file) {
loaded++;
if (loaded == _jsFiles.length && _callback) {
_callback.call(_context);
}
});
}
},
includeCSS: function(_cssFile) {
//Check whether the requested file has already been included
if (typeof files[_cssFile] === 'undefined')
{
files[_cssFile] = true;
// Create the node which is used to include the css fiel
var cssnode = document.createElement('link');
cssnode.type = "text/css";
cssnode.rel = "stylesheet";
cssnode.href = _cssFile;
// Get the head node and append the newly created "link" node
// to it.
var head = document.getElementsByTagName('head')[0];
head.appendChild(cssnode);
}
}
}
});

View File

@ -16,7 +16,7 @@
egw_core;
*/
egw().extend('images', function() {
egw.extend('images', egw.MODULE_GLOBAL, function() {
/**
* Map to serverside available images for users template-set

View File

@ -0,0 +1,325 @@
/**
* 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 <RalfBecker@outdoor-training.de>
* @version $Id$
*/
"use strict";
/*egw:uses
jquery.jquery;
egw_core;
egw_utils;
egw_files;
*/
egw.extend('json', egw.MODULE_WND_LOCAL, function(_egw, _wnd) {
/**
* Object which contains all registered handlers for JS responses.
* The handlers are organized per response type in the top level of the
* object, where each response type can have an array of handlers attached
* to it.
*/
var plugins = {};
/**
* Internal implementation of the JSON request object.
*/
function json_request(_menuaction, _parameters, _callback, _context, _egw)
{
// Initialize undefined parameters
if (typeof _parameters === 'undefined')
{
_parameters = [];
}
if (typeof _callback === 'undefined')
{
_callback = null;
}
if (typeof _context === 'undefined')
{
_context = null;
}
// Copy the parameters
this.parameters = _parameters;
this.egw = _egw;
this.callback = _callback;
this.context = _context;
this.request = null;
this.sender = null;
this.callback = null;
this.onLoadFinish = null;
this.jsFiles = 0;
this.jsCount = 0;
this.alertHandler = this.alertFunc;
}
/**
* Function which is currently used to display alerts -- may be replaced by
* some API function.
*/
json_request.prototype.alertFunc = function(_message, _details)
{
alert(_message);
if(_details) _egw_json_debug_log(_message, _details);
}
var json = {
/** The constructor of the egw_json_request class.
*
* @param _menuaction the menuaction function which should be called and
* which handles the actual request. If the menuaction is a full featured
* url, this one will be used instead.
* @param _parameters which should be passed to the menuaction function.
* @param _callback specifies the callback function which should be
* called, once the request has been sucessfully executed.
* @param _context is the context which will be used for the callback function
*/
request: function(_menuaction, _parameters, _callback, _context)
{
return new json_request(_menuaction, _parameters, _callback,
_context, this);
}
/**
* Registers a new handler plugin.
*
* @param _callback is the callback function which should be called
* whenever a response is comming from the server.
* @param _context is the context in which the callback function should
* be called. If null is given, the plugin is executed in the context
* of the request object.
* @param _type is an optional parameter defaulting to 'global'.
* it describes the response type which this plugin should be
* handling.
*/
registerJSONPlugin: function(_callback, _context, _type)
{
// _type defaults to 'global'
if (typeof _type === 'undefined')
{
_type = 'global';
}
// Create an array for the given category inside the plugins object
if (typeof plugins[_type] === 'undefined')
{
plugins[_type] = [];
}
// Add the entry
plugins[_type].push({
'callback': _callback,
'context': _context,
});
},
/**
* Removes a previously registered plugin.
*
* @param _callback is the callback function which should be called
* whenever a response is comming from the server.
* @param _context is the context in which the callback function should
* be called.
* @param _type is an optional parameter defaulting to 'global'.
* it describes the response type which this plugin should be
* handling.
*/
unregisterJSONPlugin: function(_callback, _context, _type)
{
// _type defaults to 'global'
if (typeof _type === 'undefined')
{
_type = 'global';
}
if (typeof plugins[_type] !== 'undefined') {
for (var i = 0; i < plugins[_type].length; i++)
{
if (plugins[_type][i].callback == _callback &&
plugins[_type][i].context == _context)
{
plugins[_type].slice(i, 1);
break;
}
}
}
}
};
// Regisert the "alert" plugin
json.registerPlugin(function(type, res) {
//Check whether all needed parameters have been passed and call the alertHandler function
if ((typeof res.data.message != 'undefined') &&
(typeof res.data.details != 'undefined'))
{
this.alertHandler(
res.data.message,
res.data.details)
return true;
}
throw 'Invalid parameters';
}, null, 'alert');
// Register the "assign" plugin
json.registerPlugin(function(type, res) {
//Check whether all needed parameters have been passed and call the alertHandler function
if ((typeof res.data.id != 'undefined') &&
(typeof res.data.key != 'undefined') &&
(typeof res.data.value != 'undefined'))
{
var obj = document.getElementById(res.data.id);
if (obj)
{
obj[res.data.key] = res.data.value;
if (res.data.key == "innerHTML")
{
egw_insertJS(res.data.value);
}
return true;
}
return false;
}
throw 'Invalid parameters';
}, null, 'assign');
// Register the "data" plugin
json.registerPlugin(function(type, res) {
//Callback the caller in order to allow him to handle the data
if (this.callback)
{
this.callback.call(this.sender, res.data);
return true;
}
}, null, 'data');
// Register the "script" plugin
json.registerPlugin(function(type, res) {
if (typeof res.data == 'string')
{
try
{
var func = new Function(res.data);
func.call(window);
}
catch (e)
{
this.egw.debug('error', 'Error while executing script: ',
res.data)
}
return true;
}
throw 'Invalid parameters';
}, null, 'script');
// Register the "apply" plugin
json.registerPlugin(function(type, res) {
if (typeof res.data.func == 'string' &&
typeof window[res.data.func] == 'function')
{
try
{
window[res.data.func].apply(window, res.data.parms);
}
catch (e)
{
this.egw.debug('error', 'Function', res.data.func,
'Parameters', res.data.parms);
}
return true;
}
throw 'Invalid parameters';
}, null, 'apply');
// Register the "jquery" plugin
json.registerPlugin(function(type, res) {
if (typeof res.data.select == 'string' &&
typeof res.data.func == 'string')
{
try
{
var jQueryObject = $j(res.data.select, this.context);
jQueryObject[res.data.func].apply(jQueryObject, res.data.parms);
}
catch (e)
{
this.egw.debug('error', 'Function', res.data.func,
'Parameters', res.data.parms);
}
return true;
}
throw 'Invalid parameters';
}, null, 'jquery');
// Register the "redirect" plugin
json.registerPlugin(function(type, res) {
//console.log(res.data.url);
if (typeof res.data.url == 'string' &&
typeof res.data.global == 'boolean')
{
//Special handling for framework reload
res.data.global |= (res.data.url.indexOf("?cd=10") > 0);
if (res.data.global)
{
egw_topWindow().location.href = res.data.url;
}
else
{
egw_appWindowOpen(this.app, res.data.url);
}
return true;
}
throw 'Invalid parameters';
}, null, 'redirect');
// Register the 'css' plugin
json.registerPlugin(function(type, res) {
if (typeof res.data == 'string')
{
this.egw.includeCSS(res.data);
return true;
}
throw 'Invalid parameters';
}, null, 'css');
// Register the 'js' plugin
json.registerPlugin(function(type, res) {
if (typeof res.data == 'string')
{
this.jsCount++;
var self = this;
this.egw.includeJS(res.data, function() {
self.jsFiles++;
if (self.jsFiles == self.jsCount && this.onLoadFinish)
{
this.onLoadFinish.call(this.sender);
}
});
}
throw 'Invalid parameters';
}, null, 'js');
// Return the extension
return json;
});

View File

@ -14,9 +14,10 @@
/*egw:uses
egw_core;
egw_debug;
*/
egw().extend('jsonq', function() {
egw.extend('jsonq', egw.MODULE_GLOBAL, function() {
/**
* Queued json requests (objects with attributes menuaction, parameters, context, callback, sender and callbeforesend)
@ -35,6 +36,79 @@ egw().extend('jsonq', function() {
*/
var jsonq_timer = null;
/**
* Dispatch responses received
*
* @param object _data uid => response pairs
*/
function jsonq_callback(_data)
{
if (typeof _data != 'object') throw "jsonq_callback called with NO object as parameter!";
var json = new egw_json_request('none');
for(var uid in _data)
{
if (typeof jsonq_queue[uid] == 'undefined')
{
console.log("jsonq_callback received response for not existing queue uid="+uid+"!");
console.log(_data[uid]);
continue;
}
var job = jsonq_queue[uid];
var response = _data[uid];
// fake egw_json_request object, to call it with the current response
json.callback = job.callback;
json.sender = job.sender;
json.handleResponse({response: response});
delete jsonq_queue[uid];
}
// if nothing left in queue, stop interval-timer to give browser a rest
if (jsonq_timer && typeof jsonq_queue['u'+(jsonq_uid-1)] != 'object')
{
window.clearInterval(jsonq_timer);
jsonq_timer = null;
}
}
/**
* Send the whole job-queue to the server in a single json request with menuaction=queue
*/
function jsonq_send()
{
if (jsonq_uid > 0 && typeof jsonq_queue['u'+(jsonq_uid-1)] == 'object')
{
var jobs_to_send = {};
var something_to_send = false;
for(var uid in jsonq_queue)
{
var job = jsonq_queue[uid];
if (job.menuaction == 'send') continue; // already send to server
// if job has a callbeforesend callback, call it to allow it to modify pararmeters
if (typeof job.callbeforesend == 'function')
{
job.callbeforesend.call(job.sender, job.parameters);
}
jobs_to_send[uid] = {
menuaction: job.menuaction,
parameters: job.parameters
};
job.menuaction = 'send';
job.parameters = null;
something_to_send = true;
}
if (something_to_send)
{
// TODO: Passing this to the "home" application looks quite ugly
var request = new egw_json_request('home.queue', jobs_to_send, this);
request.sendRequest(true, jsonq_callback, this);
}
}
}
return {
/**
* Send a queued JSON call to the server
@ -64,82 +138,12 @@ egw().extend('jsonq', function() {
// check / send queue every N ms
var self = this;
jsonq_timer = window.setInterval(function(){
self.jsonq_send();
jsonq_send.call(self);
}, 100);
}
return uid;
},
/**
* Send the whole job-queue to the server in a single json request with menuaction=queue
*/
jsonq_send: function()
{
if (jsonq_uid > 0 && typeof jsonq_queue['u'+(jsonq_uid-1)] == 'object')
{
var jobs_to_send = {};
var something_to_send = false;
for(var uid in jsonq_queue)
{
var job = jsonq_queue[uid];
if (job.menuaction == 'send') continue; // already send to server
// if job has a callbeforesend callback, call it to allow it to modify pararmeters
if (typeof job.callbeforesend == 'function')
{
job.callbeforesend.call(job.sender, job.parameters);
}
jobs_to_send[uid] = {
menuaction: job.menuaction,
parameters: job.parameters
};
job.menuaction = 'send';
job.parameters = null;
something_to_send = true;
}
if (something_to_send)
{
new egw_json_request('home.queue', jobs_to_send, this).sendRequest(true, this.jsonq_callback, this);
}
}
},
/**
* Dispatch responses received
*
* @param object _data uid => response pairs
*/
jsonq_callback: function(_data)
{
if (typeof _data != 'object') throw "jsonq_callback called with NO object as parameter!";
var json = new egw_json_request('none');
for(var uid in _data)
{
if (typeof jsonq_queue[uid] == 'undefined')
{
console.log("jsonq_callback received response for not existing queue uid="+uid+"!");
console.log(_data[uid]);
continue;
}
var job = jsonq_queue[uid];
var response = _data[uid];
// fake egw_json_request object, to call it with the current response
json.callback = job.callback;
json.sender = job.sender;
json.handleResponse({response: response});
delete jsonq_queue[uid];
}
// if nothing left in queue, stop interval-timer to give browser a rest
if (jsonq_timer && typeof jsonq_queue['u'+(jsonq_uid-1)] != 'object')
{
window.clearInterval(jsonq_timer);
jsonq_timer = null;
}
},
};
});

View File

@ -16,7 +16,7 @@
egw_core;
*/
egw().extend('lang', function() {
egw.extend('lang', egw.MODULE_GLOBAL, function() {
/**
* Translations

View File

@ -17,7 +17,7 @@
egw_link;
*/
egw().extend('links', function() {
egw.extend('links', egw.MODULE_GLOBAL, function() {
/**
* Link registry

View File

@ -16,7 +16,7 @@
egw_core;
*/
egw().extend('preferences', function() {
egw.extend('preferences', egw.MODULE_GLOBAL, function() {
/**
* Object holding the prefences as 2-dim. associative array, use

View File

@ -16,7 +16,7 @@
egw_core;
*/
egw().extend('user', function() {
egw.extend('user', egw.MODULE_GLOBAL, function() {
/**
* Data about current user

View File

@ -0,0 +1,165 @@
/**
* 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 <RalfBecker@outdoor-training.de>
* @version $Id$
*/
"use strict";
/*egw:uses
egw_core;
*/
egw.extend('utils', egw.MODULE_GLOBAL, function() {
function json_escape_string(input)
{
var len = input.length;
var res = "";
for (var i = 0; i < len; i++)
{
switch (input.charAt(i))
{
case '"':
res += '\\"';
break;
case '\n':
res += '\\n';
break;
case '\r':
res += '\\r';
break;
case '\\':
res += '\\\\';
break;
case '\/':
res += '\\/';
break;
case '\b':
res += '\\b';
break;
case '\f':
res += '\\f';
break;
case '\t':
res += '\\t';
break;
default:
res += input.charAt(i);
}
}
return res;
}
function json_encode_simple(input)
{
switch (input.constructor)
{
case String:
return '"' + json_escape_string(input) + '"';
case Number:
return input.toString();
case Boolean:
return input ? 'true' : 'false';
default:
return null;
}
}
function json_encode(input)
{
if (input == null || !input && input.length == 0) return 'null';
var simple_res = json_encode_simple(input);
if (simple_res == null)
{
switch (input.constructor)
{
case Array:
var buf = [];
for (var k in input)
{
//Filter non numeric entries
if (!isNaN(k))
buf.push(json_encode(input[k]));
}
return '[' + buf.join(',') + ']';
case Object:
var buf = [];
for (var k in input)
{
buf.push(json_encode_simple(k) + ':' + json_encode(input[k]));
}
return '{' + buf.join(',') + '}';
default:
switch(typeof input)
{
case 'array':
var buf = [];
for (var k in input)
{
//Filter non numeric entries
if (!isNaN(k))
buf.push(json_encode(input[k]));
}
return '[' + buf.join(',') + ']';
case 'object':
var buf = [];
for (var k in input)
{
buf.push(json_encode_simple(k) + ':' + json_encode(input[k]));
}
return '{' + buf.join(',') + '}';
}
return 'null';
}
}
else
{
return simple_res;
}
}
// Create the utils object which contains references to all functions
// covered by it.
var utils = {};
// Check whether the browser already supports encoding JSON -- if yes, use
// its implementation, otherwise our own
if (typeof window.JSON !== 'undefined' && typeof window.JSON.stringify !== 'undefined')
{
utils["jsonEncode"] = JSON.stringify;
}
else
{
utils["jsonEncode"] = json_encode;
}
// Return the extension
return {"utils": utils};
});