diff --git a/admin/inc/class.customfields.inc.php b/admin/inc/class.customfields.inc.php index 0d56406f4e..70ec40fdd0 100644 --- a/admin/inc/class.customfields.inc.php +++ b/admin/inc/class.customfields.inc.php @@ -90,6 +90,7 @@ class customfields 'ajax_select' => array('cf_values' => true), 'radio' => array('cf_values' => true), 'checkbox' => array('cf_values' => true), + 'filemanager' => array('cf_values' => true), ); /** diff --git a/etemplate/inc/class.etemplate_widget_customfields.inc.php b/etemplate/inc/class.etemplate_widget_customfields.inc.php index 1a7ec2b118..6faa767d9a 100644 --- a/etemplate/inc/class.etemplate_widget_customfields.inc.php +++ b/etemplate/inc/class.etemplate_widget_customfields.inc.php @@ -41,7 +41,6 @@ class etemplate_widget_customfields extends etemplate_widget_transformer 'select-account' => 'Select account', 'button' => 'Button', // button to execute javascript 'url' => 'Url', - 'url-email'=> 'EMail', 'url-phone'=> 'Phone number', 'htmlarea' => 'Formatted Text (HTML)', 'link-entry' => 'Select entry', // should be last type, as the individual apps get added behind @@ -265,7 +264,14 @@ class etemplate_widget_customfields extends etemplate_widget_transformer // Link-tos needs to change from appname to link-to if($link_types[$field['type']]) { - $type = 'link-to'; + if($type == 'filemanager') + { + $type = 'vfs-upload'; + } + else + { + $type = 'link-to'; + } } $widget = self::factory($type, '<'.$type.' type="'.$type.'" id="'.self::$prefix.$fname.'"/>', self::$prefix.$fname); $widget->id = self::$prefix.$fname; @@ -281,6 +287,12 @@ class etemplate_widget_customfields extends etemplate_widget_transformer if($field['values']['max']) $widget->attrs['min'] = $field['values']['max']; break; + case 'vfs-upload': + $widget->attrs['path'] = $field['app'] . ':' . + self::expand_name('$cont['.egw_link::get_registry($field['app'],'view_id').']',0,0,0,0,self::$request->content). + ':'.$field['label']; + break; + case 'link-to': $widget->attrs['only_app'] = $field['type']; break; diff --git a/etemplate/inc/class.etemplate_widget_vfs.inc.php b/etemplate/inc/class.etemplate_widget_vfs.inc.php index a8c5fba560..de5ef65ced 100644 --- a/etemplate/inc/class.etemplate_widget_vfs.inc.php +++ b/etemplate/inc/class.etemplate_widget_vfs.inc.php @@ -31,12 +31,21 @@ class etemplate_widget_vfs extends etemplate_widget_file */ public function beforeSendToClient($cname, $expand = array()) { - if($this->type == 'vfs-upload') + if($this->type == 'vfs-upload' || $this->attrs['type'] == 'vfs-upload') { $form_name = self::form_name($cname, $this->id, $expand ? $expand : array('cont'=>self::$request->content)); + if($this->attrs['path']) + { + $path = $this->attrs['path']; + } + else + { + $path = $this->id; + } + $this->setElementAttribute($form_name, 'path', $path); // ID maps to path - check there for any existing files - list($app,$id,$relpath) = explode(':',$this->id,3); + list($app,$id,$relpath) = explode(':',$path,3); if($app && $id) { if(!is_numeric($id)) @@ -52,24 +61,44 @@ class etemplate_widget_vfs extends etemplate_widget_file $path = egw_link::vfs_path($app,$id,'',true); if (!empty($relpath)) $path .= '/'.$relpath; + $value = array(); + // Single file, already existing if (substr($path,-1) != '/' && egw_vfs::file_exists($path) && !egw_vfs::is_dir($path)) { $file = egw_vfs::stat($path); - $file['path'] = egw_vfs::resolve_url($path); + $file['path'] = $path; $file['name'] = egw_vfs::basename($file['path']); $file['mime'] = egw_vfs::mime_content_type($file['path']); $value = array($file); } + // Single file, missing extension in path + else if (substr($path, -1) != '/' && !egw_vfs::file_exists($path) && $relpath && substr($relpath,-4,1) !== '.') + { + $find = egw_vfs::find(substr($path,0, - strlen($relpath)), array( + 'type' => 'f', + 'maxdepth' => 1, + 'name' => $relpath . '*' + )); + foreach($find as $file) + { + $file_info = egw_vfs::stat($file); + $file_info['path'] = $file; + $file_info['name'] = egw_vfs::basename($file_info['path']); + $file_info['mime'] = egw_vfs::mime_content_type($file_info['path']); + $value[] = $file_info; + } + } else if (substr($path, -1) == '/' && egw_vfs::is_dir($path)) { - $value = egw_vfs::scandir($path); - foreach($value as &$file) + $scan = egw_vfs::scandir($path); + foreach($scan as $file) { - $file = egw_vfs::stat("$path$file"); - $file['path'] = $file['url']; - $file['name'] = egw_vfs::basename($file['path']); - $file['mime'] = egw_vfs::mime_content_type($file['path']); + $file_info = egw_vfs::stat("$path$file"); + $file_info['path'] = "$path$file"; + $file_info['name'] = egw_vfs::basename($file_info['path']); + $file_info['mime'] = egw_vfs::mime_content_type($file_info['path']); + $value[] = $file_info; } } } @@ -80,7 +109,7 @@ class etemplate_widget_vfs extends etemplate_widget_file parent::ajax_upload(); foreach($_FILES as $field => $file) { - self::store_file($_REQUEST['widget_id'], $file); + self::store_file($_REQUEST['path'] ? $_REQUEST['path'] : $_REQUEST['widget_id'], $file); } } diff --git a/etemplate/js/et2_extension_customfields.js b/etemplate/js/et2_extension_customfields.js index dcbae50553..61cc936b29 100644 --- a/etemplate/js/et2_extension_customfields.js +++ b/etemplate/js/et2_extension_customfields.js @@ -575,6 +575,10 @@ var et2_customfields_list = et2_valueWidget.extend([et2_IDetachedDOM, et2_IInput } }, _setup_link_entry: function(field_name, field, attrs) { + if(field.type === 'filemanager') + { + return this._setup_filemanager(field_name, field, attrs); + } // No label on the widget itself delete(attrs.label); @@ -583,6 +587,12 @@ var et2_customfields_list = et2_valueWidget.extend([et2_IDetachedDOM, et2_IInput return true; }, + _setup_filemanager: function(field_name, field, attrs) { + attrs.type = 'vfs-upload'; + delete(attrs.label); + return true; + }, + /** * Set which fields are visible, by name * diff --git a/etemplate/js/et2_widget_file.js b/etemplate/js/et2_widget_file.js index 8bed84eb03..0b7fb4268f 100644 --- a/etemplate/js/et2_widget_file.js +++ b/etemplate/js/et2_widget_file.js @@ -395,9 +395,9 @@ var et2_file = et2_inputWidget.extend( else { // Wrong mime type - show in the list of files - return self.createStatus( - self.egw().lang("File is of wrong type (%1 != %2)!", this.files[index].type, self.options.mime), - file_name + return this.createStatus( + this.egw().lang("File is of wrong type (%1 != %2)!", file.file.type, this.options.mime), + file ); } diff --git a/etemplate/js/et2_widget_vfs.js b/etemplate/js/et2_widget_vfs.js index 7d595afa49..24939359f1 100644 --- a/etemplate/js/et2_widget_vfs.js +++ b/etemplate/js/et2_widget_vfs.js @@ -645,6 +645,12 @@ var et2_vfsUpload = et2_file.extend( attributes: { "value": { "type": "any", // Either nothing, or an object with file info + }, + "path": { + "name": "Path", + "description": "Upload files to the specified VFS path", + "type": "string", + "default": '' } }, legacyOptions: ["mime"], @@ -663,9 +669,13 @@ var et2_vfsUpload = et2_file.extend( init: function(_parent, attrs) { this._super.apply(this, arguments); $j(this.node).addClass("et2_vfs"); - - // If the ID is a directory, allow multiple uploads - if(this.options.id.substr(-1) == '/') + + if(!this.options.path) + { + this.options.path = this.options.id; + } + // If the path is a directory, allow multiple uploads + if(this.options.path.substr(-1) == '/') { this.set_multiple(true); } @@ -674,18 +684,40 @@ var et2_vfsUpload = et2_file.extend( /** * If there is a file / files in the specified location, display them + * Value is the information for the file[s] in the specified location. * * @param {Object[]} _value */ set_value: function(_value) { + // Remove previous + while(this._children.length > 0) + { + var node = this._children[this._children.length-1]; + this.removeChild(node); + node.free(); + } this.progress.empty(); this.list.empty(); - for(var i = 0; i < _value.length; i++) + + // Set new + if(typeof _value == 'object' && _value && _value.length) { - this._addFile(_value[i]); + for(var i = 0; i < _value.length; i++) + { + this._addFile(_value[i]); + } } }, + /** + * Value is determined by what's at the location specified by path + * + * @returns {null} + */ + getValue: function() { + return null; + }, + getDOMNode: function(sender) { if(sender !== this && sender._type.indexOf('vfs') >= 0 ) { @@ -706,9 +738,21 @@ var et2_vfsUpload = et2_file.extend( } }, + /** + * Add in the request id + */ + beforeSend: function(form) + { + var instance = this.getInstanceManager(); + + var extra = this._super.apply(this, arguments); + extra.path = this.options.path; + return extra; + }, + _addFile: function(file_data) { var row = $j(document.createElement("tr")) - .attr("data-path", file_data.url) + .attr("data-path", file_data.path) .attr("draggable", "true") .appendTo(this.list); var mime = $j(document.createElement("td")) @@ -720,6 +764,40 @@ var et2_vfsUpload = et2_file.extend( .appendTo(row); var mime = et2_createWidget('vfs-mime',{value: file_data},this); var vfs = et2_createWidget('vfs', {value: file_data}, this); + + // Add in delete button + if (!this.options.readonly) + { + var self = this; + var delete_button = $j(document.createElement("td")) + .appendTo(row); + $j("
") + .appendTo(delete_button) + // We don't use ui-icon because it assigns a bg image + .addClass("delete icon") + .bind( 'click', function() { + et2_dialog.show_dialog( + function(button) { + if(button == et2_dialog.YES_BUTTON) + { + egw.json("filemanager_ui::ajax_action", [ + 'delete', + [row.attr('data-path')], + '' + ], + function(data) { + if(data && data.errs == 0) {row.slideUp(row.remove);} + if(data && data.msg) { + self.egw().message(data.msg, data.errs == 0 ? 'success' : 'error'); + } + } + ).sendRequest(); + } + }, + egw.lang('Delete file?') + ); + }); + } } }); et2_register_widget(et2_vfsUpload, ["vfs-upload"]); diff --git a/etemplate/templates/default/etemplate2.css b/etemplate/templates/default/etemplate2.css index 141302c207..256b6391e0 100644 --- a/etemplate/templates/default/etemplate2.css +++ b/etemplate/templates/default/etemplate2.css @@ -767,7 +767,7 @@ ul.et2_link_string { .et2_link_list td.remark { font-style: italic; } -.et2_link_list td div.delete { +.et2_link_list td div.delete, .et2_vfs td div.delete { visibility: hidden; background-image: url("images/close.png"); background-position: center; @@ -775,12 +775,13 @@ ul.et2_link_string { padding: 0px; } .et2_link_list .icon img, -.et2_link_list .icon { +.et2_link_list .icon, +.et2_vfs .icon img, .et2_vfs .icon { width: 16px; height: 16px; display: inline-block; } -.et2_link_list tr:hover div.delete { +.et2_link_list tr:hover div.delete, .et2_vfs tr:hover div.delete { visibility: visible; } .egw_tooltip { @@ -872,6 +873,7 @@ ul.et2_vfs { } .et2_vfs td.icon { width: 16px; + max-width: 16px; } button.et2_vfs_btn { margin: 0;