- Nicer UI for status

- Implement server side callback function when file is uploaded
- Send needed file info back to client instead of storing in session
This commit is contained in:
Nathan Gray 2011-09-06 19:55:52 +00:00
parent 02c414129a
commit b2e032245a
5 changed files with 183 additions and 32 deletions

View File

@ -40,8 +40,17 @@ class etemplate_widget_file extends etemplate_widget
$response->error("Could not read session");
return;
}
foreach ($_FILES as $field => $file) {
if ($file['error'] == UPLOAD_ERR_OK) {
if (!($template = etemplate_widget_template::instance(self::$request->template['name'], self::$request->template['template_set'],
self::$request->template['version'], self::$request->template['load_via'])))
{
// Can't use callback
error_log("Could not get template for file upload, callback skipped");
}
$file_data = array();
foreach ($_FILES as $field => &$file) {
if ($file['error'] == UPLOAD_ERR_OK && trim($file['name']) != '' && $file['size'] > 0) {
if (is_dir($GLOBALS['egw_info']['server']['temp_dir']) && is_writable($GLOBALS['egw_info']['server']['temp_dir']))
{
$new_file = tempnam($GLOBALS['egw_info']['server']['temp_dir'],'egw_');
@ -50,19 +59,30 @@ class etemplate_widget_file extends etemplate_widget
{
$new_file = $value['file']['tmp_name'].'+';
}
// Files come from ajax Base64 encoded
if(move_uploaded_file($file['tmp_name'], $new_file)) {
$file['tmp_name'] = $new_file;
$handle = fopen($new_file, 'w');
list($prefix, $data) = explode(',', file_get_contents($file['tmp_name']));
$file['tmp_name'] = $new_file;
fwrite($handle, base64_decode($data));
fclose($handle);
// Data to send back to client
$temp_name = basename($file['tmp_name']);
$file_data[$temp_name] = array(
'name' => $file['name'],
'type' => $file['type']
);
}
}
}
$response->data($file_data);
// Store info for future submit
$data = egw_session::appsession($request_id.'_files');
$form_name = self::form_name($cname, $field);
$data[$form_name][] = $file;
egw_session::appsession($request_id.'_files','',$data);
// Check for a callback, call it if there is one
foreach($_FILES as $field => $file) {
if($element = $template->getElementById($field))
{
$callback = $element->attrs['callback'];
if(!$callback) $callback = $template->getElementAttribute($field, 'callback');
if($callback)
{
ExecMethod($callback, $_FILES[$field]);
}
}
}
}
@ -81,8 +101,29 @@ class etemplate_widget_file extends etemplate_widget
$value = $value_in = self::get_array($content, $form_name);
$valid =& self::get_array($validated, $form_name, true);
$files = egw_session::appsession(self::$request->id().'_files');
$valid = $files[$form_name];
if(!is_array($value)) $value = array();
foreach($value as $tmp => $file)
{
if (is_dir($GLOBALS['egw_info']['server']['temp_dir']) && is_writable($GLOBALS['egw_info']['server']['temp_dir']))
{
$path = $GLOBALS['egw_info']['server']['temp_dir'].'/'.$tmp;
}
else
{
$path = $tmp.'+';
}
$stat = stat($path);
$valid[] = array(
'name' => $file['name'],
'type' => $file['type'],
'tmp_name' => $path,
'error' => UPLOAD_ERR_OK, // Always OK if we get this far
'size' => $stat['size'],
'ip' => $_SERVER['REMOTE_ADDR'], // Assume it's the same as for when it was uploaded...
);
}
if($valid && !$this->attrs['multiple']) $valid = $valid[0];
}
}
etemplate_widget::registerWidget('etemplate_widget_file', array('file'));

View File

