feat(editor): add upload and preview buttons

This commit is contained in:
Jitesh Doshi 2023-02-07 15:37:03 -05:00
parent ff3367ac42
commit 7676c52deb

View File

@ -4,6 +4,25 @@
<action icon="close" :label="$t('buttons.close')" @action="close()" /> <action icon="close" :label="$t('buttons.close')" @action="close()" />
<title>{{ req.name }}</title> <title>{{ req.name }}</title>
<action
v-if="headerButtons.upload"
icon="file_upload"
id="upload-button"
:label="$t('buttons.upload')"
@action="upload"
/>
<a
v-if="previewLink"
aria-label="preview"
title="Preview"
class="action"
:href="previewLink"
id="preview"
target="preview"
>
<i class="material-icons">preview</i>
<span>preview</span>
</a>
<action <action
v-if="user.perm.modify" v-if="user.perm.modify"
id="save-button" id="save-button"
@ -16,6 +35,21 @@
<breadcrumbs base="/files" noLink /> <breadcrumbs base="/files" noLink />
<form id="editor"></form> <form id="editor"></form>
<input
style="display: none"
type="file"
id="upload-input"
@change="uploadInput($event)"
multiple
/>
<input
style="display: none"
type="file"
id="upload-folder-input"
@change="uploadInput($event)"
webkitdirectory
multiple
/>
</div> </div>
</template> </template>
@ -33,6 +67,7 @@ import "ace-builds/webpack-resolver";
import HeaderBar from "@/components/header/HeaderBar"; import HeaderBar from "@/components/header/HeaderBar";
import Action from "@/components/header/Action"; import Action from "@/components/header/Action";
import Breadcrumbs from "@/components/Breadcrumbs"; import Breadcrumbs from "@/components/Breadcrumbs";
import * as upload from "@/utils/upload";
export default { export default {
name: "editor", name: "editor",
@ -46,6 +81,16 @@ export default {
}, },
computed: { computed: {
...mapState(["req", "user"]), ...mapState(["req", "user"]),
previewLink() {
return this.$route.path
.replace(/^\/files\//, "/")
.replace(/[^/]*$/, "");
},
headerButtons() {
return {
upload: this.user.perm.create,
};
},
breadcrumbs() { breadcrumbs() {
let parts = this.$route.path.split("/"); let parts = this.$route.path.split("/");
@ -78,8 +123,12 @@ export default {
}, },
created() { created() {
window.addEventListener("keydown", this.keyEvent); window.addEventListener("keydown", this.keyEvent);
window.addEventListener("drop", this.drop);
window.addEventListener("paste", this.drop);
}, },
beforeDestroy() { beforeDestroy() {
window.removeEventListener("paste", this.drop);
window.removeEventListener("drop", this.drop);
window.removeEventListener("keydown", this.keyEvent); window.removeEventListener("keydown", this.keyEvent);
this.editor.destroy(); this.editor.destroy();
}, },
@ -104,6 +153,129 @@ export default {
let uri = url.removeLastDir(this.$route.path) + "/"; let uri = url.removeLastDir(this.$route.path) + "/";
this.$router.push({ path: uri }); this.$router.push({ path: uri });
}, },
dragEnter() {
this.dragCounter++;
// When the user starts dragging an item, put every
// file on the listing with 50% opacity.
let items = document.getElementsByClassName("item");
Array.from(items).forEach((file) => {
file.style.opacity = 0.5;
});
},
dragLeave() {
this.dragCounter--;
if (this.dragCounter == 0) {
this.resetOpacity();
}
},
drop: async function (event) {
event.preventDefault();
this.dragCounter = 0;
this.resetOpacity();
let dt = event.dataTransfer ?? event.clipboardData;
let el = event.target;
if (dt.files.length <= 0) return;
for (let i = 0; i < 5; i++) {
if (el !== null && !el.classList.contains("item")) {
el = el.parentElement;
}
}
let files = await upload.scanFiles(dt);
let items = this.req.items;
let path = this.$route.path.replace(/\/[^/]*$/, "/");
if (
el !== null &&
el.classList.contains("item") &&
el.dataset.dir === "true"
) {
// Get url from ListingItem instance
path = el.__vue__.url;
try {
items = (await api.fetch(path)).items;
} catch (error) {
this.$showError(error);
}
}
let conflict = upload.checkConflict(files, items);
if (conflict) {
this.$store.commit("showHover", {
prompt: "replace",
confirm: (event) => {
event.preventDefault();
this.$store.commit("closeHovers");
upload.handleFiles(files, path, true);
},
});
return;
}
upload.handleFiles(files, path);
const alt = files[0].name;
const link = files[0].name;
this.editor.insert(`![${alt}](${link})`);
},
uploadInput(event) {
this.$store.commit("closeHovers");
let files = event.currentTarget.files;
let folder_upload =
files[0].webkitRelativePath !== undefined &&
files[0].webkitRelativePath !== "";
if (folder_upload) {
for (let i = 0; i < files.length; i++) {
let file = files[i];
files[i].fullPath = file.webkitRelativePath;
}
}
let path = this.$route.path.replace(/\/[^/]*$/, "/");
let conflict = upload.checkConflict(files, this.req.items);
if (conflict) {
this.$store.commit("showHover", {
prompt: "replace",
confirm: (event) => {
event.preventDefault();
this.$store.commit("closeHovers");
upload.handleFiles(files, path, true);
},
});
return;
}
upload.handleFiles(files, path);
},
resetOpacity() {
let items = document.getElementsByClassName("item");
Array.from(items).forEach((file) => {
file.style.opacity = 1;
});
},
upload: function () {
if (
typeof window.DataTransferItem !== "undefined" &&
typeof DataTransferItem.prototype.webkitGetAsEntry !== "undefined"
) {
this.$store.commit("showHover", "upload");
} else {
document.getElementById("upload-input").click();
}
},
keyEvent(event) { keyEvent(event) {
if (!event.ctrlKey && !event.metaKey) { if (!event.ctrlKey && !event.metaKey) {
return; return;