Frontend: Refactor file download #895

This commit is contained in:
Michael Mayer 2021-01-17 11:28:39 +01:00
parent 54579f0ce9
commit 19c0df4791
19 changed files with 388 additions and 318 deletions

View File

@ -0,0 +1,57 @@
/*
Copyright (c) 2018 - 2021 Michael Mayer <hello@photoprism.org>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
PhotoPrism® is a registered trademark of Michael Mayer. You may use it as required
to describe our software, run your own server, for educational purposes, but not for
offering commercial goods, products, or services without prior written permission.
In other words, please ask.
Feel free to send an e-mail to hello@photoprism.org if you have questions,
want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide:
https://docs.photoprism.org/developer-guide/
*/
// Downloads a file from the server.
export default function download(url, name) {
// Abort if download url is empty.
if (!url) {
console.warn("can't download: empty url");
return;
}
// Create download link.
const link = document.createElement("a");
if (name) {
link.download = name;
}
link.href = url;
link.target = "_blank";
link.style.display = "none";
document.body.appendChild(link);
// Start download.
link.click();
// Remove download link.
document.body.removeChild(link);
}

View File

@ -96,6 +96,7 @@
import Api from "common/api";
import Notify from "common/notify";
import Album from "model/album";
import download from "common/download";
export default {
name: 'PAlbumClipboard',
@ -178,10 +179,8 @@ export default {
},
onDownload(path) {
Notify.success(this.$gettext("Downloading…"));
const link = document.createElement('a');
link.href = path;
link.download = "album.zip";
link.click();
download(path, "album.zip");
},
}
};

View File

@ -1,6 +1,6 @@
<template>
<v-form lazy-validation dense
ref="form" autocomplete="off" class="p-photo-toolbar p-album-toolbar" accept-charset="UTF-8"
<v-form ref="form" lazy-validation
dense autocomplete="off" class="p-photo-toolbar p-album-toolbar" accept-charset="UTF-8"
@submit.prevent="filterChange">
<v-toolbar flat :dense="$vuetify.breakpoint.smAndDown" color="secondary">
<v-toolbar-title :title="album.Title">
@ -9,36 +9,36 @@
<v-spacer></v-spacer>
<v-btn icon @click.stop="refresh" class="hidden-xs-only action-reload" :title="$gettext('Reload')">
<v-btn icon class="hidden-xs-only action-reload" :title="$gettext('Reload')" @click.stop="refresh">
<v-icon>refresh</v-icon>
</v-btn>
<v-btn icon @click.stop="dialog.edit = true" class="action-edit" :title="$gettext('Edit')">
<v-btn icon class="action-edit" :title="$gettext('Edit')" @click.stop="dialog.edit = true">
<v-icon>edit</v-icon>
</v-btn>
<v-btn icon @click.stop="dialog.share = true" v-if="$config.feature('share')" class="action-share"
:title="$gettext('Share')">
<v-btn v-if="$config.feature('share')" icon class="action-share" :title="$gettext('Share')"
@click.stop="dialog.share = true">
<v-icon>share</v-icon>
</v-btn>
<v-btn icon @click.stop="download" v-if="$config.feature('download')" class="hidden-xs-only action-download"
:title="$gettext('Download')">
<v-btn v-if="$config.feature('download')" icon class="hidden-xs-only action-download" :title="$gettext('Download')"
@click.stop="download">
<v-icon>get_app</v-icon>
</v-btn>
<v-btn icon v-if="settings.view === 'cards'" @click.stop="setView('list')" :title="$gettext('Toggle View')">
<v-btn v-if="settings.view === 'cards'" icon :title="$gettext('Toggle View')" @click.stop="setView('list')">
<v-icon>view_list</v-icon>
</v-btn>
<v-btn icon v-else-if="settings.view === 'list'" @click.stop="setView('mosaic')" :title="$gettext('Toggle View')">
<v-btn v-else-if="settings.view === 'list'" icon :title="$gettext('Toggle View')" @click.stop="setView('mosaic')">
<v-icon>view_comfy</v-icon>
</v-btn>
<v-btn icon v-else @click.stop="setView('cards')" :title="$gettext('Toggle View')">
<v-btn v-else icon :title="$gettext('Toggle View')" @click.stop="setView('cards')">
<v-icon>view_column</v-icon>
</v-btn>
<v-btn icon @click.stop="showUpload()" v-if="!$config.values.readonly && $config.feature('upload')"
class="hidden-sm-and-down action-upload" :title="$gettext('Upload')">
<v-btn v-if="!$config.values.readonly && $config.feature('upload')" icon class="hidden-sm-and-down action-upload"
:title="$gettext('Upload')" @click.stop="showUpload()">
<v-icon>cloud_upload</v-icon>
</v-btn>
</v-toolbar>
@ -70,9 +70,10 @@
<script>
import Event from "pubsub-js";
import Notify from "common/notify";
import download from "common/download";
export default {
name: 'p-album-toolbar',
name: 'PAlbumToolbar',
props: {
album: Object,
filter: Object,
@ -148,7 +149,7 @@ export default {
if (this.filter.order !== this.album.Order) {
this.album.Order = this.filter.order;
this.updateAlbum()
this.updateAlbum();
}
},
setView(name) {
@ -164,10 +165,8 @@ export default {
},
onDownload(path) {
Notify.success(this.$gettext("Downloading…"));
const link = document.createElement('a')
link.href = path;
link.download = "album.zip";
link.click();
download(path, "album.zip");
},
}
};

View File

@ -64,6 +64,7 @@
<script>
import Api from "common/api";
import Notify from "common/notify";
import download from "common/download";
export default {
name: 'PFileClipboard',
@ -104,10 +105,8 @@ export default {
},
onDownload(path) {
Notify.success(this.$gettext("Downloading…"));
const link = document.createElement('a');
link.href = path;
link.download = "photos.zip";
link.click();
download(path, "photos.zip");
},
}
};

