egroupware/api/js/etemplate/vfsSelectUI.ts
ralf ba35be1d86 Change Et2Checkbox to behave closer to legacy et2_widget_checkbox and thereby fixing all sorts of errors with it.
Fix vfsSelectUI to be able to select files again with click on the row and only submit selected files.
Also change Et2Widget.iterateOver and legacy et2_widget.interateOver to be called with new web-component classes like Et2Checkbox. Also make Et2Widget matching all widgets by default like et2_widget.
Remove legacy et2_widget_checkbox code.
2022-08-07 10:10:33 +02:00

363 lines
9.1 KiB
TypeScript

/**
* EGroupware - VFS SELECT Widget UI
*
* @link https://www.egroupware.org
* @package et2_vfsSelect
* @author Hadi Nategh <hn@egroupware.org>
* @copyright (c) 2013-2021 by Hadi Nategh <hn@egroupware.org>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
*/
/*egw:uses
/api/js/jsapi/egw_app.js
*/
import {EgwApp} from "../jsapi/egw_app";
import {et2_vfs, et2_vfsPath, et2_vfsSelect} from "./et2_widget_vfs";
import {egw} from "../jsapi/egw_global";
import {et2_file} from "./et2_widget_file";
import {Et2Button} from "./Et2Button/Et2Button";
import {Et2Select} from "./Et2Select/Et2Select";
import {Et2Dialog} from "./Et2Dialog/Et2Dialog";
import {Et2Checkbox} from "./Et2Checkbox/Et2Checkbox";
/**
* UI for VFS Select widget
*
*/
export class vfsSelectUI extends EgwApp
{
readonly appname: 'filemanager';
private dirContent: {};
private vfsSelectWidget : et2_vfsSelect;
private path_widget: et2_vfsPath;
/**
* Constructor
*
*/
constructor()
{
// call parent
super('vfsSelectUI');
this.egw.langRequireApp(this.egw.window, 'filemanager');
}
/**
* Destructor
*/
destroy(_app)
{
delete this.path_widget;
delete this.vfsSelectWidget;
// call parent
super.destroy(_app);
}
/**
* 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(et2,name)
{
this.path_widget = <et2_vfsPath>this.et2.getWidgetById('path');
this.dirContent = this.et2.getArrayMgr('content').data.dir;
}
/**
* Get directory of a path
*
* @param {string} _path
* @returns string
*/
dirname(_path)
{
let parts = _path.split('/');
parts.pop();
return parts.join('/') || '/';
}
/**
* Get name of a path
*
* @param {string} _path
* @returns string
*/
basename(_path)
{
return _path.split('/').pop();
}
/**
* Get current working directory
*
* @return string
*/
get_path()
{
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
*/
storeFile(_event)
{
let path = this.get_path();
if (!jQuery.isEmptyObject(_event.data.getValue()))
{
let widget = _event.data;
egw(window).json('EGroupware\\Api\\Etemplate\\Widget\\Vfs::ajax_vfsSelect_storeFile', [widget.getValue(), path],
this._storeFile_callback, this, true, this
).sendRequest(true);
widget.set_value('');
}
}
/**
* Callback for server response to storeFile request:
* - display message and refresh list
* - ask use to confirm overwritting existing files or rename upload
*
* @param {object} _data values for attributes msg, files, ...
*/
_storeFile_callback(_data : {msg : string, uploaded : any[], path : string})
{
if (_data.msg || _data.uploaded) egw(window).message(_data.msg);
let that = this;
for(let file in _data.uploaded)
{
if (_data.uploaded[file].confirm && !_data.uploaded[file].confirmed)
{
let buttons = [
{
label: this.egw.lang("Yes"),
id: "overwrite",
class: "ui-priority-primary",
"default": true,
image: 'check'
},
{label: this.egw.lang("Rename"), id: "rename", image: 'edit'},
{label: this.egw.lang("Cancel"), id: "cancel"}
];
if(_data.uploaded[file].confirm === "is_dir")
{
buttons.shift();
}
let dialog = Et2Dialog.show_prompt(function(_button_id, _value)
{
let 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('EGroupware\\Api\\Etemplate\\Widget\\Vfs::ajax_vfsSelect_storeFile', [uploaded, this.my_data.path],
that._storeFile_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 = {
file: file,
path: _data.path,
data: _data.uploaded[file],
};
}
else
{
this.submit();
}
}
}
/**
* 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(action, selected)
{
let self = this;
Et2Dialog.show_prompt(function(button, dir)
{
if(button && dir)
{
let 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
*/
change_dir(_dir : string)
{
if (_dir == '..')
{
_dir = this.dirname(this.get_path());
}
this.path_widget.set_value(_dir);
}
/**
* Row or filename in select-file dialog clicked
*
* @param {jQuery.event} event
* @param {et2_widget} widget
*/
select_clicked(event : JQueryEventObject, widget : et2_vfs)
{
if (!widget || typeof widget.value != 'object')
{
}
else if (widget.value.is_dir) // true for "httpd/unix-directory" and "egw/*"
{
let path = widget.getRoot().getWidgetById("path");
if(path)
{
path.set_value(widget.value.path);
}
}
else if (this.et2 && this.et2.getArrayMgr('content').getEntry('mode') != 'open-multiple')
{
this.et2.setValueById('name', widget.value.name);
}
else
{
let file = widget.value.name;
widget.getParent().iterateOver(function(widget)
{
if(widget.options.selectedValue === file)
{
widget.set_value(widget.get_value() === file ? widget.options.unselectedValue : file);
}
}, null, Et2Checkbox);
}
// 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(action : string, widget : Et2Button | Et2Select | et2_vfsPath)
{
if (!action) return;
let field = '', value : string|string[] = '' ;
switch (action)
{
case 'path': field = 'path'; value = (<et2_vfsPath>widget).getValue(); break;
case 'home': field = 'action'; value = 'home'; break;
case 'app': field = 'app'; value = (<Et2Select>widget).getValue(); break;
case 'mime': field = 'mime'; value = (<Et2Select>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(_field? : string, _val? : any, _callback? : Function)
{
let arrMgrs = this.et2.getArrayMgrs();
if (_field)
{
arrMgrs.content.data[_field] = _val;
jQuery.extend(arrMgrs.content.data, arrMgrs.modifications.data);
this.et2.setArrayMgrs(arrMgrs);
}
// preserve value of the name
if (arrMgrs && this.et2.getWidgetById('name'))
{
arrMgrs.content.data['name'] = this.et2.getWidgetById('name').get_value();
}
this.vfsSelectWidget._content(arrMgrs.content.data, _callback);
}
/**
* search through dir content and set its content base on searched query
* @returns
*/
search(_widget)
{
let dir = <et2_vfsPath>this.et2.getWidgetById('dir');
let query = _widget.get_value();
if (query == "")
{
dir.set_value({content: this.dirContent});
return;
}
let self = this;
let searchQuery = function (_query)
{
let result = {};
let reg = RegExp(_query, 'ig');
let key = 0;
for (let i in self.dirContent)
{
if (typeof self.dirContent[i]['name'] != 'undefined' && self.dirContent[i]['name'].match(reg))
{
result[key] = self.dirContent[i];
key++;
}
else if (typeof self.dirContent[i]['name'] == 'undefined' && isNaN(<number><unknown>i))
{
result[i] = self.dirContent[i];
}
}
return result;
};
dir.set_value({content: searchQuery(query)});
}
}
app.classes.vfsSelectUI = vfsSelectUI;