2011-03-24 18:06:44 +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
|
|
|
|
*/
|
|
|
|
|
2011-08-03 16:04:30 +02:00
|
|
|
/*egw:uses
|
|
|
|
egw_action;
|
|
|
|
egw_action_common;
|
|
|
|
egw_action_popup;
|
2016-06-06 17:38:20 +02:00
|
|
|
vendor.bower-asset.jquery.dist.jquery;
|
2011-08-03 16:04:30 +02:00
|
|
|
*/
|
2011-03-24 18:06:44 +01:00
|
|
|
|
2021-06-08 14:11:59 +02:00
|
|
|
import {egwAction,egwActionImplementation} from "./egw_action.js";
|
2021-07-06 12:41:16 +02:00
|
|
|
import {getPopupImplementation} from "./egw_action_popup.js";
|
|
|
|
import {EGW_AI_DRAG_OUT, EGW_AI_DRAG_OVER, EGW_AO_EXEC_THIS} from "./egw_action_constants.js";
|
2021-06-08 14:11:59 +02:00
|
|
|
|
2011-03-24 18:06:44 +01:00
|
|
|
/**
|
|
|
|
* Register the drag and drop handlers
|
|
|
|
*/
|
|
|
|
if (typeof window._egwActionClasses == "undefined")
|
2014-02-25 16:02:49 +01:00
|
|
|
window._egwActionClasses = {};
|
2011-03-24 18:06:44 +01:00
|
|
|
_egwActionClasses["drag"] = {
|
|
|
|
"actionConstructor": egwDragAction,
|
|
|
|
"implementation": getDragImplementation
|
2014-02-25 16:02:49 +01:00
|
|
|
};
|
2011-03-24 18:06:44 +01:00
|
|
|
_egwActionClasses["drop"] = {
|
|
|
|
"actionConstructor": egwDropAction,
|
|
|
|
"implementation": getDropImplementation
|
2014-02-25 16:02:49 +01:00
|
|
|
};
|
2011-03-24 18:06:44 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The egwDragAction class overwrites the egwAction class and adds the new
|
|
|
|
* "dragType" propery. The "onExecute" event of the drag action will be called
|
|
|
|
* whenever dragging starts. The onExecute JS handler should return the
|
|
|
|
* drag-drop helper object - otherwise an default helper will be generated.
|
2014-02-25 16:02:49 +01:00
|
|
|
*
|
|
|
|
* @param {egwAction} _id
|
|
|
|
* @param {string} _handler
|
|
|
|
* @param {string} _caption
|
|
|
|
* @param {string} _icon
|
|
|
|
* @param {(string|function)} _onExecute
|
|
|
|
* @param {bool} _allowOnMultiple
|
|
|
|
* @returns {egwDragAction}
|
2011-03-24 18:06:44 +01:00
|
|
|
*/
|
2021-06-08 14:11:59 +02:00
|
|
|
export function egwDragAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple)
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
|
|
|
var action = new egwAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple);
|
|
|
|
|
|
|
|
action.type = "drag";
|
|
|
|
action.dragType = "default";
|
|
|
|
action.hideOnDisabled = true;
|
|
|
|
|
|
|
|
action.set_dragType = function(_value) {
|
|
|
|
action.dragType = _value;
|
2014-02-25 16:02:49 +01:00
|
|
|
};
|
2011-03-24 18:06:44 +01:00
|
|
|
|
|
|
|
return action;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var
|
|
|
|
_dragActionImpl = null;
|
|
|
|
|
2021-06-08 14:11:59 +02:00
|
|
|
export function getDragImplementation()
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
|
|
|
if (!_dragActionImpl)
|
|
|
|
{
|
|
|
|
_dragActionImpl = new egwDragActionImplementation();
|
|
|
|
}
|
2014-02-25 16:02:49 +01:00
|
|
|
return _dragActionImpl;
|
2011-03-24 18:06:44 +01:00
|
|
|
}
|
|
|
|
|
2021-06-08 14:11:59 +02:00
|
|
|
export function egwDragActionImplementation()
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
|
|
|
var ai = new egwActionImplementation();
|
|
|
|
|
|
|
|
ai.type = "drag";
|
|
|
|
|
|
|
|
ai.helper = null;
|
|
|
|
ai.ddTypes = [];
|
|
|
|
ai.selected = [];
|
2014-10-24 14:19:16 +02:00
|
|
|
|
2014-10-17 18:34:14 +02:00
|
|
|
// Define default helper DOM
|
2014-10-20 13:41:59 +02:00
|
|
|
// default helper also can be called later in application code in order to customization
|
2014-10-17 18:34:14 +02:00
|
|
|
ai.defaultDDHelper = function (_selected)
|
|
|
|
{
|
|
|
|
// Table containing clone of rows
|
2016-06-02 16:51:15 +02:00
|
|
|
var table = jQuery(document.createElement("table")).addClass('egwGridView_grid et2_egw_action_ddHelper_row');
|
2014-10-17 18:34:14 +02:00
|
|
|
// tr element to use as last row to show lable more ...
|
2016-06-02 16:51:15 +02:00
|
|
|
var moreRow = jQuery(document.createElement('tr')).addClass('et2_egw_action_ddHelper_moreRow');
|
2014-10-17 18:34:14 +02:00
|
|
|
// Main div helper container
|
2016-06-02 16:51:15 +02:00
|
|
|
var div = jQuery(document.createElement("div")).append(table);
|
2014-10-24 14:19:16 +02:00
|
|
|
|
2014-10-17 18:34:14 +02:00
|
|
|
var rows = [];
|
|
|
|
// Maximum number of rows to show
|
|
|
|
var maxRows = 3;
|
2014-10-21 16:31:18 +02:00
|
|
|
// item label
|
|
|
|
var itemLabel = egw.lang(egw.link_get_registry(egw.app_name(),_selected.length > 1?'entries':'entry')||egw.app_name());
|
2014-10-24 14:19:16 +02:00
|
|
|
|
2014-10-17 18:34:14 +02:00
|
|
|
var index = 0;
|
2018-07-25 11:22:04 +02:00
|
|
|
|
|
|
|
// Take select all into account when counting number of rows, because they may not be
|
|
|
|
// in _selected object
|
2018-07-25 14:11:45 +02:00
|
|
|
var pseudoNumRows = (_selected[0] && _selected[0]._context && _selected[0]._context._selectionMgr &&
|
|
|
|
_selected[0]._context._selectionMgr._selectAll) ?
|
|
|
|
_selected[0]._context._selectionMgr._total : _selected.length;
|
2018-07-25 11:22:04 +02:00
|
|
|
|
2014-10-17 18:34:14 +02:00
|
|
|
for (var i = 0; i < _selected.length;i++)
|
|
|
|
{
|
2016-06-02 16:51:15 +02:00
|
|
|
var row = jQuery(_selected[i].iface.getDOMNode()).clone();
|
2014-10-17 18:34:14 +02:00
|
|
|
if (row)
|
|
|
|
{
|
|
|
|
rows.push(row);
|
|
|
|
table.append(row);
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
if (index == maxRows)
|
|
|
|
{
|
2014-10-20 13:41:59 +02:00
|
|
|
// Lable to show number of items
|
2016-06-02 16:51:15 +02:00
|
|
|
var spanCnt = jQuery(document.createElement('span'))
|
2014-10-20 13:41:59 +02:00
|
|
|
.addClass('et2_egw_action_ddHelper_itemsCnt')
|
|
|
|
.appendTo(div);
|
2014-10-24 14:19:16 +02:00
|
|
|
|
2018-07-25 11:22:04 +02:00
|
|
|
spanCnt.text(pseudoNumRows +' '+ itemLabel);
|
2014-10-21 16:31:18 +02:00
|
|
|
// Number of not shown rows
|
2018-07-25 11:22:04 +02:00
|
|
|
var restRows = pseudoNumRows - maxRows;
|
2014-10-20 13:41:59 +02:00
|
|
|
if (restRows)
|
|
|
|
{
|
2020-04-16 19:34:10 +02:00
|
|
|
moreRow.text(egw.lang("%1 more %2 selected ...", (pseudoNumRows - maxRows), itemLabel));
|
2014-10-20 13:41:59 +02:00
|
|
|
}
|
2014-10-17 18:34:14 +02:00
|
|
|
table.append(moreRow);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-10-24 14:19:16 +02:00
|
|
|
|
2016-06-02 16:51:15 +02:00
|
|
|
var text = jQuery(document.createElement('div')).addClass('et2_egw_action_ddHelper_tip');
|
2014-10-17 18:34:14 +02:00
|
|
|
div.append(text);
|
2011-03-24 18:06:44 +01:00
|
|
|
|
2014-10-21 15:35:19 +02:00
|
|
|
// Add notice of Ctrl key, if supported
|
2014-10-17 18:34:14 +02:00
|
|
|
if('draggable' in document.createElement('span') &&
|
2014-10-21 16:31:18 +02:00
|
|
|
navigator && navigator.userAgent.indexOf('Chrome') >= 0 && egw.app_name() == 'filemanager') // currently only filemanager supports drag out
|
2014-10-17 18:34:14 +02:00
|
|
|
{
|
2014-10-24 14:19:16 +02:00
|
|
|
var key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ?
|
|
|
|
egw.lang('Alt') : egw.lang('Command ⌘');
|
|
|
|
text.text(egw.lang('Hold [%1] and [%2] key to drag %3 to your desktop', key, egw.lang('Shift ⇧'), itemLabel));
|
2014-10-17 18:34:14 +02:00
|
|
|
}
|
2014-10-20 13:41:59 +02:00
|
|
|
// Final html DOM return as helper structor
|
2014-10-17 18:34:14 +02:00
|
|
|
return div;
|
2014-10-23 18:23:25 +02:00
|
|
|
};
|
2014-10-24 14:19:16 +02:00
|
|
|
|
2011-03-24 18:06:44 +01:00
|
|
|
ai.doRegisterAction = function(_aoi, _callback, _context)
|
|
|
|
{
|
|
|
|
var node = _aoi.getDOMNode();
|
|
|
|
|
|
|
|
if (node)
|
|
|
|
{
|
2011-03-25 14:12:24 +01:00
|
|
|
// Prevent selection
|
|
|
|
node.onselectstart = function () {
|
|
|
|
return false;
|
|
|
|
};
|
2013-08-29 00:31:14 +02:00
|
|
|
if (!(window.FileReader && 'draggable' in document.createElement('span')) )
|
|
|
|
{
|
|
|
|
// No DnD support
|
|
|
|
return;
|
|
|
|
}
|
2014-02-25 16:02:49 +01:00
|
|
|
|
2013-08-29 00:31:14 +02:00
|
|
|
// It shouldn't be so hard to get the action...
|
|
|
|
var action = null;
|
|
|
|
var groups = _context.getActionImplementationGroups();
|
|
|
|
if(!groups.drag) return;
|
|
|
|
for(var i = 0; i < groups.drag.length; i++)
|
|
|
|
{
|
|
|
|
// dragType 'file' says it can be dragged as a file
|
2014-10-20 17:03:31 +02:00
|
|
|
if(groups.drag[i].link.actionObj.dragType == 'file' || groups.drag[i].link.actionObj.dragType.indexOf('file') > -1)
|
2013-08-29 00:31:14 +02:00
|
|
|
{
|
|
|
|
action = groups.drag[i].link.actionObj;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(action)
|
|
|
|
{
|
|
|
|
/**
|
2014-10-21 15:35:19 +02:00
|
|
|
* We found an action with dragType 'file', so by holding Ctrl
|
2013-08-29 00:31:14 +02:00
|
|
|
* key & dragging, user can drag from browser to system.
|
|
|
|
* The global data store must provide a full, absolute URL in 'download_url'
|
|
|
|
* and a mime in 'mime'.
|
2014-02-25 16:02:49 +01:00
|
|
|
*
|
2013-08-29 00:31:14 +02:00
|
|
|
* Unfortunately, Native DnD to drag the file conflicts with jQueryUI draggable,
|
|
|
|
* which handles all the other DnD actions. We get around this by:
|
2014-10-21 15:35:19 +02:00
|
|
|
* 1. Require the user indicate a file drag with Ctrl key
|
2013-08-29 00:31:14 +02:00
|
|
|
* 2. Disable jQueryUI draggable, then turn on native draggable attribute
|
2014-02-25 16:02:49 +01:00
|
|
|
* This way we can at least toggle which one is operating, so they
|
2013-08-29 00:31:14 +02:00
|
|
|
* both work alternately if not together.
|
|
|
|
*/
|
2014-10-24 13:15:33 +02:00
|
|
|
// Native DnD - Doesn't play nice with jQueryUI Sortable
|
|
|
|
// Tell jQuery to include this property
|
|
|
|
jQuery.event.props.push('dataTransfer');
|
2014-02-25 16:02:49 +01:00
|
|
|
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery(node).off("mousedown")
|
2014-10-24 13:15:33 +02:00
|
|
|
.on("mousedown", function(event) {
|
|
|
|
var dragOut = _context.isDragOut(event);
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery(this).attr("draggable", dragOut? "true" : "");
|
|
|
|
jQuery(node).draggable("option","disabled",dragOut);
|
2014-10-24 13:15:33 +02:00
|
|
|
if (dragOut)
|
2014-10-21 15:35:19 +02:00
|
|
|
{
|
2014-10-24 13:15:33 +02:00
|
|
|
// Disabling draggable adds some UI classes, but we don't care so remove them
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery(node).removeClass("ui-draggable-disabled ui-state-disabled");
|
2014-10-24 14:19:16 +02:00
|
|
|
|
2014-10-21 15:35:19 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-10-24 13:15:33 +02:00
|
|
|
if (_context.isSelection(event))
|
|
|
|
{
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery(node).draggable("disable");
|
2014-10-24 13:15:33 +02:00
|
|
|
// Disabling draggable adds some UI classes, but we don't care so remove them
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery(node).removeClass("ui-draggable-disabled ui-state-disabled");
|
2014-10-24 13:15:33 +02:00
|
|
|
}
|
|
|
|
else if(event.which != 3)
|
|
|
|
{
|
|
|
|
document.getSelection().removeAllRanges();
|
|
|
|
}
|
|
|
|
if(!(dragOut) || !this.addEventListener) return;
|
2013-08-29 00:31:14 +02:00
|
|
|
}
|
2014-10-24 13:15:33 +02:00
|
|
|
})
|
|
|
|
.on ("mouseup", function (event){
|
|
|
|
if (_context.isSelection(event))
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery(node).draggable("enable");
|
2014-10-24 13:15:33 +02:00
|
|
|
})
|
|
|
|
.on("dragstart", function(event) {
|
|
|
|
if(_context.isSelection(event)) return;
|
|
|
|
if(event.dataTransfer == null) {
|
|
|
|
return;
|
2013-08-29 00:31:14 +02:00
|
|
|
}
|
2014-10-24 13:15:33 +02:00
|
|
|
event.dataTransfer.effectAllowed="copy";
|
2014-02-25 16:02:49 +01:00
|
|
|
|
2014-10-24 13:15:33 +02:00
|
|
|
// Get all selected
|
|
|
|
// Multiples aren't supported by event.dataTransfer, yet, so
|
|
|
|
// select only the row they clicked on.
|
|
|
|
// var selected = _context.getSelectedLinks('drag');
|
|
|
|
var selected = [_context];
|
|
|
|
_context.parent.setAllSelected(false);
|
|
|
|
_context.setSelected(true);
|
|
|
|
|
|
|
|
// Set file data
|
|
|
|
for(var i = 0; i < selected.length; i++)
|
|
|
|
{
|
|
|
|
var data = selected[i].data || egw.dataGetUIDdata(selected[i].id).data || {};
|
|
|
|
if(data && data.mime && data.download_url)
|
2014-10-23 18:23:25 +02:00
|
|
|
{
|
2014-10-24 13:15:33 +02:00
|
|
|
var url = data.download_url;
|
|
|
|
|
|
|
|
// NEED an absolute URL
|
|
|
|
if (url[0] == '/') url = egw.link(url);
|
|
|
|
// egw.link adds the webserver, but that might not be an absolute URL - try again
|
|
|
|
if (url[0] == '/') url = window.location.origin+url;
|
|
|
|
|
|
|
|
// Unfortunately, dragging files is currently only supported by Chrome
|
|
|
|
if(navigator && navigator.userAgent.indexOf('Chrome'))
|
|
|
|
{
|
|
|
|
event.dataTransfer.setData("DownloadURL", data.mime+':'+data.name+':'+url);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Include URL as a fallback
|
|
|
|
event.dataTransfer.setData("text/uri-list", url);
|
|
|
|
}
|
2014-10-23 18:23:25 +02:00
|
|
|
}
|
|
|
|
}
|
2014-10-24 13:15:33 +02:00
|
|
|
if(event.dataTransfer.types.length == 0)
|
|
|
|
{
|
|
|
|
// No file data? Abort: drag does nothing
|
|
|
|
event.preventDefault();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create drag icon
|
|
|
|
_callback.call(_context, _context, ai);
|
|
|
|
// Drag icon must be visible for setDragImage() - we'll remove it on drag
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery("body").append(ai.helper);
|
2014-10-24 13:15:33 +02:00
|
|
|
event.dataTransfer.setDragImage(ai.helper[0],-12,-12);
|
|
|
|
})
|
|
|
|
.on("drag", function(e) {
|
|
|
|
// Remove the helper, it has been copied into the dataTransfer object now
|
|
|
|
// Hopefully user didn't notice it...
|
|
|
|
if(e.dataTransfer != null)
|
|
|
|
{
|
|
|
|
ai.helper.remove();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Use Ctrl key in order to select content
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery(node).off("mousedown")
|
2014-10-24 13:15:33 +02:00
|
|
|
.on({
|
|
|
|
mousedown: function(event){
|
|
|
|
if (_context.isSelection(event)){
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery(node).draggable("disable");
|
2014-10-24 13:15:33 +02:00
|
|
|
// Disabling draggable adds some UI classes, but we don't care so remove them
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery(node).removeClass("ui-draggable-disabled ui-state-disabled");
|
2014-10-24 13:15:33 +02:00
|
|
|
}
|
|
|
|
else if(event.which != 3)
|
|
|
|
{
|
|
|
|
document.getSelection().removeAllRanges();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
mouseup: function (){
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery(node).draggable("enable");
|
2015-01-15 17:06:00 +01:00
|
|
|
// Set cursor back to auto. Seems FF can't handle cursor reversion
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery('body').css({cursor:'auto'});
|
2014-10-24 13:15:33 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery(node).draggable(
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
|
|
|
"distance": 20,
|
|
|
|
"cursor": "move",
|
|
|
|
"cursorAt": { top: -12, left: -12 },
|
|
|
|
"helper": function(e) {
|
|
|
|
// The helper function is called before the start function
|
|
|
|
// is evoked. Call the given callback function. The callback
|
|
|
|
// function will gather the selected elements and action links
|
|
|
|
// and call the doExecuteImplementation function. This
|
|
|
|
// will call the onExecute function of the first action
|
|
|
|
// in order to obtain the helper object (stored in ai.helper)
|
|
|
|
// and the multiple dragDropTypes (ai.ddTypes)
|
|
|
|
_callback.call(_context, false, ai);
|
|
|
|
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery(node).data("ddTypes", ai.ddTypes);
|
|
|
|
jQuery(node).data("selected", ai.selected);
|
2011-03-24 18:06:44 +01:00
|
|
|
|
2011-03-25 14:12:24 +01:00
|
|
|
if (ai.helper)
|
|
|
|
{
|
2014-10-17 18:34:14 +02:00
|
|
|
// Add a basic class to the helper in order to standardize the background layout
|
|
|
|
ai.helper.addClass('et2_egw_action_ddHelper');
|
2014-10-24 14:19:16 +02:00
|
|
|
|
2011-03-25 14:12:24 +01:00
|
|
|
// Append the helper object to the body element - this
|
|
|
|
// fixes a bug in IE: If the element isn't inserted into
|
|
|
|
// the DOM-tree jquery appends it to the parent node.
|
|
|
|
// In case this is a table it doesn't work correctly
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery("body").append(ai.helper);
|
2011-03-25 14:12:24 +01:00
|
|
|
return ai.helper;
|
|
|
|
}
|
|
|
|
|
2011-03-24 18:06:44 +01:00
|
|
|
// Return an empty div if the helper dom node is not set
|
2016-06-02 16:51:15 +02:00
|
|
|
return ai.defaultDDHelper(ai.selected);//jQuery(document.createElement("div")).addClass('et2_egw_action_ddHelper');
|
2011-03-24 18:06:44 +01:00
|
|
|
},
|
|
|
|
"start": function(e) {
|
|
|
|
return ai.helper != null;
|
|
|
|
},
|
2014-10-16 16:41:30 +02:00
|
|
|
revert: function(valid)
|
|
|
|
{
|
|
|
|
var dTarget = this;
|
|
|
|
if (!valid)
|
|
|
|
{
|
|
|
|
// Tolerance value of pixels arround the draggable target
|
|
|
|
// to distinguish whether the action was intended for dragging or selecting content.
|
|
|
|
var tipTelorance = 10;
|
|
|
|
var helperTop = ai.helper.position().top;
|
2014-10-24 14:19:16 +02:00
|
|
|
|
|
|
|
if (helperTop >= dTarget.offset().top
|
2014-10-16 16:41:30 +02:00
|
|
|
&& helperTop <= (dTarget.height() + dTarget.offset().top) + tipTelorance)
|
|
|
|
{
|
2014-10-24 14:19:16 +02:00
|
|
|
var key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ?
|
|
|
|
egw.lang("Ctrl") : egw.lang("Command ⌘");
|
2016-03-29 14:49:05 +02:00
|
|
|
// We can not use Ctrl key for FF because FF has specific function
|
|
|
|
// for element selection bound to ctrl key and it would confilicts
|
|
|
|
// with our selection functionallity. Therefore, we use Alt key when
|
|
|
|
// it comes to FF regardless of OS.
|
|
|
|
if (window.navigator.userAgent.match(/firefox/i)) key = egw.lang("Alt");
|
2014-10-24 14:19:16 +02:00
|
|
|
egw.message(egw.lang('Hold [%1] key to select text eg. to copy it', key), 'info');
|
2014-10-16 16:41:30 +02:00
|
|
|
}
|
2016-03-29 14:49:05 +02:00
|
|
|
|
2014-10-16 16:41:30 +02:00
|
|
|
// Invalid target
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Valid target
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
},
|
2011-03-25 14:12:24 +01:00
|
|
|
// Solves problem with scroll position changing in the grid
|
2011-03-24 19:17:27 +01:00
|
|
|
// component
|
|
|
|
"refreshPositions": true,
|
2011-03-25 14:12:24 +01:00
|
|
|
"scroll": false,
|
2014-10-17 18:34:14 +02:00
|
|
|
//"containment": "document",
|
2015-12-16 16:40:17 +01:00
|
|
|
"iframeFix": true,
|
|
|
|
"delay": 300
|
2011-03-24 18:06:44 +01:00
|
|
|
}
|
|
|
|
);
|
2014-02-25 16:02:49 +01:00
|
|
|
|
2011-03-24 18:06:44 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2014-02-25 16:02:49 +01:00
|
|
|
};
|
2011-03-24 18:06:44 +01:00
|
|
|
|
|
|
|
ai.doUnregisterAction = function(_aoi)
|
|
|
|
{
|
2011-06-26 16:57:05 +02:00
|
|
|
var node = _aoi.getDOMNode();
|
|
|
|
|
2016-06-02 16:51:15 +02:00
|
|
|
if (node && jQuery(node).data("uiDraggable")){
|
|
|
|
jQuery(node).draggable("destroy");
|
2011-06-26 16:57:05 +02:00
|
|
|
}
|
2014-02-25 16:02:49 +01:00
|
|
|
};
|
2011-03-24 18:06:44 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds the context menu and shows it at the given position/DOM-Node.
|
2014-02-25 16:02:49 +01:00
|
|
|
*
|
|
|
|
* @param {string} _context
|
|
|
|
* @param {array} _selected
|
|
|
|
* @param {object} _links
|
2011-03-24 18:06:44 +01:00
|
|
|
*/
|
|
|
|
ai.doExecuteImplementation = function(_context, _selected, _links)
|
|
|
|
{
|
|
|
|
// Reset the helper object of the action implementation
|
|
|
|
this.helper = null;
|
|
|
|
var hasLink = false;
|
|
|
|
|
|
|
|
// Store the drag-drop types
|
|
|
|
this.ddTypes = [];
|
|
|
|
this.selected = _selected;
|
|
|
|
|
|
|
|
// Call the onExecute event of the first actionObject
|
2011-04-23 11:07:31 +02:00
|
|
|
for (var k in _links)
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
|
|
|
if (_links[k].visible)
|
|
|
|
{
|
|
|
|
hasLink = true;
|
|
|
|
|
|
|
|
// Only execute the following code if a JS function is registered
|
|
|
|
// for the action and this is the first action link
|
2011-05-07 13:22:23 +02:00
|
|
|
if (!this.helper && _links[k].actionObj.onExecute.hasHandler())
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
|
|
|
this.helper = _links[k].actionObj.execute(_selected);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Push the dragType of the associated action object onto the
|
|
|
|
// drag type list - this allows an element to support multiple
|
|
|
|
// drag/drop types.
|
2016-06-02 16:51:15 +02:00
|
|
|
var type = jQuery.isArray(_links[k].actionObj.dragType) ? _links[k].actionObj.dragType : [_links[k].actionObj.dragType];
|
2013-04-11 14:53:23 +02:00
|
|
|
for(var i = 0; i < type.length; i++)
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
2013-04-11 14:53:23 +02:00
|
|
|
if (this.ddTypes.indexOf(type[i]) == -1)
|
|
|
|
{
|
|
|
|
this.ddTypes.push(type[i]);
|
|
|
|
}
|
2011-03-24 18:06:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If no helper has been defined, create an default one
|
|
|
|
if (!this.helper && hasLink)
|
|
|
|
{
|
2014-10-17 18:34:14 +02:00
|
|
|
this.helper = ai.defaultDDHelper(_selected);
|
2011-03-24 18:06:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2014-02-25 16:02:49 +01:00
|
|
|
};
|
2011-03-24 18:06:44 +01:00
|
|
|
|
|
|
|
return ai;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The egwDropAction class overwrites the egwAction class and adds the "acceptedTypes"
|
2014-02-25 16:02:49 +01:00
|
|
|
* property. This array should contain all "dragTypes" the drop action is allowed to
|
|
|
|
*
|
|
|
|
* @param {egwAction} _id
|
|
|
|
* @param {string} _handler
|
|
|
|
* @param {string} _caption
|
|
|
|
* @param {string} _icon
|
|
|
|
* @param {(string|function)} _onExecute
|
|
|
|
* @param {bool} _allowOnMultiple
|
|
|
|
* @returns {egwDropAction}
|
2011-03-24 18:06:44 +01:00
|
|
|
*/
|
2021-06-08 14:11:59 +02:00
|
|
|
export function egwDropAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple)
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
|
|
|
var action = new egwAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple);
|
|
|
|
|
|
|
|
action.type = "drop";
|
|
|
|
action.acceptedTypes = ["default"];
|
|
|
|
action.canHaveChildren = ["drag","popup"];
|
|
|
|
action["default"] = false;
|
|
|
|
action.order = 0;
|
|
|
|
action.group = 0;
|
|
|
|
|
|
|
|
action.set_default = function(_value) {
|
|
|
|
action["default"] = _value;
|
2014-02-25 16:02:49 +01:00
|
|
|
};
|
2011-03-24 18:06:44 +01:00
|
|
|
|
|
|
|
action.set_order = function(_value) {
|
|
|
|
action.order = _value;
|
2014-02-25 16:02:49 +01:00
|
|
|
};
|
2011-03-24 18:06:44 +01:00
|
|
|
|
|
|
|
action.set_group = function(_value) {
|
|
|
|
action.group = _value;
|
2014-02-25 16:02:49 +01:00
|
|
|
};
|
2011-03-24 18:06:44 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The acceptType property allows strings as well as arrays - strings are
|
|
|
|
* automatically included in an array.
|
2014-02-25 16:02:49 +01:00
|
|
|
*
|
|
|
|
* @param {(string|array)} _value
|
2011-03-24 18:06:44 +01:00
|
|
|
*/
|
|
|
|
action.set_acceptedTypes = function(_value) {
|
|
|
|
if (_value instanceof Array)
|
|
|
|
{
|
|
|
|
action.acceptedTypes = _value;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
action.acceptedTypes = [_value];
|
|
|
|
}
|
2014-02-25 16:02:49 +01:00
|
|
|
};
|
2011-03-24 18:06:44 +01:00
|
|
|
|
|
|
|
return action;
|
|
|
|
}
|
|
|
|
|
|
|
|
var
|
|
|
|
_dropActionImpl = null;
|
|
|
|
|
2021-06-08 14:11:59 +02:00
|
|
|
export function getDropImplementation()
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
|
|
|
if (!_dropActionImpl)
|
|
|
|
{
|
|
|
|
_dropActionImpl = new egwDropActionImplementation();
|
|
|
|
}
|
2014-02-25 16:02:49 +01:00
|
|
|
return _dropActionImpl;
|
2011-03-24 18:06:44 +01:00
|
|
|
}
|
|
|
|
|
2021-06-08 14:11:59 +02:00
|
|
|
export function egwDropActionImplementation()
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
|
|
|
var ai = new egwActionImplementation();
|
|
|
|
|
|
|
|
ai.type = "drop";
|
|
|
|
|
|
|
|
ai.doRegisterAction = function(_aoi, _callback, _context)
|
|
|
|
{
|
|
|
|
var node = _aoi.getDOMNode();
|
2011-06-26 16:57:05 +02:00
|
|
|
var self = this;
|
2011-03-24 18:06:44 +01:00
|
|
|
|
|
|
|
if (node)
|
|
|
|
{
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery(node).droppable(
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
|
|
|
"accept": function(_draggable) {
|
2011-06-19 13:15:37 +02:00
|
|
|
if (typeof _draggable.data("ddTypes") != "undefined")
|
|
|
|
{
|
2011-06-26 16:57:05 +02:00
|
|
|
var accepted = self._fetchAccepted(
|
|
|
|
_callback.call(_context, "links", self, EGW_AO_EXEC_THIS));
|
2011-03-24 18:06:44 +01:00
|
|
|
|
2011-06-19 13:15:37 +02:00
|
|
|
// Check whether all drag types of the selected objects
|
|
|
|
// are accepted
|
|
|
|
var ddTypes = _draggable.data("ddTypes");
|
2011-03-24 18:06:44 +01:00
|
|
|
|
2011-06-19 13:15:37 +02:00
|
|
|
for (var i = 0; i < ddTypes.length; i++)
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
2013-04-11 14:53:23 +02:00
|
|
|
if (accepted.indexOf(ddTypes[i]) != -1)
|
2011-06-19 13:15:37 +02:00
|
|
|
{
|
2013-04-11 14:53:23 +02:00
|
|
|
return true;
|
2011-06-19 13:15:37 +02:00
|
|
|
}
|
2011-03-24 18:06:44 +01:00
|
|
|
}
|
|
|
|
|
2013-04-11 14:53:23 +02:00
|
|
|
return false;
|
2011-06-19 13:15:37 +02:00
|
|
|
}
|
2011-03-24 18:06:44 +01:00
|
|
|
},
|
|
|
|
"drop": function(event, ui) {
|
|
|
|
var draggable = ui.draggable;
|
|
|
|
var ddTypes = draggable.data("ddTypes");
|
|
|
|
var selected = draggable.data("selected");
|
|
|
|
|
2011-06-26 16:57:05 +02:00
|
|
|
var links = _callback.call(_context, "links", self, EGW_AO_EXEC_THIS);
|
2011-03-24 18:06:44 +01:00
|
|
|
|
|
|
|
// Disable all links which only accept types which are not
|
|
|
|
// inside ddTypes
|
2011-04-23 11:07:31 +02:00
|
|
|
for (var k in links)
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
|
|
|
var accepted = links[k].actionObj.acceptedTypes;
|
|
|
|
|
2014-02-25 16:02:49 +01:00
|
|
|
var enabled = false;
|
2011-03-24 18:06:44 +01:00
|
|
|
for (var i = 0; i < ddTypes.length; i++)
|
|
|
|
{
|
2013-04-11 14:53:23 +02:00
|
|
|
if (accepted.indexOf(ddTypes[i]) != -1)
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
2013-04-11 14:53:23 +02:00
|
|
|
enabled = true;
|
2014-02-25 16:02:49 +01:00
|
|
|
break;
|
2013-04-11 14:53:23 +02:00
|
|
|
}
|
|
|
|
}
|
2013-05-29 21:20:36 +02:00
|
|
|
// Check for allowing multiple selected
|
|
|
|
if(!links[k].actionObj.allowOnMultiple && selected.length > 1)
|
|
|
|
{
|
|
|
|
enabled = false;
|
|
|
|
}
|
2013-04-11 14:53:23 +02:00
|
|
|
if(!enabled)
|
|
|
|
{
|
|
|
|
links[k].enabled = false;
|
2014-02-25 16:02:49 +01:00
|
|
|
links[k].visible = !links[k].actionObj.hideOnDisabled;
|
2011-03-24 18:06:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether there is only one link
|
|
|
|
var cnt = 0;
|
|
|
|
var lnk = null;
|
2011-04-23 11:07:31 +02:00
|
|
|
for (var k in links)
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
|
|
|
if (links[k].enabled && links[k].visible)
|
|
|
|
{
|
|
|
|
lnk = links[k];
|
|
|
|
cnt += 1 + links[k].actionObj.children.length;
|
2013-05-29 21:20:36 +02:00
|
|
|
|
|
|
|
// Add ui, so you know what happened where
|
|
|
|
lnk.actionObj.ui = ui;
|
|
|
|
|
2011-03-24 18:06:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cnt == 1)
|
|
|
|
{
|
2011-07-21 12:50:33 +02:00
|
|
|
window.setTimeout(function() {
|
|
|
|
lnk.actionObj.execute(selected, _context);
|
|
|
|
},0);
|
2011-03-24 18:06:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cnt > 1)
|
|
|
|
{
|
|
|
|
// More than one drop action link is associated
|
|
|
|
// to the drop event - show those as a popup menu
|
|
|
|
// and let the user decide which one to use.
|
|
|
|
// This is possible as the popup and the popup action
|
|
|
|
// object and the drop action object share same
|
|
|
|
// set of properties.
|
|
|
|
var popup = getPopupImplementation();
|
2012-03-16 13:30:52 +01:00
|
|
|
var pos = popup._getPageXY(event.originalEvent);
|
2016-03-29 14:49:05 +02:00
|
|
|
|
2014-11-19 18:59:16 +01:00
|
|
|
// Don't add paste actions, this is a drop
|
|
|
|
popup.auto_paste = false;
|
2016-03-29 14:49:05 +02:00
|
|
|
|
2011-03-25 14:12:24 +01:00
|
|
|
window.setTimeout(function() {
|
|
|
|
popup.doExecuteImplementation(pos, selected, links,
|
|
|
|
_context);
|
2014-11-19 18:59:16 +01:00
|
|
|
// Reset, popup is reused
|
|
|
|
popup.auto_paste = true;
|
2011-03-25 14:12:24 +01:00
|
|
|
}, 0); // Timeout is needed to have it working in IE
|
2011-03-24 18:06:44 +01:00
|
|
|
}
|
2015-01-15 10:56:37 +01:00
|
|
|
// Set cursor back to auto. Seems FF can't handle cursor reversion
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery('body').css({cursor:'auto'});
|
2016-03-29 14:49:05 +02:00
|
|
|
|
2015-06-10 23:51:28 +02:00
|
|
|
_aoi.triggerEvent(EGW_AI_DRAG_OUT,{event: event,ui:ui});
|
2011-03-24 18:06:44 +01:00
|
|
|
},
|
2015-06-10 23:51:28 +02:00
|
|
|
"over": function(event, ui) {
|
|
|
|
_aoi.triggerEvent(EGW_AI_DRAG_OVER,{event: event,ui:ui});
|
2011-03-24 18:06:44 +01:00
|
|
|
},
|
2015-06-10 23:51:28 +02:00
|
|
|
"out": function(event,ui) {
|
|
|
|
_aoi.triggerEvent(EGW_AI_DRAG_OUT,{event: event,ui:ui});
|
2011-03-24 18:06:44 +01:00
|
|
|
},
|
2013-04-11 14:53:23 +02:00
|
|
|
"tolerance": "pointer",
|
2014-03-05 13:31:32 +01:00
|
|
|
hoverClass: "drop-hover",
|
2013-05-29 00:09:03 +02:00
|
|
|
// Greedy is for nested droppables - children consume the action
|
2014-02-25 16:02:49 +01:00
|
|
|
greedy: true
|
2011-03-24 18:06:44 +01:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2014-02-25 16:02:49 +01:00
|
|
|
};
|
2011-03-24 18:06:44 +01:00
|
|
|
|
|
|
|
ai.doUnregisterAction = function(_aoi)
|
|
|
|
{
|
2011-06-26 16:57:05 +02:00
|
|
|
var node = _aoi.getDOMNode();
|
|
|
|
|
2016-06-02 16:51:15 +02:00
|
|
|
if (node && jQuery(node).data("uiDroppable")) {
|
|
|
|
jQuery(node).droppable("destroy");
|
2011-06-26 16:57:05 +02:00
|
|
|
}
|
2014-02-25 16:02:49 +01:00
|
|
|
};
|
2011-03-24 18:06:44 +01:00
|
|
|
|
|
|
|
ai._fetchAccepted = function(_links)
|
|
|
|
{
|
|
|
|
// Accumulate the accepted types
|
|
|
|
var accepted = [];
|
2011-04-23 11:07:31 +02:00
|
|
|
for (var k in _links)
|
2011-03-24 18:06:44 +01:00
|
|
|
{
|
|
|
|
for (var i = 0; i < _links[k].actionObj.acceptedTypes.length; i++)
|
|
|
|
{
|
|
|
|
var type = _links[k].actionObj.acceptedTypes[i];
|
|
|
|
|
|
|
|
if (accepted.indexOf(type) == -1)
|
|
|
|
{
|
|
|
|
accepted.push(type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return accepted;
|
2014-02-25 16:02:49 +01:00
|
|
|
};
|
2011-03-24 18:06:44 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds the context menu and shows it at the given position/DOM-Node.
|
2014-02-25 16:02:49 +01:00
|
|
|
*
|
|
|
|
* @param {string} _context
|
|
|
|
* @param {array} _selected
|
|
|
|
* @param {object} _links
|
2011-03-24 18:06:44 +01:00
|
|
|
*/
|
|
|
|
ai.doExecuteImplementation = function(_context, _selected, _links)
|
|
|
|
{
|
|
|
|
if (_context == "links")
|
|
|
|
{
|
|
|
|
return _links;
|
|
|
|
}
|
2014-02-25 16:02:49 +01:00
|
|
|
};
|
2011-03-24 18:06:44 +01:00
|
|
|
|
|
|
|
return ai;
|
|
|
|
}
|