View File

@ -76,6 +76,7 @@
<script>
import Api from "common/api";
import Notify from "common/notify";
import download from "common/download";
export default {
name: 'PLabelClipboard',
@ -129,10 +130,8 @@ export default {
},
onDownload(path) {
Notify.success(this.$gettext("Downloading…"));
const link = document.createElement('a');
link.href = path;
link.download = "label.zip";
link.click();
download(path, "label.zip");
},
}
};

View File

@ -181,6 +181,9 @@
</v-container>
</template>
<script>
import download from "common/download";
import Notify from "../../common/notify";
export default {
name: 'PPhotoCards',
props: {
@ -228,11 +231,10 @@ export default {
if (player) player.pause();
},
downloadFile(index) {
Notify.success(this.$gettext("Downloading…"));
const photo = this.photos[index];
const link = document.createElement('a');
link.href = `/api/v1/dl/${photo.Hash}?t=${this.$config.downloadToken()}`;
link.download = photo.FileName;
link.click();
download(`/api/v1/dl/${photo.Hash}?t=${this.$config.downloadToken()}`, photo.FileName);
},
onSelect(ev, index) {
if (ev.shiftKey) {

View File

@ -143,6 +143,7 @@
import Api from "common/api";
import Notify from "common/notify";
import Event from "pubsub-js";
import download from "common/download";
export default {
name: 'PPhotoClipboard',
@ -235,10 +236,8 @@ export default {
},
onDownload(path) {
Notify.success(this.$gettext("Downloading…"));
const link = document.createElement('a');
link.href = path;
link.download = "photos.zip";
link.click();
download(path, "photos.zip");
},
edit() {
// Open Edit Dialog

View File

@ -106,6 +106,9 @@
</div>
</template>
<script>
import download from "common/download";
import Notify from "../../common/notify";
export default {
name: 'PPhotoList',
props: {
@ -158,11 +161,10 @@ export default {
},
methods: {
downloadFile(index) {
Notify.success(this.$gettext("Downloading…"));
const photo = this.photos[index];
const link = document.createElement('a');
link.href = `/api/v1/dl/${photo.Hash}?t=${this.$config.downloadToken()}`;
link.download = photo.FileName;
link.click();
download(`/api/v1/dl/${photo.Hash}?t=${this.$config.downloadToken()}`, photo.FileName);
},
onSelect(ev, index) {
if (ev.shiftKey) {

View File

@ -255,8 +255,8 @@
#photoprism .search-results .type-image:hover .input-view,
#photoprism .search-results .type-raw .input-open,
#photoprism .search-results .type-live.is-playable .input-open,
#photoprism .search-results .type-image.is-stack .input-open {
#photoprism .search-results .type-live.is-playable .input-open,
#photoprism .search-results .type-image.is-stack .input-open {
display: inline-flex;
}

View File

@ -201,6 +201,7 @@
<script>
import Thumb from "model/thumb";
import {DateTime} from "luxon";
import Notify from "../../common/notify";
export default {
name: 'PTabPhotoFiles',
@ -241,6 +242,8 @@ export default {
this.$viewer.show([Thumb.fromFile(this.model, file)], 0);
},
downloadFile(file) {
Notify.success(this.$gettext("Downloading…"));
file.download();
},
showDeleteDialog(file) {

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,7 @@ import { DateTime } from "luxon";
import Util from "common/util";
import { config } from "../session";
import { $gettext } from "common/vm";
import download from "common/download";
export class File extends RestModel {
getDefaults() {
@ -130,10 +131,7 @@ export class File extends RestModel {
return;
}
let link = document.createElement("a");
link.href = this.getDownloadUrl();
link.download = this.baseName(this.Name);
link.click();
download(this.getDownloadUrl(), this.baseName(this.Name));
}
calculateSize(width, height) {

View File

@ -37,6 +37,8 @@ import { config } from "../session";
import countries from "options/countries.json";
import { $gettext } from "common/vm";
import Clipboard from "common/clipboard";
import download from "common/download";
import Notify from "../common/notify";
export const SrcManual = "manual";
export const CodecAvc1 = "avc1";
@ -407,11 +409,13 @@ export class Photo extends RestModel {
}
downloadAll() {
Notify.success(this.$gettext("Downloading…"));
if (!this.Files) {
let link = document.createElement("a");
link.href = `/api/v1/dl/${this.mainFileHash()}?t=${config.downloadToken()}`;
link.download = this.baseName(false);
link.click();
download(
`/api/v1/dl/${this.mainFileHash()}?t=${config.downloadToken()}`,
this.baseName(false)
);
return;
}
@ -421,10 +425,7 @@ export class Photo extends RestModel {
return;
}
let link = document.createElement("a");
link.href = `/api/v1/dl/${file.Hash}?t=${config.downloadToken()}`;
link.download = this.fileBase(file.Name);
link.click();
download(`/api/v1/dl/${file.Hash}?t=${config.downloadToken()}`, this.fileBase(file.Name));
});
}

View File

@ -114,6 +114,7 @@ import RestModel from "model/rest";
import {Folder} from "model/folder";
import Notify from "common/notify";
import {MaxItems} from "common/clipboard";
import download from "common/download";
export default {
name: 'PPageFiles',
@ -209,11 +210,10 @@ export default {
}
},
downloadFile(index) {
Notify.success(this.$gettext("Downloading…"));
const model = this.results[index];
const link = document.createElement('a');
link.href = `/api/v1/dl/${model.Hash}?t=${this.$config.downloadToken()}`;
link.download = model.Name;
link.click();
download(`/api/v1/dl/${model.Hash}?t=${this.$config.downloadToken()}`, model.Name);
},
selectRange(rangeEnd, models) {
if (!models || !models[rangeEnd] || !(models[rangeEnd] instanceof RestModel)) {

View File

@ -1,15 +1,15 @@
<template>
<div>
<v-container fluid class="pa-0" v-if="selection.length > 0">
<v-container v-if="selection.length > 0" fluid class="pa-0">
<v-speed-dial
fixed bottom right
id="t-clipboard" v-model="expanded" fixed
bottom
right
direction="top"
v-model="expanded"
transition="slide-y-reverse-transition"
class="p-clipboard p-album-clipboard"
id="t-clipboard"
>
<template v-slot:activator>
<template #activator>
<v-btn
fab dark
color="accent darken-2"
@ -24,9 +24,9 @@
fab dark small
:title="$gettext('Download')"
color="download"
@click.stop="download()"
class="action-download"
:disabled="selection.length !== 1 || !$config.feature('download')"
@click.stop="download()"
>
<v-icon>get_app</v-icon>
</v-btn>
@ -34,8 +34,8 @@
<v-btn
fab dark small
color="accent"
@click.stop="clearClipboard()"
class="action-clear"
@click.stop="clearClipboard()"
>
<v-icon>clear</v-icon>
</v-btn>
@ -46,9 +46,10 @@
<script>
import Notify from "common/notify";
import Album from "model/album";
import download from "common/download";
export default {
name: 'p-album-clipboard',
name: 'PAlbumClipboard',
props: {
selection: Array,
refresh: Function,
@ -85,10 +86,8 @@ export default {
},
onDownload(path) {
Notify.success(this.$gettext("Downloading…"));
const link = document.createElement('a')
link.href = path;
link.download = "album.zip";
link.click();
download(path, "album.zip");
},
}
};

View File

@ -135,6 +135,9 @@
</v-container>
</template>
<script>
import download from "common/download";
import Notify from "../../common/notify";
export default {
name: 'PPhotoCards',
props: {
@ -182,11 +185,10 @@ export default {
if (player) player.pause();
},
downloadFile(index) {
Notify.success(this.$gettext("Downloading…"));
const photo = this.photos[index];
const link = document.createElement('a');
link.href = `/api/v1/dl/${photo.Hash}?t=${this.$config.downloadToken()}`;
link.download = photo.FileName;
link.click();
download(`/api/v1/dl/${photo.Hash}?t=${this.$config.downloadToken()}`, photo.FileName);
},
onSelect(ev, index) {
if (ev.shiftKey) {

View File

@ -48,6 +48,7 @@
<script>
import Api from "common/api";
import Notify from "common/notify";
import download from "common/download";
export default {
name: 'PPhotoClipboard',
@ -86,10 +87,8 @@ export default {
},
onDownload(path) {
Notify.success(this.$gettext("Downloading…"));
const link = document.createElement('a');
link.href = path;
link.download = "photos.zip";
link.click();
download(path, "photos.zip");
},
}
};

View File

@ -90,6 +90,9 @@
</div>
</template>
<script>
import download from "common/download";
import Notify from "../../common/notify";
export default {
name: 'PPhotoList',
props: {
@ -137,11 +140,10 @@ export default {
},
methods: {
downloadFile(index) {
Notify.success(this.$gettext("Downloading…"));
const photo = this.photos[index];
const link = document.createElement('a');
link.href = `/api/v1/dl/${photo.Hash}?t=${this.$config.downloadToken()}`;
link.download = photo.FileName;
link.click();
download(`/api/v1/dl/${photo.Hash}?t=${this.$config.downloadToken()}`, photo.FileName);
},
onSelect(ev, index) {
if (ev.shiftKey) {

View File

@ -91,6 +91,7 @@ import Album from "model/album";
import Event from "pubsub-js";
import Thumb from "model/thumb";
import Notify from "common/notify";
import download from "common/download";
export default {
name: 'PPageAlbumPhotos',
@ -569,10 +570,8 @@ export default {
},
onDownload(path) {
Notify.success(this.$gettext("Downloading…"));
const link = document.createElement('a');
link.href = path;
link.download = "album.zip";
link.click();
download(path, "album.zip");
},
},
};