From 1f754d485b030210b73e4902e86bb31aba29db88 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Tue, 26 Mar 2013 21:19:17 +0000 Subject: [PATCH] Tie egw_action system into etemplate widgets - allows actions on widgets --- etemplate/js/et2_core_DOMWidget.js | 140 +++++++++++++++++++++++- etemplate/js/et2_extension_nextmatch.js | 10 ++ etemplate/js/et2_widget_tree.js | 29 +---- 3 files changed, 152 insertions(+), 27 deletions(-) diff --git a/etemplate/js/et2_core_DOMWidget.js b/etemplate/js/et2_core_DOMWidget.js index 30f7c63418..630e77debd 100644 --- a/etemplate/js/et2_core_DOMWidget.js +++ b/etemplate/js/et2_core_DOMWidget.js @@ -15,6 +15,7 @@ /*egw:uses et2_core_interfaces; et2_core_widget; + /phpgwapi/js/egw_action/egw_action.js; */ /** @@ -60,7 +61,13 @@ var et2_DOMWidget = et2_widget.extend(et2_IDOMNode, { "type": "string", "default": et2_no_init, "description": "Insert into the target DOM node instead of the normal location" - } + }, + "actions": { + "name": "Actions list", + "type": "any", + "default": et2_no_init, + "description": "List of egw actions that can be done on the widget. This includes context menu, drag and drop. TODO: Link to action documentation" + }, }, /** @@ -345,6 +352,100 @@ var et2_DOMWidget = et2_widget.extend(et2_IDOMNode, { { $j(node).css("overflow", _value); } + }, + + /** + * Set Actions on the widget + * + * Each action is defined as an object: + * + * move: { + * type: "drop", + * acceptedTypes: "mail", + * icon: "move", + * caption: "Move to" + * onExecute: javascript:mail_move" + * } + * + * This will turn the widget into a drop target for "mail" drag types. When "mail" drag types are dropped, + * the global function mail_move(egwAction action, egwActionObject sender) will be called. The ID of the + * dragged "mail" will be in sender.id, some information about the sender will be in sender.context. The + * etemplate2 widget involved can typically be found in action.parent.data.widget, so your handler + * can operate in the widget context easily. The location varies depending on your action though. It + * might be action.parent.parent.data.widget + * + * To customise how the actions are handled for a particular widget, override _link_actions(). It handles + * the more widget-specific parts. + * + * @param Object {ID: {attributes..}+} map of egw action information + * @see etemplate/inc/class.etemplate_widget_nextmatch->egw_actions() + */ + set_actions: function(actions) + { + if(this.id == "" || typeof this.id == "undefined") + { + this.egw().debug("warn", "Widget should have an ID if you want actions",this); + return; + } + + // Initialize the action manager and add some actions to it + var gam = egw_getAppActionManager(); + this._actionManager = gam.addAction("actionManager", this.id); + // ActionManager wants an array + var parsed_actions = []; + if(typeof actions == "object" && actions) + { + for(var key in actions) + { + actions[key].id = key; + if(typeof actions[key].icon != "undefined" && actions[key].icon) + { + actions[key].iconUrl = this.egw().image(actions[key].icon); + } + parsed_actions.push(actions[key]); + } + } + else + { + parsed_actions = actions; + } + this._actionManager.updateActions(parsed_actions); + + // Put a reference to the widget into the action stuff, so we can + // easily get back to widget context from the action handler + this._actionManager.data = {widget: this}; + + // Link the actions to the DOM + this._link_actions(parsed_actions); + }, + + /** + * Link the actions to the DOM nodes / widget bits. + * + */ + _link_actions: function(parsed_actions) + { + // Get the top level element for the tree + var objectManager = egw_getAppObjectManager(true); + var widget_object = objectManager.getObjectById(this.id); + if (widget_object == null) { + // Add a new container to the object manager which will hold the widget + // objects + widget_object = objectManager.addObject(this.id, new et2_action_object_impl(this)); + } + + // Delete all old objects + widget_object.clear(); + + // Go over the widget & add links - this is where we decide which actions are + // 'allowed' for this widget at this time + var action_links = []; + for(var i = 0; i < parsed_actions.length; i++) + { + action_links.push(parsed_actions[i].id); + } + + widget_object.updateActionLinks(action_links); } }); @@ -554,4 +655,41 @@ var et2_surroundingsMgr = Class.extend({ }); +/** + * The egw_action system requires an egwActionObjectInterface Interface implementation + * to tie actions to DOM nodes. This one can be used by any widget. + * + * The class extension is different than the widgets + * + */ +function et2_action_object_impl(widget) +{ + var aoi = new egwActionObjectInterface(); + aoi.doGetDOMNode = function() { + return widget.getDOMNode(); + }; +// _outerCall may be used to determine, whether the state change has been +// evoked from the outside and the stateChangeCallback has to be called +// or not. + aoi.doSetState = function(_state, _outerCall) { + }; + +// The doTiggerEvent function may be overritten by the aoi if it wants to +// support certain action implementation specific events like EGW_AI_DRAG_OVER +// or EGW_AI_DRAG_OUT + aoi.doTriggerEvent = function(_event, _data) { + switch(_event) + { + case EGW_AI_DRAG_OVER: + $j(this.node).addClass("ui-state-active"); + break; + case EGW_AI_DRAG_OUT: + $j(this.node).removeClass("ui-state-active"); + break; + } + }; + + + return aoi; +}; diff --git a/etemplate/js/et2_extension_nextmatch.js b/etemplate/js/et2_extension_nextmatch.js index 67f89e1899..282f9e67af 100644 --- a/etemplate/js/et2_extension_nextmatch.js +++ b/etemplate/js/et2_extension_nextmatch.js @@ -1024,6 +1024,11 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput], { } }, + /** + * Actions are handled by the controller, so ignore these + */ + set_actions: function(actions) {}, + getDOMNode: function(_sender) { if (_sender == this) { @@ -1119,6 +1124,11 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, { this._createHeader(); }, + /** + * Actions are handled by the controller, so ignore these + */ + set_actions: function(actions) {}, + _createHeader: function() { var self = this; diff --git a/etemplate/js/et2_widget_tree.js b/etemplate/js/et2_widget_tree.js index 7c165d90f6..1adad82490 100644 --- a/etemplate/js/et2_widget_tree.js +++ b/etemplate/js/et2_widget_tree.js @@ -302,33 +302,10 @@ var et2_tree = et2_inputWidget.extend({ * the global function mail_move(egwAction action, egwActionObject sender) will be called. The ID of the * dragged "mail" will be in sender.id, some information about the sender will be in sender.context. * - * @param Object {ID: {attributes..}+} map of egw action information + * @param Array[ {ID, attributes..}+] array of egw action information - this is different from what is passed in to + * set_actions, which takes a more human-friendly Object map. */ - set_actions: function(actions) { - // TODO: This goes in the parent, when we're ready to have general actions on anything // - // Initialize the action manager and add some actions to it - var gam = egw_getAppActionManager(); - this._actionManager = gam.addAction("actionManager", this.id); - // ActionManager wants an array - var parsed_actions = []; - if(typeof actions == "object" && actions) - { - for(var key in actions) - { - actions[key].id = key; - if(typeof actions[key].icon != "undefined" && actions[key].icon) - { - actions[key].iconUrl = this.egw().image(actions[key].icon); - } - parsed_actions.push(actions[key]); - } - } - else - { - parsed_actions = actions; - } - this._actionManager.updateActions(parsed_actions); - //// + _link_actions: function(parsed_actions) { // Get the top level element for the tree var objectManager = egw_getAppObjectManager(true);