* All App: get text selection in lists working with Alt/Cmd modifier and file drag-out with Shift+Alt/Cmd modifier

r49174: Apply Ctrl+Alt keys in order to be able to distinguish between content selection and dnd for draggable actions
r49176: * 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)

r49177: text and German translations for drag-n-drop modifier hints
r49178: fix IDE warnings
This commit is contained in:
Ralf Becker 2014-10-24 12:57:16 +00:00
parent 7689e486ea
commit f5783649c1
5 changed files with 238 additions and 117 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

@ -15,6 +15,7 @@
egw_action_popup; egw_action_popup;
jquery.jquery; jquery.jquery;
jquery.jquery-ui; jquery.jquery-ui;
/phpgwapi/js/jquery/jquery-ui-touch-punch/touch.js;
*/ */
/** /**
@ -136,12 +137,13 @@ function egwDragActionImplementation()
if('draggable' in document.createElement('span') && if('draggable' in document.createElement('span') &&
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 ?
text.text(egw.lang('Hold %1 to drag %2 to your computer',key, itemLabel)); 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));
} }
// Final html DOM return as helper structor // Final html DOM return as helper structor
return div; return div;
} };
ai.doRegisterAction = function(_aoi, _callback, _context) ai.doRegisterAction = function(_aoi, _callback, _context)
{ {
@ -193,14 +195,36 @@ function egwDragActionImplementation()
$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);
if (dragOut)
{
// Disabling draggable adds some UI classes, but we don't care so remove them // Disabling draggable adds some UI classes, but we don't care so remove them
$j(node).removeClass("ui-draggable-disabled ui-state-disabled"); $j(node).removeClass("ui-draggable-disabled ui-state-disabled");
if(!(event.ctrlKey || event.metaKey) || !this.addEventListener) return;
}
else
{
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();
}
if(!(dragOut) || !this.addEventListener) return;
}
})
.on ("mouseup", function (event){
if (_context.isSelection(event))
$j(node).draggable("enable");
}) })
.on("dragstart", function(event) { .on("dragstart", function(event) {
if(_context.isSelection(event)) return;
if(event.dataTransfer == null) { if(event.dataTransfer == null) {
return; return;
} }
@ -261,6 +285,27 @@ function egwDragActionImplementation()
} }
}); });
} }
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");
}
});
}
$j(node).draggable( $j(node).draggable(
{ {
"distance": 20, "distance": 20,
@ -311,9 +356,9 @@ 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 key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ? 'Ctrl' : 'Command'; var key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ?
// Comment this out ATM till we get the ctrl and content selection functionality working egw.lang("Ctrl") : egw.lang("Command ⌘");
//egw.message(egw.lang('Hold %1 key to select content.', key),'info'); egw.message(egw.lang('Hold [%1] key to select text eg. to copy it', key), 'info');
} }
// Invalid target // Invalid target
return true; return true;

View File

@ -16,11 +16,11 @@
*/ */
if (typeof window._egwActionClasses == "undefined") if (typeof window._egwActionClasses == "undefined")
window._egwActionClasses = {} window._egwActionClasses = {};
_egwActionClasses["popup"] = { _egwActionClasses["popup"] = {
"actionConstructor": egwPopupAction, "actionConstructor": egwPopupAction,
"implementation": getPopupImplementation "implementation": getPopupImplementation
} };
function egwPopupAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple) function egwPopupAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple)
{ {
@ -38,34 +38,34 @@ function egwPopupAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMult
action.set_default = function(_value) { action.set_default = function(_value) {
action["default"] = _value; action["default"] = _value;
} };
action.set_order = function(_value) { action.set_order = function(_value) {
action.order = _value; action.order = _value;
} };
action.set_group = function(_value) { action.set_group = function(_value) {
action.group = _value; action.group = _value;
} };
action.set_hint = function(_value) { action.set_hint = function(_value) {
action.hint = _value; action.hint = _value;
} };
// If true, the action will be rendered as checkbox // If true, the action will be rendered as checkbox
action.set_checkbox = function(_value) { action.set_checkbox = function(_value) {
action.checkbox = _value; action.checkbox = _value;
} };
action.set_checked = function(_value) { action.set_checked = function(_value) {
action.checked = _value; action.checked = _value;
} };
// If radioGroup is >0 and the element is a checkbox, radioGroup specifies // If radioGroup is >0 and the element is a checkbox, radioGroup specifies
// the group of radio buttons this one belongs to // the group of radio buttons this one belongs to
action.set_radioGroup = function(_value) { action.set_radioGroup = function(_value) {
action.radioGroup = _value; action.radioGroup = _value;
} };
action.set_shortcut = function(_value) { action.set_shortcut = function(_value) {
if (_value) if (_value)
@ -75,7 +75,7 @@ function egwPopupAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMult
"shift": false, "shift": false,
"ctrl": false, "ctrl": false,
"alt": false "alt": false
} };
if (typeof _value == "object" && typeof _value.keyCode != "undefined" && if (typeof _value == "object" && typeof _value.keyCode != "undefined" &&
typeof _value.caption != "undefined") typeof _value.caption != "undefined")
@ -93,7 +93,7 @@ function egwPopupAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMult
{ {
this.shortcut = false; this.shortcut = false;
} }
} };
return action; return action;
} }
@ -107,7 +107,7 @@ function getPopupImplementation()
{ {
_popupActionImpl = new egwPopupActionImplementation(); _popupActionImpl = new egwPopupActionImplementation();
} }
return _popupActionImpl return _popupActionImpl;
} }
function egwPopupActionImplementation() function egwPopupActionImplementation()
@ -118,8 +118,14 @@ function egwPopupActionImplementation()
/** /**
* Registers the handler for the default action * Registers the handler for the default action
*
* @param {DOMNode} _node
* @param {function} _callback
* @param {object} _context
* @returns {boolean}
*/ */
ai._registerDefault = function(_node, _callback, _context) { ai._registerDefault = function(_node, _callback, _context)
{
var defaultHandler = function(e) { var defaultHandler = function(e) {
if (typeof document.selection != "undefined" && typeof document.selection.empty != "undefined") if (typeof document.selection != "undefined" && typeof document.selection.empty != "undefined")
{ {
@ -134,14 +140,14 @@ function egwPopupActionImplementation()
_callback.call(_context, "default", ai); _callback.call(_context, "default", ai);
return false; return false;
} };
if (egwIsMobile()) { if (egwIsMobile()) {
$j(_node).bind('click', defaultHandler); $j(_node).bind('click', defaultHandler);
} else { } else {
_node.ondblclick = defaultHandler; _node.ondblclick = defaultHandler;
} }
} };
ai._getDefaultLink = function(_links) { ai._getDefaultLink = function(_links) {
var defaultAction = null; var defaultAction = null;
@ -155,7 +161,7 @@ function egwPopupActionImplementation()
} }
return defaultAction; return defaultAction;
} };
ai._searchShortcut = function (_key, _objs, _links) { ai._searchShortcut = function (_key, _objs, _links) {
for (var i = 0; i < _objs.length; i++) for (var i = 0; i < _objs.length; i++)
@ -174,7 +180,7 @@ function egwPopupActionImplementation()
return obj; return obj;
} }
} }
} };
ai._searchShortcutInLinks = function(_key, _links) { ai._searchShortcutInLinks = function(_key, _links) {
var objs = []; var objs = [];
@ -187,10 +193,16 @@ function egwPopupActionImplementation()
} }
return ai._searchShortcut(_key, objs, _links); return ai._searchShortcut(_key, objs, _links);
} };
/** /**
* Handles a key press * Handles a key press
*
* @param {object} _key
* @param {type} _selected
* @param {type} _links
* @param {type} _target
* @returns {Boolean}
*/ */
ai._handleKeyPress = function(_key, _selected, _links, _target) { ai._handleKeyPress = function(_key, _selected, _links, _target) {
// Handle the default // Handle the default
@ -219,12 +231,18 @@ function egwPopupActionImplementation()
} }
return false; return false;
} };
/** /**
* Registers the handler for the context menu * Registers the handler for the context menu
*
* @param {DOMNode} _node
* @param {function} _callback
* @param {object} _context
* @returns {boolean}
*/ */
ai._registerContext = function(_node, _callback, _context) { ai._registerContext = function(_node, _callback, _context)
{
var contextHandler = function(e) { var contextHandler = function(e) {
//Obtain the event object //Obtain the event object
if (!e) if (!e)
@ -234,28 +252,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)
{ {
@ -268,15 +286,21 @@ function egwPopupActionImplementation()
return true; return true;
} }
return false; return false;
} };
ai.doUnregisterAction = function(_aoi) ai.doUnregisterAction = function(_aoi)
{ {
// //
} };
/** /**
* Builds the context menu and shows it at the given position/DOM-Node. * Builds the context menu and shows it at the given position/DOM-Node.
*
* @param {object} _context
* @param {type} _selected
* @param {type} _links
* @param {type} _target
* @returns {Boolean}
*/ */
ai.doExecuteImplementation = function(_context, _selected, _links, _target) ai.doExecuteImplementation = function(_context, _selected, _links, _target)
{ {
@ -301,7 +325,7 @@ function egwPopupActionImplementation()
x = $j(node).offset().left; x = $j(node).offset().left;
y = $j(node).offset().top; y = $j(node).offset().top;
_context = {"posx": x, "posy": y} _context = {"posx": x, "posy": y};
} }
var menu = ai._buildMenu(_links, _selected, _target); var menu = ai._buildMenu(_links, _selected, _target);
@ -319,10 +343,14 @@ function egwPopupActionImplementation()
} }
return false; return false;
} };
/** /**
* Groups and sorts the given action tree layer * Groups and sorts the given action tree layer
*
* @param {type} _layer
* @param {type} _links
* @param {type} _parentGroup
*/ */
ai._groupLayers = function(_layer, _links, _parentGroup) ai._groupLayers = function(_layer, _links, _parentGroup)
{ {
@ -407,10 +435,16 @@ function egwPopupActionImplementation()
} }
_parentGroup.groups = groups2; _parentGroup.groups = groups2;
} };
/** /**
* Build the menu layers * Build the menu layers
*
* @param {type} _menu
* @param {type} _groups
* @param {type} _selected
* @param {type} _enabled
* @param {type} _target
*/ */
ai._buildMenuLayer = function(_menu, _groups, _selected, _enabled, _target) ai._buildMenuLayer = function(_menu, _groups, _selected, _enabled, _target)
{ {
@ -487,10 +521,15 @@ function egwPopupActionImplementation()
firstGroup = firstGroup && firstElem; firstGroup = firstGroup && firstElem;
} }
} };
/** /**
* Builds the context menu from the given action links * Builds the context menu from the given action links
*
* @param {type} _links
* @param {type} _selected
* @param {type} _target
* @returns {egwMenu|egwActionImplementation._buildMenu.menu}
*/ */
ai._buildMenu = function(_links, _selected, _target) ai._buildMenu = function(_links, _selected, _target)
{ {
@ -520,7 +559,7 @@ function egwPopupActionImplementation()
this._buildMenuLayer(menu, groups.groups, _selected, true, _target); this._buildMenuLayer(menu, groups.groups, _selected, true, _target);
return menu; return menu;
} };
ai._getPageXY = function getPageXY(event) ai._getPageXY = function getPageXY(event)
{ {
@ -531,7 +570,7 @@ function egwPopupActionImplementation()
document.documentElement.scrollLeft; document.documentElement.scrollLeft;
return {'posx': (event.clientX + scrollLeft), 'posy': (event.clientY + scrollTop)}; return {'posx': (event.clientX + scrollLeft), 'posy': (event.clientY + scrollTop)};
} };
return ai; return ai;
} }

