2021-03-31 16:50:42 +02:00

215 lines
6.9 KiB
TypeScript

// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, Output, OnInit, EventEmitter, ViewChild, ElementRef } from '@angular/core';
import { FileEntry } from '@ionic-native/file/ngx';
import { CoreIonLoadingElement } from '@classes/ion-loading';
import { CoreFile } from '@services/file';
import { CoreFileHelper } from '@services/file-helper';
import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreMimetypeUtils } from '@services/utils/mimetype';
import { CoreTextUtils } from '@services/utils/text';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreUtils } from '@services/utils/utils';
import { CoreForms } from '@singletons/form';
/**
* Component to handle a local file. Only files inside the app folder can be managed.
*
* Shows the file name, icon (depending on extension), size and time modified.
* Also, if managing is enabled it will also show buttons to rename and delete the file.
*/
@Component({
selector: 'core-local-file',
templateUrl: 'core-local-file.html',
})
export class CoreLocalFileComponent implements OnInit {
@Input() file?: FileEntry; // A fileEntry retrieved using CoreFileProvider.getFile or similar.
@Input() manage?: boolean | string; // Whether the user can manage the file (edit and delete).
@Input() overrideClick?: boolean | string; // Whether the default item click should be overridden.
@Output() onDelete = new EventEmitter<void>(); // Will notify when the file is deleted.
@Output() onRename = new EventEmitter<{ file: FileEntry }>(); // Will notify when the file is renamed.
@Output() onClick = new EventEmitter<void>(); // Will notify when the file is clicked. Only if overrideClick is true.
@ViewChild('nameForm') formElement?: ElementRef;
fileName?: string;
fileIcon?: string;
fileExtension?: string;
size?: string;
timemodified?: string;
newFileName = '';
editMode = false;
relativePath?: string;
/**
* Component being initialized.
*/
async ngOnInit(): Promise<void> {
this.manage = CoreUtils.isTrueOrOne(this.manage);
if (!this.file) {
return;
}
this.loadFileBasicData(this.file);
// Get the size and timemodified.
const metadata = await CoreFile.getMetadata(this.file);
if (metadata.size >= 0) {
this.size = CoreTextUtils.bytesToSize(metadata.size, 2);
}
this.timemodified = CoreTimeUtils.userDate(metadata.modificationTime.getTime(), 'core.strftimedatetimeshort');
}
/**
* Load the basic data for the file.
*/
protected loadFileBasicData(file: FileEntry): void {
this.fileName = file.name;
this.fileIcon = CoreMimetypeUtils.getFileIcon(file.name);
this.fileExtension = CoreMimetypeUtils.getFileExtension(file.name);
// Let's calculate the relative path for the file.
this.relativePath = CoreFile.removeBasePath(file.toURL());
if (!this.relativePath) {
// Didn't find basePath, use fullPath but if the user tries to manage the file it'll probably fail.
this.relativePath = file.fullPath;
}
}
/**
* File clicked.
*
* @param e Click event.
*/
async fileClicked(e: Event): Promise<void> {
if (this.editMode) {
return;
}
e.preventDefault();
e.stopPropagation();
if (CoreUtils.isTrueOrOne(this.overrideClick) && this.onClick.observers.length) {
this.onClick.emit();
return;
}
if (!CoreFileHelper.isOpenableInApp(this.file!)) {
try {
await CoreFileHelper.showConfirmOpenUnsupportedFile();
} catch (error) {
return; // Cancelled, stop.
}
}
CoreUtils.openFile(this.file!.toURL());
}
/**
* Activate the edit mode.
*
* @param e Click event.
*/
activateEdit(e: Event): void {
e.preventDefault();
e.stopPropagation();
this.editMode = true;
this.newFileName = this.file!.name;
}
/**
* Rename the file.
*
* @param newName New name.
* @param e Click event.
*/
async changeName(newName: string, e: Event): Promise<void> {
e.preventDefault();
e.stopPropagation();
if (newName == this.file!.name) {
// Name hasn't changed, stop.
this.editMode = false;
CoreForms.triggerFormCancelledEvent(this.formElement, CoreSites.getCurrentSiteId());
return;
}
const modal = await CoreDomUtils.showModalLoading();
const fileAndDir = CoreFile.getFileAndDirectoryFromPath(this.relativePath!);
const newPath = CoreTextUtils.concatenatePaths(fileAndDir.directory, newName);
try {
// Check if there's a file with this name.
await CoreFile.getFile(newPath);
// There's a file with this name, show error and stop.
CoreDomUtils.showErrorModal('core.errorfileexistssamename', true);
} catch {
try {
// File doesn't exist, move it.
const fileEntry = await CoreFile.moveFile(this.relativePath!, newPath);
CoreForms.triggerFormSubmittedEvent(this.formElement, false, CoreSites.getCurrentSiteId());
this.editMode = false;
this.file = fileEntry;
this.loadFileBasicData(this.file);
this.onRename.emit({ file: this.file });
} catch (error) {
CoreDomUtils.showErrorModalDefault(error, 'core.errorrenamefile', true);
}
} finally {
modal.dismiss();
}
}
/**
* Delete the file.
*
* @param e Click event.
*/
async deleteFile(e: Event): Promise<void> {
e.preventDefault();
e.stopPropagation();
let modal: CoreIonLoadingElement | undefined;
try {
// Ask confirmation.
await CoreDomUtils.showDeleteConfirm('core.confirmdeletefile');
modal = await CoreDomUtils.showModalLoading('core.deleting', true);
await CoreFile.removeFile(this.relativePath!);
this.onDelete.emit();
} catch (error) {
CoreDomUtils.showErrorModalDefault(error, 'core.errordeletefile', true);
} finally {
modal?.dismiss();
}
}
}