mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-24 17:04:14 +01:00
Further work on Et2VfsSelect
- Button opens dialog & handles action - Button shows feedback while processing - Fix dialog flex spacing - Fix dialog re-use was not clean
This commit is contained in:
parent
d132609165
commit
2e553911b0
@ -14,7 +14,7 @@ export default css`
|
||||
}
|
||||
|
||||
.vfs_select__listbox {
|
||||
flex: 1 1 auto;
|
||||
flex: 2 1 auto;
|
||||
min-height: 15em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
@ -49,4 +49,8 @@ export default css`
|
||||
.vfs_select__mimefilter {
|
||||
flex: 0 0;
|
||||
}
|
||||
|
||||
:host::part(form-control-help-text) {
|
||||
flex-basis: min-content !important;
|
||||
}
|
||||
`;
|
@ -11,7 +11,8 @@ import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
|
||||
import {html, LitElement, nothing} from "lit";
|
||||
import {HasSlotController} from "../Et2Widget/slot";
|
||||
import {property} from "lit/decorators/property.js";
|
||||
import {FileInfo} from "./Et2VfsSelectDialog";
|
||||
import {Et2VfsSelectDialog, FileInfo} from "./Et2VfsSelectDialog";
|
||||
import {waitForEvent} from "../Et2Widget/event";
|
||||
|
||||
/**
|
||||
* @summary Button to open a file selection dialog, and return the selected path(s) as a value
|
||||
@ -75,44 +76,90 @@ export class Et2VfsSelectButton extends Et2InputWidget(LitElement)
|
||||
*/
|
||||
@property() method : string = "";
|
||||
/** ID passed to method */
|
||||
@property() method_id : string;
|
||||
@property({type: String, reflect: true}) methodId : string;
|
||||
|
||||
protected readonly hasSlotController = new HasSlotController(this, '');
|
||||
protected processingPromise : Promise<FileActionResult> = null;
|
||||
|
||||
//private _dialog : Et2VfsSelectDialog = this.shadowRoot.querySelector("et2-vfs-select-dialog") ?? null;
|
||||
get _dialog() : Et2VfsSelectDialog {return this.shadowRoot.querySelector("et2-vfs-select-dialog") ?? null};
|
||||
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.handleDialogClose = this.handleDialogClose.bind(this);
|
||||
}
|
||||
|
||||
protected handleClick(event)
|
||||
{
|
||||
const dialog : any = this.shadowRoot.querySelector("et2-vfs-select-dialog");
|
||||
if(dialog && typeof dialog.show == "function")
|
||||
if(this._dialog && typeof this._dialog.show == "function")
|
||||
{
|
||||
dialog.show();
|
||||
this._dialog.show();
|
||||
// Avoids dialog showing old value if reused
|
||||
this._dialog.requestUpdate("value");
|
||||
|
||||
// This is were we bind to get informed when user closes the dialog
|
||||
waitForEvent(this._dialog, "sl-after-show").then(async() =>
|
||||
{
|
||||
this.processDialogComplete(await this._dialog.getComplete());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected handleDialogClose(event)
|
||||
protected processDialogComplete([button, paths])
|
||||
{
|
||||
debugger;
|
||||
this.value = dialog.value ?? [];
|
||||
// Cancel or close do nothing
|
||||
if(!button)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const oldValue = this.value;
|
||||
this.value = paths ?? [];
|
||||
this.requestUpdate("value", oldValue);
|
||||
|
||||
if(this.method && this.method == "download")
|
||||
{
|
||||
// download
|
||||
this.value.forEach(path =>
|
||||
{
|
||||
this.egw().open_link(this._dialog.fileInfo(path)?.downloadUrl, "blank", "view", 'download');
|
||||
});
|
||||
}
|
||||
else if(this.method)
|
||||
{
|
||||
this.sendFiles();
|
||||
}
|
||||
this.updateComplete.then(() =>
|
||||
{
|
||||
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||
|
||||
// Reset value after processing
|
||||
if(this.method)
|
||||
{
|
||||
this.value = [];
|
||||
this.requestUpdate("value");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
protected sendFiles()
|
||||
{
|
||||
this.processingPromise = this.egw().request(
|
||||
this.method,
|
||||
[this.methodId, this.value/*, submit_button_id, savemode*/]
|
||||
).then((data) =>
|
||||
{
|
||||
this.processingPromise = null;
|
||||
|
||||
// UI update now that we're done
|
||||
this.requestUpdate();
|
||||
return {success: true};
|
||||
}
|
||||
);
|
||||
|
||||
// UI update, we're busy
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
protected dialogTemplate()
|
||||
{
|
||||
@ -126,9 +173,7 @@ export class Et2VfsSelectButton extends Et2InputWidget(LitElement)
|
||||
.filename=${this.filename ?? nothing}
|
||||
.mime=${this.mime ?? nothing}
|
||||
.buttonLabel=${this.buttonLabel ?? nothing}
|
||||
@close=${this.handleDialogClose}
|
||||
>
|
||||
|
||||
</et2-vfs-select-dialog>
|
||||
`;
|
||||
}
|
||||
@ -137,18 +182,28 @@ export class Et2VfsSelectButton extends Et2InputWidget(LitElement)
|
||||
render()
|
||||
{
|
||||
const hasUserDialog = this.hasSlotController.test("[default]");
|
||||
const processing = this.processingPromise !== null;
|
||||
const image = processing ? "" : (this.image || "filemanager/navbar");
|
||||
|
||||
return html`
|
||||
<et2-button image=${this.image || "filemanager/navbar"}
|
||||
<et2-button image=${image}
|
||||
?disabled=${this.disabled}
|
||||
?readonly=${this.readonly}
|
||||
?readonly=${this.readonly || processing}
|
||||
.noSubmit=${true}
|
||||
@click=${this.handleClick}
|
||||
>
|
||||
${processing ? html`
|
||||
<sl-spinner></sl-spinner>` : nothing}
|
||||
</et2-button>
|
||||
<slot>${hasUserDialog ? nothing : this.dialogTemplate()}</slot>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("et2-vfs-select", Et2VfsSelectButton);
|
||||
customElements.define("et2-vfs-select", Et2VfsSelectButton);
|
||||
|
||||
export interface FileActionResult
|
||||
{
|
||||
success : boolean,
|
||||
message? : string
|
||||
}
|
@ -177,7 +177,6 @@ export class Et2VfsSelectDialog extends Et2InputWidget(LitElement) implements Se
|
||||
// Use filemanager translations
|
||||
this.egw().langRequireApp(this.egw().window, "filemanager", () => {this.requestUpdate()});
|
||||
|
||||
this.handleButtonClick = this.handleButtonClick.bind(this);
|
||||
this.handleCreateDirectory = this.handleCreateDirectory.bind(this);
|
||||
this.handleSearchKeyDown = this.handleSearchKeyDown.bind(this);
|
||||
}
|
||||
@ -266,6 +265,17 @@ export class Et2VfsSelectDialog extends Et2InputWidget(LitElement) implements Se
|
||||
return parts.join('/') || '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file information of currently displayed paths
|
||||
*
|
||||
* Returns null if the path is not currently displayed
|
||||
* @param _path
|
||||
*/
|
||||
public fileInfo(_path)
|
||||
{
|
||||
return this._fileList.find(f => f.path == _path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the dialog.
|
||||
*/
|
||||
@ -292,11 +302,13 @@ export class Et2VfsSelectDialog extends Et2InputWidget(LitElement) implements Se
|
||||
return this._dialog.hide();
|
||||
}
|
||||
|
||||
getComplete() : Promise<string[]>
|
||||
getComplete() : Promise<[number, Object]>
|
||||
{
|
||||
return this._dialog.getComplete().then(() =>
|
||||
return this._dialog.getComplete().then((value) =>
|
||||
{
|
||||
return this.value;
|
||||
// Overwrite dialog's value with what we say
|
||||
value[1] = this.value;
|
||||
return value
|
||||
});
|
||||
}
|
||||
|
||||
@ -459,12 +471,6 @@ export class Et2VfsSelectDialog extends Et2InputWidget(LitElement) implements Se
|
||||
}
|
||||
}
|
||||
|
||||
protected handleButtonClick(event : MouseEvent)
|
||||
{
|
||||
this.open = false;
|
||||
this.requestUpdate("open", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new directory in the current one
|
||||
* @param {MouseEvent | KeyboardEvent} event
|
||||
@ -680,8 +686,8 @@ export class Et2VfsSelectDialog extends Et2InputWidget(LitElement) implements Se
|
||||
}
|
||||
|
||||
const buttons = [
|
||||
{id: "ok", label: this.buttonLabel, image: image},
|
||||
{id: "cancel", label: "cancel", image: "cancel"}
|
||||
{id: "ok", label: this.buttonLabel, image: image, button_id: Et2Dialog.OK_BUTTON},
|
||||
{id: "cancel", label: "cancel", image: "cancel", button_id: Et2Dialog.CANCEL_BUTTON}
|
||||
];
|
||||
|
||||
return html`
|
||||
@ -689,13 +695,13 @@ export class Et2VfsSelectDialog extends Et2InputWidget(LitElement) implements Se
|
||||
{
|
||||
return html`
|
||||
<et2-button id=${button.id}
|
||||
button_id=${button.button_id}
|
||||
class="et2_button et2_vfs__button"
|
||||
label=${button.label}
|
||||
variant=${index == 0 ? "primary" : "default"}
|
||||
slot="footer"
|
||||
.image=${ifDefined(button.image)}
|
||||
.noSubmit=${true}
|
||||
@click=${this.handleButtonClick}
|
||||
>${button.label}
|
||||
</et2-button>
|
||||
`
|
||||
@ -794,5 +800,7 @@ export interface FileInfo
|
||||
isDir : boolean,
|
||||
path? : string,
|
||||
// We want to show it, but not act with it. File is disabled for the UI
|
||||
disabled? : boolean
|
||||
disabled? : boolean,
|
||||
// Direct download link
|
||||
downloadUrl? : string
|
||||
}
|
@ -644,12 +644,14 @@ class Vfs extends File
|
||||
$path = $path['path'] ?? $path;
|
||||
$is_dir = $path['isDir'] ?? Api\Vfs::is_dir($path);
|
||||
$mime = $path['mime'] ?? Api\Vfs::mime_content_type($path);
|
||||
$download = $path['download_url'] ?? Api\Vfs::download_url($path);
|
||||
|
||||
$response['files'][] = array(
|
||||
'name' => $name,
|
||||
'path' => $path,
|
||||
'mime' => $mime,
|
||||
'isDir' => $is_dir
|
||||
'isDir' => $is_dir,
|
||||
'downloadUrl' => $download
|
||||
);
|
||||
}
|
||||
Json\Response::get()->data($response);
|
||||
|
Loading…
Reference in New Issue
Block a user