Frontend: Refactor file download #895
This commit is contained in:
parent
54579f0ce9
commit
19c0df4791
57
frontend/src/common/download.js
Normal file
57
frontend/src/common/download.js
Normal 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);
|
||||
}
|
|
@ -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");
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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");
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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");
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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");
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
@ -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) {
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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");
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user