* All Applications: Get all drag and drop action functionality working cross platform

-Fix drag Out to desktop functionality with Command+Shift keys (for Mac) or Alt+Shift keys (for other platforms)
-Fix content selection functionality with Command key (for Mac only) or Ctrl key (for other platforms)
This commit is contained in:
Hadi Nategh 2014-10-24 11:15:33 +00:00
parent bcbf679f64
commit 981a0a1eb9
3 changed files with 147 additions and 104 deletions

View File

@ -2152,6 +2152,35 @@ egwActionObject.prototype.getActionImplementationGroups = function(_test, _group
return _groups; return _groups;
}; };
/**
* Check if user tries to get dragOut action
*
* keys for dragOut:
* -Mac: Command + Shift
* -Others: Alt + Shift
*
* @param {event} _event
* @return {boolean} return true if Alt+Shift keys and left mouse click arre pressed, otherwise false
*/
egwActionObject.prototype.isDragOut = function (_event)
{
return (_event.altKey || _event.metaKey) && _event.shiftKey && _event.which == 1;
};
/**
* Check if user tries to get selection action
*
* Keys for selection:
* -Mac: Command key
* -Others: Ctrl key
*
* @param {type} _event
* @returns {Boolean} return true if left mouse click and Ctrl key are pressed, otherwise false
*/
egwActionObject.prototype.isSelection = function (_event)
{
return !(_event.shiftKey) && _event.which == 1 && (_event.metaKey || _event.ctrlKey);
};
/** egwActionObjectInterface Interface **/ /** egwActionObjectInterface Interface **/

View File

