mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-08 09:04:53 +01:00
Drag & drop files from user's system onto nextmatch row uploads & links file to that row
This commit is contained in:
parent
4e2843b4a1
commit
6028ac8eca
@ -100,6 +100,11 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput],
|
||||
"type": "string",
|
||||
"description": "JS code which gets executed when rows are selected. Can also be a app.appname.func(selected) style method"
|
||||
},
|
||||
"onfiledrop": {
|
||||
"name": "onFileDrop",
|
||||
"type": "js",
|
||||
"description": "JS code that gets executed when a _file_ is dropped on a row. Other drop interactions are handled by the action system. Return false to prevent the default link action."
|
||||
},
|
||||
"settings": {
|
||||
"name": "Settings",
|
||||
"type": "any",
|
||||
@ -213,6 +218,46 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput],
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
doLoadingFinished: function() {
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
// Register handler for dropped files, if possible
|
||||
if(this.options.settings.row_id)
|
||||
{
|
||||
// Appname should be first part of the template name
|
||||
var split = this.options.template.split('.');
|
||||
var appname = split[0];
|
||||
|
||||
// Check link registry
|
||||
if(this.egw().link_get_registry(appname))
|
||||
{
|
||||
var self = this;
|
||||
// Register a handler
|
||||
$j('table.egwGridView_grid',this.div)
|
||||
.on('dragenter','tr',function(e) {
|
||||
var row = self.controller._getIndexEntry($j(this).index());
|
||||
if(!row || !row.uid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
e.stopPropagation(); e.preventDefault();
|
||||
self.controller._selectionMgr.setFocused(row.uid,true);
|
||||
return false;
|
||||
})
|
||||
.on('dragexit','tr', function(e) {
|
||||
self.controller._selectionMgr.setFocused();
|
||||
})
|
||||
.on('dragover','tr',false).attr("dropzone","copy")
|
||||
|
||||
.on('drop', 'tr',function(e) {
|
||||
self.handle_drop(e,this);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -436,8 +481,8 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput],
|
||||
*/
|
||||
onselect: function(action,senders) {
|
||||
// Execute the JS code connected to the event handler
|
||||
if (this.options.onselect)
|
||||
{
|
||||
if (this.options.onselect)
|
||||
{
|
||||
if (typeof this.options.onselect == "string" &&
|
||||
this.options.onselect.substr(0,4) == "app." && window.app)
|
||||
{
|
||||
@ -451,12 +496,12 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput],
|
||||
}
|
||||
}
|
||||
|
||||
// Exectute the legacy JS code
|
||||
else if (!(et2_compileLegacyJS(this.options.onselect, this, this.div))())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Exectute the legacy JS code
|
||||
else if (!(et2_compileLegacyJS(this.options.onselect, this, this.div))())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1180,6 +1225,107 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput],
|
||||
* Actions are handled by the controller, so ignore these
|
||||
*/
|
||||
set_actions: function(actions) {},
|
||||
|
||||
/**
|
||||
* Set a different / additional handler for dropped files.
|
||||
*
|
||||
* File dropping doesn't work with the action system, so we handle it in the
|
||||
* nextmatch by linking automatically to the target row. This allows an additional handler.
|
||||
* It should accept a row UID and a File[], and return a boolean Execute the default (link) action
|
||||
*
|
||||
* @param {String|Function} handler
|
||||
*/
|
||||
set_onfiledrop: function(handler) {
|
||||
this.options.onfiledrop = handler;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle drops of files by linking to the row, if possible.
|
||||
*
|
||||
* HTML5 / native file drops conflict with jQueryUI draggable, which handles
|
||||
* all our drop actions. So we side-step the issue by registering an additional
|
||||
* drop handler on the rows parent. If the row/actions itself doesn't handle
|
||||
* the drop, it should bubble and get handled here.
|
||||
*/
|
||||
handle_drop: function(event, target) {
|
||||
// Check to see if we can handle the link
|
||||
// First, find the UID
|
||||
var row = this.controller._getIndexEntry($j(target).index());
|
||||
if(!row || !row.uid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var uid = row.uid;
|
||||
|
||||
// Get the file information
|
||||
var files = [];
|
||||
if(event.originalEvent && event.originalEvent.dataTransfer &&
|
||||
event.originalEvent.dataTransfer.files && event.originalEvent.dataTransfer.files.length > 0)
|
||||
{
|
||||
files = event.originalEvent.dataTransfer.files;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Exectute the custom handler code
|
||||
if (this.options.onfiledrop && !this.options.onfiledrop.call(this, uid, files))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
// Link the file to the row
|
||||
// just use a link widget, it's all already done
|
||||
var split = uid.split('::');
|
||||
var link_value = {
|
||||
to_app: split.shift(),
|
||||
to_id: split.join('::')
|
||||
}
|
||||
// Create widget and mangle to our needs
|
||||
var link = et2_createWidget("link-to", {value: link_value}, this);
|
||||
link.loadingFinished();
|
||||
link.file_upload.set_drop_target(false);
|
||||
|
||||
if(row.row.tr)
|
||||
{
|
||||
// Ignore most of the UI, just use the status indicators
|
||||
var status = $j(document.createElement("div"))
|
||||
.addClass('et2_link_to')
|
||||
.height(row.row.tr.height())
|
||||
.width(row.row.tr.width())
|
||||
.position({my: "left top", at: "left top", of: row.row.tr})
|
||||
.append(link.status_span)
|
||||
.append(link.file_upload.progress)
|
||||
.appendTo(row.row.tr);
|
||||
|
||||
// Bind to link event so we can remove when done
|
||||
link.div.on('link.et2_link_to', function(e, linked) {
|
||||
if(!linked)
|
||||
{
|
||||
$j("li.success", link.file_upload.progress)
|
||||
.removeClass('success').addClass('validation_error');
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update row
|
||||
link._parent.refresh(uid,'edit');
|
||||
}
|
||||
// Fade out nicely
|
||||
status.delay(linked ? 1 : 2000)
|
||||
.fadeOut(500, function() {
|
||||
link.free();
|
||||
status.remove();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// Upload and link - this triggers the upload, which triggers the link, which triggers the cleanup and refresh
|
||||
link.file_upload.set_value(files);
|
||||
},
|
||||
|
||||
getDOMNode: function(_sender) {
|
||||
if (_sender == this)
|
||||
|
@ -214,7 +214,7 @@ var et2_link_to = et2_inputWidget.extend(
|
||||
id: this.id + '_file',
|
||||
|
||||
// Make the whole template a drop target
|
||||
drop_target: this.getRoot(),
|
||||
drop_target: this.getInstanceManager().DOMContainer.getAttribute("id"),
|
||||
|
||||
// Change to this tab when they drop
|
||||
onStart: function(event, file_count) {
|
||||
@ -316,6 +316,7 @@ var et2_link_to = et2_inputWidget.extend(
|
||||
if(success) {
|
||||
this.comment.hide();
|
||||
this.link_button.hide().attr("disabled", false);
|
||||
this.status_span.removeClass("error").addClass("success");
|
||||
this.status_span.fadeIn().delay(1000).fadeOut();
|
||||
delete this.options.value.app;
|
||||
delete this.options.value.id;
|
||||
@ -335,6 +336,12 @@ var et2_link_to = et2_inputWidget.extend(
|
||||
this, et2_link_list
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.status_span.removeClass("success").addClass("error")
|
||||
.fadeIn();
|
||||
}
|
||||
this.div.trigger('link.et2_link_to',success);
|
||||
},
|
||||
|
||||
set_no_files: function(no_files)
|
||||
|
@ -537,12 +537,17 @@ div.et2_link_entry input.ui-autocomplete-input {
|
||||
.et2_link_to span.status {
|
||||
background-repeat: no-repeat;
|
||||
background-position: 3px center;
|
||||
background-image:url(images/tick.png);
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display: block;
|
||||
float: right;
|
||||
}
|
||||
.et2_link_to span.status.success {
|
||||
background-image:url(images/tick.png);
|
||||
}
|
||||
.et2_link_to span.status.error {
|
||||
background-image:url(images/error.png);
|
||||
}
|
||||
.et2_link_to .progress {
|
||||
max-height: 12em;
|
||||
}
|
||||
@ -550,6 +555,9 @@ div.et2_link_entry input.ui-autocomplete-input {
|
||||
width: 100%;
|
||||
margin-right: -20px; /* Leave room for remove icon */
|
||||
}
|
||||
.et2_link_to .progress li {
|
||||
list-style: none;
|
||||
}
|
||||
.et2_link_to .progress li.success span.ui-icon-comment {
|
||||
display: none;
|
||||
float: right;
|
||||
@ -777,6 +785,7 @@ div.message.floating {
|
||||
border-color: #a93030;
|
||||
background-image:url(images/error.png);
|
||||
background-repeat: no-repeat;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
.message.success {
|
||||
@ -786,6 +795,7 @@ div.message.floating {
|
||||
border-color: #9ea930;
|
||||
background-image:url(images/tick.png);
|
||||
background-repeat: no-repeat;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
.message.hint {
|
||||
@ -795,6 +805,7 @@ div.message.floating {
|
||||
color: #56729a;
|
||||
background-image:url(images/hint.png);
|
||||
background-repeat: no-repeat;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -966,6 +977,14 @@ div.message.floating {
|
||||
|
||||
/* End of hierarchy */
|
||||
|
||||
/* Mangled link-to widget inside a nextmatch - used for DnD uploads */
|
||||
.et2_nextmatch * .et2_link_to {
|
||||
position: fixed;
|
||||
left: 0px;
|
||||
background: white;
|
||||
border: 1px gray;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.et2_clickable {
|
||||
cursor: pointer;
|
||||
|
Loading…
Reference in New Issue
Block a user