Initial commit of the current JS implementation of the egw_action system, which will later be used to create context sensitive menus and drag and drop capabilities. The egw_menu.js/egw_menu_dhtml.js files are fully functional (see test in the test dir), implementation of egw_action.js has just started and not even a single line of that has been tested yet.
474
phpgwapi/js/egw_action/egw_action.js
Normal file
@ -0,0 +1,474 @@
|
|||||||
|
/**
|
||||||
|
* eGroupWare egw_action framework - egw action framework
|
||||||
|
*
|
||||||
|
* @link http://www.egroupware.org
|
||||||
|
* @author Andreas Stöckel <as@stylite.de>
|
||||||
|
* @copyright 2011 by Andreas Stöckel
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
* @package egw_action
|
||||||
|
* @version $Id:$
|
||||||
|
*/
|
||||||
|
|
||||||
|
// XXX WARNING: UNTESTED, UNFINISHED, NOT (YET) WORKING CODE! XXX
|
||||||
|
|
||||||
|
/** egwActionHandler Interface **/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for the egwActionHandler interface which (at least) should have the
|
||||||
|
* execute function implemented.
|
||||||
|
*/
|
||||||
|
function egwActionHandler(_executeEvent)
|
||||||
|
{
|
||||||
|
//Copy the executeEvent parameter
|
||||||
|
this.execute = _executeEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** egwAction Object **/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associative array where action classes may register themselves
|
||||||
|
*/
|
||||||
|
var _egwActionClasses =
|
||||||
|
{
|
||||||
|
"default":
|
||||||
|
{
|
||||||
|
"actionConstructor": egwAction,
|
||||||
|
"implementationConstructor": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function egwAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple)
|
||||||
|
{
|
||||||
|
//Default and check the values
|
||||||
|
if (typeof _id != "string" || !_id)
|
||||||
|
throw "egwAction _id must be a non-empty string!";
|
||||||
|
if (typeof _handler == "undefined")
|
||||||
|
this.handler = null;
|
||||||
|
if (typeof _label == "undefined")
|
||||||
|
_label = "";
|
||||||
|
if (typeof _icon == "undefined")
|
||||||
|
_icon = "";
|
||||||
|
if (typeof _onExecute == "undefined")
|
||||||
|
_onExecute = null;
|
||||||
|
if (typeof _allowOnMultiple == "undefined")
|
||||||
|
_allowOnMultiple = true;
|
||||||
|
|
||||||
|
this.id = _id;
|
||||||
|
this.caption = _caption;
|
||||||
|
this.icon = _icon;
|
||||||
|
this.allowOnMultiple = _allowOnMultiple;
|
||||||
|
this.type = "default"; //All derived classes have to override this!
|
||||||
|
|
||||||
|
this.execJSFnct = null;
|
||||||
|
this.execHandler = false;
|
||||||
|
this.set_onExecute(_onExecute);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes this action by using the method specified in the onExecute setter.
|
||||||
|
*
|
||||||
|
* @param array_senders array with references to the objects which caused the action
|
||||||
|
* //TODO: With DragDrop we don't only have senders but also one(!) target.
|
||||||
|
*/
|
||||||
|
egwAction.prototype.execute = function(_senders)
|
||||||
|
{
|
||||||
|
if (this.execJSFnct && typeof this.execJSFnct == "function")
|
||||||
|
{
|
||||||
|
this.execJSFnct(this, _senders);
|
||||||
|
}
|
||||||
|
else if (this.execHandler)
|
||||||
|
{
|
||||||
|
this.handler.execute(this, _senders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set_onExecute function is the setter function for the onExecute event of
|
||||||
|
* the egwAction object. There are three possible types the passed "_value" may
|
||||||
|
* take:
|
||||||
|
* 1. _value may be a string with the word "javaScript:" prefixed. The function
|
||||||
|
* which is specified behind the colon and which has to be in the global scope
|
||||||
|
* will be executed.
|
||||||
|
* 2. _value may be a boolean, which specifies whether the external onExecute handler
|
||||||
|
* (passed as "_handler" in the constructor) will be used.
|
||||||
|
* 3. _value may be a JS functino which will then be called.
|
||||||
|
* In all possible situation, the called function will get the following parameters:
|
||||||
|
* 1. A reference to this action
|
||||||
|
* 2. The senders, an array of all objects (JS)/object ids (PHP) which evoked the event
|
||||||
|
*/
|
||||||
|
egwAction.prototype.set_onExecute(_value)
|
||||||
|
{
|
||||||
|
//Reset the onExecute handlers
|
||||||
|
this.execJSFnct = null;
|
||||||
|
this.execHandler = false;
|
||||||
|
|
||||||
|
if (typeof _value == "string")
|
||||||
|
{
|
||||||
|
// Check whether the given string contains a javaScript function which
|
||||||
|
// should be called upon executing the action
|
||||||
|
if (_value.substr(0, 11) == "javaScript:")
|
||||||
|
{
|
||||||
|
//Check whether the given function exists
|
||||||
|
var fnct = _value.substr(11);
|
||||||
|
if (typeof window[fnct] == "function")
|
||||||
|
{
|
||||||
|
this.execJSFnct = window[fnct];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (typeof _value == "boolean")
|
||||||
|
{
|
||||||
|
// There is no direct reference to the PHP code which should be executed,
|
||||||
|
// as the PHP code has knowledge about this.
|
||||||
|
this.execHandler = _value;
|
||||||
|
}
|
||||||
|
else if (typeof _value == "function")
|
||||||
|
{
|
||||||
|
//The JS function has been passed directly
|
||||||
|
this.execJSFnct = _value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
egwAction.prototype.set_caption(_value)
|
||||||
|
{
|
||||||
|
this.caption = _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
egwAction.prototype.set_icon(_value)
|
||||||
|
{
|
||||||
|
this.icon = _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
egwAction.prototype.set_allowOnMultiple(_value)
|
||||||
|
{
|
||||||
|
this.allowOnMultiple = _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** egwActionManager Object **/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* egwActionManager manages a list of actions, provides functions to add new
|
||||||
|
* actions or to update them via JSON.
|
||||||
|
*/
|
||||||
|
function egwActionManager(_handler)
|
||||||
|
{
|
||||||
|
//Preset the handler parameter to null
|
||||||
|
if (typeof _handler == "undefined")
|
||||||
|
_handler = null;
|
||||||
|
|
||||||
|
this.handler = _handler;
|
||||||
|
this.actions = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
egwActionManager.prototype.addAction = function(_type, _id, _caption, _icon,
|
||||||
|
_onExecute, _allowOnMultiple)
|
||||||
|
{
|
||||||
|
//Get the constructor for the given action type
|
||||||
|
if (!_type)
|
||||||
|
_type = "default";
|
||||||
|
var constructor = _egwActionClasses[_type].actionConstructor;
|
||||||
|
|
||||||
|
if (typeof constructor == "function")
|
||||||
|
{
|
||||||
|
var action = new constructor(_id, this.handler, _caption, _icon, _onExecute,
|
||||||
|
_allowOnMultiple);
|
||||||
|
this.actions.push[action];
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw "Given action type not registered.";
|
||||||
|
}
|
||||||
|
|
||||||
|
egwActionManager.prototype.updateActions = function(_actions)
|
||||||
|
{
|
||||||
|
for (var i = 0 ; i < _actions.length; i++)
|
||||||
|
{
|
||||||
|
//Check whether the given action is already part of this action manager instance
|
||||||
|
var elem = _actions[i];
|
||||||
|
if (typeof elem == "object" && typeof elem.id == "string" && elem.id)
|
||||||
|
{
|
||||||
|
//Check whether the action already exists, and if no, add it to the
|
||||||
|
//actions list
|
||||||
|
var action = this.getAction(elem.id);
|
||||||
|
if (!action)
|
||||||
|
{
|
||||||
|
if (typeof elem.type == "undefined")
|
||||||
|
elem.type = "default";
|
||||||
|
|
||||||
|
var constructor = _egwActionClasses[elem.type].actionConstructor;
|
||||||
|
|
||||||
|
if (typeof constructor == "function")
|
||||||
|
action = new constructor(elem.id, this.handler);
|
||||||
|
else
|
||||||
|
throw "Given action type not registered.";
|
||||||
|
|
||||||
|
this.actions.push(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update the actions by calling the corresponding setter functions
|
||||||
|
//TODO: Hirachical actions will need a reference to their parent -
|
||||||
|
// this parent is has to be translated to a js object
|
||||||
|
//TODO: Maby the setter, JSON, update stuff should somehow be moved
|
||||||
|
// to a own base class.
|
||||||
|
egwActionStoreJSON(elem, action, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
egwActionManager.prototype.getAction = function(_id)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < this.actions.length; i++)
|
||||||
|
{
|
||||||
|
if (this.actions[i].id == _id)
|
||||||
|
return this.actions[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** egwActionImplementation Interface **/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract interface for the egwActionImplementation object. The egwActionImplementation
|
||||||
|
* object is responsible for inserting the actual action representation (context menu,
|
||||||
|
* drag-drop code) into the DOM Tree by using the egwActionObjectInterface object
|
||||||
|
* supplied by the object.
|
||||||
|
* To write a "class" which derives from this object, simply write a own constructor,
|
||||||
|
* which replaces "this" with a "new egwActionImplementation" and implement your
|
||||||
|
* code in "doRegisterAction" und "doUnregisterAction".
|
||||||
|
* Register your own implementation within the _egwActionClasses object.
|
||||||
|
*
|
||||||
|
* @param object _action is the parent egwAction object for that instance.
|
||||||
|
*/
|
||||||
|
function egwActionImplementation(_action)
|
||||||
|
{
|
||||||
|
this.action = _action;
|
||||||
|
|
||||||
|
this.doRegisterAction = null;
|
||||||
|
this.doUnregisterAction = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injects the implementation code into the DOM tree by using the supplied
|
||||||
|
* actionObjectInterface.
|
||||||
|
*
|
||||||
|
* @returns true if the Action had been successfully registered, false if it
|
||||||
|
* had not.
|
||||||
|
*/
|
||||||
|
egwActionImplementation.registerAction = function(_actionObjectInterface)
|
||||||
|
{
|
||||||
|
if (this.doRegisterAction == null)
|
||||||
|
{
|
||||||
|
throw "Abstract function call: registerAction";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return this.doRegisterAction(_action, _actionObjectInterface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister action will be called before an actionObjectInterface is destroyed,
|
||||||
|
* which gives the egwActionImplementation the opportunity to remove the previously
|
||||||
|
* injected code.
|
||||||
|
*
|
||||||
|
* @returns true if the Action had been successfully unregistered, false if it
|
||||||
|
* had not.
|
||||||
|
*/
|
||||||
|
egwActionImplementation.unregisterAction = function(_actionObjectInterface)
|
||||||
|
{
|
||||||
|
if (this.doUnregisterAction == null)
|
||||||
|
{
|
||||||
|
throw "Abstract function call: unregisterAction";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return this.doUnregisterAction(_action, _actionObjectInterface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** egwActionLink Object **/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The egwActionLink is used to interconnect egwActionObjects and egwActions.
|
||||||
|
* This gives each action object the possibility to decide, whether the action
|
||||||
|
* should be active in this context or not.
|
||||||
|
*
|
||||||
|
* @param _manager is a reference to the egwActionManager whic contains the action
|
||||||
|
* the object wants to link to.
|
||||||
|
*/
|
||||||
|
function egwActionLink(_manager)
|
||||||
|
{
|
||||||
|
this.enabled = true;
|
||||||
|
this.actionId = "";
|
||||||
|
this.actionObj = null;
|
||||||
|
this.manager = _manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
egwActionLink.prototype.updateLink = function (_data)
|
||||||
|
{
|
||||||
|
egwActionStoreJSON(_data, this, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
egwActionLink.prototype.set_enabled = function(_value)
|
||||||
|
{
|
||||||
|
this.enabled = _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
egwActionLink.prototype.set_actionId = function(_value)
|
||||||
|
{
|
||||||
|
this.actionId = _value;
|
||||||
|
this.actionObj = this.manager.getAction(_value);
|
||||||
|
|
||||||
|
if (!this.actionObj)
|
||||||
|
throw "Given action object does not exist!"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** egwActionObject Object **/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The egwActionObject represents an abstract object to which actions may be
|
||||||
|
* applied. Communication with the DOM tree is established by using the
|
||||||
|
* egwActionObjectInterface (AOI), which is passed in the constructor.
|
||||||
|
* egwActionObjects are organized in a tree structure.
|
||||||
|
*
|
||||||
|
* @param string _id is the identifier of the object which
|
||||||
|
* @param object _parent is the parent object in the hirachy. This may be set to NULL
|
||||||
|
* @param object _manager is the action manager this object is connected to
|
||||||
|
* @param object _interaction is the egwActionObjectInterface which connects
|
||||||
|
* this object to the DOM tree.
|
||||||
|
*/
|
||||||
|
function egwActionObject(_id, _parent, _manager, _interaction)
|
||||||
|
{
|
||||||
|
this.id = _id;
|
||||||
|
this.parent = _parent;
|
||||||
|
this.interaction = _interaction;
|
||||||
|
this.children = [];
|
||||||
|
this.actionLinks = [];
|
||||||
|
this.manager = _manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the actionLinks of the given ActionObject.
|
||||||
|
*
|
||||||
|
* @param array _actionLinks contains the information about the actionLinks which
|
||||||
|
* should be updated as an array of objects. Example
|
||||||
|
* [
|
||||||
|
* {
|
||||||
|
* "actionId": "file_delete",
|
||||||
|
* "enabled": true
|
||||||
|
* }
|
||||||
|
* ]
|
||||||
|
* If an supplied link doesn't exist yet, it will be created (if _doCreate is true)
|
||||||
|
* and added to the list. Otherwise the information will just be updated.
|
||||||
|
* @param boolean _recursive If true, the settings will be applied to all child
|
||||||
|
* object (default false)
|
||||||
|
* @param boolean _doCreate If true, not yet existing links will be created (default true)
|
||||||
|
*/
|
||||||
|
egwActionObject.prototype.updateActionLinks = function(_actionLinks, _recursive, _doCreate)
|
||||||
|
{
|
||||||
|
if (typeof _recursive == "undefined")
|
||||||
|
_recursive = false;
|
||||||
|
if (typeof _doCreate == "undefined")
|
||||||
|
_doCreate = true;
|
||||||
|
|
||||||
|
for (var i = 0; i < _actionLinks.length; i++)
|
||||||
|
{
|
||||||
|
var elem = _actionLinks[i];
|
||||||
|
if (typeof elem.actionId != "undefined" && elem.actionId)
|
||||||
|
{
|
||||||
|
//Get the action link object, if it doesn't exists yet, create it
|
||||||
|
var actionLink = this.getActionLink(elem.actionId);
|
||||||
|
if (!actionLink && _doCreate)
|
||||||
|
{
|
||||||
|
actionLink = new egwActionLink(this.manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set the supplied data
|
||||||
|
if (actionLink)
|
||||||
|
{
|
||||||
|
actionLink.updateLink(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_recursive)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < this.children.length; i++)
|
||||||
|
{
|
||||||
|
this.children[i].updateActionLinks(_actionLinks, true, _doCreate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the action link, which contains the association to the action with
|
||||||
|
* the given actionId.
|
||||||
|
*
|
||||||
|
* @param string _actionId name of the action associated to the link
|
||||||
|
*/
|
||||||
|
egwActionObject.prototype.getActionLink = function(_actionId)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < this.actionLinks.length; i++)
|
||||||
|
{
|
||||||
|
if (this.actionLinks[i].actionObj.id == _actionId)
|
||||||
|
{
|
||||||
|
return this.actionLinks[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all actions associated to the object tree, grouped by type.
|
||||||
|
*
|
||||||
|
* @param function _test gets an egwActionObject and should return, whether the
|
||||||
|
* actions of this object are added to the result. Defaults to a "always true"
|
||||||
|
* function.
|
||||||
|
* @param object _groups is an internally used parameter, may be omitted.
|
||||||
|
*/
|
||||||
|
egwActionObject.prototype.getActionImplementationGroups = function(_test, _groups)
|
||||||
|
{
|
||||||
|
// If the _groups parameter hasn't been given preset it to an empty object
|
||||||
|
// (associative array).
|
||||||
|
if (typeof _groups == "undefined")
|
||||||
|
_groups = {};
|
||||||
|
if (typeof _test == "undefined")
|
||||||
|
_test = function(_obj) {return true};
|
||||||
|
|
||||||
|
for (var i = 0; i < this.actionLinks.length; i++)
|
||||||
|
{
|
||||||
|
var action = this.actionsLink[i].actionObj;
|
||||||
|
if (typeof action != "undefined" && _test(this))
|
||||||
|
{
|
||||||
|
if (typeof _groups[action.type] == "undefined")
|
||||||
|
{
|
||||||
|
_groups[action.type] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
_groups[action.type].push(
|
||||||
|
{
|
||||||
|
"object": this,
|
||||||
|
"link": this.actionLinks[i]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively add the actions of the children to the result (as _groups is)
|
||||||
|
// a object, only the reference is passed.
|
||||||
|
for (var i = 0; i < this.children.length; i++)
|
||||||
|
{
|
||||||
|
this.children[i].getActionImplementationGroups(_test, _groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _groups;
|
||||||
|
}
|
||||||
|
|
39
phpgwapi/js/egw_action/egw_action_common.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* eGroupWare egw_action framework - egw action framework
|
||||||
|
*
|
||||||
|
* @link http://www.egroupware.org
|
||||||
|
* @author Andreas Stöckel <as@stylite.de>
|
||||||
|
* @copyright 2011 by Andreas Stöckel
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
* @package egw_action
|
||||||
|
* @version $Id:$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets properties given in _data in _obj. Checks whether the property keys
|
||||||
|
* exists and if corresponding setter functions are available. Properties starting
|
||||||
|
* with "_" are ignored.
|
||||||
|
*
|
||||||
|
* @param object _data may be an object with data that will be stored inside the
|
||||||
|
* given object.
|
||||||
|
* @param object _obj is the object where the data will be stored.
|
||||||
|
*/
|
||||||
|
function egwActionStoreJSON(_data, _obj, _setterOnly)
|
||||||
|
{
|
||||||
|
for (key in _data)
|
||||||
|
{
|
||||||
|
if (key.charAt(0) != '_')
|
||||||
|
{
|
||||||
|
//Check whether there is a setter function available
|
||||||
|
if (typeof _obj['set_' + key] == "function")
|
||||||
|
{
|
||||||
|
_obj['set_' + key](_data[key]);
|
||||||
|
}
|
||||||
|
else if (typeof _obj[key] != "undefined" && !_setterOnly)
|
||||||
|
{
|
||||||
|
_obj[key] = _data[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
377
phpgwapi/js/egw_action/egw_menu.js
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
/**
|
||||||
|
* eGroupWare egw_action framework - JS Menu abstraction
|
||||||
|
*
|
||||||
|
* @link http://www.egroupware.org
|
||||||
|
* @author Andreas Stöckel <as@stylite.de>
|
||||||
|
* @copyright 2011 by Andreas Stöckel
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
* @package egw_action
|
||||||
|
* @version $Id:$
|
||||||
|
*/
|
||||||
|
|
||||||
|
//Global variable which is used to store the currently active menu so that it
|
||||||
|
//may be closed when another menu openes
|
||||||
|
var _egw_active_menu = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function which generates a menu item with the given parameters as used
|
||||||
|
* in e.g. the egwMenu.addItem function.
|
||||||
|
*/
|
||||||
|
//TODO Icons: write PHP GD script which is cabable of generating the menu icons in various states (disabled, highlighted)
|
||||||
|
function _egwGenMenuItem(_parent, _id, _label, _iconUrl, _onClick)
|
||||||
|
{
|
||||||
|
//Preset the parameters
|
||||||
|
if (typeof _parent == "undefined")
|
||||||
|
_parent = null;
|
||||||
|
if (typeof _id == "undefined")
|
||||||
|
_id = "";
|
||||||
|
if (typeof _label == "undefined")
|
||||||
|
_label = "";
|
||||||
|
if (typeof _iconUrl == "undefined")
|
||||||
|
_iconUrl = "";
|
||||||
|
if (typeof _onClick == "undefined")
|
||||||
|
_onClick = null;
|
||||||
|
|
||||||
|
//Create a menu item with no parent (null) and set the given parameters
|
||||||
|
var item = new egwMenuItem(_parent, _id);
|
||||||
|
item.set_caption(_label);
|
||||||
|
item.set_iconUrl(_iconUrl);
|
||||||
|
item.set_onClick(_onClick);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function which parses the given menu tree in _elements and adds the
|
||||||
|
* elements to the given parent.
|
||||||
|
*/
|
||||||
|
function _egwGenMenuStructure(_elements, _parent)
|
||||||
|
{
|
||||||
|
var items = [];
|
||||||
|
|
||||||
|
//Go through each object in the elements array
|
||||||
|
for (var i = 0; i < _elements.length; i++)
|
||||||
|
{
|
||||||
|
//Go through each key of the current object
|
||||||
|
var obj = _elements[i];
|
||||||
|
var item = new egwMenuItem(_parent, null);
|
||||||
|
for (key in obj)
|
||||||
|
{
|
||||||
|
if (key == "children" && obj[key].constructor === Array)
|
||||||
|
{
|
||||||
|
//Recursively load the children.
|
||||||
|
item.children = _egwGenMenuStructure(obj[key], item);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Directly set the other keys
|
||||||
|
//TODO Sanity neccessary checks here?
|
||||||
|
//TODO Implement menu item getters?
|
||||||
|
if (key == "id" || key == "caption" || key == "iconUrl" ||
|
||||||
|
key == "checkbox" || key == "checked" || key == "groupIndex" ||
|
||||||
|
key == "enabled" || key == "default" || key == "onClick")
|
||||||
|
{
|
||||||
|
item['set_' + key](obj[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function which searches for the given ID inside an element tree.
|
||||||
|
*/
|
||||||
|
function _egwSearchMenuItem(_elements, _id)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < _elements.length; i++)
|
||||||
|
{
|
||||||
|
if (_elements[i].id === _id)
|
||||||
|
return _elements[i];
|
||||||
|
|
||||||
|
var item = _egwSearchMenuItem(_elements[i].children, _id);
|
||||||
|
if (item)
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function which alows to set the onClick handler of multiple menu items
|
||||||
|
*/
|
||||||
|
function _egwSetMenuOnClick(_elements, _onClick)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < _elements.length; i++)
|
||||||
|
{
|
||||||
|
if (_elements[i].onClick === null)
|
||||||
|
{
|
||||||
|
_elements[i].onClick = _onClick;
|
||||||
|
}
|
||||||
|
_egwSetMenuOnClick(_elements[i].children, _onClick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for the egwMenu object. The egwMenu object is a abstract representation
|
||||||
|
* of a context/popup menu. The actual generation of the menu can by done by so
|
||||||
|
* called menu implementations. Those are activated by simply including the JS file
|
||||||
|
* of such an implementation.
|
||||||
|
*
|
||||||
|
* The currently available implementation is the "egwDhtmlxMenu.js" which is based
|
||||||
|
* upon the dhtmlxmenu component.
|
||||||
|
*/
|
||||||
|
function egwMenu()
|
||||||
|
{
|
||||||
|
//The "items" variable contains all menu items of the menu
|
||||||
|
this.children = [];
|
||||||
|
|
||||||
|
//The "instance" variable contains the currently opened instance. There may
|
||||||
|
//only be one instance opened at a time.
|
||||||
|
this.instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The private _checkImpl function checks whether a menu implementation is available.
|
||||||
|
*
|
||||||
|
* @returns bool whether a menu implemenation is available.
|
||||||
|
*/
|
||||||
|
egwMenu.prototype._checkImpl = function()
|
||||||
|
{
|
||||||
|
return typeof egwMenuImpl == 'function';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The showAtElement function shows the menu at the given screen position in an
|
||||||
|
* (hopefully) optimal orientation. There can only be one instance of the menu opened at
|
||||||
|
* one time and the menu implementation should care that there is only one menu
|
||||||
|
* opened globaly at all.
|
||||||
|
*
|
||||||
|
* @param int _x is the x position at which the menu will be opened
|
||||||
|
* @param int _y is the y position at which the menu will be opened
|
||||||
|
* @param bool _force if true, the menu will be reopened at the given position,
|
||||||
|
* even if it already had been opened. Defaults to false.
|
||||||
|
* @returns bool whether the menu had been opened
|
||||||
|
*/
|
||||||
|
egwMenu.prototype.showAt = function(_x, _y, _force)
|
||||||
|
{
|
||||||
|
if (typeof _force == "undefined")
|
||||||
|
_force = false;
|
||||||
|
|
||||||
|
//Hide any other currently active menu
|
||||||
|
if (_egw_active_menu != null)
|
||||||
|
{
|
||||||
|
if (_egw_active_menu == this && !_force)
|
||||||
|
{
|
||||||
|
this.hide();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_egw_active_menu.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.instance == null && this._checkImpl)
|
||||||
|
{
|
||||||
|
//Obtain a new egwMenuImpl object and pass this instance to it
|
||||||
|
this.instance = new egwMenuImpl(this.children);
|
||||||
|
|
||||||
|
_egw_active_menu = this;
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
this.instance.showAt(_x, _y, function() {
|
||||||
|
self.instance = null;
|
||||||
|
_egw_active_menu = null;
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides the menu if it is currently opened. Otherwise nothing happenes.
|
||||||
|
*/
|
||||||
|
egwMenu.prototype.hide = function()
|
||||||
|
{
|
||||||
|
//Reset the currently active menu variable
|
||||||
|
if (_egw_active_menu == this)
|
||||||
|
_egw_active_menu = null;
|
||||||
|
|
||||||
|
//Check whether an currently opened instance exists. If it does, close it.
|
||||||
|
if (this.instance != null)
|
||||||
|
{
|
||||||
|
this.instance.hide();
|
||||||
|
this.instance = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new menu item to the list and returns a reference to that object.
|
||||||
|
*
|
||||||
|
* @param string _id is a unique identifier of the menu item. You can use the
|
||||||
|
* the getItem function to search a specific menu item inside the menu tree. The
|
||||||
|
* id may also be false, null or "", which makes sense for items like seperators,
|
||||||
|
* which you don't want to access anymore after adding them to the menu tree.
|
||||||
|
* @param string _label is the label of the newly generated menu item. Set the label
|
||||||
|
* to "-" in order to create a sperator.
|
||||||
|
* @param string _iconUrl is the URL of the icon which should be prepended to the
|
||||||
|
* menu item. It may be false, null or "" if you don't want a icon to be displayed.
|
||||||
|
* @param function _onClick is the JS function which is being executed when the
|
||||||
|
* menu item is clicked.
|
||||||
|
* @returns egwMenuItem the newly generated menu item, which had been appended to the
|
||||||
|
* menu item list.
|
||||||
|
*/
|
||||||
|
egwMenu.prototype.addItem = function(_id, _label, _iconUrl, _onClick)
|
||||||
|
{
|
||||||
|
//Append the item to the list
|
||||||
|
var item = _egwGenMenuItem(this, _id, _label, _iconUrl, _onClick);
|
||||||
|
this.children.push(item);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all elements fromt the menu structure.
|
||||||
|
*/
|
||||||
|
egwMenu.prototype.clear = function()
|
||||||
|
{
|
||||||
|
this.children = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the menu structure from the given object tree. The object tree is an array
|
||||||
|
* of objects which may contain a subset of the menu item properties. The "children"
|
||||||
|
* property of such an object is interpreted as a new sub-menu tree and appended
|
||||||
|
* to that child.
|
||||||
|
*
|
||||||
|
* @param array _elements is a array of elements which should be added to the menu
|
||||||
|
*/
|
||||||
|
egwMenu.prototype.loadStructure = function(_elements)
|
||||||
|
{
|
||||||
|
this.children = _egwGenMenuStructure(_elements, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for the given item id within the element tree.
|
||||||
|
*/
|
||||||
|
egwMenu.prototype.getItem = function(_id)
|
||||||
|
{
|
||||||
|
return _egwSearchMenuItem(this.children, _id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the given onClick handler to all menu items which don't have a clicked
|
||||||
|
* handler assigned yet.
|
||||||
|
*/
|
||||||
|
egwMenu.prototype.setGlobalOnClick = function(_onClick)
|
||||||
|
{
|
||||||
|
_egwSetMenuOnClick(this.children, _onClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for the egwMenuItem. Each entry in a menu (including seperators)
|
||||||
|
* is represented by a menu item.
|
||||||
|
*/
|
||||||
|
function egwMenuItem(_parent, _id)
|
||||||
|
{
|
||||||
|
this.id = _id;
|
||||||
|
this.caption = "";
|
||||||
|
this.checkbox = false;
|
||||||
|
this.checked = false;
|
||||||
|
this.groupIndex = 0;
|
||||||
|
this.enabled = true;
|
||||||
|
this.iconUrl = "";
|
||||||
|
this.onClick = null;
|
||||||
|
this.default = false;
|
||||||
|
|
||||||
|
this.children = [];
|
||||||
|
this.parent = _parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for the given item id within the element tree.
|
||||||
|
*/
|
||||||
|
egwMenuItem.prototype.getItem = function(_id)
|
||||||
|
{
|
||||||
|
if (this.id === _id)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
return _egwSearchMenuItem(this.children, _id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the given onClick handler to all menu items which don't have a clicked
|
||||||
|
* handler assigned yet.
|
||||||
|
*/
|
||||||
|
egwMenuItem.prototype.setGlobalOnClick = function(_onClick)
|
||||||
|
{
|
||||||
|
this.onClick = _onClick;
|
||||||
|
_egwSetMenuOnClick(this.children, _onClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Setter functions for the menuitem properties
|
||||||
|
|
||||||
|
egwMenuItem.prototype.set_id = function(_value)
|
||||||
|
{
|
||||||
|
this.id = _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
egwMenuItem.prototype.set_caption = function(_value)
|
||||||
|
{
|
||||||
|
//A value of "-" means that this element is a seperator.
|
||||||
|
this.caption = _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
egwMenuItem.prototype.set_checkbox = function(_value)
|
||||||
|
{
|
||||||
|
this.checkbox = _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
egwMenuItem.prototype.set_checked = function(_value)
|
||||||
|
{
|
||||||
|
if (_value && this.groupIndex > 0)
|
||||||
|
{
|
||||||
|
//Uncheck all other elements in this radio group
|
||||||
|
for (var i = 0; i < this.parent.children.length; i++)
|
||||||
|
{
|
||||||
|
var obj = this.parent.children[i];
|
||||||
|
if (obj.groupIndex == this.groupIndex)
|
||||||
|
obj.checked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.checked = _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
egwMenuItem.prototype.set_groupIndex = function(_value)
|
||||||
|
{
|
||||||
|
//If groupIndex is greater than 0 and the element is a checkbox, it is
|
||||||
|
//treated like a radio box
|
||||||
|
this.groupIndex = _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
egwMenuItem.prototype.set_enabled = function(_value)
|
||||||
|
{
|
||||||
|
this.enabled = _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
egwMenuItem.prototype.set_onClick = function(_value)
|
||||||
|
{
|
||||||
|
this.onClick = _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
egwMenuItem.prototype.set_iconUrl = function(_value)
|
||||||
|
{
|
||||||
|
this.iconUrl = _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
egwMenuItem.prototype.set_default = function(_value)
|
||||||
|
{
|
||||||
|
this.default = _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
147
phpgwapi/js/egw_action/egw_menu_dhtmlx.js
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/**
|
||||||
|
* eGroupWare egw_action framework - JS Menu abstraction
|
||||||
|
*
|
||||||
|
* @link http://www.egroupware.org
|
||||||
|
* @author Andreas Stöckel <as@stylite.de>
|
||||||
|
* @copyright 2011 by Andreas Stöckel
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
* @package egw_action
|
||||||
|
* @version $Id:$
|
||||||
|
*/
|
||||||
|
|
||||||
|
function egwMenuImpl(_structure)
|
||||||
|
{
|
||||||
|
//Create a new dhtmlxmenu object
|
||||||
|
this.dhtmlxmenu = new dhtmlXMenuObject();
|
||||||
|
this.dhtmlxmenu.setSkin("egw");
|
||||||
|
this.dhtmlxmenu.renderAsContextMenu();
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
//Attach the simple click handler
|
||||||
|
this.dhtmlxmenu.attachEvent("onClick", function(id) {
|
||||||
|
if (id)
|
||||||
|
{
|
||||||
|
var elem = self.dhtmlxmenu.getUserData(id, 'egw_menu');
|
||||||
|
if (elem && elem.onClick)
|
||||||
|
{
|
||||||
|
elem.onClick(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Attach the radiobutton click handler
|
||||||
|
this.dhtmlxmenu.attachEvent("onRadioClick", function(group, idChecked, idClicked, zoneId, casState) {
|
||||||
|
if (idClicked)
|
||||||
|
{
|
||||||
|
var elem = self.dhtmlxmenu.getUserData(idClicked, 'egw_menu');
|
||||||
|
if (elem)
|
||||||
|
{
|
||||||
|
elem.set_checked(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
//Attach the radiobutton click handler
|
||||||
|
this.dhtmlxmenu.attachEvent("onCheckboxClick", function(id, state, zoneId, casState) {
|
||||||
|
if (id)
|
||||||
|
{
|
||||||
|
var elem = self.dhtmlxmenu.getUserData(id, 'egw_menu');
|
||||||
|
if (elem)
|
||||||
|
{
|
||||||
|
elem.set_checked(!state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
//Translate the given structure to the dhtmlx object structure
|
||||||
|
this._translateStructure(_structure, this.dhtmlxmenu.topId, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
egwMenuImpl.prototype._translateStructure = function(_structure, _parentId, _idCnt)
|
||||||
|
{
|
||||||
|
//Initialize the counter which we will use to generate unique id's for all
|
||||||
|
//dhtmlx menu objects
|
||||||
|
var counter = 0;
|
||||||
|
var last_id = null;
|
||||||
|
|
||||||
|
for (var i = 0; i < _structure.length; i++)
|
||||||
|
{
|
||||||
|
var id = 'elem_' + (_idCnt + counter);
|
||||||
|
var elem = _structure[i];
|
||||||
|
|
||||||
|
counter++;
|
||||||
|
|
||||||
|
//Check whether this element is a seperator
|
||||||
|
if (elem.caption == '-' && last_id != null)
|
||||||
|
{
|
||||||
|
//Add the separator next to last_id with the id "id"
|
||||||
|
this.dhtmlxmenu.addNewSeparator(last_id, id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (elem.checkbox && elem.groupIndex === 0)
|
||||||
|
{
|
||||||
|
//Add checkbox
|
||||||
|
this.dhtmlxmenu.addCheckbox("child", _parentId, i, id,
|
||||||
|
elem.caption, elem.checked, !elem.enabled);
|
||||||
|
}
|
||||||
|
else if (elem.checkbox && elem.groupIndex > 0)
|
||||||
|
{
|
||||||
|
//Add radiobox
|
||||||
|
elem._dhtmlx_grpid = "grp_" + _idCnt + '_' + elem.groupIndex;
|
||||||
|
this.dhtmlxmenu.addRadioButton("child", _parentId, i, id,
|
||||||
|
elem.caption, elem._dhtmlx_grpid, elem.checked, !elem.enabled);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var caption = elem.caption;
|
||||||
|
if (elem.default)
|
||||||
|
caption = "<b>" + caption + "</b>"
|
||||||
|
this.dhtmlxmenu.addNewChild(_parentId, i, id, caption, !elem.enabled,
|
||||||
|
elem.iconUrl, elem.iconUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elem.children.length > 0)
|
||||||
|
{
|
||||||
|
counter += this._translateStructure(elem.children, id, (_idCnt + counter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set the actual egw menu as user data element
|
||||||
|
this.dhtmlxmenu.setUserData(id, 'egw_menu', elem);
|
||||||
|
|
||||||
|
var last_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
egwMenuImpl.prototype.showAt = function(_x, _y, _onHide)
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (_onHide)
|
||||||
|
{
|
||||||
|
this.dhtmlxmenu.attachEvent("onHide", function(id) {
|
||||||
|
if (id === null)
|
||||||
|
{
|
||||||
|
_onHide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.dhtmlxmenu.showContextMenu(_x, _y);
|
||||||
|
}
|
||||||
|
|
||||||
|
egwMenuImpl.prototype.hide = function()
|
||||||
|
{
|
||||||
|
this.dhtmlxmenu.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
BIN
phpgwapi/js/egw_action/test/imgs/dhxmenu_chrd.gif
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
phpgwapi/js/egw_action/test/imgs/dhxmenu_loader.gif
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
phpgwapi/js/egw_action/test/imgs/dhxmenu_subar.gif
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
phpgwapi/js/egw_action/test/imgs/dhxmenu_subselbg.gif
Normal file
After Width: | Height: | Size: 52 B |
BIN
phpgwapi/js/egw_action/test/imgs/dhxmenu_subselbg.png
Normal file
After Width: | Height: | Size: 433 B |
BIN
phpgwapi/js/egw_action/test/imgs/dhxmenu_subsepbg.gif
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
phpgwapi/js/egw_action/test/imgs/dhxmenu_topbg.gif
Normal file
After Width: | Height: | Size: 66 B |
BIN
phpgwapi/js/egw_action/test/imgs/dhxmenu_topselbg.gif
Normal file
After Width: | Height: | Size: 45 B |
BIN
phpgwapi/js/egw_action/test/imgs/dhxmenu_topsepbg.gif
Normal file
After Width: | Height: | Size: 68 B |
BIN
phpgwapi/js/egw_action/test/imgs/dhxmenu_upar.gif
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
phpgwapi/js/egw_action/test/imgs/disk.png
Executable file
After Width: | Height: | Size: 620 B |
BIN
phpgwapi/js/egw_action/test/imgs/folder.png
Executable file
After Width: | Height: | Size: 537 B |
BIN
phpgwapi/js/egw_action/test/imgs/page.png
Executable file
After Width: | Height: | Size: 635 B |
BIN
phpgwapi/js/egw_action/test/imgs/wrench.png
Executable file
After Width: | Height: | Size: 610 B |
928
phpgwapi/js/egw_action/test/js/dhtmlxcommon.js
Normal file
@ -0,0 +1,928 @@
|
|||||||
|
dhtmlx=function(obj){
|
||||||
|
for (var a in obj) dhtmlx[a]=obj[a];
|
||||||
|
return dhtmlx; //simple singleton
|
||||||
|
};
|
||||||
|
dhtmlx.extend_api=function(name,map,ext){
|
||||||
|
var t = window[name];
|
||||||
|
if (!t) return; //component not defined
|
||||||
|
window[name]=function(obj){
|
||||||
|
if (obj && typeof obj == "object" && !obj.tagName){
|
||||||
|
var that = t.apply(this,(map._init?map._init(obj):arguments));
|
||||||
|
//global settings
|
||||||
|
for (var a in dhtmlx)
|
||||||
|
if (map[a]) this[map[a]](dhtmlx[a]);
|
||||||
|
//local settings
|
||||||
|
for (var a in obj){
|
||||||
|
if (map[a]) this[map[a]](obj[a]);
|
||||||
|
else if (a.indexOf("on")==0){
|
||||||
|
this.attachEvent(a,obj[a]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
var that = t.apply(this,arguments);
|
||||||
|
if (map._patch) map._patch(this);
|
||||||
|
return that||this;
|
||||||
|
};
|
||||||
|
window[name].prototype=t.prototype;
|
||||||
|
if (ext)
|
||||||
|
dhtmlXHeir(window[name].prototype,ext);
|
||||||
|
};
|
||||||
|
|
||||||
|
dhtmlxAjax={
|
||||||
|
get:function(url,callback){
|
||||||
|
var t=new dtmlXMLLoaderObject(true);
|
||||||
|
t.async=(arguments.length<3);
|
||||||
|
t.waitCall=callback;
|
||||||
|
t.loadXML(url)
|
||||||
|
return t;
|
||||||
|
},
|
||||||
|
post:function(url,post,callback){
|
||||||
|
var t=new dtmlXMLLoaderObject(true);
|
||||||
|
t.async=(arguments.length<4);
|
||||||
|
t.waitCall=callback;
|
||||||
|
t.loadXML(url,true,post)
|
||||||
|
return t;
|
||||||
|
},
|
||||||
|
getSync:function(url){
|
||||||
|
return this.get(url,null,true)
|
||||||
|
},
|
||||||
|
postSync:function(url,post){
|
||||||
|
return this.post(url,post,null,true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc: xmlLoader object
|
||||||
|
* @type: private
|
||||||
|
* @param: funcObject - xml parser function
|
||||||
|
* @param: object - jsControl object
|
||||||
|
* @param: async - sync/async mode (async by default)
|
||||||
|
* @param: rSeed - enable/disable random seed ( prevent IE caching)
|
||||||
|
* @topic: 0
|
||||||
|
*/
|
||||||
|
function dtmlXMLLoaderObject(funcObject, dhtmlObject, async, rSeed){
|
||||||
|
this.xmlDoc="";
|
||||||
|
|
||||||
|
if (typeof (async) != "undefined")
|
||||||
|
this.async=async;
|
||||||
|
else
|
||||||
|
this.async=true;
|
||||||
|
|
||||||
|
this.onloadAction=funcObject||null;
|
||||||
|
this.mainObject=dhtmlObject||null;
|
||||||
|
this.waitCall=null;
|
||||||
|
this.rSeed=rSeed||false;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* @desc: xml loading handler
|
||||||
|
* @type: private
|
||||||
|
* @param: dtmlObject - xmlLoader object
|
||||||
|
* @topic: 0
|
||||||
|
*/
|
||||||
|
dtmlXMLLoaderObject.prototype.waitLoadFunction=function(dhtmlObject){
|
||||||
|
var once = true;
|
||||||
|
this.check=function (){
|
||||||
|
if ((dhtmlObject)&&(dhtmlObject.onloadAction != null)){
|
||||||
|
if ((!dhtmlObject.xmlDoc.readyState)||(dhtmlObject.xmlDoc.readyState == 4)){
|
||||||
|
if (!once)
|
||||||
|
return;
|
||||||
|
|
||||||
|
once=false; //IE 5 fix
|
||||||
|
if (typeof dhtmlObject.onloadAction == "function")
|
||||||
|
dhtmlObject.onloadAction(dhtmlObject.mainObject, null, null, null, dhtmlObject);
|
||||||
|
|
||||||
|
if (dhtmlObject.waitCall){
|
||||||
|
dhtmlObject.waitCall.call(this,dhtmlObject);
|
||||||
|
dhtmlObject.waitCall=null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return this.check;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc: return XML top node
|
||||||
|
* @param: tagName - top XML node tag name (not used in IE, required for Safari and Mozilla)
|
||||||
|
* @type: private
|
||||||
|
* @returns: top XML node
|
||||||
|
* @topic: 0
|
||||||
|
*/
|
||||||
|
dtmlXMLLoaderObject.prototype.getXMLTopNode=function(tagName, oldObj){
|
||||||
|
if (this.xmlDoc.responseXML){
|
||||||
|
var temp = this.xmlDoc.responseXML.getElementsByTagName(tagName);
|
||||||
|
if(temp.length==0 && tagName.indexOf(":")!=-1)
|
||||||
|
var temp = this.xmlDoc.responseXML.getElementsByTagName((tagName.split(":"))[1]);
|
||||||
|
var z = temp[0];
|
||||||
|
} else
|
||||||
|
var z = this.xmlDoc.documentElement;
|
||||||
|
|
||||||
|
if (z){
|
||||||
|
this._retry=false;
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_isIE)&&(!this._retry)){
|
||||||
|
//fall back to MS.XMLDOM
|
||||||
|
var xmlString = this.xmlDoc.responseText;
|
||||||
|
var oldObj = this.xmlDoc;
|
||||||
|
this._retry=true;
|
||||||
|
this.xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
|
||||||
|
this.xmlDoc.async=false;
|
||||||
|
this.xmlDoc["loadXM"+"L"](xmlString);
|
||||||
|
|
||||||
|
return this.getXMLTopNode(tagName, oldObj);
|
||||||
|
}
|
||||||
|
dhtmlxError.throwError("LoadXML", "Incorrect XML", [
|
||||||
|
(oldObj||this.xmlDoc),
|
||||||
|
this.mainObject
|
||||||
|
]);
|
||||||
|
|
||||||
|
return document.createElement("DIV");
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc: load XML from string
|
||||||
|
* @type: private
|
||||||
|
* @param: xmlString - xml string
|
||||||
|
* @topic: 0
|
||||||
|
*/
|
||||||
|
dtmlXMLLoaderObject.prototype.loadXMLString=function(xmlString){
|
||||||
|
{
|
||||||
|
try{
|
||||||
|
var parser = new DOMParser();
|
||||||
|
this.xmlDoc=parser.parseFromString(xmlString, "text/xml");
|
||||||
|
}
|
||||||
|
catch (e){
|
||||||
|
this.xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
|
||||||
|
this.xmlDoc.async=this.async;
|
||||||
|
this.xmlDoc["loadXM"+"L"](xmlString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onloadAction(this.mainObject, null, null, null, this);
|
||||||
|
|
||||||
|
if (this.waitCall){
|
||||||
|
this.waitCall();
|
||||||
|
this.waitCall=null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @desc: load XML
|
||||||
|
* @type: private
|
||||||
|
* @param: filePath - xml file path
|
||||||
|
* @param: postMode - send POST request
|
||||||
|
* @param: postVars - list of vars for post request
|
||||||
|
* @topic: 0
|
||||||
|
*/
|
||||||
|
dtmlXMLLoaderObject.prototype.loadXML=function(filePath, postMode, postVars, rpc){
|
||||||
|
if (this.rSeed)
|
||||||
|
filePath+=((filePath.indexOf("?") != -1) ? "&" : "?")+"a_dhx_rSeed="+(new Date()).valueOf();
|
||||||
|
this.filePath=filePath;
|
||||||
|
|
||||||
|
if ((!_isIE)&&(window.XMLHttpRequest))
|
||||||
|
this.xmlDoc=new XMLHttpRequest();
|
||||||
|
else {
|
||||||
|
this.xmlDoc=new ActiveXObject("Microsoft.XMLHTTP");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.async)
|
||||||
|
this.xmlDoc.onreadystatechange=new this.waitLoadFunction(this);
|
||||||
|
this.xmlDoc.open(postMode ? "POST" : "GET", filePath, this.async);
|
||||||
|
|
||||||
|
if (rpc){
|
||||||
|
this.xmlDoc.setRequestHeader("User-Agent", "dhtmlxRPC v0.1 ("+navigator.userAgent+")");
|
||||||
|
this.xmlDoc.setRequestHeader("Content-type", "text/xml");
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (postMode)
|
||||||
|
this.xmlDoc.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||||
|
|
||||||
|
this.xmlDoc.setRequestHeader("X-Requested-With","XMLHttpRequest");
|
||||||
|
this.xmlDoc.send(null||postVars);
|
||||||
|
|
||||||
|
if (!this.async)
|
||||||
|
(new this.waitLoadFunction(this))();
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* @desc: destructor, cleans used memory
|
||||||
|
* @type: private
|
||||||
|
* @topic: 0
|
||||||
|
*/
|
||||||
|
dtmlXMLLoaderObject.prototype.destructor=function(){
|
||||||
|
this._filterXPath = null;
|
||||||
|
this._getAllNamedChilds = null;
|
||||||
|
this._retry = null;
|
||||||
|
this.async = null;
|
||||||
|
this.rSeed = null;
|
||||||
|
this.filePath = null;
|
||||||
|
this.onloadAction = null;
|
||||||
|
this.mainObject = null;
|
||||||
|
this.xmlDoc = null;
|
||||||
|
this.doXPath = null;
|
||||||
|
this.doXPathOpera = null;
|
||||||
|
this.doXSLTransToObject = null;
|
||||||
|
this.doXSLTransToString = null;
|
||||||
|
this.loadXML = null;
|
||||||
|
this.loadXMLString = null;
|
||||||
|
// this.waitLoadFunction = null;
|
||||||
|
this.doSerialization = null;
|
||||||
|
this.xmlNodeToJSON = null;
|
||||||
|
this.getXMLTopNode = null;
|
||||||
|
this.setXSLParamValue = null;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtmlXMLLoaderObject.prototype.xmlNodeToJSON = function(node){
|
||||||
|
var t={};
|
||||||
|
for (var i=0; i<node.attributes.length; i++)
|
||||||
|
t[node.attributes[i].name]=node.attributes[i].value;
|
||||||
|
t["_tagvalue"]=node.firstChild?node.firstChild.nodeValue:"";
|
||||||
|
for (var i=0; i<node.childNodes.length; i++){
|
||||||
|
var name=node.childNodes[i].tagName;
|
||||||
|
if (name){
|
||||||
|
if (!t[name]) t[name]=[];
|
||||||
|
t[name].push(this.xmlNodeToJSON(node.childNodes[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc: Call wrapper
|
||||||
|
* @type: private
|
||||||
|
* @param: funcObject - action handler
|
||||||
|
* @param: dhtmlObject - user data
|
||||||
|
* @returns: function handler
|
||||||
|
* @topic: 0
|
||||||
|
*/
|
||||||
|
function callerFunction(funcObject, dhtmlObject){
|
||||||
|
this.handler=function(e){
|
||||||
|
if (!e)
|
||||||
|
e=window.event;
|
||||||
|
funcObject(e, dhtmlObject);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
return this.handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc: Calculate absolute position of html object
|
||||||
|
* @type: private
|
||||||
|
* @param: htmlObject - html object
|
||||||
|
* @topic: 0
|
||||||
|
*/
|
||||||
|
function getAbsoluteLeft(htmlObject){
|
||||||
|
return getOffset(htmlObject).left;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @desc: Calculate absolute position of html object
|
||||||
|
* @type: private
|
||||||
|
* @param: htmlObject - html object
|
||||||
|
* @topic: 0
|
||||||
|
*/
|
||||||
|
function getAbsoluteTop(htmlObject){
|
||||||
|
return getOffset(htmlObject).top;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOffsetSum(elem) {
|
||||||
|
var top=0, left=0;
|
||||||
|
while(elem) {
|
||||||
|
top = top + parseInt(elem.offsetTop);
|
||||||
|
left = left + parseInt(elem.offsetLeft);
|
||||||
|
elem = elem.offsetParent;
|
||||||
|
}
|
||||||
|
return {top: top, left: left};
|
||||||
|
}
|
||||||
|
function getOffsetRect(elem) {
|
||||||
|
var box = elem.getBoundingClientRect();
|
||||||
|
var body = document.body;
|
||||||
|
var docElem = document.documentElement;
|
||||||
|
var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
|
||||||
|
var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;
|
||||||
|
var clientTop = docElem.clientTop || body.clientTop || 0;
|
||||||
|
var clientLeft = docElem.clientLeft || body.clientLeft || 0;
|
||||||
|
var top = box.top + scrollTop - clientTop;
|
||||||
|
var left = box.left + scrollLeft - clientLeft;
|
||||||
|
return { top: Math.round(top), left: Math.round(left) };
|
||||||
|
}
|
||||||
|
function getOffset(elem) {
|
||||||
|
if (elem.getBoundingClientRect) {
|
||||||
|
return getOffsetRect(elem);
|
||||||
|
} else {
|
||||||
|
return getOffsetSum(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc: Convert string to it boolean representation
|
||||||
|
* @type: private
|
||||||
|
* @param: inputString - string for covertion
|
||||||
|
* @topic: 0
|
||||||
|
*/
|
||||||
|
function convertStringToBoolean(inputString){
|
||||||
|
if (typeof (inputString) == "string")
|
||||||
|
inputString=inputString.toLowerCase();
|
||||||
|
|
||||||
|
switch (inputString){
|
||||||
|
case "1":
|
||||||
|
case "true":
|
||||||
|
case "yes":
|
||||||
|
case "y":
|
||||||
|
case 1:
|
||||||
|
case true:
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc: find out what symbol to use as url param delimiters in further params
|
||||||
|
* @type: private
|
||||||
|
* @param: str - current url string
|
||||||
|
* @topic: 0
|
||||||
|
*/
|
||||||
|
function getUrlSymbol(str){
|
||||||
|
if (str.indexOf("?") != -1)
|
||||||
|
return "&"
|
||||||
|
else
|
||||||
|
return "?"
|
||||||
|
}
|
||||||
|
|
||||||
|
function dhtmlDragAndDropObject(){
|
||||||
|
if (window.dhtmlDragAndDrop)
|
||||||
|
return window.dhtmlDragAndDrop;
|
||||||
|
|
||||||
|
this.lastLanding=0;
|
||||||
|
this.dragNode=0;
|
||||||
|
this.dragStartNode=0;
|
||||||
|
this.dragStartObject=0;
|
||||||
|
this.tempDOMU=null;
|
||||||
|
this.tempDOMM=null;
|
||||||
|
this.waitDrag=0;
|
||||||
|
window.dhtmlDragAndDrop=this;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
dhtmlDragAndDropObject.prototype.removeDraggableItem=function(htmlNode){
|
||||||
|
htmlNode.onmousedown=null;
|
||||||
|
htmlNode.dragStarter=null;
|
||||||
|
htmlNode.dragLanding=null;
|
||||||
|
}
|
||||||
|
dhtmlDragAndDropObject.prototype.addDraggableItem=function(htmlNode, dhtmlObject){
|
||||||
|
htmlNode.onmousedown=this.preCreateDragCopy;
|
||||||
|
htmlNode.dragStarter=dhtmlObject;
|
||||||
|
this.addDragLanding(htmlNode, dhtmlObject);
|
||||||
|
}
|
||||||
|
dhtmlDragAndDropObject.prototype.addDragLanding=function(htmlNode, dhtmlObject){
|
||||||
|
htmlNode.dragLanding=dhtmlObject;
|
||||||
|
}
|
||||||
|
dhtmlDragAndDropObject.prototype.preCreateDragCopy=function(e){
|
||||||
|
if ((e||window.event) && (e||event).button == 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (window.dhtmlDragAndDrop.waitDrag){
|
||||||
|
window.dhtmlDragAndDrop.waitDrag=0;
|
||||||
|
document.body.onmouseup=window.dhtmlDragAndDrop.tempDOMU;
|
||||||
|
document.body.onmousemove=window.dhtmlDragAndDrop.tempDOMM;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.dhtmlDragAndDrop.waitDrag=1;
|
||||||
|
window.dhtmlDragAndDrop.tempDOMU=document.body.onmouseup;
|
||||||
|
window.dhtmlDragAndDrop.tempDOMM=document.body.onmousemove;
|
||||||
|
window.dhtmlDragAndDrop.dragStartNode=this;
|
||||||
|
window.dhtmlDragAndDrop.dragStartObject=this.dragStarter;
|
||||||
|
document.body.onmouseup=window.dhtmlDragAndDrop.preCreateDragCopy;
|
||||||
|
document.body.onmousemove=window.dhtmlDragAndDrop.callDrag;
|
||||||
|
window.dhtmlDragAndDrop.downtime = new Date().valueOf();
|
||||||
|
|
||||||
|
|
||||||
|
if ((e)&&(e.preventDefault)){
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
dhtmlDragAndDropObject.prototype.callDrag=function(e){
|
||||||
|
if (!e)
|
||||||
|
e=window.event;
|
||||||
|
dragger=window.dhtmlDragAndDrop;
|
||||||
|
if ((new Date()).valueOf()-dragger.downtime<100) return;
|
||||||
|
|
||||||
|
if ((e.button == 0)&&(_isIE))
|
||||||
|
return dragger.stopDrag();
|
||||||
|
|
||||||
|
if (!dragger.dragNode&&dragger.waitDrag){
|
||||||
|
dragger.dragNode=dragger.dragStartObject._createDragNode(dragger.dragStartNode, e);
|
||||||
|
|
||||||
|
if (!dragger.dragNode)
|
||||||
|
return dragger.stopDrag();
|
||||||
|
|
||||||
|
dragger.dragNode.onselectstart=function(){return false;}
|
||||||
|
dragger.gldragNode=dragger.dragNode;
|
||||||
|
document.body.appendChild(dragger.dragNode);
|
||||||
|
document.body.onmouseup=dragger.stopDrag;
|
||||||
|
dragger.waitDrag=0;
|
||||||
|
dragger.dragNode.pWindow=window;
|
||||||
|
dragger.initFrameRoute();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dragger.dragNode.parentNode != window.document.body){
|
||||||
|
var grd = dragger.gldragNode;
|
||||||
|
|
||||||
|
if (dragger.gldragNode.old)
|
||||||
|
grd=dragger.gldragNode.old;
|
||||||
|
|
||||||
|
//if (!document.all) dragger.calculateFramePosition();
|
||||||
|
grd.parentNode.removeChild(grd);
|
||||||
|
var oldBody = dragger.dragNode.pWindow;
|
||||||
|
|
||||||
|
if (grd.pWindow && grd.pWindow.dhtmlDragAndDrop.lastLanding)
|
||||||
|
grd.pWindow.dhtmlDragAndDrop.lastLanding.dragLanding._dragOut(grd.pWindow.dhtmlDragAndDrop.lastLanding);
|
||||||
|
|
||||||
|
// var oldp=dragger.dragNode.parentObject;
|
||||||
|
if (_isIE){
|
||||||
|
var div = document.createElement("Div");
|
||||||
|
div.innerHTML=dragger.dragNode.outerHTML;
|
||||||
|
dragger.dragNode=div.childNodes[0];
|
||||||
|
} else
|
||||||
|
dragger.dragNode=dragger.dragNode.cloneNode(true);
|
||||||
|
|
||||||
|
dragger.dragNode.pWindow=window;
|
||||||
|
// dragger.dragNode.parentObject=oldp;
|
||||||
|
|
||||||
|
dragger.gldragNode.old=dragger.dragNode;
|
||||||
|
document.body.appendChild(dragger.dragNode);
|
||||||
|
oldBody.dhtmlDragAndDrop.dragNode=dragger.dragNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
dragger.dragNode.style.left=e.clientX+15+(dragger.fx
|
||||||
|
? dragger.fx*(-1)
|
||||||
|
: 0)
|
||||||
|
+(document.body.scrollLeft||document.documentElement.scrollLeft)+"px";
|
||||||
|
dragger.dragNode.style.top=e.clientY+3+(dragger.fy
|
||||||
|
? dragger.fy*(-1)
|
||||||
|
: 0)
|
||||||
|
+(document.body.scrollTop||document.documentElement.scrollTop)+"px";
|
||||||
|
|
||||||
|
if (!e.srcElement)
|
||||||
|
var z = e.target;
|
||||||
|
else
|
||||||
|
z=e.srcElement;
|
||||||
|
dragger.checkLanding(z, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
dhtmlDragAndDropObject.prototype.calculateFramePosition=function(n){
|
||||||
|
//this.fx = 0, this.fy = 0;
|
||||||
|
if (window.name){
|
||||||
|
var el = parent.frames[window.name].frameElement.offsetParent;
|
||||||
|
var fx = 0;
|
||||||
|
var fy = 0;
|
||||||
|
|
||||||
|
while (el){
|
||||||
|
fx+=el.offsetLeft;
|
||||||
|
fy+=el.offsetTop;
|
||||||
|
el=el.offsetParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((parent.dhtmlDragAndDrop)){
|
||||||
|
var ls = parent.dhtmlDragAndDrop.calculateFramePosition(1);
|
||||||
|
fx+=ls.split('_')[0]*1;
|
||||||
|
fy+=ls.split('_')[1]*1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n)
|
||||||
|
return fx+"_"+fy;
|
||||||
|
else
|
||||||
|
this.fx=fx;
|
||||||
|
this.fy=fy;
|
||||||
|
}
|
||||||
|
return "0_0";
|
||||||
|
}
|
||||||
|
dhtmlDragAndDropObject.prototype.checkLanding=function(htmlObject, e){
|
||||||
|
if ((htmlObject)&&(htmlObject.dragLanding)){
|
||||||
|
if (this.lastLanding)
|
||||||
|
this.lastLanding.dragLanding._dragOut(this.lastLanding);
|
||||||
|
this.lastLanding=htmlObject;
|
||||||
|
this.lastLanding=this.lastLanding.dragLanding._dragIn(this.lastLanding, this.dragStartNode, e.clientX,
|
||||||
|
e.clientY, e);
|
||||||
|
this.lastLanding_scr=(_isIE ? e.srcElement : e.target);
|
||||||
|
} else {
|
||||||
|
if ((htmlObject)&&(htmlObject.tagName != "BODY"))
|
||||||
|
this.checkLanding(htmlObject.parentNode, e);
|
||||||
|
else {
|
||||||
|
if (this.lastLanding)
|
||||||
|
this.lastLanding.dragLanding._dragOut(this.lastLanding, e.clientX, e.clientY, e);
|
||||||
|
this.lastLanding=0;
|
||||||
|
|
||||||
|
if (this._onNotFound)
|
||||||
|
this._onNotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dhtmlDragAndDropObject.prototype.stopDrag=function(e, mode){
|
||||||
|
dragger=window.dhtmlDragAndDrop;
|
||||||
|
|
||||||
|
if (!mode){
|
||||||
|
dragger.stopFrameRoute();
|
||||||
|
var temp = dragger.lastLanding;
|
||||||
|
dragger.lastLanding=null;
|
||||||
|
|
||||||
|
if (temp)
|
||||||
|
temp.dragLanding._drag(dragger.dragStartNode, dragger.dragStartObject, temp, (_isIE
|
||||||
|
? event.srcElement
|
||||||
|
: e.target));
|
||||||
|
}
|
||||||
|
dragger.lastLanding=null;
|
||||||
|
|
||||||
|
if ((dragger.dragNode)&&(dragger.dragNode.parentNode == document.body))
|
||||||
|
dragger.dragNode.parentNode.removeChild(dragger.dragNode);
|
||||||
|
dragger.dragNode=0;
|
||||||
|
dragger.gldragNode=0;
|
||||||
|
dragger.fx=0;
|
||||||
|
dragger.fy=0;
|
||||||
|
dragger.dragStartNode=0;
|
||||||
|
dragger.dragStartObject=0;
|
||||||
|
document.body.onmouseup=dragger.tempDOMU;
|
||||||
|
document.body.onmousemove=dragger.tempDOMM;
|
||||||
|
dragger.tempDOMU=null;
|
||||||
|
dragger.tempDOMM=null;
|
||||||
|
dragger.waitDrag=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dhtmlDragAndDropObject.prototype.stopFrameRoute=function(win){
|
||||||
|
if (win)
|
||||||
|
window.dhtmlDragAndDrop.stopDrag(1, 1);
|
||||||
|
|
||||||
|
for (var i = 0; i < window.frames.length; i++){
|
||||||
|
try{
|
||||||
|
if ((window.frames[i] != win)&&(window.frames[i].dhtmlDragAndDrop))
|
||||||
|
window.frames[i].dhtmlDragAndDrop.stopFrameRoute(window);
|
||||||
|
} catch(e){}
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
if ((parent.dhtmlDragAndDrop)&&(parent != window)&&(parent != win))
|
||||||
|
parent.dhtmlDragAndDrop.stopFrameRoute(window);
|
||||||
|
} catch(e){}
|
||||||
|
}
|
||||||
|
dhtmlDragAndDropObject.prototype.initFrameRoute=function(win, mode){
|
||||||
|
if (win){
|
||||||
|
window.dhtmlDragAndDrop.preCreateDragCopy();
|
||||||
|
window.dhtmlDragAndDrop.dragStartNode=win.dhtmlDragAndDrop.dragStartNode;
|
||||||
|
window.dhtmlDragAndDrop.dragStartObject=win.dhtmlDragAndDrop.dragStartObject;
|
||||||
|
window.dhtmlDragAndDrop.dragNode=win.dhtmlDragAndDrop.dragNode;
|
||||||
|
window.dhtmlDragAndDrop.gldragNode=win.dhtmlDragAndDrop.dragNode;
|
||||||
|
window.document.body.onmouseup=window.dhtmlDragAndDrop.stopDrag;
|
||||||
|
window.waitDrag=0;
|
||||||
|
|
||||||
|
if (((!_isIE)&&(mode))&&((!_isFF)||(_FFrv < 1.8)))
|
||||||
|
window.dhtmlDragAndDrop.calculateFramePosition();
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
if ((parent.dhtmlDragAndDrop)&&(parent != window)&&(parent != win))
|
||||||
|
parent.dhtmlDragAndDrop.initFrameRoute(window);
|
||||||
|
}catch(e){}
|
||||||
|
|
||||||
|
for (var i = 0; i < window.frames.length; i++){
|
||||||
|
try{
|
||||||
|
if ((window.frames[i] != win)&&(window.frames[i].dhtmlDragAndDrop))
|
||||||
|
window.frames[i].dhtmlDragAndDrop.initFrameRoute(window, ((!win||mode) ? 1 : 0));
|
||||||
|
} catch(e){}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _isFF = false;
|
||||||
|
var _isIE = false;
|
||||||
|
var _isOpera = false;
|
||||||
|
var _isKHTML = false;
|
||||||
|
var _isMacOS = false;
|
||||||
|
var _isChrome = false;
|
||||||
|
|
||||||
|
if (navigator.userAgent.indexOf('Macintosh') != -1)
|
||||||
|
_isMacOS=true;
|
||||||
|
|
||||||
|
|
||||||
|
if (navigator.userAgent.toLowerCase().indexOf('chrome')>-1)
|
||||||
|
_isChrome=true;
|
||||||
|
|
||||||
|
if ((navigator.userAgent.indexOf('Safari') != -1)||(navigator.userAgent.indexOf('Konqueror') != -1)){
|
||||||
|
var _KHTMLrv = parseFloat(navigator.userAgent.substr(navigator.userAgent.indexOf('Safari')+7, 5));
|
||||||
|
|
||||||
|
if (_KHTMLrv > 525){ //mimic FF behavior for Safari 3.1+
|
||||||
|
_isFF=true;
|
||||||
|
var _FFrv = 1.9;
|
||||||
|
} else
|
||||||
|
_isKHTML=true;
|
||||||
|
} else if (navigator.userAgent.indexOf('Opera') != -1){
|
||||||
|
_isOpera=true;
|
||||||
|
_OperaRv=parseFloat(navigator.userAgent.substr(navigator.userAgent.indexOf('Opera')+6, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
else if (navigator.appName.indexOf("Microsoft") != -1){
|
||||||
|
_isIE=true;
|
||||||
|
if (navigator.appVersion.indexOf("MSIE 8.0")!= -1 && document.compatMode != "BackCompat") _isIE=8;
|
||||||
|
if (navigator.appVersion.indexOf("MSIE 9.0")!= -1 && document.compatMode != "BackCompat") _isIE=8;
|
||||||
|
} else {
|
||||||
|
_isFF=true;
|
||||||
|
var _FFrv = parseFloat(navigator.userAgent.split("rv:")[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//multibrowser Xpath processor
|
||||||
|
dtmlXMLLoaderObject.prototype.doXPath=function(xpathExp, docObj, namespace, result_type){
|
||||||
|
if (_isKHTML || (!_isIE && !window.XPathResult))
|
||||||
|
return this.doXPathOpera(xpathExp, docObj);
|
||||||
|
|
||||||
|
if (_isIE){ //IE
|
||||||
|
if (!docObj)
|
||||||
|
if (!this.xmlDoc.nodeName)
|
||||||
|
docObj=this.xmlDoc.responseXML
|
||||||
|
else
|
||||||
|
docObj=this.xmlDoc;
|
||||||
|
|
||||||
|
if (!docObj)
|
||||||
|
dhtmlxError.throwError("LoadXML", "Incorrect XML", [
|
||||||
|
(docObj||this.xmlDoc),
|
||||||
|
this.mainObject
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (namespace != null)
|
||||||
|
docObj.setProperty("SelectionNamespaces", "xmlns:xsl='"+namespace+"'"); //
|
||||||
|
|
||||||
|
if (result_type == 'single'){
|
||||||
|
return docObj.selectSingleNode(xpathExp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return docObj.selectNodes(xpathExp)||new Array(0);
|
||||||
|
}
|
||||||
|
} else { //Mozilla
|
||||||
|
var nodeObj = docObj;
|
||||||
|
|
||||||
|
if (!docObj){
|
||||||
|
if (!this.xmlDoc.nodeName){
|
||||||
|
docObj=this.xmlDoc.responseXML
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
docObj=this.xmlDoc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!docObj)
|
||||||
|
dhtmlxError.throwError("LoadXML", "Incorrect XML", [
|
||||||
|
(docObj||this.xmlDoc),
|
||||||
|
this.mainObject
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (docObj.nodeName.indexOf("document") != -1){
|
||||||
|
nodeObj=docObj;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nodeObj=docObj;
|
||||||
|
docObj=docObj.ownerDocument;
|
||||||
|
}
|
||||||
|
var retType = XPathResult.ANY_TYPE;
|
||||||
|
|
||||||
|
if (result_type == 'single')
|
||||||
|
retType=XPathResult.FIRST_ORDERED_NODE_TYPE
|
||||||
|
var rowsCol = new Array();
|
||||||
|
var col = docObj.evaluate(xpathExp, nodeObj, function(pref){
|
||||||
|
return namespace
|
||||||
|
}, retType, null);
|
||||||
|
|
||||||
|
if (retType == XPathResult.FIRST_ORDERED_NODE_TYPE){
|
||||||
|
return col.singleNodeValue;
|
||||||
|
}
|
||||||
|
var thisColMemb = col.iterateNext();
|
||||||
|
|
||||||
|
while (thisColMemb){
|
||||||
|
rowsCol[rowsCol.length]=thisColMemb;
|
||||||
|
thisColMemb=col.iterateNext();
|
||||||
|
}
|
||||||
|
return rowsCol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _dhtmlxError(type, name, params){
|
||||||
|
if (!this.catches)
|
||||||
|
this.catches=new Array();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dhtmlxError.prototype.catchError=function(type, func_name){
|
||||||
|
this.catches[type]=func_name;
|
||||||
|
}
|
||||||
|
_dhtmlxError.prototype.throwError=function(type, name, params){
|
||||||
|
if (this.catches[type])
|
||||||
|
return this.catches[type](type, name, params);
|
||||||
|
|
||||||
|
if (this.catches["ALL"])
|
||||||
|
return this.catches["ALL"](type, name, params);
|
||||||
|
|
||||||
|
alert("Error type: "+arguments[0]+"\nDescription: "+arguments[1]);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.dhtmlxError=new _dhtmlxError();
|
||||||
|
|
||||||
|
|
||||||
|
//opera fake, while 9.0 not released
|
||||||
|
//multibrowser Xpath processor
|
||||||
|
dtmlXMLLoaderObject.prototype.doXPathOpera=function(xpathExp, docObj){
|
||||||
|
//this is fake for Opera
|
||||||
|
var z = xpathExp.replace(/[\/]+/gi, "/").split('/');
|
||||||
|
var obj = null;
|
||||||
|
var i = 1;
|
||||||
|
|
||||||
|
if (!z.length)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
if (z[0] == ".")
|
||||||
|
obj=[docObj]; else if (z[0] == ""){
|
||||||
|
obj=(this.xmlDoc.responseXML||this.xmlDoc).getElementsByTagName(z[i].replace(/\[[^\]]*\]/g, ""));
|
||||||
|
i++;
|
||||||
|
} else
|
||||||
|
return [];
|
||||||
|
|
||||||
|
for (i; i < z.length; i++)obj=this._getAllNamedChilds(obj, z[i]);
|
||||||
|
|
||||||
|
if (z[i-1].indexOf("[") != -1)
|
||||||
|
obj=this._filterXPath(obj, z[i-1]);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtmlXMLLoaderObject.prototype._filterXPath=function(a, b){
|
||||||
|
var c = new Array();
|
||||||
|
var b = b.replace(/[^\[]*\[\@/g, "").replace(/[\[\]\@]*/g, "");
|
||||||
|
|
||||||
|
for (var i = 0; i < a.length; i++)
|
||||||
|
if (a[i].getAttribute(b))
|
||||||
|
c[c.length]=a[i];
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
dtmlXMLLoaderObject.prototype._getAllNamedChilds=function(a, b){
|
||||||
|
var c = new Array();
|
||||||
|
|
||||||
|
if (_isKHTML)
|
||||||
|
b=b.toUpperCase();
|
||||||
|
|
||||||
|
for (var i = 0; i < a.length; i++)for (var j = 0; j < a[i].childNodes.length; j++){
|
||||||
|
if (_isKHTML){
|
||||||
|
if (a[i].childNodes[j].tagName&&a[i].childNodes[j].tagName.toUpperCase() == b)
|
||||||
|
c[c.length]=a[i].childNodes[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (a[i].childNodes[j].tagName == b)
|
||||||
|
c[c.length]=a[i].childNodes[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
function dhtmlXHeir(a, b){
|
||||||
|
for (var c in b)
|
||||||
|
if (typeof (b[c]) == "function")
|
||||||
|
a[c]=b[c];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
function dhtmlxEvent(el, event, handler){
|
||||||
|
if (el.addEventListener)
|
||||||
|
el.addEventListener(event, handler, false);
|
||||||
|
|
||||||
|
else if (el.attachEvent)
|
||||||
|
el.attachEvent("on"+event, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============= XSL Extension ===================================
|
||||||
|
|
||||||
|
dtmlXMLLoaderObject.prototype.xslDoc=null;
|
||||||
|
dtmlXMLLoaderObject.prototype.setXSLParamValue=function(paramName, paramValue, xslDoc){
|
||||||
|
if (!xslDoc)
|
||||||
|
xslDoc=this.xslDoc
|
||||||
|
|
||||||
|
if (xslDoc.responseXML)
|
||||||
|
xslDoc=xslDoc.responseXML;
|
||||||
|
var item =
|
||||||
|
this.doXPath("/xsl:stylesheet/xsl:variable[@name='"+paramName+"']", xslDoc,
|
||||||
|
"http:/\/www.w3.org/1999/XSL/Transform", "single");
|
||||||
|
|
||||||
|
if (item != null)
|
||||||
|
item.firstChild.nodeValue=paramValue
|
||||||
|
}
|
||||||
|
dtmlXMLLoaderObject.prototype.doXSLTransToObject=function(xslDoc, xmlDoc){
|
||||||
|
if (!xslDoc)
|
||||||
|
xslDoc=this.xslDoc;
|
||||||
|
|
||||||
|
if (xslDoc.responseXML)
|
||||||
|
xslDoc=xslDoc.responseXML
|
||||||
|
|
||||||
|
if (!xmlDoc)
|
||||||
|
xmlDoc=this.xmlDoc;
|
||||||
|
|
||||||
|
if (xmlDoc.responseXML)
|
||||||
|
xmlDoc=xmlDoc.responseXML
|
||||||
|
|
||||||
|
//MOzilla
|
||||||
|
if (!_isIE){
|
||||||
|
if (!this.XSLProcessor){
|
||||||
|
this.XSLProcessor=new XSLTProcessor();
|
||||||
|
this.XSLProcessor.importStylesheet(xslDoc);
|
||||||
|
}
|
||||||
|
var result = this.XSLProcessor.transformToDocument(xmlDoc);
|
||||||
|
} else {
|
||||||
|
var result = new ActiveXObject("Msxml2.DOMDocument.3.0");
|
||||||
|
try{
|
||||||
|
xmlDoc.transformNodeToObject(xslDoc, result);
|
||||||
|
}catch(e){
|
||||||
|
result = xmlDoc.transformNode(xslDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtmlXMLLoaderObject.prototype.doXSLTransToString=function(xslDoc, xmlDoc){
|
||||||
|
var res = this.doXSLTransToObject(xslDoc, xmlDoc);
|
||||||
|
if(typeof(res)=="string")
|
||||||
|
return res;
|
||||||
|
return this.doSerialization(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtmlXMLLoaderObject.prototype.doSerialization=function(xmlDoc){
|
||||||
|
if (!xmlDoc)
|
||||||
|
xmlDoc=this.xmlDoc;
|
||||||
|
if (xmlDoc.responseXML)
|
||||||
|
xmlDoc=xmlDoc.responseXML
|
||||||
|
if (!_isIE){
|
||||||
|
var xmlSerializer = new XMLSerializer();
|
||||||
|
return xmlSerializer.serializeToString(xmlDoc);
|
||||||
|
} else
|
||||||
|
return xmlDoc.xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc:
|
||||||
|
* @type: private
|
||||||
|
*/
|
||||||
|
dhtmlxEventable=function(obj){
|
||||||
|
obj.attachEvent=function(name, catcher, callObj){
|
||||||
|
name='ev_'+name.toLowerCase();
|
||||||
|
if (!this[name])
|
||||||
|
this[name]=new this.eventCatcher(callObj||this);
|
||||||
|
|
||||||
|
return(name+':'+this[name].addEvent(catcher)); //return ID (event name & event ID)
|
||||||
|
}
|
||||||
|
obj.callEvent=function(name, arg0){
|
||||||
|
name='ev_'+name.toLowerCase();
|
||||||
|
if (this[name])
|
||||||
|
return this[name].apply(this, arg0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
obj.checkEvent=function(name){
|
||||||
|
return (!!this['ev_'+name.toLowerCase()])
|
||||||
|
}
|
||||||
|
obj.eventCatcher=function(obj){
|
||||||
|
var dhx_catch = [];
|
||||||
|
var z = function(){
|
||||||
|
var res = true;
|
||||||
|
for (var i = 0; i < dhx_catch.length; i++){
|
||||||
|
if (dhx_catch[i] != null){
|
||||||
|
var zr = dhx_catch[i].apply(obj, arguments);
|
||||||
|
res=res&&zr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
z.addEvent=function(ev){
|
||||||
|
if (typeof (ev) != "function")
|
||||||
|
ev=eval(ev);
|
||||||
|
if (ev)
|
||||||
|
return dhx_catch.push(ev)-1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
z.removeEvent=function(id){
|
||||||
|
dhx_catch[id]=null;
|
||||||
|
}
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
obj.detachEvent=function(id){
|
||||||
|
if (id != false){
|
||||||
|
var list = id.split(':'); //get EventName and ID
|
||||||
|
this[list[0]].removeEvent(list[1]); //remove event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.detachAllEvents = function(){
|
||||||
|
for (var name in this){
|
||||||
|
if (name.indexOf("ev_")==0)
|
||||||
|
delete this[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2190
phpgwapi/js/egw_action/test/js/dhtmlxmenu.js
Normal file
18
phpgwapi/js/egw_action/test/js/dhtmlxmenu_ext.js
Normal file
360
phpgwapi/js/egw_action/test/skins/dhtmlxmenu_egw.css
Normal file
@ -0,0 +1,360 @@
|
|||||||
|
/*
|
||||||
|
"DHX SKYBLUE" DHTMLXMENU SKIN 2009
|
||||||
|
*/
|
||||||
|
/****************************************************************************************************************************************************/
|
||||||
|
/* TOPLEVEL */
|
||||||
|
.dhtmlxMenu_egw_Middle {
|
||||||
|
position: relative;
|
||||||
|
height: 20px;
|
||||||
|
border: none;
|
||||||
|
background-image: url("../imgs/dhxmenu_topbg.gif");
|
||||||
|
background-position: top;
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
-moz-user-select: none;
|
||||||
|
padding: 0px 7px;
|
||||||
|
}
|
||||||
|
.dhtmlx_winviewport.dhtmlx_skin_egw div.dhtmlxMenu_egw_Middle,
|
||||||
|
.dhxlayout_fullscreened div.dhtmlxMenu_egw_Middle,
|
||||||
|
.dhx_tabbar_zone.dhx_tabbar_zone_egw div.dhtmlxMenu_egw_Middle,
|
||||||
|
.dhx_acc_base_egw div.dhtmlxMenu_egw_Middle,
|
||||||
|
.dhtmlx_skin_egw div.dhtmlx_window_active div.dhtmlxMenu_egw_Middle,
|
||||||
|
.dhtmlx_skin_egw div.dhtmlx_window_inactive div.dhtmlxMenu_egw_Middle,
|
||||||
|
table.dhtmlxLayoutPolyContainer_egw td.dhtmlxLayoutSinglePoly div.dhtmlxMenu_egw_Middle {
|
||||||
|
height: 29px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dhtmlxMenu_egw_Middle.dir_left div.align_left {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.dhtmlxMenu_egw_Middle.dir_left div.align_right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* menu in window, layout, accordion have bottom margin 9px */
|
||||||
|
/*
|
||||||
|
.dhtmlx_skin_egw div.dhtmlx_wins_body_inner div.dhtmlxMenu_egw_Middle,
|
||||||
|
table.dhtmlxLayoutPolyContainer_egw td.dhtmlxLayoutSinglePoly div.dhtmlxMenu_egw_Middle {
|
||||||
|
height: 27px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.dhtmlxMenu_egw_Layout, .dhtmlxMenu_egw_Accordion {
|
||||||
|
border-bottom: #cedce8 1px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dhtmlxMenu_egw_Middle.in_acccell, .dhtmlxMenu_egw_Middle.in_layoutcell {
|
||||||
|
height: 27px;
|
||||||
|
background-image: url("../imgs/dhxmenu_egw/dhxmenu_bg_acccell.gif");
|
||||||
|
background-position: top;
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/****************************************************************************************************************************************************/
|
||||||
|
/* TOPLEVEL ITEMS */
|
||||||
|
/* toplevel item normal */
|
||||||
|
div.dhtmlxMenu_egw_TopLevel_Item_Normal,
|
||||||
|
div.dhtmlxMenu_egw_TopLevel_Item_Disabled,
|
||||||
|
div.dhtmlxMenu_egw_TopLevel_Item_Selected {
|
||||||
|
position: relative;
|
||||||
|
float: left;
|
||||||
|
font-family: Arial, Helvetica, Sans-Serif;
|
||||||
|
font-size: 10pt;
|
||||||
|
font-weight: normal;
|
||||||
|
cursor: default;
|
||||||
|
white-space: nowrap;
|
||||||
|
-moz-user-select: none;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin: 0px 2px 100px 0px;
|
||||||
|
padding: 0px 5px;
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_TopLevel_Item_Normal {
|
||||||
|
border-left: #ececec 1px solid !important;
|
||||||
|
border-right: #ececec 1px solid !important;
|
||||||
|
/*
|
||||||
|
background-image:url("../imgs/dhxmenu_egw/dhxmenu_topsepbg.gif");
|
||||||
|
background-position:right center;
|
||||||
|
background-repeat:no-repeat;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
/* toplevel item disabled */
|
||||||
|
div.dhtmlxMenu_egw_TopLevel_Item_Disabled {
|
||||||
|
color: #999999 !important;
|
||||||
|
}
|
||||||
|
/* toplevel item selected (over) */
|
||||||
|
div.dhtmlxMenu_egw_TopLevel_Item_Selected {
|
||||||
|
background-image: url("../imgs/dhxmenu_topselbg.gif");
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
border-left: #ffffff 1px solid !important;
|
||||||
|
border-right: #ffffff 1px solid !important;
|
||||||
|
}
|
||||||
|
/* toplevel separator */
|
||||||
|
.dhtmlxMenu_egw_Middle div.top_sep {
|
||||||
|
font-size: 1px;
|
||||||
|
cursor: default;
|
||||||
|
-moz-user-select: none;
|
||||||
|
background-image: url("../imgs/dhxmenu_topsepbg.gif");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: top center;
|
||||||
|
height: 20px;
|
||||||
|
position: relative;
|
||||||
|
float: left;
|
||||||
|
width: 3px;
|
||||||
|
margin-left: 0px;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
/* top level image */
|
||||||
|
.dhtmlxMenu_egw_Middle img.dhtmlxMenu_TopLevel_Item_Icon {
|
||||||
|
float: left;
|
||||||
|
margin: 2px 2px 0px 2px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* top level text*/
|
||||||
|
div.dhtmlxMenu_egw_TopLevel_Item_Normal div.top_level_text,
|
||||||
|
div.dhtmlxMenu_egw_TopLevel_Item_Disabled div.top_level_text,
|
||||||
|
div.dhtmlxMenu_egw_TopLevel_Item_Selected div.top_level_text {
|
||||||
|
float: left;
|
||||||
|
margin-left: 2px;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
/****************************************************************************************************************************************************/
|
||||||
|
/* SUBLEVEL POLYGON */
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon {
|
||||||
|
position: absolute;
|
||||||
|
background-color: #ececec;
|
||||||
|
border: #aaaaaa 1px outset;
|
||||||
|
overflow: hidden;
|
||||||
|
padding-top: 1px;
|
||||||
|
padding-bottom: 1px;
|
||||||
|
box-shadow: 2px 3px 13px #666666;
|
||||||
|
-moz-box-shadow: 2px 3px 13px #666666;
|
||||||
|
-webkit-box-shadow: 2px 3px 13px #666666;
|
||||||
|
-khtml-box-shadow: 2px 3px 13px #666666;
|
||||||
|
filter:progid:DXImageTransform.Microsoft.Shadow(color=#999999,direction=135,strength=3);
|
||||||
|
-moz-user-select: none;
|
||||||
|
|
||||||
|
}
|
||||||
|
/* IE6 sublevel undercover fix */
|
||||||
|
iframe.dhtmlxMenu_IE6CoverFix_egw {
|
||||||
|
position: absolute;
|
||||||
|
border: none;
|
||||||
|
background: #000000;
|
||||||
|
filter: alpha(opacity=100);
|
||||||
|
}
|
||||||
|
/****************************************************************************************************************************************************/
|
||||||
|
/* SUBLEVEL ITEMS */
|
||||||
|
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl {
|
||||||
|
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl tr.sub_item {
|
||||||
|
height: 28px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl tr.sub_item_dis {
|
||||||
|
height: 28px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl tr.sub_item_selected {
|
||||||
|
height: 28px;
|
||||||
|
cursor: default;
|
||||||
|
background-image: url("../imgs/dhxmenu_subselbg.png");
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl td.sub_item_icon {
|
||||||
|
width: 24px;
|
||||||
|
text-align: left;
|
||||||
|
-moz-user-select: none;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl td.sub_item_icon img.sub_icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
margin: 6px 2px 2px 8px;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl td.sub_item_text {
|
||||||
|
vertical-align: middle;
|
||||||
|
padding-left: 4px;
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl div.sub_item_text {
|
||||||
|
font-family: Arial, Helvetica, Sans-Serif;
|
||||||
|
font-size: 10pt;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #000000;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl tr.sub_item_dis div.sub_item_text {
|
||||||
|
color: #999999 !important;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl td.sub_item_hk {
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl td.sub_item_hk div.sub_item_hk {
|
||||||
|
font-family: Arial, Helvetica, Sans-Serif;
|
||||||
|
font-size: 10px;
|
||||||
|
color: #a4bed4;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl tr.sub_item_selected td.sub_item_hk div.sub_item_hk {
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl tr.sub_item_dis td.sub_item_hk div.sub_item_hk {
|
||||||
|
color: #cecece !important;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon tr.sub_sep {
|
||||||
|
height: 3px;
|
||||||
|
font-size: 1px;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon div.sub_sep {
|
||||||
|
font-size: 1px;
|
||||||
|
border-top: 2px #eeeeee groove;
|
||||||
|
cursor: default;
|
||||||
|
height: 2px;
|
||||||
|
}
|
||||||
|
/****************************************************************************************************************************************************/
|
||||||
|
/* SUBLEVEL ARROWS */
|
||||||
|
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl div.complex_arrow {
|
||||||
|
width: 7px;
|
||||||
|
height: 24px;
|
||||||
|
background-image: url("../imgs/dhxmenu_subar.gif");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 0px 0px;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl tr.sub_item_selected div.complex_arrow {
|
||||||
|
background-position: -7px 0px !important;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl tr.sub_item_dis div.complex_arrow {
|
||||||
|
background-position: -14px 0px !important;
|
||||||
|
}
|
||||||
|
/****************************************************************************************************************************************************/
|
||||||
|
/* LOADING ICON */
|
||||||
|
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl div.complex_arrow_loading {
|
||||||
|
width: 7px;
|
||||||
|
height: 24px;
|
||||||
|
background-image: url("../imgs/dhxmenu_loader.gif");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
/****************************************************************************************************************************************************/
|
||||||
|
/* UP/DOWN OVERFLOW ARROWS */
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Arrow {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
text-align: center;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Arrow div.dhtmlxMenu_SubLevelArea_Arrow_Icon {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
width: 29px;
|
||||||
|
height: 8px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-image: url("../imgs/dhxmenu_upar.gif");
|
||||||
|
}
|
||||||
|
/* up arrows */
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_ArrowUp,
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_ArrowUp_Over,
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_ArrowUp_Disabled {
|
||||||
|
position: absolute;
|
||||||
|
height: 20px;
|
||||||
|
font-size: 1px;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_ArrowUp div.dhtmlxMenu_SubLevelArea_Arrow_Icon { background-position: -87px 0px; }
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_ArrowUp_Over div.dhtmlxMenu_SubLevelArea_Arrow_Icon { background-position: -116px 0px; }
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_ArrowUp_Disabled div.dhtmlxMenu_SubLevelArea_Arrow_Icon { background-position: -145px 0px; }
|
||||||
|
/* down arrows */
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_ArrowDown,
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_ArrowDown_Over,
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_ArrowDown_Disabled {
|
||||||
|
position: absolute;
|
||||||
|
height: 20px;
|
||||||
|
font-size: 1px;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_ArrowDown div.dhtmlxMenu_SubLevelArea_Arrow_Icon { background-position: 0px 0px; }
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_ArrowDown_Over div.dhtmlxMenu_SubLevelArea_Arrow_Icon { background-position: -29px 0px; }
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_ArrowDown_Disabled div.dhtmlxMenu_SubLevelArea_Arrow_Icon { background-position: -58px 0px; }
|
||||||
|
/****************************************************************************************************************************************************/
|
||||||
|
/* TOPLEVEL TEXT */
|
||||||
|
.dhtmlxMenu_egw_Middle div.dhtmlxMenu_TopLevel_Text_right {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
vertical-align: middle;
|
||||||
|
left: none;
|
||||||
|
right: 8px;
|
||||||
|
font-family: Arial, Helvetica, Sans-Serif;
|
||||||
|
font-size: 10pt;
|
||||||
|
color: #000000;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.dhtmlxMenu_egw_Middle div.dhtmlxMenu_TopLevel_Text_left {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
vertical-align: middle;
|
||||||
|
right: none;
|
||||||
|
left: 8px;
|
||||||
|
font-family: Arial, Helvetica, Sans-Serif;
|
||||||
|
font-size: 10pt;
|
||||||
|
color: #000000;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
/****************************************************************************************************************************************************/
|
||||||
|
/* ITEM'S CHECKS, RADIOS */
|
||||||
|
/* sublevel */
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl div.sub_icon {
|
||||||
|
float: left;
|
||||||
|
margin: 2px 4px 2px 8px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
background-position: top right;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-image: url("../imgs/dhxmenu_chrd.gif");
|
||||||
|
}
|
||||||
|
/* checkboxes */
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl div.sub_icon.chbx_0 {
|
||||||
|
background-position: 0px 0px !important;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl div.sub_icon.chbx_1 {
|
||||||
|
background-position: -18px 0px !important;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl tr.sub_item_dis div.sub_icon.chbx_0 {
|
||||||
|
background-position: -36px 0px !important;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl tr.sub_item_dis div.sub_icon.chbx_1 {
|
||||||
|
background-position: -54px 0px !important;
|
||||||
|
}
|
||||||
|
/* radios */
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl div.sub_icon.rdbt_0 {
|
||||||
|
background-position: -72px 0px !important;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl div.sub_icon.rdbt_1 {
|
||||||
|
background-position: -90px 0px !important;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl tr.sub_item_dis div.sub_icon.rdbt_0 {
|
||||||
|
background-position: -108px 0px !important;
|
||||||
|
}
|
||||||
|
div.dhtmlxMenu_egw_SubLevelArea_Polygon table.dhtmlxMebu_SubLevelArea_Tbl tr.sub_item_dis div.sub_icon.rdbt_1 {
|
||||||
|
background-position: -126px 0px !important;
|
||||||
|
}
|
187
phpgwapi/js/egw_action/test/test_menu.html
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test page for the egw menu</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="skins/dhtmlxmenu_egw.css">
|
||||||
|
<script src="js/dhtmlxcommon.js"></script>
|
||||||
|
<script src="js/dhtmlxmenu.js"></script>
|
||||||
|
<script src="js/dhtmlxmenu_ext.js"></script>
|
||||||
|
<script src="../egw_menu.js"></script>
|
||||||
|
<script src="../egw_menu_dhtmlx.js"></script>
|
||||||
|
</head>
|
||||||
|
<body style="width:95%; height:95%; font-family: sans-serif">
|
||||||
|
<script>
|
||||||
|
|
||||||
|
var menu = new egwMenu();
|
||||||
|
|
||||||
|
menu.loadStructure(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "file_menu",
|
||||||
|
"caption": "Test1",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "file_open",
|
||||||
|
"caption": "Open file...",
|
||||||
|
"iconUrl": "imgs/folder.png",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "-"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "file_save",
|
||||||
|
"caption": "Save",
|
||||||
|
"enabled": false,
|
||||||
|
"iconUrl": "imgs/disk.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "file_save_as",
|
||||||
|
"caption": "Save as..."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "-"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Recently loaded",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "rec1",
|
||||||
|
"caption": "file1.txt",
|
||||||
|
"iconUrl": "imgs/page.png",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "rec2",
|
||||||
|
"caption": "file2.txt",
|
||||||
|
"iconUrl": "imgs/page.png",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "rec3",
|
||||||
|
"caption": "file3.txt",
|
||||||
|
"iconUrl": "imgs/page.png",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Test2",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"caption": "Use speed enhancer",
|
||||||
|
"checkbox": true,
|
||||||
|
"groupIndex": 0,
|
||||||
|
"checked": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Reduce memory impact",
|
||||||
|
"checkbox": true,
|
||||||
|
"groupIndex": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Test3",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"caption": "Option1.1",
|
||||||
|
"checkbox": true,
|
||||||
|
"groupIndex": 1,
|
||||||
|
"checked": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Option1.2",
|
||||||
|
"checkbox": true,
|
||||||
|
"groupIndex": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Option1.3",
|
||||||
|
"checkbox": true,
|
||||||
|
"groupIndex": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "-"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Option2.1",
|
||||||
|
"checkbox": true,
|
||||||
|
"groupIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Option2.2",
|
||||||
|
"checkbox": true,
|
||||||
|
"groupIndex": 2,
|
||||||
|
"checked": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Option2.3",
|
||||||
|
"checkbox": true,
|
||||||
|
"groupIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "-"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Extra options",
|
||||||
|
"iconUrl": "imgs/wrench.png",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"caption": "Option1.1",
|
||||||
|
"checkbox": true,
|
||||||
|
"groupIndex": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Option1.2",
|
||||||
|
"checkbox": true,
|
||||||
|
"groupIndex": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "Option1.3",
|
||||||
|
"checkbox": true,
|
||||||
|
"groupIndex": 1,
|
||||||
|
"checked": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
menu.setGlobalOnClick(alertCaption);
|
||||||
|
|
||||||
|
function alertCaption(elem)
|
||||||
|
{
|
||||||
|
if (console && console.log)
|
||||||
|
console.log(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPageXY(event)
|
||||||
|
{
|
||||||
|
// document.body.scrollTop does not work in IE
|
||||||
|
var scrollTop = document.body.scrollTop ? document.body.scrollTop :
|
||||||
|
document.documentElement.scrollTop;
|
||||||
|
var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft :
|
||||||
|
document.documentElement.scrollLeft;
|
||||||
|
|
||||||
|
// hide the menu first to avoid an "up-then-over" visual effect
|
||||||
|
return {'x': (event.clientX + scrollLeft), 'y': (event.clientY + scrollTop)};
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.oncontextmenu = function(e)
|
||||||
|
{
|
||||||
|
if (!e)
|
||||||
|
e = window.event;
|
||||||
|
|
||||||
|
var pos = getPageXY(e);
|
||||||
|
show_menu(pos.x, pos.y);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function show_menu(_x, _y)
|
||||||
|
{
|
||||||
|
menu.showAt(_x, _y);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|