From 6a8e85c3e184a9c786bcd69f56211e391cc212e8 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 18 Aug 2014 18:00:00 +0000 Subject: [PATCH] Add drag&drop for email and link lists --- .../inc/class.etemplate_widget_link.inc.php | 1 + etemplate/js/et2_widget_grid.js | 9 ++- etemplate/js/et2_widget_link.js | 66 ++++++++++++++++++ etemplate/templates/default/etemplate2.css | 6 ++ mail/inc/class.mail_ui.inc.php | 3 +- mail/js/app.js | 67 +++++++++++++++++++ phpgwapi/js/egw_action/egw_action_dragdrop.js | 8 +-- 7 files changed, 154 insertions(+), 6 deletions(-) diff --git a/etemplate/inc/class.etemplate_widget_link.inc.php b/etemplate/inc/class.etemplate_widget_link.inc.php index 3d0afe4635..83d29e61c4 100644 --- a/etemplate/inc/class.etemplate_widget_link.inc.php +++ b/etemplate/inc/class.etemplate_widget_link.inc.php @@ -183,6 +183,7 @@ class etemplate_widget_link extends etemplate_widget } $link['title'] = egw_vfs::decodePath($link['title']); $link['icon'] = egw_link::vfs_path($link['app2'],$link['id2'],$link['id'],true); + $link['download_url'] = egw_vfs::download_url($link['icon']); } else { diff --git a/etemplate/js/et2_widget_grid.js b/etemplate/js/et2_widget_grid.js index 75f0ddae88..13eca54885 100644 --- a/etemplate/js/et2_widget_grid.js +++ b/etemplate/js/et2_widget_grid.js @@ -916,8 +916,15 @@ var et2_grid = et2_DOMWidget.extend([et2_IDetachedDOM, et2_IAligned], // Add a new action object to the object manager var row = $j('tr', this.tbody)[i]; var aoi = new et2_action_object_impl(this, row); + var content = this.getArrayMgr('content').getEntry(i); + var obj = widget_object.addObject(content.id || "row_"+i, aoi); + + // Set the data to the content so it's available for the action + if(content) + { + obj.data = content; + } - var obj = widget_object.addObject("row_"+i, aoi); obj.updateActionLinks(action_links); } }, diff --git a/etemplate/js/et2_widget_link.js b/etemplate/js/et2_widget_link.js index c266e7f370..1dd202cb83 100644 --- a/etemplate/js/et2_widget_link.js +++ b/etemplate/js/et2_widget_link.js @@ -1511,6 +1511,11 @@ var et2_link_list = et2_link_string.extend( var row = jQuery('#link_'+(self.context.data.dom_id ? self.context.data.dom_id : self.context.data.link_id), self.list); self._delete_link(link_id, row); }); + + // Native DnD - Doesn't play nice with jQueryUI Sortable + // Tell jQuery to include this property + jQuery.event.props.push('dataTransfer'); + }, destroy: function() { @@ -1569,6 +1574,7 @@ var et2_link_list = et2_link_string.extend( _add_link: function(_link_data) { var row = $j(document.createElement("tr")) .attr("id", "link_"+(_link_data.dom_id ? _link_data.dom_id : _link_data.link_id)) + .attr("draggable", _link_data.app == 'file' ? "true" : "") .appendTo(this.list); // Icon @@ -1646,12 +1652,72 @@ var et2_link_list = et2_link_string.extend( self.context.showAt(e.pageX, e.pageY, true); e.preventDefault(); }); + + + // Drag - adapted from egw_action_dragdrop, sidestepping action system + // so all linked files get it + // // Unfortunately, dragging files is currently only supported by Chrome + if(navigator && navigator.userAgent.indexOf('Chrome') >= 0) + { + row.on("dragstart", _link_data, function(event) { + if(event.dataTransfer == null) { + return; + } + var data = event.data || {}; + if(data && data.type && data.download_url) + { + event.dataTransfer.dropEffect="copy"; + event.dataTransfer.effectAllowed="copy"; + + 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.type+':'+data.title+':'+url); + } + + // Include URL as a fallback + event.dataTransfer.setData("text/uri-list", url); + } + + if(event.dataTransfer.types.length == 0) + { + // No file data? Abort: drag does nothing + event.preventDefault(); + return; + } + //event.dataTransfer.setDragImage(event.delegate.target,0,0); + var div = $j(document.createElement("div")) + .attr('id', 'drag_helper') + .css({ + position: 'absolute', + top: '0px', + left: '0px', + width: '300px' + }); + div.append(event.target.cloneNode(true)); + + self.list.append(div); + + event.dataTransfer.setDragImage(div.get(0),0,0) + }) + .on('drag', function() { + $j('#drag_helper',self.list).remove(); + }); + } }, _delete_link: function(link_id, row) { if(row) { var delete_button = jQuery('.delete',row); delete_button.removeClass("delete").addClass("loading"); + row.off(); } if(typeof link_id != "object") { diff --git a/etemplate/templates/default/etemplate2.css b/etemplate/templates/default/etemplate2.css index 150ee89ba7..c02ad018bc 100644 --- a/etemplate/templates/default/etemplate2.css +++ b/etemplate/templates/default/etemplate2.css @@ -664,6 +664,12 @@ ul.et2_link_string { } .et2_link_list { border-collapse: collapse; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } .et2_link_list tr { cursor: pointer; diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index 859e9ecb96..815f700ab6 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -2057,6 +2057,7 @@ class mail_ui 'onExecute' => 'javaScript:app.mail.drag_attachment' ) )); +//_debug_array($content); $readonlys = $preserv = $content; $etpl->exec('mail.mail_ui.displayMessage',$content,$sel_options,$readonlys,$preserv,2); } @@ -2107,7 +2108,7 @@ class mail_ui $attachmentHTML[$key]['partID']=$value['partID']; $attachmentHTML[$key]['winmailFlag']=$value['is_winmail']; $attachmentHTML[$key]['classSaveAllPossiblyDisabled'] = "mail_DisplayNone"; - + switch(strtoupper($value['mimeType'])) { case 'MESSAGE/RFC822': diff --git a/mail/js/app.js b/mail/js/app.js index 50cca99a52..f661d02f1b 100644 --- a/mail/js/app.js +++ b/mail/js/app.js @@ -180,6 +180,12 @@ app.classes.mail = AppJS.extend( } } window.resizeTo((w_h[0]?w_h[0]:870),(w_h[1]?w_h[1]:(screen.availHeight>egw_getWindowOuterHeight()?screen.availHeight:egw_getWindowOuterHeight()))); + + // Register attachments for drag + this.register_for_drag( + this.et2.getArrayMgr("content").getEntry('mail_id'), + this.et2.getArrayMgr("content").getEntry('mail_displayattachments') + ); break; case 'mail.compose': var that = this; @@ -987,6 +993,67 @@ app.classes.mail = AppJS.extend( { egw.jsonq('mail_ui::ajax_refreshVacationNotice',[_server]); }, + /** + * Make sure attachments have all needed data, so they can be found for + * HTML5 native dragging + * + * @param {string} mail_id Mail UID + * @param {array} attachments Attachment information. + */ + register_for_drag: function(mail_id, attachments) + { + // Put required info in global store + var data = {}; + for (var i = 0; i < attachments.length; i++) + { + var data = attachments[i] || {}; + if(!data.filename || !data.type) continue; + + // Add required info + data.mime = data.type; + data.download_url = egw.link('/index.php', { + menuaction: 'mail.mail_ui.getAttachment', + id: mail_id, + part: data.partID, + is_winmail: data.winmailFlag + }); + data.name = data.filename; + } + }, + + /** + * Display helper for dragging attachments + * + * @param {egwAction} _action + * @param {egwActionElement[]} _elems + * @returns {DOMNode} + */ + drag_attachment: function(_action, _elems) + { + var div = $j(document.createElement("div")) + .css({ + position: 'absolute', + top: '0px', + left: '0px', + width: '300px' + }); + + var data = _elems[0].data || {}; + + var text = $j(document.createElement('div')).css({left: '30px', position: 'absolute'}); + // add filename or number of files for multiple files + text.text(_elems.length > 1 ? _elems.length+' '+this.egw.lang('files') : data.name || ''); + div.append(text); + + // Add notice of Ctrl key, if supported + if(window.FileReader && 'draggable' in document.createElement('span') && + navigator && navigator.userAgent.indexOf('Chrome') >= 0) + { + var key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ? 'Ctrl' : 'Command'; + text.append('
' + this.egw.lang('Hold %1 to drag files to your computer',key)); + } + return div; + }, /** * mail_refreshVacationNotice, function to call with appropriate data to refresh the vacationnotice for the active server diff --git a/phpgwapi/js/egw_action/egw_action_dragdrop.js b/phpgwapi/js/egw_action/egw_action_dragdrop.js index 42ee7d5d8b..fdff8ef275 100644 --- a/phpgwapi/js/egw_action/egw_action_dragdrop.js +++ b/phpgwapi/js/egw_action/egw_action_dragdrop.js @@ -157,10 +157,10 @@ function egwDragActionImplementation() // Set file data for(var i = 0; i < selected.length; i++) { - var data = egw.dataGetUIDdata(selected[i].id); - if(data && data.data.mime && data.data.download_url) + var data = selected[i].data || egw.dataGetUIDdata(selected[i].id).data || {}; + if(data && data.mime && data.download_url) { - var url = data.data.download_url; + var url = data.download_url; // NEED an absolute URL if (url[0] == '/') url = egw.link(url); @@ -170,7 +170,7 @@ function egwDragActionImplementation() // Unfortunately, dragging files is currently only supported by Chrome if(navigator && navigator.userAgent.indexOf('Chrome')) { - event.dataTransfer.setData("DownloadURL", data.data.mime+':'+data.data.name+':'+url); + event.dataTransfer.setData("DownloadURL", data.mime+':'+data.name+':'+url); } else {