forked from extern/egroupware
W.I.P of VFS Select widget restructure
This commit is contained in:
parent
f9aec1bf46
commit
448cc8975f
@ -195,7 +195,8 @@ module.exports = function (grunt) {
|
|||||||
"api/js/etemplate/et2_widget_itempicker.js",
|
"api/js/etemplate/et2_widget_itempicker.js",
|
||||||
"api/js/etemplate/et2_widget_script.js",
|
"api/js/etemplate/et2_widget_script.js",
|
||||||
"api/js/etemplate/et2_core_legacyJSFunctions.js",
|
"api/js/etemplate/et2_core_legacyJSFunctions.js",
|
||||||
"api/js/etemplate/etemplate2.js"
|
"api/js/etemplate/etemplate2.js",
|
||||||
|
"api/js/etemplate/vfsSelectUI.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -633,7 +633,7 @@ var et2_customfields_list = (function(){ "use strict"; return et2_valueWidget.ex
|
|||||||
{
|
{
|
||||||
label: '',
|
label: '',
|
||||||
mode: widget.options.multiple ? 'open-multiple' : 'open',
|
mode: widget.options.multiple ? 'open-multiple' : 'open',
|
||||||
method: 'EGroupware\\Api\\Etemplate\\Widget\\Link::link_existing',
|
method: 'EGroupware\\Api\\Etemplate\\Widget\\Link::ajax_link_existing',
|
||||||
method_id: attrs.path,
|
method_id: attrs.path,
|
||||||
button_label: egw.lang('Link')
|
button_label: egw.lang('Link')
|
||||||
},{type: 'vfs-select'});
|
},{type: 'vfs-select'});
|
||||||
|
@ -183,40 +183,40 @@ var et2_link_to = (function(){ "use strict"; return et2_inputWidget.extend(
|
|||||||
var select_attrs = {
|
var select_attrs = {
|
||||||
button_label: egw.lang('Link'),
|
button_label: egw.lang('Link'),
|
||||||
button_caption: '',
|
button_caption: '',
|
||||||
readonly: this.options.readonly
|
readonly: this.options.readonly,
|
||||||
|
onchange: function() {
|
||||||
|
var values = true;
|
||||||
|
// If entry not yet saved, store for linking on server
|
||||||
|
if(!self.options.value.to_id || typeof self.options.value.to_id == 'object')
|
||||||
|
{
|
||||||
|
values = self.options.value.to_id || {};
|
||||||
|
var files = self.vfs_select.getValue();
|
||||||
|
if(typeof files !== 'undefined')
|
||||||
|
{
|
||||||
|
for(var i = 0; i < files.length; i++)
|
||||||
|
{
|
||||||
|
values['link:'+files[i]] = {
|
||||||
|
app: 'link',
|
||||||
|
id: files[i],
|
||||||
|
type: 'unknown',
|
||||||
|
icon: 'link',
|
||||||
|
remark: '',
|
||||||
|
title: files[i]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self._link_result(values);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// only set server-side callback, if we have a real application-id (not null or array)
|
// only set server-side callback, if we have a real application-id (not null or array)
|
||||||
// otherwise it only gives an error on server-side
|
// otherwise it only gives an error on server-side
|
||||||
if (self.options.value && self.options.value.to_id && typeof self.options.value.to_id != 'object') {
|
if (self.options.value && self.options.value.to_id && typeof self.options.value.to_id != 'object') {
|
||||||
select_attrs.method = 'EGroupware\\Api\\Etemplate\\Widget\\Link::link_existing';
|
select_attrs.method = 'EGroupware\\Api\\Etemplate\\Widget\\Link::ajax_link_existing';
|
||||||
select_attrs.method_id = self.options.value.to_app + ':' + self.options.value.to_id;
|
select_attrs.method_id = self.options.value.to_app + ':' + self.options.value.to_id;
|
||||||
}
|
}
|
||||||
this.vfs_select = et2_createWidget("vfs-select", select_attrs,this);
|
this.vfs_select = et2_createWidget("vfs-select", select_attrs,this);
|
||||||
this.vfs_select.set_readonly(this.options.readonly);
|
this.vfs_select.set_readonly(this.options.readonly);
|
||||||
jQuery(this.vfs_select.getDOMNode()).change( function() {
|
|
||||||
var values = true;
|
|
||||||
// If entry not yet saved, store for linking on server
|
|
||||||
if(!self.options.value.to_id || typeof self.options.value.to_id == 'object')
|
|
||||||
{
|
|
||||||
values = self.options.value.to_id || {};
|
|
||||||
var files = self.vfs_select.getValue();
|
|
||||||
if(typeof files !== 'undefined')
|
|
||||||
{
|
|
||||||
for(var i = 0; i < files.length; i++)
|
|
||||||
{
|
|
||||||
values['link:'+files[i]] = {
|
|
||||||
app: 'link',
|
|
||||||
id: files[i],
|
|
||||||
type: 'unknown',
|
|
||||||
icon: 'link',
|
|
||||||
remark: '',
|
|
||||||
title: files[i]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self._link_result(values);
|
|
||||||
});
|
|
||||||
|
|
||||||
// File upload
|
// File upload
|
||||||
var file_attrs = {
|
var file_attrs = {
|
||||||
@ -633,7 +633,7 @@ var et2_link_entry = (function(){ "use strict"; return et2_inputWidget.extend(
|
|||||||
var buttonItem = jQuery( "<span>", {
|
var buttonItem = jQuery( "<span>", {
|
||||||
"class": "ui-selectmenu-text",
|
"class": "ui-selectmenu-text",
|
||||||
title: value
|
title: value
|
||||||
})
|
});
|
||||||
|
|
||||||
jQuery('.ui-selectmenu-text', this.button).replaceWith(buttonItem);
|
jQuery('.ui-selectmenu-text', this.button).replaceWith(buttonItem);
|
||||||
buttonItem.css('background-image', 'url('+url+')');
|
buttonItem.css('background-image', 'url('+url+')');
|
||||||
@ -786,7 +786,7 @@ var et2_link_entry = (function(){ "use strict"; return et2_inputWidget.extend(
|
|||||||
// Normal stuff
|
// Normal stuff
|
||||||
li.append(jQuery( "<a></a>" ).text( item.label ))
|
li.append(jQuery( "<a></a>" ).text( item.label ))
|
||||||
.appendTo(ul);
|
.appendTo(ul);
|
||||||
window.setTimeout(function(){ul.css('max-width', jQuery('.et2_container').width()-ul.offset().left)}, 300);
|
window.setTimeout(function(){ul.css('max-width', jQuery('.et2_container').width()-ul.offset().left);}, 300);
|
||||||
return li;
|
return li;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
/*egw:uses
|
/*egw:uses
|
||||||
/vendor/bower-asset/jquery/dist/jquery.js;
|
/vendor/bower-asset/jquery/dist/jquery.js;
|
||||||
|
vfsSelectUI;
|
||||||
et2_core_inputWidget;
|
et2_core_inputWidget;
|
||||||
et2_core_valueWidget;
|
et2_core_valueWidget;
|
||||||
et2_widget_description;
|
et2_widget_description;
|
||||||
@ -867,12 +868,15 @@ var et2_vfsSelect = (function(){ "use strict"; return et2_inputWidget.extend(
|
|||||||
"method": {
|
"method": {
|
||||||
name: "Server side callback",
|
name: "Server side callback",
|
||||||
type: "string",
|
type: "string",
|
||||||
description: "Server side callback to process selected value(s) in app.class.method or class::method format. The first parameter will be Method ID, the second the file list."
|
description: "Server side callback to process selected value(s) in \n\
|
||||||
|
app.class.method or class::method format. The first parameter will \n\
|
||||||
|
be Method ID, the second the file list."
|
||||||
},
|
},
|
||||||
"method_id": {
|
"method_id": {
|
||||||
name: "Method ID",
|
name: "Method ID",
|
||||||
type: "any",
|
type: "any",
|
||||||
description: "optional parameter passed to server side callback. Can be a string or a function.",
|
description: "optional parameter passed to server side callback.\n\
|
||||||
|
Can be a string or a function.",
|
||||||
default: ""
|
default: ""
|
||||||
},
|
},
|
||||||
"path": {
|
"path": {
|
||||||
@ -926,7 +930,7 @@ var et2_vfsSelect = (function(){ "use strict"; return et2_inputWidget.extend(
|
|||||||
{
|
{
|
||||||
this.button.hide();
|
this.button.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.button_caption != "")
|
if (this.options.button_caption != "")
|
||||||
{
|
{
|
||||||
this.button.text(this.options.button_caption);
|
this.button.text(this.options.button_caption);
|
||||||
@ -934,61 +938,117 @@ var et2_vfsSelect = (function(){ "use strict"; return et2_inputWidget.extend(
|
|||||||
this.setDOMNode(egw.app('filemanager') ? this.button[0]:document.createElement('span'));
|
this.setDOMNode(egw.app('filemanager') ? this.button[0]:document.createElement('span'));
|
||||||
},
|
},
|
||||||
|
|
||||||
click: function(e) {
|
_content: function (_content, _callback)
|
||||||
|
{
|
||||||
// No permission
|
egw(window).loading_prompt('vfs-select', true, '', 'body');
|
||||||
if(!egw.app('filemanager')) return;
|
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
if (typeof app.vfsSelectUI !="undefined")
|
||||||
var attrs = {
|
|
||||||
menuaction: 'filemanager.filemanager_select.select',
|
|
||||||
mode: this.options.mode,
|
|
||||||
method: this.options.method,
|
|
||||||
label: this.options.button_label,
|
|
||||||
id: typeof this.options.method_id == "function" ? this.options.method_id.call(): this.options.method_id
|
|
||||||
};
|
|
||||||
if(this.options.path)
|
|
||||||
{
|
{
|
||||||
attrs.path = this.options.path;
|
if (this.dialog && this.dialog.div) this.dialog.div.dialog('close');
|
||||||
|
delete app.vfsSelectUI;
|
||||||
}
|
}
|
||||||
if(this.options.mime)
|
var attrs = {
|
||||||
{
|
mode: this.options.mode,
|
||||||
attrs.mime = this.options.mime;
|
label: this.options.button_label,
|
||||||
|
path: this.options.path || null,
|
||||||
|
mime: this.options.mime || null
|
||||||
};
|
};
|
||||||
|
var callback = _callback || this._buildDialog;
|
||||||
|
egw(window).json(
|
||||||
|
'EGroupware\\Api\\Etemplate\\Widget\\Vfs::ajax_vfsSelect_content',
|
||||||
|
[_content, attrs],
|
||||||
|
function(_content){
|
||||||
|
egw(window).loading_prompt('vfs-select', false);
|
||||||
|
callback.apply(self, arguments);
|
||||||
|
}
|
||||||
|
).sendRequest(true);
|
||||||
|
},
|
||||||
|
|
||||||
// Open the filemanager select in a popup
|
/**
|
||||||
var popup = this.egw(window).open_link(
|
* Builds file navigator dialog
|
||||||
this.egw().link('/index.php', attrs),
|
*
|
||||||
'link_existing',
|
* @param {object} _data content
|
||||||
'680x400'
|
*/
|
||||||
);
|
_buildDialog: function (_data)
|
||||||
if(popup)
|
{
|
||||||
|
if (!_data.content.mode.match(/open|open-multiple|saveas|select-dir/)) {
|
||||||
|
egw.debug('Mode is not matched!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var self = this;
|
||||||
|
var buttons = [
|
||||||
|
{text: egw.lang(_data.content.label), id:"submit"},
|
||||||
|
{text: egw.lang("Close"), id:"close"}
|
||||||
|
];
|
||||||
|
var data = jQuery.extend(_data, {'currentapp': egw.app_name()});
|
||||||
|
|
||||||
|
// define a mini app object for vfs select UI
|
||||||
|
app.vfsSelectUI = new app.classes.vfsSelectUI;
|
||||||
|
|
||||||
|
this.dialog = et2_createWidget("dialog",
|
||||||
{
|
{
|
||||||
// Safari and IE lose reference to global variables after window close
|
callback: function(_button_id, _value)
|
||||||
// Try to get updated data before window is closed then later we trigger
|
{
|
||||||
// change event on widget
|
if (_button_id == 'submit' && _value)
|
||||||
self.egw().window.setTimeout(function(){
|
{
|
||||||
jQuery(popup).bind('unload',function(){
|
var files = [];
|
||||||
// Set selected files to widget
|
switch(_data.content.mode)
|
||||||
self.value = this.selected_files;
|
{
|
||||||
|
case 'open-multiple':
|
||||||
// Update path to where the user wound up]
|
if (_value.dir && _value.dir.selected)
|
||||||
if (typeof this.etemplate2 !='undefined') self.options.path = this.etemplate2.getByApplication('filemanager')[0].widgetContainer.getArrayMgr("content").getEntry('path');
|
{
|
||||||
});
|
Object.keys(_value.dir.selected)
|
||||||
},1000);
|
.forEach((key) => (_value.dir.selected[key] != "")
|
||||||
|
&& files.push(_value.path+'/'+_value.dir.selected[key]));
|
||||||
// Update on close doesn't always (ever, in chrome) work, so poll
|
}
|
||||||
var poll = self.egw().window.setInterval(
|
break;
|
||||||
function() {
|
case 'select-dir':
|
||||||
if(popup.closed) {
|
files = _value.path;
|
||||||
self.egw().window.clearInterval(poll);
|
break;
|
||||||
// Fire a change event so any handlers run
|
default:
|
||||||
|
files = _value.path+'/'+_value.name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.value = files;
|
||||||
|
if (self.options.method)
|
||||||
|
{
|
||||||
|
egw(window).json(
|
||||||
|
self.options.method,
|
||||||
|
[self.options.method_id, files],
|
||||||
|
function(){
|
||||||
|
jQuery(self.node).change();
|
||||||
|
}
|
||||||
|
).sendRequest(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
jQuery(self.node).change();
|
jQuery(self.node).change();
|
||||||
}
|
}
|
||||||
},1000
|
delete app.vfsSelectUI;
|
||||||
);
|
}
|
||||||
}
|
},
|
||||||
|
title: egw.lang('Save File'),
|
||||||
|
buttons: buttons,
|
||||||
|
minWidth: 500,
|
||||||
|
minHeight: 400,
|
||||||
|
value: data,
|
||||||
|
template: egw.webserverUrl+'/api/templates/default/vfsSelectUI.xet?1',
|
||||||
|
resizable: false
|
||||||
|
}, et2_dialog._create_parent('api'));
|
||||||
|
this.dialog.template.uniqueId = 'api.vfsSelectUI';
|
||||||
|
app.vfsSelectUI.et2 = this.dialog.template.widgetContainer;
|
||||||
|
app.vfsSelectUI.vfsSelectWidget = this;
|
||||||
|
this.dialog.div.on('load', function(e) {
|
||||||
|
app.vfsSelectUI.et2_ready(app.vfsSelectUI.et2, 'api.vfsSelectUI');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* click handler
|
||||||
|
* @param {event object} e
|
||||||
|
*/
|
||||||
|
click: function(e) {
|
||||||
|
this._content.call(this, null);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1038,7 +1098,7 @@ var et2_vfsSelect = (function(){ "use strict"; return et2_inputWidget.extend(
|
|||||||
|
|
||||||
set_readonly: function(readonly) {
|
set_readonly: function(readonly) {
|
||||||
this.options.readonly = Boolean(readonly);
|
this.options.readonly = Boolean(readonly);
|
||||||
|
|
||||||
if(this.options.readonly)
|
if(this.options.readonly)
|
||||||
{
|
{
|
||||||
this.button.hide();
|
this.button.hide();
|
||||||
|
315
api/js/etemplate/vfsSelectUI.js
Normal file
315
api/js/etemplate/vfsSelectUI.js
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
/**
|
||||||
|
* EGroupware - VFS SELECT Widget UI
|
||||||
|
*
|
||||||
|
* @link http://www.egroupware.org
|
||||||
|
* @package et2_vfsSelect
|
||||||
|
* @author Hadi Nategh <hn@egroupware.org>
|
||||||
|
* @copyright (c) 2013-2017 by Hadi Nategh <hn@egroupware.org>
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
/**
|
||||||
|
* UI for VFS Select widget
|
||||||
|
*
|
||||||
|
* @augments AppJS
|
||||||
|
*/
|
||||||
|
app.classes.vfsSelectUI = AppJS.extend({
|
||||||
|
|
||||||
|
vfsSelectWidget: {},
|
||||||
|
path_widget: {},
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @memberOf app.filemanager
|
||||||
|
*/
|
||||||
|
init: function()
|
||||||
|
{
|
||||||
|
// call parent
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor
|
||||||
|
*/
|
||||||
|
destroy: function()
|
||||||
|
{
|
||||||
|
delete this.path_widget;
|
||||||
|
delete this.vfsSelectWidget;
|
||||||
|
// call parent
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called when the etemplate2 object is loaded
|
||||||
|
* and ready. If you must store a reference to the et2 object,
|
||||||
|
* make sure to clean it up in destroy().
|
||||||
|
*
|
||||||
|
* @param et2 etemplate2 Newly ready object
|
||||||
|
* @param {string} name template name
|
||||||
|
*/
|
||||||
|
et2_ready: function(et2,name)
|
||||||
|
{
|
||||||
|
this.path_widget = this.et2.getWidgetById('path');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get directory of a path
|
||||||
|
*
|
||||||
|
* @param {string} _path
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
|
dirname: function(_path)
|
||||||
|
{
|
||||||
|
var parts = _path.split('/');
|
||||||
|
parts.pop();
|
||||||
|
return parts.join('/') || '/';
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get name of a path
|
||||||
|
*
|
||||||
|
* @param {string} _path
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
|
basename: function(_path)
|
||||||
|
{
|
||||||
|
return _path.split('/').pop();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current working directory
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
get_path: function()
|
||||||
|
{
|
||||||
|
return this.path_widget.get_value();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send names of uploaded files (again) to server, to process them: either copy to vfs or ask overwrite/rename
|
||||||
|
*
|
||||||
|
* @param {event} _event
|
||||||
|
* @param {number} _file_count
|
||||||
|
* @param {string=} _path where the file is uploaded to, default current directory
|
||||||
|
*/
|
||||||
|
upload: function(_event, _file_count, _path)
|
||||||
|
{
|
||||||
|
if(typeof _path == 'undefined')
|
||||||
|
{
|
||||||
|
_path = this.get_path();
|
||||||
|
}
|
||||||
|
if (_file_count && !jQuery.isEmptyObject(_event.data.getValue()))
|
||||||
|
{
|
||||||
|
var widget = _event.data;
|
||||||
|
egw(window).json('filemanager_ui::ajax_action', ['upload', widget.getValue(), _path],
|
||||||
|
this._upload_callback, this, true, this
|
||||||
|
).sendRequest(true);
|
||||||
|
widget.set_value('');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for server response to upload request:
|
||||||
|
* - display message and refresh list
|
||||||
|
* - ask use to confirm overwritting existing files or rename upload
|
||||||
|
*
|
||||||
|
* @param {object} _data values for attributes msg, files, ...
|
||||||
|
*/
|
||||||
|
_upload_callback: function(_data)
|
||||||
|
{
|
||||||
|
if (_data.msg || _data.uploaded) window.egw_refresh(_data.msg, this.appname);
|
||||||
|
|
||||||
|
var that = this;
|
||||||
|
for(var file in _data.uploaded)
|
||||||
|
{
|
||||||
|
if (_data.uploaded[file].confirm && !_data.uploaded[file].confirmed)
|
||||||
|
{
|
||||||
|
var buttons = [
|
||||||
|
{text: this.egw.lang("Yes"), id: "overwrite", class: "ui-priority-primary", "default": true, image: 'check'},
|
||||||
|
{text: this.egw.lang("Rename"), id:"rename", image: 'edit'},
|
||||||
|
{text: this.egw.lang("Cancel"), id:"cancel"}
|
||||||
|
];
|
||||||
|
if (_data.uploaded[file].confirm === "is_dir")
|
||||||
|
buttons.shift();
|
||||||
|
var dialog = et2_dialog.show_prompt(function(_button_id, _value) {
|
||||||
|
var uploaded = {};
|
||||||
|
uploaded[this.my_data.file] = this.my_data.data;
|
||||||
|
switch (_button_id)
|
||||||
|
{
|
||||||
|
case "overwrite":
|
||||||
|
uploaded[this.my_data.file].confirmed = true;
|
||||||
|
// fall through
|
||||||
|
case "rename":
|
||||||
|
uploaded[this.my_data.file].name = _value;
|
||||||
|
delete uploaded[this.my_data.file].confirm;
|
||||||
|
// send overwrite-confirmation and/or rename request to server
|
||||||
|
egw.json('filemanager_ui::ajax_action', [this.my_data.action, uploaded, this.my_data.path, this.my_data.props],
|
||||||
|
that._upload_callback, that, true, that
|
||||||
|
).sendRequest();
|
||||||
|
return;
|
||||||
|
case "cancel":
|
||||||
|
// Remove that file from every file widget...
|
||||||
|
that.et2.iterateOver(function(_widget) {
|
||||||
|
_widget.remove_file(this.my_data.data.name);
|
||||||
|
}, this, et2_file);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_data.uploaded[file].confirm === "is_dir" ?
|
||||||
|
this.egw.lang("There's already a directory with that name!") :
|
||||||
|
this.egw.lang('Do you want to overwrite existing file %1 in directory %2?', _data.uploaded[file].name, _data.path),
|
||||||
|
this.egw.lang('File %1 already exists', _data.uploaded[file].name),
|
||||||
|
_data.uploaded[file].name, buttons, file);
|
||||||
|
// setting required data for callback in as my_data
|
||||||
|
dialog.my_data = {
|
||||||
|
action: _data.action,
|
||||||
|
file: file,
|
||||||
|
path: _data.path,
|
||||||
|
data: _data.uploaded[file],
|
||||||
|
props: _data.props
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompt user for directory to create
|
||||||
|
*
|
||||||
|
* @param {egwAction|undefined|jQuery.Event} action Action, event or undefined if called directly
|
||||||
|
* @param {egwActionObject[] | undefined} selected Selected row, or undefined if called directly
|
||||||
|
*/
|
||||||
|
createdir: function(action, selected)
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
et2_dialog.show_prompt(function(button, dir){
|
||||||
|
if (button && dir)
|
||||||
|
{
|
||||||
|
var path = self.get_path();
|
||||||
|
self.egw.json('EGroupware\\Api\\Etemplate\\Widget\\Vfs::ajax_create_dir', [dir, path], function(msg){
|
||||||
|
self.egw.message(msg);
|
||||||
|
self.change_dir((path == '/' ? '' : path)+'/'+ dir);
|
||||||
|
}).sendRequest(false);
|
||||||
|
}
|
||||||
|
},this.egw.lang('New directory'),this.egw.lang('Create directory'));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change directory
|
||||||
|
*
|
||||||
|
* @param {string} _dir directory to change to incl. '..' for one up
|
||||||
|
* @param {et2_widget} widget
|
||||||
|
*/
|
||||||
|
change_dir: function(_dir, widget)
|
||||||
|
{
|
||||||
|
switch (_dir)
|
||||||
|
{
|
||||||
|
case '..':
|
||||||
|
_dir = this.dirname(this.get_path());
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.path_widget.set_value(_dir);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Row or filename in select-file dialog clicked
|
||||||
|
*
|
||||||
|
* @param {jQuery.event} event
|
||||||
|
* @param {et2_widget} widget
|
||||||
|
*/
|
||||||
|
select_clicked: function(event, widget)
|
||||||
|
{
|
||||||
|
if (!widget || typeof widget.value != 'object')
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (widget.value.is_dir) // true for "httpd/unix-directory" and "egw/*"
|
||||||
|
{
|
||||||
|
var path = null;
|
||||||
|
// Cannot do this, there are multiple widgets named path
|
||||||
|
// widget.getRoot().getWidgetById("path");
|
||||||
|
widget.getRoot().iterateOver(function(widget) {
|
||||||
|
if(widget.id == "path") path = widget;
|
||||||
|
},null, et2_textbox);
|
||||||
|
if(path)
|
||||||
|
{
|
||||||
|
path.set_value(widget.value.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (this.et2 && this.et2.getArrayMgr('content').getEntry('mode') != 'open-multiple')
|
||||||
|
{
|
||||||
|
var editfield = this.et2.getWidgetById('name');
|
||||||
|
if(editfield)
|
||||||
|
{
|
||||||
|
editfield.set_value(widget.value.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var file = widget.value.name;
|
||||||
|
widget.getParent().iterateOver(function(widget)
|
||||||
|
{
|
||||||
|
if(widget.options.selected_value == file)
|
||||||
|
{
|
||||||
|
widget.set_value(widget.get_value() == file ? widget.options.unselected_value : file);
|
||||||
|
}
|
||||||
|
}, null, et2_checkbox);
|
||||||
|
|
||||||
|
}
|
||||||
|
// Stop event or it will toggle back off
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles action and offer it to the submit
|
||||||
|
*
|
||||||
|
* @param {string} action action name
|
||||||
|
* @param {object} widget widget which action was called from
|
||||||
|
*/
|
||||||
|
do_action: function (action, widget)
|
||||||
|
{
|
||||||
|
if (!action) return;
|
||||||
|
var field = '', value = '';
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case 'path': field = 'path'; value = widget.getValue(); break;
|
||||||
|
case 'home': field = 'action'; value = 'home'; break;
|
||||||
|
case 'app': field = 'app'; value = widget.getValue(); break;
|
||||||
|
}
|
||||||
|
this.submit(field, value);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sumbits content value after modification
|
||||||
|
*
|
||||||
|
* @param {string} _field content field to be modified
|
||||||
|
* @param {any} _val value of field
|
||||||
|
* @param {function} _callback
|
||||||
|
*/
|
||||||
|
submit: function(_field, _val, _callback)
|
||||||
|
{
|
||||||
|
var arrMgrs = this.et2.getArrayMgrs();
|
||||||
|
arrMgrs.content.data[_field] = _val;
|
||||||
|
if (_field == 'dir') arrMgrs.content.data['button'] = 'ok';
|
||||||
|
jQuery.extend(arrMgrs.content.data, arrMgrs.modifications.data);
|
||||||
|
this.et2.setArrayMgrs(arrMgrs);
|
||||||
|
this.vfsSelectWidget._content(arrMgrs.content.data, _callback);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {type} _widget
|
||||||
|
* @returns {undefined}
|
||||||
|
* @todo: implementation of upload file
|
||||||
|
*/
|
||||||
|
uploaded: function (_widget)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
@ -247,7 +247,7 @@ class Link extends Etemplate\Widget
|
|||||||
/**
|
/**
|
||||||
* Symlink an existing file in filemanager
|
* Symlink an existing file in filemanager
|
||||||
*/
|
*/
|
||||||
public static function link_existing($app_id, $files)
|
public static function ajax_link_existing($app_id, $files)
|
||||||
{
|
{
|
||||||
list($app, $id, $dest_file) = explode(':', $app_id);
|
list($app, $id, $dest_file) = explode(':', $app_id);
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
namespace EGroupware\Api\Etemplate\Widget;
|
namespace EGroupware\Api\Etemplate\Widget;
|
||||||
|
|
||||||
use EGroupware\Api\Etemplate;
|
use EGroupware\Api\Etemplate;
|
||||||
|
use EGroupware\Api\Framework;
|
||||||
|
use EGroupware\Api\Json;
|
||||||
use EGroupware\Api;
|
use EGroupware\Api;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -368,4 +370,208 @@ class Vfs extends File
|
|||||||
if (!empty($relpath)) $path .= '/'.$relpath;
|
if (!empty($relpath)) $path .= '/'.$relpath;
|
||||||
return $path;
|
return $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function behaves like etemplate app function for set/get content of
|
||||||
|
* VFS Select Widget UI
|
||||||
|
*
|
||||||
|
* There are the following ($params) parameters:
|
||||||
|
*
|
||||||
|
* - mode=(open|open-multiple|saveas|select-dir) (required)
|
||||||
|
* - method=app.class.method (optional callback, gets called with id and selected file(s))
|
||||||
|
* - id=... (optional parameter passed to callback)
|
||||||
|
* - path=... (optional start path in VFS)
|
||||||
|
* - mime=... (optional mime-type to limit display to given type)
|
||||||
|
* - label=... (optional label for submit button, default "Open")
|
||||||
|
*
|
||||||
|
* @param array $content
|
||||||
|
* @param array $params
|
||||||
|
* @throws Api\Exception\WrongParameter
|
||||||
|
*/
|
||||||
|
public static function ajax_vfsSelect_content (array $content=null, $params = null)
|
||||||
|
{
|
||||||
|
$response = Json\Response::get();
|
||||||
|
$readonlys = $sel_options = array();
|
||||||
|
if (!is_array($content))
|
||||||
|
{
|
||||||
|
$content = array_merge($params, array(
|
||||||
|
'label' => isset($params['label']) ? $params['label'] : lang('Open'),
|
||||||
|
'name' => (string)$params['name'],
|
||||||
|
'path' => empty($params['path']) ?
|
||||||
|
Api\Cache::getSession('filemanger', 'select_path'): $params['path'],
|
||||||
|
));
|
||||||
|
|
||||||
|
if (!in_array($content['mode'],array('open','open-multiple','saveas','select-dir')))
|
||||||
|
{
|
||||||
|
throw new Api\Exception\WrongParameter("Wrong or unset required mode parameter!");
|
||||||
|
}
|
||||||
|
if (isset($content['options-mime']))
|
||||||
|
{
|
||||||
|
$sel_options['mime'] = array();
|
||||||
|
foreach((array)$params['mime'] as $key => $value)
|
||||||
|
{
|
||||||
|
if (is_numeric($key))
|
||||||
|
{
|
||||||
|
$sel_options['mime'][$value] = lang('%1 files',strtoupper(Api\MimeMagic::mime2ext($value))).' ('.$value.')';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$sel_options['mime'][$key] = lang('%1 files',strtoupper($value)).' ('.$key.')';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list($content['mime']) = each($sel_options['mime']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif(isset($content['action']))
|
||||||
|
{
|
||||||
|
$action = $content['action'];
|
||||||
|
unset($content['action']);
|
||||||
|
switch($action)
|
||||||
|
{
|
||||||
|
case 'home':
|
||||||
|
$content['path'] = \EGroupware\Api\Vfs::get_home_dir();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($content['app']) && $content['old_app'] != $content['app'])
|
||||||
|
{
|
||||||
|
$content['path'] = $content['app'] == 'home'? \EGroupware\Api\Vfs::get_home_dir():
|
||||||
|
'/apps/'.$content['app'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$favorites_flag = substr($content['path'],0,strlen('/apps/favorites')) == '/apps/favorites';
|
||||||
|
if (!$favorites_flag && (!$content['path'] || !\EGroupware\Api\Vfs::is_dir($content['path'])))
|
||||||
|
{
|
||||||
|
$content['path'] = \EGroupware\Api\Vfs::get_home_dir();
|
||||||
|
}
|
||||||
|
elseif ($favorites_flag)
|
||||||
|
{
|
||||||
|
// Display favorites as if they were folders
|
||||||
|
$files = array();
|
||||||
|
$favorites = \EGroupware\Api\Framework\Favorites::get_favorites('filemanager');
|
||||||
|
$n = 0;
|
||||||
|
foreach($favorites as $favorite)
|
||||||
|
{
|
||||||
|
$path = $favorite['state']['path'];
|
||||||
|
// Just directories
|
||||||
|
if(!$path) continue;
|
||||||
|
if ($path == $content['path']) continue; // remove directory itself
|
||||||
|
|
||||||
|
$mime = \EGroupware\Api\Vfs::mime_content_type($path);
|
||||||
|
$content['dir'][$n] = array(
|
||||||
|
'name' => $favorite['name'],
|
||||||
|
'path' => $path,
|
||||||
|
'mime' => $mime,
|
||||||
|
'is_dir' => true
|
||||||
|
);
|
||||||
|
if ($content['mode'] == 'open-multiple')
|
||||||
|
{
|
||||||
|
$readonlys['selected['.$favorite['name'].']'] = true;
|
||||||
|
}
|
||||||
|
++$n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!($files = \EGroupware\Api\Vfs::find($content['path'],array(
|
||||||
|
'dirsontop' => true,
|
||||||
|
'order' => 'name',
|
||||||
|
'sort' => 'ASC',
|
||||||
|
'maxdepth' => 1,
|
||||||
|
))))
|
||||||
|
{
|
||||||
|
$content['msg'] = lang("Can't open directory %1!",$content['path']);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$n = 0;
|
||||||
|
$content['dir'] = array('mode' => $content['mode']);
|
||||||
|
foreach($files as $path)
|
||||||
|
{
|
||||||
|
if ($path == $content['path']) continue; // remove directory itself
|
||||||
|
|
||||||
|
$name = \EGroupware\Api\Vfs::basename($path);
|
||||||
|
$is_dir = \EGroupware\Api\Vfs::is_dir($path);
|
||||||
|
$mime = \EGroupware\Api\Vfs::mime_content_type($path);
|
||||||
|
if ($content['mime'] && !$is_dir && $mime != $content['mime'])
|
||||||
|
{
|
||||||
|
continue; // does not match mime-filter --> ignore
|
||||||
|
}
|
||||||
|
$content['dir'][$n] = array(
|
||||||
|
'name' => $name,
|
||||||
|
'path' => $path,
|
||||||
|
'mime' => $mime,
|
||||||
|
'is_dir' => $is_dir
|
||||||
|
);
|
||||||
|
if ($is_dir && $content['mode'] == 'open-multiple')
|
||||||
|
{
|
||||||
|
$readonlys['selected['.$name.']'] = true;
|
||||||
|
}
|
||||||
|
++$n;
|
||||||
|
}
|
||||||
|
if (!$n) $readonlys['selected[]'] = true; // remove checkbox from empty line
|
||||||
|
}
|
||||||
|
$readonlys = array_merge($readonlys, array(
|
||||||
|
'createdir' => !\EGroupware\Api\Vfs::is_writable($content['path']),
|
||||||
|
'upload_file' => !\EGroupware\Api\Vfs::is_writable($content['path']) ||
|
||||||
|
!in_array($content['mode'],array('open', 'open-multiple')),
|
||||||
|
));
|
||||||
|
|
||||||
|
$sel_options = array_merge($sel_options, array(
|
||||||
|
'app' => self::get_apps()
|
||||||
|
));
|
||||||
|
Api\Cache::setSession('filemanger', 'select_path', $content['path']);
|
||||||
|
// Response
|
||||||
|
$response->data(array(
|
||||||
|
'content' => $content,
|
||||||
|
'sel_options' => $sel_options,
|
||||||
|
'readonlys' => $readonlys,
|
||||||
|
'modifications' => array (
|
||||||
|
'mode' => $content['mode'],
|
||||||
|
'method' => $content['method'],
|
||||||
|
'id' => $content['id'],
|
||||||
|
'label' => $content['label'],
|
||||||
|
'mime' => $content['mime'],
|
||||||
|
'options-mime' => $sel_options['mime'],
|
||||||
|
'old_path' => $content['path'],
|
||||||
|
'old_app' => $content['app']
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to create directory in the given path
|
||||||
|
*
|
||||||
|
* @param type $dir name of the directory
|
||||||
|
* @param type $path path to create directory in it
|
||||||
|
*/
|
||||||
|
public static function ajax_create_dir ($dir, $path)
|
||||||
|
{
|
||||||
|
$response = Json\Response::get();
|
||||||
|
$msg = '';
|
||||||
|
if (!empty($dir) && !empty($path))
|
||||||
|
{
|
||||||
|
$dst = \EGroupware\Api\Vfs::concat($path, $dir);
|
||||||
|
if (\EGroupware\Api\Vfs::mkdir($dst, null, STREAM_MKDIR_RECURSIVE))
|
||||||
|
{
|
||||||
|
$msg = lang("Directory successfully created.");
|
||||||
|
}
|
||||||
|
$msg = lang("Error while creating directory.");
|
||||||
|
}
|
||||||
|
$response->data($msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list off all apps having an application directory in VFS
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
static function get_apps()
|
||||||
|
{
|
||||||
|
$apps = array(false); // index starting from 1
|
||||||
|
if (isset($GLOBALS['egw_info']['apps']['stylite'])) $apps = array('favorites' => lang('Favorites'));
|
||||||
|
$apps += \EGroupware\Api\Link::app_list('query');
|
||||||
|
// they do NOT support adding files to VFS
|
||||||
|
unset($apps['addressbook-email'], $apps['mydms'], $apps['wiki'],
|
||||||
|
$apps['api-accounts']);
|
||||||
|
return $apps;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1286,7 +1286,7 @@ button.et2_vfs_btn {
|
|||||||
background-position: 4px center;
|
background-position: 4px center;
|
||||||
background-size: 20px auto;
|
background-size: 20px auto;
|
||||||
}
|
}
|
||||||
img.vfsMimeIcon, #filemanager-select img.vfsMimeIcon {
|
img.vfsMimeIcon, #api\.vfsSelectUI img.vfsMimeIcon {
|
||||||
max-height: 16px;
|
max-height: 16px;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
@ -1945,7 +1945,9 @@ div.ui-dialog div.ui-dialog-content > div[id] {
|
|||||||
padding-left: 3px;
|
padding-left: 3px;
|
||||||
background-image: none;
|
background-image: none;
|
||||||
}
|
}
|
||||||
.et2_toolbar button, .nextmatch_header_row button, .et2_toolbar div.et2_progress, .nextmatch_header_row div.et2_progress {
|
.et2_toolbar button, .nextmatch_header_row button,
|
||||||
|
.et2_toolbar div.et2_progress,
|
||||||
|
.nextmatch_header_row div.et2_progress {
|
||||||
margin: 1px 4px 1px 0;
|
margin: 1px 4px 1px 0;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
@ -2827,4 +2829,40 @@ div.eml div.emlDelete {
|
|||||||
div.eml div.emlDelete:hover, div.eml div.emlEdit:hover {
|
div.eml div.emlDelete:hover, div.eml div.emlEdit:hover {
|
||||||
opacity:1;
|
opacity:1;
|
||||||
filter:contrast(9);
|
filter:contrast(9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vfs-select-container .et2_toolbar *{
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.vfs-select-toggle {display:none;}
|
||||||
|
.vfs-select-app {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
.vfs-select-container .selectFiles {
|
||||||
|
height: 250px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.vfs-select-container div.et2_file span {
|
||||||
|
width: 22px !important;
|
||||||
|
height: 22px !important;
|
||||||
|
padding: 0;
|
||||||
|
background-position-x: 3px !important;
|
||||||
|
background-image: url(../../../pixelegg/images/add.png);
|
||||||
|
overflow: hidden !important;
|
||||||
|
text-indent: 100px !important;
|
||||||
|
}
|
||||||
|
.vfs-select-container div.et2_file {
|
||||||
|
width: 24px;
|
||||||
|
}
|
||||||
|
.vfs-select-container div.et2_file .progress {
|
||||||
|
width: 252px;
|
||||||
|
max-height: 12em;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0px;
|
||||||
|
float: right !important;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
#api\.vfsSelectUI_app {width:205px}
|
||||||
|
#api\.vfsSelectUI_name {padding-right: 4px;}
|
52
api/templates/default/vfsSelectUI.xet
Normal file
52
api/templates/default/vfsSelectUI.xet
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE overlay PUBLIC "-//EGroupware GmbH//eTemplate 2//EN" "http://www.egroupware.org/etemplate2.dtd">
|
||||||
|
<!-- $Id$ -->
|
||||||
|
<overlay>
|
||||||
|
<template id="api.vfsSelectUI" template="" lang="" group="0" version="1.9.002">
|
||||||
|
<grid width="100%" class="vfs-select-container" resize_ratio="0">
|
||||||
|
<columns>
|
||||||
|
<column width="80"/>
|
||||||
|
<column width="200"/>
|
||||||
|
</columns>
|
||||||
|
<rows >
|
||||||
|
<row class="et2_toolbar" disabled="@mode=/(open-multiple|select-dir)/">
|
||||||
|
<description value="File Name" label="%s:"/>
|
||||||
|
<textbox label="File Name" id="name" width="200"/>
|
||||||
|
</row>
|
||||||
|
<row class="nextmatch_header_row">
|
||||||
|
<box class="et2_toolbar">
|
||||||
|
<buttononly statustext="Go to your home directory" id="home" onclick="app.vfsSelectUI.do_action('home', widget)" image="gohome" background_image="1"/>
|
||||||
|
<buttononly statustext="Up" id="up" onclick="app.vfsSelectUI.change_dir('..', widget);" image="goup" background_image="1"/>
|
||||||
|
<select width="175" id="app" empty_label="Applications" no_lang="1" onchange="app.vfsSelectUI.do_action('app', widget)"/>
|
||||||
|
<buttononly statustext="Create directory" id="createdir" class="createDir" onclick="app.vfsSelectUI.createdir" image="button_createdir" ro_image="createdir_disabled" background_image="1"/>
|
||||||
|
<file id='upload_file' progress_dropdownlist = "true" onFinishOne="app.vfsSelectUI.uploadOnOne"/>
|
||||||
|
<vfs-name id="path" width="280" class="selectPath" align="left" onchange="app.vfsSelectUI.do_action('path', widget)"/>
|
||||||
|
</box>
|
||||||
|
</row>
|
||||||
|
<row >
|
||||||
|
<hbox class="selectFiles">
|
||||||
|
<grid width="100%" id="dir">
|
||||||
|
<columns>
|
||||||
|
<column width="20"/>
|
||||||
|
<column/>
|
||||||
|
<column width="1%" disabled="!@mode=open-multiple"/>
|
||||||
|
</columns>
|
||||||
|
<rows>
|
||||||
|
<row class="row">
|
||||||
|
<vfs-mime align="center" id="$row" options="16" class="selectIcon"/>
|
||||||
|
<vfs id="$row" onclick="app.vfsSelectUI.select_clicked"/>
|
||||||
|
<checkbox align="right" id="selected[]" options=""$row_cont[name]""/>
|
||||||
|
</row>
|
||||||
|
</rows>
|
||||||
|
</grid>
|
||||||
|
</hbox>
|
||||||
|
</row>
|
||||||
|
<row disabled="!@options-mime">
|
||||||
|
<menulist class="selectMime">
|
||||||
|
<menupopup id="mime" onchange="1" options="All files"/>
|
||||||
|
</menulist>
|
||||||
|
</row>
|
||||||
|
</rows>
|
||||||
|
</grid>
|
||||||
|
</template>
|
||||||
|
</overlay>
|
@ -1,366 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* EGroupware - Filemanager - select file to open or save dialog
|
|
||||||
*
|
|
||||||
* @link http://www.egroupware.org
|
|
||||||
* @package filemanager
|
|
||||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
|
||||||
* @copyright (c) 2009-2016 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
|
||||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
|
|
||||||
use EGroupware\Api;
|
|
||||||
use EGroupware\Api\Link;
|
|
||||||
use EGroupware\Api\Framework;
|
|
||||||
use EGroupware\Api\Egw;
|
|
||||||
use EGroupware\Api\Vfs;
|
|
||||||
use EGroupware\Api\Etemplate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Select file to open or save dialog
|
|
||||||
*
|
|
||||||
* This dialog can be called from applications to open or store files from the VFS.
|
|
||||||
*
|
|
||||||
* There are the following ($_GET) parameters:
|
|
||||||
* - menuaction=filemanager.filemanager_select.select (required)
|
|
||||||
* - mode=(open|open-multiple|saveas|select-dir) (required)
|
|
||||||
* - method=app.class.method (required callback, gets called with id and selected file(s))
|
|
||||||
* - id=... (optional parameter passed to callback)
|
|
||||||
* - path=... (optional start path in VFS)
|
|
||||||
* - mime=... (optional mime-type to limit display to given type)
|
|
||||||
* - label=... (optional label for submit button, default "Open")
|
|
||||||
*
|
|
||||||
* The application calls this method in a popup with size: 640x580 px
|
|
||||||
* After the user selected one or more files (depending on the mode parameter), the "method" callback gets
|
|
||||||
* called on server (!) side. Parameters are the id plus the selected files as 1. and 2. parameter.
|
|
||||||
* The callback returns javascript to eg. update it's UI AND (!) to close the current popup ("window.close();").
|
|
||||||
*/
|
|
||||||
class filemanager_select
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Methods callable via menuaction
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
var $public_functions = array(
|
|
||||||
'select' => true,
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function __construct()
|
|
||||||
{
|
|
||||||
// strip slashes from _GET parameters, if someone still has magic_quotes_gpc on
|
|
||||||
if (get_magic_quotes_gpc() && $_GET)
|
|
||||||
{
|
|
||||||
$_GET = array_stripslashes($_GET);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File selector
|
|
||||||
*
|
|
||||||
* @param array $content
|
|
||||||
*/
|
|
||||||
function select(array $content=null)
|
|
||||||
{
|
|
||||||
if (!is_array($content))
|
|
||||||
{
|
|
||||||
$content = array();
|
|
||||||
// recover from a failed upload in CkEditor, eg. > max_uploadsize
|
|
||||||
if ($_GET['failed_upload'] && $_GET['msg'])
|
|
||||||
{
|
|
||||||
$content['msg'] = $_GET['msg'];
|
|
||||||
$_GET['mode'] = 'open';
|
|
||||||
$_GET['method'] = 'ckeditor_return';
|
|
||||||
$_GET['CKEditorFuncNum'] = Api\Cache::getSession('filemanager','ckeditorfuncnum');
|
|
||||||
}
|
|
||||||
$content['mode'] = $_GET['mode'];
|
|
||||||
if (!in_array($content['mode'],array('open','open-multiple','saveas','select-dir')))
|
|
||||||
{
|
|
||||||
throw new Api\Exception\WrongParameter("Wrong or unset required mode parameter!");
|
|
||||||
}
|
|
||||||
$content['path'] = $_GET['path'];
|
|
||||||
if (empty($content['path']))
|
|
||||||
{
|
|
||||||
$content['path'] = Api\Cache::getSession('filemanger', 'select_path');
|
|
||||||
}
|
|
||||||
$content['name'] = (string)$_GET['name'];
|
|
||||||
$content['method'] = $_GET['method'];
|
|
||||||
if ($content['method'] == 'ckeditor_return')
|
|
||||||
{
|
|
||||||
if (isset($_GET['CKEditorFuncNum']) && is_numeric($_GET['CKEditorFuncNum']))
|
|
||||||
{
|
|
||||||
Api\Cache::setSession('filemanager','ckeditorfuncnum',
|
|
||||||
$content['ckeditorfuncnum'] = $_GET['CKEditorFuncNum']);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Api\Exception\WrongParameter("chkeditor_return has been specified as a method but some parameters are missing or invalid.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$content['id'] = $_GET['id'];
|
|
||||||
$content['label'] = isset($_GET['label']) ? $_GET['label'] : lang('Open');
|
|
||||||
if (($content['options-mime'] = isset($_GET['mime'])))
|
|
||||||
{
|
|
||||||
$sel_options['mime'] = array();
|
|
||||||
foreach((array)$_GET['mime'] as $key => $value)
|
|
||||||
{
|
|
||||||
if (is_numeric($key))
|
|
||||||
{
|
|
||||||
$sel_options['mime'][$value] = lang('%1 files',strtoupper(Api\MimeMagic::mime2ext($value))).' ('.$value.')';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$sel_options['mime'][$key] = lang('%1 files',strtoupper($value)).' ('.$key.')';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
list($content['mime']) = each($sel_options['mime']);
|
|
||||||
error_log(array2string($content['options-mime']));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elseif(isset($content['button']))
|
|
||||||
{
|
|
||||||
list($button) = each($content['button']);
|
|
||||||
unset($content['button']);
|
|
||||||
switch($button)
|
|
||||||
{
|
|
||||||
case 'home':
|
|
||||||
$content['path'] = filemanager_ui::get_home_dir();
|
|
||||||
break;
|
|
||||||
case 'ok':
|
|
||||||
$copy_result = null;
|
|
||||||
if (isset($content['file_upload']['name']) && file_exists($content['file_upload']['tmp_name']))
|
|
||||||
{
|
|
||||||
//Set the "content" name filed accordingly to the uploaded file
|
|
||||||
// encode chars which special meaning in url/vfs (some like / get removed!)
|
|
||||||
$content['name'] = Vfs::encodePathComponent($content['file_upload']['name']);
|
|
||||||
$to_path = Vfs::concat($content['path'],$content['name']);
|
|
||||||
|
|
||||||
$copy_result = (Vfs::is_writable($content['path']) || Vfs::is_writable($to_path)) &&
|
|
||||||
copy($content['file_upload']['tmp_name'],Vfs::PREFIX.$to_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Break on an error condition
|
|
||||||
if ((($content['mode'] == 'open' || $content['mode'] == 'saveas') && ($content['name'] == '')) || ($copy_result === false))
|
|
||||||
{
|
|
||||||
if ($copy_result === false)
|
|
||||||
{
|
|
||||||
$content['msg'] = lang('Error uploading file!');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$content['msg'] = lang('Filename must not be empty!');
|
|
||||||
}
|
|
||||||
$content['name'] = '';
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch($content['mode'])
|
|
||||||
{
|
|
||||||
case 'open-multiple':
|
|
||||||
foreach((array)$content['dir']['selected'] as $name)
|
|
||||||
{
|
|
||||||
$files[] = Vfs::concat($content['path'],$name);
|
|
||||||
}
|
|
||||||
//Add an uploaded file to the files result array2string
|
|
||||||
if ($copy_result === true) $files[] = $to_path;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'select-dir':
|
|
||||||
$files = $content['path'];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'saveas':
|
|
||||||
// Don't trust the name the user gives, encode it
|
|
||||||
$content['name'] = Vfs::encodePathComponent($content['name']);
|
|
||||||
// Fall through
|
|
||||||
|
|
||||||
default:
|
|
||||||
$files = Vfs::concat($content['path'],$content['name']);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($content['method'] && $content['method'] != 'ckeditor_return')
|
|
||||||
{
|
|
||||||
$js = ExecMethod2($content['method'],$content['id'],$files);
|
|
||||||
}
|
|
||||||
else if ($content['method'] == 'ckeditor_return')
|
|
||||||
{
|
|
||||||
$download_url = Vfs::download_url(Vfs::concat($content['path'],$content['name']));
|
|
||||||
if ($download_url[0] == '/') $download_url = Egw::link($download_url);
|
|
||||||
|
|
||||||
$response = Api\Json\Response::get();
|
|
||||||
$response->apply('window.opener.CKEDITOR.tools.callFunction', array(
|
|
||||||
$content['ckeditorfuncnum'],
|
|
||||||
str_replace("'", "\\'", $download_url)
|
|
||||||
));
|
|
||||||
Framework::window_close();
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
if(Api\Json\Response::isJSONResponse())
|
|
||||||
{
|
|
||||||
$response = Api\Json\Response::get();
|
|
||||||
if($js)
|
|
||||||
{
|
|
||||||
$response->script($js);
|
|
||||||
}
|
|
||||||
// Ahh!
|
|
||||||
// The vfs-select widget looks for this
|
|
||||||
$response->script('this.selected_files = '.json_encode($files) . ';');
|
|
||||||
Framework::window_close();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
header('Content-type: text/html; charset='.Api\Translation::charset());
|
|
||||||
echo "<html>\n<head>\n<script type='text/javascript'>\n$js\n</script>\n</head>\n</html>\n";
|
|
||||||
}
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
$sel_options['mime'] = $content['options-mime'];
|
|
||||||
}
|
|
||||||
elseif(isset($content['apps']))
|
|
||||||
{
|
|
||||||
list($app) = each($content['apps']);
|
|
||||||
if ($app == 'home') $content['path'] = filemanager_ui::get_home_dir();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Deactivate the opload field if the current directory is not writeable or
|
|
||||||
//we're currently not in the single file open mode.
|
|
||||||
$content['no_upload'] = !Vfs::is_writable($content['path']) ||
|
|
||||||
!in_array($content['mode'],array('open'));
|
|
||||||
|
|
||||||
$content['apps'] = array_keys(self::get_apps());
|
|
||||||
|
|
||||||
if (isset($app))
|
|
||||||
{
|
|
||||||
$content['path'] = '/apps/'.(isset($content['apps'][$app]) ? $content['apps'][$app] : $app);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a flag for easy detection as we go
|
|
||||||
$favorites_flag = substr($content['path'],0,strlen('/apps/favorites')) == '/apps/favorites';
|
|
||||||
|
|
||||||
if (!$favorites_flag && (!$content['path'] || !Vfs::is_dir($content['path'])))
|
|
||||||
{
|
|
||||||
$content['path'] = filemanager_ui::get_home_dir();
|
|
||||||
}
|
|
||||||
$tpl = new Etemplate('filemanager.select');
|
|
||||||
|
|
||||||
if ($favorites_flag)
|
|
||||||
{
|
|
||||||
// Display favorites as if they were folders
|
|
||||||
$files = array();
|
|
||||||
$favorites = Framework\Favorites::get_favorites('filemanager');
|
|
||||||
$n = 0;
|
|
||||||
foreach($favorites as $favorite)
|
|
||||||
{
|
|
||||||
$path = $favorite['state']['path'];
|
|
||||||
// Just directories
|
|
||||||
if(!$path) continue;
|
|
||||||
if ($path == $content['path']) continue; // remove directory itself
|
|
||||||
|
|
||||||
$mime = Vfs::mime_content_type($path);
|
|
||||||
$content['dir'][$n] = array(
|
|
||||||
'name' => $favorite['name'],
|
|
||||||
'path' => $path,
|
|
||||||
'mime' => $mime,
|
|
||||||
'is_dir' => true
|
|
||||||
);
|
|
||||||
if ($content['mode'] == 'open-multiple')
|
|
||||||
{
|
|
||||||
$readonlys['selected['.$favorite['name'].']'] = true;
|
|
||||||
}
|
|
||||||
++$n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!($files = Vfs::find($content['path'],array(
|
|
||||||
'dirsontop' => true,
|
|
||||||
'order' => 'name',
|
|
||||||
'sort' => 'ASC',
|
|
||||||
'maxdepth' => 1,
|
|
||||||
))))
|
|
||||||
{
|
|
||||||
$content['msg'] = lang("Can't open directory %1!",$content['path']);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$n = 0;
|
|
||||||
$content['dir'] = array('mode' => $content['mode']);
|
|
||||||
foreach($files as $path)
|
|
||||||
{
|
|
||||||
if ($path == $content['path']) continue; // remove directory itself
|
|
||||||
|
|
||||||
$name = Vfs::basename($path);
|
|
||||||
$is_dir = Vfs::is_dir($path);
|
|
||||||
$mime = Vfs::mime_content_type($path);
|
|
||||||
if ($content['mime'] && !$is_dir && $mime != $content['mime'])
|
|
||||||
{
|
|
||||||
continue; // does not match mime-filter --> ignore
|
|
||||||
}
|
|
||||||
$content['dir'][$n] = array(
|
|
||||||
'name' => $name,
|
|
||||||
'path' => $path,
|
|
||||||
'mime' => $mime,
|
|
||||||
'is_dir' => $is_dir
|
|
||||||
);
|
|
||||||
if ($is_dir && $content['mode'] == 'open-multiple')
|
|
||||||
{
|
|
||||||
$readonlys['selected['.$name.']'] = true;
|
|
||||||
}
|
|
||||||
++$n;
|
|
||||||
}
|
|
||||||
if (!$n) $readonlys['selected[]'] = true; // remove checkbox from empty line
|
|
||||||
}
|
|
||||||
$readonlys['button[createdir]'] = !Vfs::is_writable($content['path']);
|
|
||||||
|
|
||||||
//_debug_array($readonlys);
|
|
||||||
Api\Cache::setSession('filemanger', 'select_path', $content['path']);
|
|
||||||
$preserve = array(
|
|
||||||
'mode' => $content['mode'],
|
|
||||||
'method' => $content['method'],
|
|
||||||
'id' => $content['id'],
|
|
||||||
'label' => $content['label'],
|
|
||||||
'mime' => $content['mime'],
|
|
||||||
'options-mime' => $sel_options['mime'],
|
|
||||||
'old_path' => $content['path'],
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isset($content['ckeditorfuncnum']))
|
|
||||||
{
|
|
||||||
$preserve['ckeditorfuncnum'] = $content['ckeditorfuncnum'];
|
|
||||||
$preserve['ckeditor'] = $content['ckeditor'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// tell framework we need inline javascript for ckeditor_return
|
|
||||||
if ($content['method'] == 'ckeditor_return')
|
|
||||||
{
|
|
||||||
Api\Header\ContentSecurityPolicy::add('script-src', 'unsafe-inline');
|
|
||||||
}
|
|
||||||
$tpl->exec('filemanager.filemanager_select.select',$content,$sel_options,$readonlys,$preserve,2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list off all apps having an application directory in VFS
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
static function get_apps()
|
|
||||||
{
|
|
||||||
$apps = array(false); // index starting from 1
|
|
||||||
if (isset($GLOBALS['egw_info']['apps']['stylite'])) $apps = array('favorites' => lang('Favorites'));
|
|
||||||
$apps += Link::app_list('query');
|
|
||||||
|
|
||||||
unset($apps['mydms']); // they do NOT support adding files to VFS
|
|
||||||
unset($apps['wiki']);
|
|
||||||
unset($apps['api-accounts']);
|
|
||||||
unset($apps['addressbook-email']);
|
|
||||||
|
|
||||||
return $apps;
|
|
||||||
}
|
|
||||||
}
|
|
@ -290,31 +290,31 @@ app.classes.filemanager = app.classes.filemanager.extend({
|
|||||||
// new file
|
// new file
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// create file selector
|
|
||||||
var vfs_select = et2_createWidget('vfs-select', {
|
var vfs_attrs = {
|
||||||
id:'savefile',
|
id:'savefile',
|
||||||
mode: 'saveas',
|
mode: 'saveas',
|
||||||
button_caption:"",
|
button_caption:"",
|
||||||
button_label:_egwAction.id == 'saveas'?"save as":"save",
|
button_label:_egwAction.id == 'saveas'?"save as":"save",
|
||||||
value: "doc.odt"
|
value: "doc.odt",
|
||||||
}, this.et2);
|
onchange: function (){
|
||||||
|
file_path = vfs_select.get_value();
|
||||||
// bind change handler for setting the selected path and calling save
|
if (vfs_select.get_value())
|
||||||
jQuery(vfs_select.getDOMNode()).on('change', function (){
|
{
|
||||||
file_path = vfs_select.get_value();
|
// Add odt extension if not exist
|
||||||
if (vfs_select.get_value())
|
if (!file_path.match(/\.odt$/,'ig')) file_path += '.odt';
|
||||||
{
|
widgetFilePath.set_value(file_path);
|
||||||
// Add odt extension if not exist
|
self.editor.getDocumentAsByteArray(saveByteArrayLocally);
|
||||||
if (!file_path.match(/\.odt$/,'ig')) file_path += '.odt';
|
self.editor_leaveSession(function(){
|
||||||
widgetFilePath.set_value(file_path);
|
var path = window.location.href.split('&path=');
|
||||||
self.editor.getDocumentAsByteArray(saveByteArrayLocally);
|
window.location.href = path[0]+'&path='+self.editor_getFilePath();
|
||||||
self.editor_leaveSession(function(){
|
});
|
||||||
var path = window.location.href.split('&path=');
|
egw.refresh('','filemanager');
|
||||||
window.location.href = path[0]+'&path='+self.editor_getFilePath();
|
}
|
||||||
});
|
|
||||||
egw.refresh('','filemanager');
|
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
// create file selector
|
||||||
|
var vfs_select = et2_createWidget('vfs-select', vfs_attrs, this.et2);
|
||||||
// start the file selector dialog
|
// start the file selector dialog
|
||||||
jQuery(vfs_select.getDOMNode()).click();
|
jQuery(vfs_select.getDOMNode()).click();
|
||||||
}
|
}
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE overlay PUBLIC "-//EGroupware GmbH//eTemplate 2//EN" "http://www.egroupware.org/etemplate2.dtd">
|
|
||||||
<!-- $Id$ -->
|
|
||||||
<overlay>
|
|
||||||
<template id="filemanager.select" template="" lang="" group="0" version="1.9.002">
|
|
||||||
<grid width="100%" resize_ratio="1">
|
|
||||||
<columns>
|
|
||||||
<column width="32"/>
|
|
||||||
<column />
|
|
||||||
</columns>
|
|
||||||
<rows>
|
|
||||||
<row valign="top">
|
|
||||||
<grid id="apps" resize_ratio="1">
|
|
||||||
<columns>
|
|
||||||
<column/>
|
|
||||||
</columns>
|
|
||||||
<rows>
|
|
||||||
<row disabled="!@0">
|
|
||||||
<button align="center" label="Favorites" id="favorites" image="favorites"/>
|
|
||||||
</row>
|
|
||||||
<row height="40">
|
|
||||||
<button align="center" label="$row_cont" id="${row}" image="$row_cont/navbar"/>
|
|
||||||
</row>
|
|
||||||
</rows>
|
|
||||||
</grid>
|
|
||||||
<grid width="100%" resize_ratio="1">
|
|
||||||
<columns>
|
|
||||||
<column/>
|
|
||||||
</columns>
|
|
||||||
<rows>
|
|
||||||
<row class="dialogHeader">
|
|
||||||
<hbox>
|
|
||||||
<html id="js"/>
|
|
||||||
<button label="Up" id="button[up]" onclick="app.filemanager.change_dir('..');" image="goup"/>
|
|
||||||
<button label="Go to your home directory" id="button[home]" image="gohome"/>
|
|
||||||
<box class="selectPathContainer">
|
|
||||||
<vfs-name id="path" class="selectPath" onchange="1"/>
|
|
||||||
</box>
|
|
||||||
<button label="Create directory" id="button[createdir]" onclick="app.filemanager.createdir" image="button_createdir" ro_image="createdir_disabled" class="createDir"/>
|
|
||||||
</hbox>
|
|
||||||
</row>
|
|
||||||
<row class="selectFiles file_dir_height" resize_ratio="1">
|
|
||||||
<grid width="100%" id="dir" resize_ratio="1" >
|
|
||||||
<columns>
|
|
||||||
<column width="20"/>
|
|
||||||
<column/>
|
|
||||||
<column width="1%" disabled="!@mode=open-multiple"/>
|
|
||||||
</columns>
|
|
||||||
<rows>
|
|
||||||
<row class="row">
|
|
||||||
<vfs-mime align="center" id="$row" options="16" class="selectIcon"/>
|
|
||||||
<vfs id="$row" onclick="app.filemanager.select_clicked"/>
|
|
||||||
<checkbox align="right" id="selected[]" options=""$row_cont[name]""/>
|
|
||||||
</row>
|
|
||||||
</rows>
|
|
||||||
</grid>
|
|
||||||
</row>
|
|
||||||
<row disabled="@mode=/(open-multiple|select-dir)/">
|
|
||||||
<textbox id="name" class="selectName"/>
|
|
||||||
</row>
|
|
||||||
<row disabled="!@options-mime">
|
|
||||||
<menulist class="selectMime">
|
|
||||||
<menupopup id="mime" onchange="1" options="All files"/>
|
|
||||||
</menulist>
|
|
||||||
</row>
|
|
||||||
<row disabled="@no_upload">
|
|
||||||
<groupbox>
|
|
||||||
<caption label="File upload"/>
|
|
||||||
<description value="Choose a file for uploading"/>
|
|
||||||
<file id="file_upload"/>
|
|
||||||
</groupbox>
|
|
||||||
</row>
|
|
||||||
</rows>
|
|
||||||
</grid>
|
|
||||||
</row>
|
|
||||||
<row class="dialogFooterToolbar">
|
|
||||||
<hbox align="right">
|
|
||||||
<button label="@label" id="button[ok]" image="save" background_image="1"/>
|
|
||||||
<buttononly label="Cancel" id="button[cancel]" onclick="window.close();" image="cancel" background_image="1"/>
|
|
||||||
</hbox>
|
|
||||||
</row>
|
|
||||||
</rows>
|
|
||||||
</grid>
|
|
||||||
</template>
|
|
||||||
</overlay>
|
|
Loading…
Reference in New Issue
Block a user