View File

@ -185,6 +185,7 @@ cocos (keeling) islands common de COCOS INSELN
collection empty. common de Collection ist leer collection empty. common de Collection ist leer
collection listing common de Auflistung der Collection collection listing common de Auflistung der Collection
colombia common de KOLUMBIEN colombia common de KOLUMBIEN
command ⌘ common de Cmd ⌘
common preferences common de Allgemeine Einstellungen common preferences common de Allgemeine Einstellungen
comoros common de KOMOREN comoros common de KOMOREN
company common de Unternehmen company common de Unternehmen
@ -373,6 +374,8 @@ height common de Höhe
help common de Hilfe help common de Hilfe
high common de Hoch high common de Hoch
highest common de Höchste highest common de Höchste
hold [%1] and [%2] key to drag %3 to your desktop common de [%1] und [%2] Tasten halten um %3 auf Ihren Schreibtisch (Desktop) zu ziehen
hold [%1] key to select text eg. to copy it common de [%1] Taste halten um Text zu markieren um ihn z.B. zu kopieren
holy see (vatican city state) common de VATICAN holy see (vatican city state) common de VATICAN
home common de Home home common de Home
home email common de private E-Mail home email common de private E-Mail
@ -730,6 +733,7 @@ setup common de Setup
setup main menu common de Setup Hauptmenü setup main menu common de Setup Hauptmenü
seychelles common de SEYCHELLEN seychelles common de SEYCHELLEN
shift common de Shift shift common de Shift
shift ⇧ common de Umschalten ⇧
show all common de alle anzeigen show all common de alle anzeigen
show all categorys common de Alle Kategorien anzeigen show all categorys common de Alle Kategorien anzeigen
show as topmenu common de Menü oben anzeigen show as topmenu common de Menü oben anzeigen

