egroupware/phpgwapi/js/egw_action/egw_action_popup.js

528 lines
12 KiB
JavaScript
Raw Normal View History

2011-02-26 20:21:55 +01:00
/**
* 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$
*/
if (typeof window._egwActionClasses == "undefined")
window._egwActionClasses = {}
_egwActionClasses["popup"] = {
"actionConstructor": egwPopupAction,
"implementation": getPopupImplementation
}
function egwPopupAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple)
{
var action = new egwAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple);
action.type = "popup";
action.canHaveChildren = ["popup"];
2011-02-26 20:21:55 +01:00
action["default"] = false;
action.order = 0;
action.group = 0;
action.hint = false;
action.checkbox = false;
action.radioGroup = 0;
action.checked = false;
action.shortcut = null;
2011-02-26 20:21:55 +01:00
action.set_default = function(_value) {
action["default"] = _value;
}
action.set_order = function(_value) {
action.order = _value;
}
action.set_group = function(_value) {
action.group = _value;
}
action.set_hint = function(_value) {
action.hint = _value;
}
// If true, the action will be rendered as checkbox
action.set_checkbox = function(_value) {
action.checkbox = _value;
}
action.set_checked = function(_value) {
action.checked = _value;
}
// If radioGroup is >0 and the element is a checkbox, radioGroup specifies
// the group of radio buttons this one belongs to
action.set_radioGroup = function(_value) {
action.radioGroup = _value;
}
action.set_shortcut = function(_value) {
2011-06-19 12:48:51 +02:00
if (_value)
{
2011-06-19 12:48:51 +02:00
var sc = {
"keyCode": -1,
"shift": false,
"ctrl": false,
"alt": false
}
if (typeof _value == "object" && _value.keyCode != "undefined" &&
_value.caption != "undefined")
2011-06-19 12:48:51 +02:00
{
sc.keyCode = _value.keyCode;
sc.caption = _value.caption;
2011-06-19 12:48:51 +02:00
sc.shift = (typeof _value.shift == "undefined") ? false : _value.shift;
sc.ctrl = (typeof _value.ctrl == "undefined") ? false : _value.ctrl;
sc.alt = (typeof _value.alt == "undefined") ? false : _value.alt;
}
2011-06-19 12:48:51 +02:00
this.shortcut = sc;
}
else
{
2011-06-19 12:48:51 +02:00
this.shortcut = false;
}
}
2011-02-26 20:21:55 +01:00
return action;
}
var
_popupActionImpl = null;
function getPopupImplementation()
{
if (!_popupActionImpl)
{
_popupActionImpl = new egwPopupActionImplementation();
}
return _popupActionImpl
}
function egwPopupActionImplementation()
{
var ai = new egwActionImplementation();
ai.type = "popup";
/**
* Registers the handler for the default action
*/
ai._registerDefault = function(_node, _callback, _context) {
var defaultHandler = function(e) {
if (typeof document.selection != "undefined" && typeof document.selection.empty != "undefined")
{
document.selection.empty();
}
else if( typeof window.getSelection != "undefined")
{
var sel = window.getSelection();
sel.removeAllRanges();
}
2011-02-26 20:21:55 +01:00
_callback.call(_context, "default", ai);
return false;
}
if (egwIsMobile()) {
* jQuery: changed $ to $j to work around mootools use in Joomla templates and other js code in imported projects required to change $ --> $j: phpgwapi/* jdots/* etemplate/* stylite/* felamimail/* admin/* news_admin/* projectmanager/* importexport/* infolog/* ranking/* required, but not automatic: importexport/setup/etemplates.inc.php phpgwapi/js/jquery/* negative, not to touch or revert later: phpgwapi/inc/savant2/Savant2/Savant2_Compiler_basic.php: '(\$(.+))' => 'print $1', phpgwapi/js/dhtmlxtree/libCompiler/core.js sitemgr/* phpfreechat/* gallery/* activesync/include/smb.php: '^\tIPC\\\$(.*)[ ]+IPC' => 'skip', etemplate/inc/class.bo_merge.inc.php: if ($this->table_plugins && preg_match_all('/\\$\\$table\\/([A-Za-z0-9_]+)\\$\\$(.*?)\\$\\$endtable\\$\\$/s',$content,$matches,PREG_SET_ORDER)) find phpgwapi jdots etemplate stylite felamimail admin news_admin projectmanager importexport infolog ranking \ \( -name '*.php' -o -name '*.js' \) -exec grep -q '\$(' {} \; -print \ -exec sed -i '' 's|\$(|$j(|g' {} \; svn revert phpgwapi/inc/savant2/Savant2/Savant2_Compiler_basic.php phpgwapi/js/dhtmlxtree/libCompiler/core.js \ importexport/setup/etemplates.inc.php phpgwapi/js/jquery/jquery.js etemplate/inc/class.bo_merge.inc.php additional changes: phpgwapi/js/jquery/jquery.js: window.$ --> window.$j phpgwapi/js/egw_json.js:291 this.request = $j.ajax({url: this.url, jdots/templates/jdots/head.tpl:59 $j(document).ready(function() { phpgwapi/js/egw_action/egw_grid_view.js: $.browser --> $j.browser importexport/setup/etemplates.inc.php: etemplate editor importexport.wizard_basic_export_csv.choose_fields onclick of check icon changed phpgwapi/js/egw_action/tests/*.html phpgwapi/js/egw_action/tests/js/jquery.js: window.$ --> window.$j
2011-07-03 11:00:36 +02:00
$j(_node).bind('click', defaultHandler);
} else {
_node.ondblclick = defaultHandler;
}
}
ai._getDefaultLink = function(_links) {
var defaultAction = null;
for (var k in _links)
{
if (_links[k].actionObj["default"] && _links[k].enabled)
{
defaultAction = _links[k].actionObj;
break;
}
}
return defaultAction;
}
2011-06-19 12:48:51 +02:00
ai._searchShortcut = function (_key, _objs, _links) {
for (var i = 0; i < _objs.length; i++)
{
var sc = _objs[i].shortcut;
if (sc && sc.keyCode == _key.keyCode && sc.shift == _key.shift &&
sc.ctrl == _key.ctrl && sc.alt == _key.alt &&
_objs[i].type == "popup" && (typeof _links[_objs[i].id] == "undefined" ||
_links[_objs[i].id].enabled))
{
return _objs[i];
}
var obj = this._searchShortcut(_key, _objs[i].children, _links);
if (obj) {
return obj;
}
}
}
ai._searchShortcutInLinks = function(_key, _links) {
var objs = [];
for (var k in _links)
{
if (_links[k].enabled)
{
objs.push(_links[k].actionObj);
}
}
return ai._searchShortcut(_key, objs, _links);
}
/**
* Handles a key press
*/
ai._handleKeyPress = function(_key, _selected, _links, _target) {
2011-06-19 12:48:51 +02:00
// Handle the default
if (_key.keyCode == EGW_KEY_ENTER && !_key.ctrl && !_key.shift && !_key.alt) {
var defaultAction = this._getDefaultLink(_links);
if (defaultAction)
{
defaultAction.execute(_selected);
2011-06-19 12:48:51 +02:00
return true;
}
}
2011-06-19 12:48:51 +02:00
// Check whether the given shortcut exists
var obj = this._searchShortcutInLinks(_key, _links);
if (obj)
{
obj.execute(_selected);
return true;
}
return false;
}
/**
* Registers the handler for the context menu
*/
ai._registerContext = function(_node, _callback, _context) {
var contextHandler = function(e) {
//Obtain the event object
if (!e)
{
e = window.event;
}
2011-02-26 20:21:55 +01:00
if (_egw_active_menu)
{
_egw_active_menu.hide()
}
else
{
_xy = ai._getPageXY(e);
_callback.call(_context, _xy, ai);
}
2011-02-26 20:21:55 +01:00
e.cancelBubble = true;
if (e.stopPropagation)
{
e.stopPropagation();
2011-02-26 20:21:55 +01:00
}
return false;
}
if (egwIsMobile()) {
* jQuery: changed $ to $j to work around mootools use in Joomla templates and other js code in imported projects required to change $ --> $j: phpgwapi/* jdots/* etemplate/* stylite/* felamimail/* admin/* news_admin/* projectmanager/* importexport/* infolog/* ranking/* required, but not automatic: importexport/setup/etemplates.inc.php phpgwapi/js/jquery/* negative, not to touch or revert later: phpgwapi/inc/savant2/Savant2/Savant2_Compiler_basic.php: '(\$(.+))' => 'print $1', phpgwapi/js/dhtmlxtree/libCompiler/core.js sitemgr/* phpfreechat/* gallery/* activesync/include/smb.php: '^\tIPC\\\$(.*)[ ]+IPC' => 'skip', etemplate/inc/class.bo_merge.inc.php: if ($this->table_plugins && preg_match_all('/\\$\\$table\\/([A-Za-z0-9_]+)\\$\\$(.*?)\\$\\$endtable\\$\\$/s',$content,$matches,PREG_SET_ORDER)) find phpgwapi jdots etemplate stylite felamimail admin news_admin projectmanager importexport infolog ranking \ \( -name '*.php' -o -name '*.js' \) -exec grep -q '\$(' {} \; -print \ -exec sed -i '' 's|\$(|$j(|g' {} \; svn revert phpgwapi/inc/savant2/Savant2/Savant2_Compiler_basic.php phpgwapi/js/dhtmlxtree/libCompiler/core.js \ importexport/setup/etemplates.inc.php phpgwapi/js/jquery/jquery.js etemplate/inc/class.bo_merge.inc.php additional changes: phpgwapi/js/jquery/jquery.js: window.$ --> window.$j phpgwapi/js/egw_json.js:291 this.request = $j.ajax({url: this.url, jdots/templates/jdots/head.tpl:59 $j(document).ready(function() { phpgwapi/js/egw_action/egw_grid_view.js: $.browser --> $j.browser importexport/setup/etemplates.inc.php: etemplate editor importexport.wizard_basic_export_csv.choose_fields onclick of check icon changed phpgwapi/js/egw_action/tests/*.html phpgwapi/js/egw_action/tests/js/jquery.js: window.$ --> window.$j
2011-07-03 11:00:36 +02:00
$j(_node).bind('taphold', contextHandler);
} else {
_node.oncontextmenu = contextHandler;
}
}
ai.doRegisterAction = function(_aoi, _callback, _context)
{
var node = _aoi.getDOMNode();
if (node)
{
this._registerDefault(node, _callback, _context);
this._registerContext(node, _callback, _context);
return true;
2011-02-26 20:21:55 +01:00
}
return false;
2011-02-26 20:21:55 +01:00
}
ai.doUnregisterAction = function(_aoi)
{
//
}
/**
* Builds the context menu and shows it at the given position/DOM-Node.
*/
ai.doExecuteImplementation = function(_context, _selected, _links, _target)
2011-02-26 20:21:55 +01:00
{
if (typeof _target == "undefined")
{
_target = null;
}
if (typeof _context == "object" && typeof _context.keyEvent == "object")
{
return ai._handleKeyPress(_context.keyEvent, _selected, _links, _target);
}
else if (_context != "default")
{
//Check whether the context has the posx and posy parameters
if ((typeof _context.posx != "number" || typeof _context.posy != "number") &&
typeof _context.id != "undefined")
{
// Calculate context menu position from the given DOM-Node
var node = _context;
* jQuery: changed $ to $j to work around mootools use in Joomla templates and other js code in imported projects required to change $ --> $j: phpgwapi/* jdots/* etemplate/* stylite/* felamimail/* admin/* news_admin/* projectmanager/* importexport/* infolog/* ranking/* required, but not automatic: importexport/setup/etemplates.inc.php phpgwapi/js/jquery/* negative, not to touch or revert later: phpgwapi/inc/savant2/Savant2/Savant2_Compiler_basic.php: '(\$(.+))' => 'print $1', phpgwapi/js/dhtmlxtree/libCompiler/core.js sitemgr/* phpfreechat/* gallery/* activesync/include/smb.php: '^\tIPC\\\$(.*)[ ]+IPC' => 'skip', etemplate/inc/class.bo_merge.inc.php: if ($this->table_plugins && preg_match_all('/\\$\\$table\\/([A-Za-z0-9_]+)\\$\\$(.*?)\\$\\$endtable\\$\\$/s',$content,$matches,PREG_SET_ORDER)) find phpgwapi jdots etemplate stylite felamimail admin news_admin projectmanager importexport infolog ranking \ \( -name '*.php' -o -name '*.js' \) -exec grep -q '\$(' {} \; -print \ -exec sed -i '' 's|\$(|$j(|g' {} \; svn revert phpgwapi/inc/savant2/Savant2/Savant2_Compiler_basic.php phpgwapi/js/dhtmlxtree/libCompiler/core.js \ importexport/setup/etemplates.inc.php phpgwapi/js/jquery/jquery.js etemplate/inc/class.bo_merge.inc.php additional changes: phpgwapi/js/jquery/jquery.js: window.$ --> window.$j phpgwapi/js/egw_json.js:291 this.request = $j.ajax({url: this.url, jdots/templates/jdots/head.tpl:59 $j(document).ready(function() { phpgwapi/js/egw_action/egw_grid_view.js: $.browser --> $j.browser importexport/setup/etemplates.inc.php: etemplate editor importexport.wizard_basic_export_csv.choose_fields onclick of check icon changed phpgwapi/js/egw_action/tests/*.html phpgwapi/js/egw_action/tests/js/jquery.js: window.$ --> window.$j
2011-07-03 11:00:36 +02:00
x = $j(node).offset().left;
y = $j(node).offset().top;
_context = {"posx": x, "posy": y}
}
var menu = ai._buildMenu(_links, _selected, _target);
menu.showAt(_context.posx, _context.posy);
return true;
}
else
{
var defaultAction = ai._getDefaultLink(_links);
if (defaultAction)
{
defaultAction.execute(_selected);
}
}
return false;
2011-02-26 20:21:55 +01:00
}
/**
* Groups and sorts the given action tree layer
*/
ai._groupLayers = function(_layer, _links, _parentGroup)
2011-02-26 20:21:55 +01:00
{
// Seperate the multiple groups out of the layer
2011-02-26 20:21:55 +01:00
var link_groups = {};
for (var i = 0; i < _layer.children.length; i++)
2011-02-26 20:21:55 +01:00
{
var actionObj = _layer.children[i].action;
2011-02-26 20:21:55 +01:00
// Check whether the link group of the current element already exists,
// if not, create the group
var grp = actionObj.group;
2011-02-26 20:21:55 +01:00
if (typeof link_groups[grp] == "undefined")
{
link_groups[grp] = [];
}
// Search the link data for this action object if none is found,
// visible and enabled = true is assumed
var visible = true;
var enabled = true;
if (typeof _links[actionObj.id] != "undefined")
{
visible = _links[actionObj.id].visible;
enabled = _links[actionObj.id].enabled;
}
2011-02-26 20:21:55 +01:00
// Insert the element in order
var inserted = false;
var groupObj = {
"actionObj": actionObj,
"visible": visible,
"enabled": enabled,
"groups": []
};
for (var j = 0; j < link_groups[grp].length; j++)
2011-02-26 20:21:55 +01:00
{
var elem = link_groups[grp][j].actionObj;
if (elem.order > actionObj.order)
2011-02-26 20:21:55 +01:00
{
inserted = true;
link_groups[grp].splice(j, 0, groupObj);
2011-02-26 20:21:55 +01:00
break;
}
}
// If the object hasn't been inserted, add it to the end of the list
if (!inserted)
{
link_groups[grp].push(groupObj);
}
// If this child itself has children, group those elements too
if (_layer.children[i].children.length > 0)
{
this._groupLayers(_layer.children[i], _links, groupObj);
2011-02-26 20:21:55 +01:00
}
}
// Transform the link_groups object into an sorted array
2011-02-26 20:21:55 +01:00
var groups = [];
for (var k in link_groups)
{
2011-02-26 20:21:55 +01:00
groups.push({"grp": k, "links": link_groups[k]});
}
2011-02-26 20:21:55 +01:00
groups.sort(function(a, b) {
var ia = parseInt(a.grp);
var ib = parseInt(b.grp);
return (ia > ib) ? 1 : ((ia < ib) ? -1 : 0);
2011-02-26 20:21:55 +01:00
});
// Append the groups to the groups2 array
var groups2 = [];
for (var i = 0; i < groups.length; i++)
{
groups2.push(groups[i].links);
}
_parentGroup.groups = groups2;
}
/**
* Build the menu layers
*/
ai._buildMenuLayer = function(_menu, _groups, _selected, _enabled, _target)
{
var firstGroup = true;
for (var i = 0; i < _groups.length; i++)
2011-02-26 20:21:55 +01:00
{
var firstElem = true;
2011-02-26 20:21:55 +01:00
// Go through the elements of each group
for (var j = 0; j < _groups[i].length; j++)
2011-02-26 20:21:55 +01:00
{
var link = _groups[i][j];
2011-02-26 20:21:55 +01:00
if (link.visible)
{
// Add an seperator after each group
if (!firstGroup && firstElem)
{
_menu.addItem("", "-");
}
firstElem = false;
var item = _menu.addItem(link.actionObj.id, link.actionObj.caption,
2011-02-26 20:21:55 +01:00
link.actionObj.iconUrl);
item["default"] = link.actionObj["default"];
// As this code is also used when a drag-drop popup menu is built,
// we have to perform this check
if (link.actionObj.type == "popup")
{
item.set_hint(link.actionObj.hint);
item.set_checkbox(link.actionObj.checkbox);
item.set_checked(link.actionObj.checked);
item.set_groupIndex(link.actionObj.radioGroup);
2011-06-19 12:48:51 +02:00
if (link.actionObj.shortcut)
{
var sc = link.actionObj.shortcut;
item.set_shortcutCaption(sc.caption);
2011-06-19 12:48:51 +02:00
}
}
item.set_data(link.actionObj);
if (link.enabled && _enabled)
2011-02-26 20:21:55 +01:00
{
item.set_onClick(function(elem) {
// Copy the "checked" state
if (typeof elem.data.checked != "undefined")
{
elem.data.checked = elem.checked;
}
elem.data.execute(_selected, _target);
if (typeof elem.data.checkbox != "undefined" && elem.data.checkbox)
{
return elem.data.checked;
}
2011-02-26 20:21:55 +01:00
});
}
else
{
item.set_enabled(false);
}
// Append the parent groups
if (link.groups)
{
this._buildMenuLayer(item, link.groups, _selected, link.enabled, _target);
}
2011-02-26 20:21:55 +01:00
}
}
firstGroup = firstGroup && firstElem;
2011-02-26 20:21:55 +01:00
}
}
/**
* Builds the context menu from the given action links
*/
ai._buildMenu = function(_links, _selected, _target)
{
// Build a tree containing all actions
var tree = {"root": []};
for (var k in _links)
{
_links[k].actionObj.appendToTree(tree);
}
// We need the dummy object container in order to pass the array by
// reference
var groups = {
"groups": []
};
if (tree.root.length > 0)
{
// Sort every action object layer by the given sort position and grouping
this._groupLayers(tree.root[0], _links, groups);
}
var menu = new egwMenu();
// Build the menu layers
this._buildMenuLayer(menu, groups.groups, _selected, true, _target);
2011-02-26 20:21:55 +01:00
return menu;
}
ai._getPageXY = 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;
return {'posx': (event.clientX + scrollLeft), 'posy': (event.clientY + scrollTop)};
}
2011-02-26 20:21:55 +01:00
return ai;
}