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.

This commit is contained in:
Andreas Stöckel 2011-02-23 18:24:16 +00:00
parent 75ba2fc475
commit e2c9cd49cc
23 changed files with 4720 additions and 0 deletions

View 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;
}

View 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];
}
}
}
}

View 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;
}

View 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();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 B

View 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];
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View 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;
}

View 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>