View File

@ -185,6 +185,7 @@ cocos (keeling) islands common en COCOS (KEELING) ISLANDS
collection empty. common en Collection empty. collection empty. common en Collection empty.
collection listing common en Collection listing collection listing common en Collection listing
colombia common en COLOMBIA colombia common en COLOMBIA
command ⌘ common en Command ⌘
common preferences common en Common preferences common preferences common en Common preferences
comoros common en COMOROS comoros common en COMOROS
company common en Company company common en Company
@ -373,6 +374,8 @@ height common en Height
help common en Help help common en Help
high common en High high common en High
highest common en Highest highest common en Highest
hold [%1] and [%2] key to drag %3 to your desktop common en Hold [%1] and [%2] key to drag %3 to your desktop
hold [%1] key to select text eg. to copy it common en Hold [%1] key to select text eg. to copy it
holy see (vatican city state) common en HOLY SEE (VATICAN CITY STATE) holy see (vatican city state) common en HOLY SEE (VATICAN CITY STATE)
home common en Home home common en Home
home email common en Home email home email common en Home email
@ -730,6 +733,7 @@ setup common en Setup
setup main menu common en Setup main menu setup main menu common en Setup main menu
seychelles common en SEYCHELLES seychelles common en SEYCHELLES
shift common en Shift shift common en Shift
shift ⇧ common en Shift ⇧
show all common en Show all show all common en Show all
show all categorys common en Show all categories show all categorys common en Show all categories
show as topmenu common en Show as top menu show as topmenu common en Show as top menu