@ -138,7 +138,7 @@ function egwDragActionImplementation()
navigator && navigator.userAgent.indexOf('Chrome') >= 0 && egw.app_name() == 'filemanager') // currently only filemanager supports drag out navigator && navigator.userAgent.indexOf('Chrome') >= 0 && egw.app_name() == 'filemanager') // currently only filemanager supports drag out
{ {
var key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ? 'Ctrl' : 'Command'; var key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ? 'Ctrl' : 'Command';
text.text(egw.lang('Hold %1 to drag %2 to your computer',key, itemLabel)); text.text(egw.lang('Hold Alt + Shift key to drag %2 to your computer',key, itemLabel));
} }
// Final html DOM return as helper structor // Final html DOM return as helper structor
return div; return div;
@ -188,99 +188,123 @@ function egwDragActionImplementation()
* This way we can at least toggle which one is operating, so they * This way we can at least toggle which one is operating, so they
* both work alternately if not together. * both work alternately if not together.
*/ */
// Native DnD - Doesn't play nice with jQueryUI Sortable // Native DnD - Doesn't play nice with jQueryUI Sortable
// Tell jQuery to include this property // Tell jQuery to include this property
jQuery.event.props.push('dataTransfer'); jQuery.event.props.push('dataTransfer');
$j(node).off("mousedown") $j(node).off("mousedown")
.on("mousedown", function(event) { .on("mousedown", function(event) {
$j(node).draggable("option","disabled",event.ctrlKey || event.metaKey); var dragOut = _context.isDragOut(event);
$j(this).attr("draggable", event.ctrlKey || event.metaKey ? "true" : ""); $j(this).attr("draggable", dragOut? "true" : "");
$j(node).draggable("option","disabled",dragOut);
// Disabling draggable adds some UI classes, but we don't care so remove them if (dragOut)
$j(node).removeClass("ui-draggable-disabled ui-state-disabled");
if(!(event.ctrlKey || event.metaKey) || !this.addEventListener) return;
})
.on("dragstart", function(event) {
if(event.dataTransfer == null) {
return;
}
event.dataTransfer.effectAllowed="copy";
// 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)
{
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); // Disabling draggable adds some UI classes, but we don't care so remove them
$j(node).removeClass("ui-draggable-disabled ui-state-disabled");
} }
else else
{ {
// Include URL as a fallback if (_context.isSelection(event))
event.dataTransfer.setData("text/uri-list", url); {
$j(node).draggable("disable");
// Disabling draggable adds some UI classes, but we don't care so remove them
$j(node).removeClass("ui-draggable-disabled ui-state-disabled");
}
else if(event.which != 3)
{
document.getSelection().removeAllRanges();
}
if(!(dragOut) || !this.addEventListener) return;
}
})
.on ("mouseup", function (event){
if (_context.isSelection(event))
$j(node).draggable("enable");
})
.on("dragstart", function(event) {
if(_context.isSelection(event)) return;
if(event.dataTransfer == null) {
return;
}
event.dataTransfer.effectAllowed="copy";
// 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)
{
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);
}
} }
} }
} if(event.dataTransfer.types.length == 0)
if(event.dataTransfer.types.length == 0) {
{ // No file data? Abort: drag does nothing
// No file data? Abort: drag does nothing event.preventDefault();
event.preventDefault(); return;
return; }
}
// Create drag icon // Create drag icon
_callback.call(_context, _context, ai); _callback.call(_context, _context, ai);
// Drag icon must be visible for setDragImage() - we'll remove it on drag // Drag icon must be visible for setDragImage() - we'll remove it on drag
$j("body").append(ai.helper); $j("body").append(ai.helper);
event.dataTransfer.setDragImage(ai.helper[0],-12,-12); event.dataTransfer.setDragImage(ai.helper[0],-12,-12);
}) })
.on("drag", function(e) { .on("drag", function(e) {
// Remove the helper, it has been copied into the dataTransfer object now // Remove the helper, it has been copied into the dataTransfer object now
// Hopefully user didn't notice it... // Hopefully user didn't notice it...
if(e.dataTransfer != null) if(e.dataTransfer != null)
{ {
ai.helper.remove(); ai.helper.remove();
} }
});
}
else
{
// Use Ctrl key in order to select content
$j(node).off("mousedown")
.on({
mousedown: function(event){
if (_context.isSelection(event)){
$j(node).draggable("disable");
// Disabling draggable adds some UI classes, but we don't care so remove them
$j(node).removeClass("ui-draggable-disabled ui-state-disabled");
}
else if(event.which != 3)
{
document.getSelection().removeAllRanges();
}
},
mouseup: function (){
$j(node).draggable("enable");
}
}); });
} }
// Use Ctrl+Alt key in order to select content
$j(node).off("mousedown")
.on({
mousedown: function(event){
if ((event.ctrlKey && event.altKey) || (event.ctrlKey && event.metaKey) && event.which == 1){
$j(node).draggable("disable");
// Disabling draggable adds some UI classes, but we don't care so remove them
$j(node).removeClass("ui-draggable-disabled ui-state-disabled");
}
else if(event.which != 3)
{
document.getSelection().removeAllRanges();
}
},
mouseup: function (){
$j(node).draggable("enable");
}
});
$j(node).draggable( $j(node).draggable(
{ {
"distance": 20, "distance": 20,
@ -331,18 +355,8 @@ function egwDragActionImplementation()
if (helperTop >= dTarget.offset().top if (helperTop >= dTarget.offset().top
&& helperTop <= (dTarget.height() + dTarget.offset().top) + tipTelorance) && helperTop <= (dTarget.height() + dTarget.offset().top) + tipTelorance)
{ {
var key1='', key2=''; var key = (["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0)?"Ctrl": "Command";
if (["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0) egw.message(egw.lang('Hold %1 key to select content.',key),'info');
{
key1 = 'Ctrl';
key2 = 'Alt';
}
else
{
key1 ='Command';
key2 ='Ctrl';
}
egw.message(egw.lang('Hold %1 + %2 key to select content.', key1, key2),'info');
} }
// Invalid target // Invalid target
return true; return true;

View File

@ -234,28 +234,28 @@ function egwPopupActionImplementation()
if (_egw_active_menu) if (_egw_active_menu)
{ {
_egw_active_menu.hide() _egw_active_menu.hide();
} }
else if (!e.ctrlKey) else if (!e.ctrlKey && e.which == 3)
{ {
_xy = ai._getPageXY(e); var _xy = ai._getPageXY(e);
_callback.call(_context, _xy, ai); _callback.call(_context, _xy, ai);
} }
e.cancelBubble = !e.ctrlKey; e.cancelBubble = !e.ctrlKey || e.which == 1;
if (e.stopPropagation && !e.ctrlKey) if (e.stopPropagation && e.cancelBubble)
{ {
e.stopPropagation(); e.stopPropagation();
} }
return e.ctrlKey; return !e.cancelBubble;
} };
if (egwIsMobile()) { if (egwIsMobile()) {
$j(_node).bind('taphold', contextHandler); $j(_node).bind('taphold', contextHandler);
} else { } else {
$j(_node).on('contextmenu', contextHandler); $j(_node).on('contextmenu', contextHandler);
} }
} };
ai.doRegisterAction = function(_aoi, _callback, _context) ai.doRegisterAction = function(_aoi, _callback, _context)
{ {