@ -62,9 +62,12 @@ var et2_file = et2_inputWidget.extend({
var self = this;
this.asyncOptions = {
// Callbacks
onStartOne: function(event, file_name) { return self.createStatus(event,file_name);},
onStart: function(event, file_count) { return self.onStart(event, file_count); },
onFinish: function(event, file_count) { return self.onFinish(event, file_count); },
onStartOne: function(event, file_name, index, file_count) { return self.createStatus(event,file_name, index,file_count);},
onFinishOne: function(event, response, name, number, total) { return self.finishUpload(event,response,name,number,total);},
onProgress: function(event, progress, name, number, total) { return self.onProgress(event,progress,name,number,total);},
onError: function(event, name, error) { return self.onError(event,name,error);},
sendBoundary: window.FormData || jQuery.browser.mozilla,
url: egw_json_request.prototype._assembleAjaxUrl("etemplate_widget_file::ajax_upload") +
"&request_id="+ instance.etemplate_exec_id
@ -84,6 +87,10 @@ var et2_file = et2_inputWidget.extend({
{
this.input.html5_upload(this.asyncOptions);
}
else
{
// This may be a problem submitting via ajax
}
this.progress = this.options.progress ?
$j(document.getElementById(this.options.progress)) :
$j(document.createElement("div")).appendTo(this.node);
@ -94,31 +101,111 @@ var et2_file = et2_inputWidget.extend({
}
this.setDOMNode(this.node[0]);
},
getValue: function() {
var value = this.options.value ? this.options.value : this.input.val();
return value;
},
getInputNode: function() {
return this.input[0];
},
/**
* Disables submit buttons while uploading
*/
onStart: function(event, file_count) {
this.disabled_buttons = $j("input[type='submit'], button").not("[disabled]").attr("disabled", true);
return true;
},
/**
* Re-enables submit buttons when done
*/
onFinish: function(event, file_count) {
this.disabled_buttons.attr("disabled", false);
},
/**
* Creates the elements used for displaying the file, and it's upload status, and
* attaches them to the DOM
*/
createStatus: function(event, file_name) {
createStatus: function(event, file_name, index, file_count) {
var error = ""
if(this.input[0].files[index]) {
var file = this.input[0].files[index];
if(file.size > this.options.max_file_size) {
error = egw.lang("File too large");
}
}
if(this.progress)
{
$j("<li file='"+file_name+"'>"+file_name+"<div class='progressBar'><p/></div></li>").appendTo(this.progress);
var status = $j("<li file='"+file_name+"'>"+file_name
+"<div class='remove'/><span class='progressBar'><p/></span></li>")
.appendTo(this.progress)
.click(this, this.cancel);
if(error != "")
{
status.addClass("message validation_error");
status.append("<div>"+error+"</diff>");
$j(".progressBar",status).css("display", "none");
}
}
return error == "";
},
onProgress: function(event, percent, name, number, total) {
if(this.progress)
{
$j("li[file='"+name+"'] > span.progressBar > p").css("width", Math.ceil(percent*100)+"%");
}
return true;
},
onError: function(event, name, error) {
console.warn(event,name,error);
},
/**
* A file upload is finished, update the UI
*/
finishUpload: function(event, response, name, number, total) {
if(this.progress)
{
$j("[file='"+name+"']",this.progress).addClass("upload_finished");
if(typeof response == 'string') response = jQuery.parseJSON(response);
if(response.response[0].data && typeof response.response[0].data.length == 'undefined') {
if(typeof this.options.value != 'object') this.options.value = {};
for(var key in response.response[0].data) {
this.options.value[key] = response.response[0].data[key];
}
if(this.progress)
{
$j("[file='"+name+"']",this.progress).addClass("message success");
}
}
else if (this.progress)
{
$j("[file='"+name+"']",this.progress).addClass("error").css("display", "block");
}
return true;
},
/**
* Cancel a file
*/
cancel: function(e) {
e.preventDefault();
// Look for file name in list
var target = $j(e.target);
for(var key in e.data.options.value) {
if(e.data.options.value[key].name == target.attr("file"))
{
delete e.data.options.value[key];
$j(e.target).remove();
return;
}
}
// In case it didn't make it to the list (error)
$j(e.target).remove();
}
});

BIN
etemplate/js/test/gfx/close.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 963 B

View File

@ -194,26 +194,49 @@ span.et2_date span {
* File upload
*/
.et2_file .progress {
width: 300px;
max-height: 6em;
overflow: auto;
margin-left: 20px;
}
-moz-column-count: 4;
-moz-column-gap: 20px;
-webkit-column-count: 4;
-webkit-column-gap: 20px;
column-count: 4;
column-gap: 20px;
.et2_file .progress span.progressBar {
height: 5px;
width: 150px;
max-width: 150px;
display: inline;
}
/* Remove icon displayed when hovering */
.et2_file .progress li div.remove {
display: none;
}
.et2_file .progress li:hover div.remove {
width: 16px;
height: 16px;
float: right;
display: block;
background-image: url("gfx/close.png");
background-position: center;
background-repeat: no-repeat;
}
.et2_file .progress p {
background-color: green;
height:5px;
margin: 0px;
}
.et2_file .progress li {
color: blue;
margin: .5ex;
cursor: pointer;
}
.et2_file .progress li.upload_finished {
color: green;
/* Hide progress bar when completed */
.et2_file .progress li.success > span.progressBar {
display: none;
}
.egw_tooltip
{
position: fixed;

View File

@ -22,7 +22,7 @@ include('../../../header.inc.php');
/*
* Test using any actual template
*/
// $template = 'etemplate.et2_test_file_upload';
$template = 'etemplate.et2_test_file_upload';
if($template) {
$etemplate = new etemplate_new('etemplate.et2_test_file_upload');
$etemplate->exec('',array());