updated
This commit is contained in:
		
							parent
							
								
									8b6a6a1afe
								
							
						
					
					
						commit
						bc768ea12f
					
				|  | @ -2,7 +2,7 @@ package version | ||||||
| 
 | 
 | ||||||
| var ( | var ( | ||||||
| 	// Version is the current File Browser version.
 | 	// Version is the current File Browser version.
 | ||||||
| 	Version = "(0.1.4)" | 	Version = "(0.2.0)" | ||||||
| 	// CommitSHA is the commmit sha.
 | 	// CommitSHA is the commmit sha.
 | ||||||
| 	CommitSHA = "(unknown)" | 	CommitSHA = "(unknown)" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | @ -0,0 +1,192 @@ | ||||||
|  | <!doctype html> | ||||||
|  | <html lang="en"> | ||||||
|  |   <head> | ||||||
|  |     <meta charset="utf-8" /> | ||||||
|  |     <meta http-equiv="X-UA-Compatible" content="IE=edge" /> | ||||||
|  |     <meta | ||||||
|  |       name="viewport" | ||||||
|  |       content="width=device-width, initial-scale=1, user-scalable=no" | ||||||
|  |     /> | ||||||
|  | 
 | ||||||
|  |     <title>File Browser</title> | ||||||
|  | 
 | ||||||
|  |     <link | ||||||
|  |       rel="icon" | ||||||
|  |       type="image/png" | ||||||
|  |       sizes="32x32" | ||||||
|  |       href="/img/icons/favicon-32x32.png" | ||||||
|  |     /> | ||||||
|  |     <link | ||||||
|  |       rel="icon" | ||||||
|  |       type="image/png" | ||||||
|  |       sizes="16x16" | ||||||
|  |       href="/img/icons/favicon-16x16.png" | ||||||
|  |     /> | ||||||
|  | 
 | ||||||
|  |     <!-- Add to home screen for Android and modern mobile browsers --> | ||||||
|  |     <link | ||||||
|  |       rel="manifest" | ||||||
|  |       id="manifestPlaceholder" | ||||||
|  |       crossorigin="use-credentials" | ||||||
|  |     /> | ||||||
|  |     <meta name="theme-color" content="#2979ff" /> | ||||||
|  | 
 | ||||||
|  |     <!-- Add to home screen for Safari on iOS/iPadOS --> | ||||||
|  |     <meta name="apple-mobile-web-app-capable" content="yes" /> | ||||||
|  |     <meta name="apple-mobile-web-app-status-bar-style" content="black" /> | ||||||
|  |     <meta name="apple-mobile-web-app-title" content="assets" /> | ||||||
|  |     <link rel="apple-touch-icon" href="/img/icons/apple-touch-icon.png" /> | ||||||
|  | 
 | ||||||
|  |     <!-- Add to home screen for Windows --> | ||||||
|  |     <meta | ||||||
|  |       name="msapplication-TileImage" | ||||||
|  |       content="/img/icons/mstile-144x144.png" | ||||||
|  |     /> | ||||||
|  |     <meta name="msapplication-TileColor" content="#2979ff" /> | ||||||
|  | 
 | ||||||
|  |     <!-- Inject Some Variables and generate the manifest json --> | ||||||
|  |     <script> | ||||||
|  |       // We can assign JSON directly | ||||||
|  |       window.FileBrowser = { | ||||||
|  |         AuthMethod: "json", | ||||||
|  |         BaseURL: "", | ||||||
|  |         CSS: false, | ||||||
|  |         Color: "", | ||||||
|  |         DisableExternal: false, | ||||||
|  |         DisableUsedPercentage: false, | ||||||
|  |         EnableExec: true, | ||||||
|  |         EnableThumbs: true, | ||||||
|  |         LoginPage: true, | ||||||
|  |         Name: "", | ||||||
|  |         NoAuth: false, | ||||||
|  |         ReCaptcha: false, | ||||||
|  |         ResizePreview: true, | ||||||
|  |         Signup: false, | ||||||
|  |         StaticURL: "", | ||||||
|  |         Theme: "", | ||||||
|  |         TusSettings: { chunkSize: 10485760, retryCount: 5 }, | ||||||
|  |         Version: "(untracked)", | ||||||
|  |       }; | ||||||
|  |       // Global function to prepend static url | ||||||
|  |       window.__prependStaticUrl = (url) => { | ||||||
|  |         return `${window.FileBrowser.StaticURL}/${url.replace(/^\/+/, "")}`; | ||||||
|  |       }; | ||||||
|  |       var dynamicManifest = { | ||||||
|  |         name: window.FileBrowser.Name || "File Browser", | ||||||
|  |         short_name: window.FileBrowser.Name || "File Browser", | ||||||
|  |         icons: [ | ||||||
|  |           { | ||||||
|  |             src: window.__prependStaticUrl( | ||||||
|  |               "/img/icons/android-chrome-192x192.png" | ||||||
|  |             ), | ||||||
|  |             sizes: "192x192", | ||||||
|  |             type: "image/png", | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             src: window.__prependStaticUrl( | ||||||
|  |               "/img/icons/android-chrome-512x512.png" | ||||||
|  |             ), | ||||||
|  |             sizes: "512x512", | ||||||
|  |             type: "image/png", | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |         start_url: window.location.origin + window.FileBrowser.BaseURL, | ||||||
|  |         display: "standalone", | ||||||
|  |         background_color: "#ffffff", | ||||||
|  |         theme_color: window.FileBrowser.Color || "#455a64", | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       const stringManifest = JSON.stringify(dynamicManifest); | ||||||
|  |       const blob = new Blob([stringManifest], { type: "application/json" }); | ||||||
|  |       const manifestURL = URL.createObjectURL(blob); | ||||||
|  |       document | ||||||
|  |         .querySelector("#manifestPlaceholder") | ||||||
|  |         .setAttribute("href", manifestURL); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <style> | ||||||
|  |       #loading { | ||||||
|  |         position: fixed; | ||||||
|  |         top: 0; | ||||||
|  |         left: 0; | ||||||
|  |         width: 100%; | ||||||
|  |         height: 100%; | ||||||
|  |         background: #fff; | ||||||
|  |         z-index: 9999; | ||||||
|  |         transition: 0.1s ease opacity; | ||||||
|  |         -webkit-transition: 0.1s ease opacity; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       #loading.done { | ||||||
|  |         opacity: 0; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       #loading .spinner { | ||||||
|  |         width: 70px; | ||||||
|  |         text-align: center; | ||||||
|  |         position: fixed; | ||||||
|  |         top: 50%; | ||||||
|  |         left: 50%; | ||||||
|  |         -webkit-transform: translate(-50%, -50%); | ||||||
|  |         transform: translate(-50%, -50%); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       #loading .spinner > div { | ||||||
|  |         width: 18px; | ||||||
|  |         height: 18px; | ||||||
|  |         background-color: #333; | ||||||
|  |         border-radius: 100%; | ||||||
|  |         display: inline-block; | ||||||
|  |         -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both; | ||||||
|  |         animation: sk-bouncedelay 1.4s infinite ease-in-out both; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       #loading .spinner .bounce1 { | ||||||
|  |         -webkit-animation-delay: -0.32s; | ||||||
|  |         animation-delay: -0.32s; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       #loading .spinner .bounce2 { | ||||||
|  |         -webkit-animation-delay: -0.16s; | ||||||
|  |         animation-delay: -0.16s; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       @-webkit-keyframes sk-bouncedelay { | ||||||
|  |         0%, | ||||||
|  |         80%, | ||||||
|  |         100% { | ||||||
|  |           -webkit-transform: scale(0); | ||||||
|  |         } | ||||||
|  |         40% { | ||||||
|  |           -webkit-transform: scale(1); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       @keyframes sk-bouncedelay { | ||||||
|  |         0%, | ||||||
|  |         80%, | ||||||
|  |         100% { | ||||||
|  |           -webkit-transform: scale(0); | ||||||
|  |           transform: scale(0); | ||||||
|  |         } | ||||||
|  |         40% { | ||||||
|  |           -webkit-transform: scale(1); | ||||||
|  |           transform: scale(1); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     </style> | ||||||
|  |   </head> | ||||||
|  |   <body> | ||||||
|  |     <div id="app"></div> | ||||||
|  | 
 | ||||||
|  |     <div id="loading"> | ||||||
|  |       <div class="spinner"> | ||||||
|  |         <div class="bounce1"></div> | ||||||
|  |         <div class="bounce2"></div> | ||||||
|  |         <div class="bounce3"></div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|  |     <script type="module" src="/src/main.js"></script> | ||||||
|  |   </body> | ||||||
|  | </html> | ||||||
|  | @ -213,3 +213,7 @@ nav { | ||||||
|   background: var(--background); |   background: var(--background); | ||||||
|   color: white |   color: white | ||||||
| } | } | ||||||
|  | #result-desktop #result-list { | ||||||
|  |   background: #2a3137; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -211,7 +211,7 @@ | ||||||
|   border-top: none; |   border-top: none; | ||||||
|   border-top-left-radius: 0px; |   border-top-left-radius: 0px; | ||||||
|   border-top-right-radius: 0px; |   border-top-right-radius: 0px; | ||||||
|   background-color: white; |   background: white; | ||||||
|   max-height: 80vh; |   max-height: 80vh; | ||||||
|   left: 50%; |   left: 50%; | ||||||
|   -webkit-transform: translateX(-50%); |   -webkit-transform: translateX(-50%); | ||||||
|  |  | ||||||
|  | @ -1,24 +1,12 @@ | ||||||
| <template> | <template> | ||||||
|   <header> |   <header> | ||||||
|     <action |  | ||||||
|       class="menu-button" |  | ||||||
|       icon="menu" |  | ||||||
|       :label="$t('buttons.toggleSidebar')" |  | ||||||
|       @action="toggleSidebar()" |  | ||||||
|     /> |  | ||||||
| 
 |  | ||||||
|     <slot /> |     <slot /> | ||||||
| 
 |  | ||||||
|     <div id="dropdown" :class="{ active: this.$store.state.show === 'more' }"> |  | ||||||
|       <slot name="actions" /> |  | ||||||
|     </div> |  | ||||||
| 
 |  | ||||||
|   </header> |   </header> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
| import { logoURL } from "@/utils/constants"; | import { logoURL } from "@/utils/constants"; | ||||||
| import Action from "@/components/header/Action"; | import Action from "@/components/header/Action.vue"; | ||||||
| 
 | 
 | ||||||
| export default { | export default { | ||||||
|   name: "header-bar", |   name: "header-bar", | ||||||
|  |  | ||||||
|  | @ -3,12 +3,10 @@ | ||||||
|     <div v-if="progress" class="progress"> |     <div v-if="progress" class="progress"> | ||||||
|       <div v-bind:style="{ width: this.progress + '%' }"></div> |       <div v-bind:style="{ width: this.progress + '%' }"></div> | ||||||
|     </div> |     </div> | ||||||
|     <header-bar showMenu showLogo> |     <editorBar v-if="getCurrentView === 'editor'"></editorBar> | ||||||
|       <search /> |     <listingBar v-else-if="getCurrentView === 'listing'"></listingBar> | ||||||
|       <template #actions> |     <previewBar v-else-if="getCurrentView === 'preview'"></previewBar> | ||||||
|         <action icon="grid_view" :label="$t('buttons.switchView')" @action="switchView" /> |     <defaultBar v-else></defaultBar> | ||||||
|       </template> |  | ||||||
|     </header-bar> |  | ||||||
|     <sidebar></sidebar> |     <sidebar></sidebar> | ||||||
|     <main> |     <main> | ||||||
|       <router-view></router-view> |       <router-view></router-view> | ||||||
|  | @ -20,60 +18,66 @@ | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
|  | import editorBar from "./files/Editor.vue" | ||||||
|  | import defaultBar from "./files/Default.vue" | ||||||
|  | import listingBar from"./files/Listing.vue" | ||||||
|  | import previewBar from "./files/Preview.vue" | ||||||
|  | import Action from "@/components/header/Action.vue"; | ||||||
| import { mapState, mapGetters } from "vuex"; | import { mapState, mapGetters } from "vuex"; | ||||||
| import Sidebar from "@/components/Sidebar"; | import Sidebar from "@/components/Sidebar.vue"; | ||||||
| import Prompts from "@/components/prompts/Prompts"; | import Prompts from "@/components/header/Action.vue"; | ||||||
| import Shell from "@/components/Shell"; | import Shell from "@/components/Shell.vue"; | ||||||
| import UploadFiles from "../components/prompts/UploadFiles"; | import UploadFiles from "../components/prompts/UploadFiles.vue"; | ||||||
| import { enableExec } from "@/utils/constants"; | import { enableExec } from "@/utils/constants"; | ||||||
| import HeaderBar from "@/components/header/HeaderBar"; |  | ||||||
| import Search from "@/components/Search"; |  | ||||||
| import Action from "@/components/header/Action"; |  | ||||||
| 
 | 
 | ||||||
| export default { | export default { | ||||||
|   name: "layout", |   name: "layout", | ||||||
|   components: { |   components: { | ||||||
|  |     defaultBar, | ||||||
|  |     editorBar, | ||||||
|  |     listingBar, | ||||||
|  |     previewBar, | ||||||
|     Action, |     Action, | ||||||
|     HeaderBar, |  | ||||||
|     Search, |  | ||||||
|     Sidebar, |     Sidebar, | ||||||
|     Prompts, |     Prompts, | ||||||
|     Shell, |     Shell, | ||||||
|     UploadFiles, |     UploadFiles, | ||||||
|   }, |   }, | ||||||
|  |   data: function () { | ||||||
|  |     return { | ||||||
|  |       showContexts: true, | ||||||
|  |       dragCounter: 0, | ||||||
|  |       width: window.innerWidth, | ||||||
|  |       itemWeight: 0, | ||||||
|  |     }; | ||||||
|  |   }, | ||||||
|   computed: { |   computed: { | ||||||
|     ...mapGetters(["isLogged", "progress"]), |     ...mapGetters(["isLogged", "progress"]), | ||||||
|     ...mapState(["user"]), |     ...mapState(["req", "user", "currentView"]), | ||||||
|  |      | ||||||
|     isExecEnabled: () => enableExec, |     isExecEnabled: () => enableExec, | ||||||
|  |     getCurrentView() { | ||||||
|  |       return this.currentView; | ||||||
|  |     }, | ||||||
|   }, |   }, | ||||||
|   watch: { |   watch: { | ||||||
|  |     getCurrentView: function () { | ||||||
|  |       console.log(this.currentView) | ||||||
|  |     }, | ||||||
|     $route: function () { |     $route: function () { | ||||||
|       this.$store.commit("resetSelected"); |       this.$store.commit("resetSelected"); | ||||||
|       this.$store.commit("multiple", false); |       this.$store.commit("multiple", false); | ||||||
|       if (this.$store.state.show !== "success") |       if (this.$store.state.show !== "success") this.$store.commit("closeHovers"); | ||||||
|         this.$store.commit("closeHovers"); |  | ||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|     switchView: async function () { |     getTitle() { | ||||||
|       this.$store.commit("closeHovers"); |       let title = "Title" | ||||||
|       const modes = { |       if (this.$route.path.startsWith('/settings/')){ | ||||||
|         list: "mosaic", |         title = "Settings" | ||||||
|         mosaic: "mosaic gallery", |  | ||||||
|         "mosaic gallery": "list", |  | ||||||
|       }; |  | ||||||
| 
 |  | ||||||
|       const data = { |  | ||||||
|         id: this.user.id, |  | ||||||
|         viewMode: modes[this.user.viewMode] || "list", |  | ||||||
|       }; |  | ||||||
|       //users.update(data, ["viewMode"]).catch(this.$showError); |  | ||||||
|       this.$store.commit("updateUser", data); |  | ||||||
| 
 |  | ||||||
|       //this.setItemWeight(); |  | ||||||
|       //this.fillWindow(); |  | ||||||
|     }, |  | ||||||
|       } |       } | ||||||
| 
 |       return title | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
| }; | }; | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
|  | @ -0,0 +1,631 @@ | ||||||
|  | <template> | ||||||
|  |   <header-bar> | ||||||
|  |     <action | ||||||
|  |       class="menu-button" | ||||||
|  |       icon="menu" | ||||||
|  |       :label="$t('buttons.toggleSidebar')" | ||||||
|  |       @action="toggleSidebar()" | ||||||
|  |     /> | ||||||
|  |     <search /> | ||||||
|  |     <action | ||||||
|  |       class="menu-button" | ||||||
|  |       icon="grid_view" | ||||||
|  |       :label="$t('buttons.switchView')" | ||||||
|  |       @action="switchView" | ||||||
|  |     /> | ||||||
|  |   </header-bar> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <style> | ||||||
|  | .flexbar { | ||||||
|  |   display:flex; | ||||||
|  |   flex-direction:block; | ||||||
|  |   justify-content: space-between; | ||||||
|  | } | ||||||
|  | </style> | ||||||
|  | 
 | ||||||
|  | <script> | ||||||
|  | import Vue from "vue"; | ||||||
|  | import { mapState, mapGetters, mapMutations } from "vuex"; | ||||||
|  | import { users, files as api } from "@/api"; | ||||||
|  | import { enableExec } from "@/utils/constants"; | ||||||
|  | import HeaderBar from "@/components/header/HeaderBar.vue"; | ||||||
|  | import Action from "@/components/header/Action.vue"; | ||||||
|  | import * as upload from "@/utils/upload"; | ||||||
|  | import css from "@/utils/css"; | ||||||
|  | import throttle from "lodash.throttle"; | ||||||
|  | import Search from "@/components/Search.vue"; | ||||||
|  | 
 | ||||||
|  | import Item from "@/components/files/ListingItem.vue"; | ||||||
|  | 
 | ||||||
|  | export default { | ||||||
|  |   name: "listing", | ||||||
|  |   components: { | ||||||
|  |     HeaderBar, | ||||||
|  |     Action, | ||||||
|  |     Search, | ||||||
|  |     Item, | ||||||
|  |   }, | ||||||
|  |   data: function () { | ||||||
|  |     return { | ||||||
|  |       showLimit: 50, | ||||||
|  |       columnWidth: 280, | ||||||
|  |       dragCounter: 0, | ||||||
|  |       width: window.innerWidth, | ||||||
|  |       itemWeight: 0, | ||||||
|  |     }; | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(["req", "selected", "user", "show", "multiple", "selected", "loading"]), | ||||||
|  |     ...mapGetters(["selectedCount"]), | ||||||
|  |     nameSorted() { | ||||||
|  |       return this.req.sorting.by === "name"; | ||||||
|  |     }, | ||||||
|  |     sizeSorted() { | ||||||
|  |       return this.req.sorting.by === "size"; | ||||||
|  |     }, | ||||||
|  |     modifiedSorted() { | ||||||
|  |       return this.req.sorting.by === "modified"; | ||||||
|  |     }, | ||||||
|  |     ascOrdered() { | ||||||
|  |       return this.req.sorting.asc; | ||||||
|  |     }, | ||||||
|  |     items() { | ||||||
|  |       const dirs = []; | ||||||
|  |       const files = []; | ||||||
|  | 
 | ||||||
|  |       this.req.items.forEach((item) => { | ||||||
|  |         if (item.isDir) { | ||||||
|  |           dirs.push(item); | ||||||
|  |         } else { | ||||||
|  |           files.push(item); | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       return { dirs, files }; | ||||||
|  |     }, | ||||||
|  |     dirs() { | ||||||
|  |       return this.items.dirs.slice(0, this.showLimit); | ||||||
|  |     }, | ||||||
|  |     files() { | ||||||
|  |       let showLimit = this.showLimit - this.items.dirs.length; | ||||||
|  | 
 | ||||||
|  |       if (showLimit < 0) showLimit = 0; | ||||||
|  | 
 | ||||||
|  |       return this.items.files.slice(0, showLimit); | ||||||
|  |     }, | ||||||
|  |     nameIcon() { | ||||||
|  |       if (this.nameSorted && !this.ascOrdered) { | ||||||
|  |         return "arrow_upward"; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return "arrow_downward"; | ||||||
|  |     }, | ||||||
|  |     sizeIcon() { | ||||||
|  |       if (this.sizeSorted && this.ascOrdered) { | ||||||
|  |         return "arrow_downward"; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return "arrow_upward"; | ||||||
|  |     }, | ||||||
|  |     modifiedIcon() { | ||||||
|  |       if (this.modifiedSorted && this.ascOrdered) { | ||||||
|  |         return "arrow_downward"; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return "arrow_upward"; | ||||||
|  |     }, | ||||||
|  |     viewIcon() { | ||||||
|  |       const icons = { | ||||||
|  |         list: "view_module", | ||||||
|  |         mosaic: "grid_view", | ||||||
|  |         "mosaic gallery": "view_list", | ||||||
|  |       }; | ||||||
|  |       return icons[this.user.viewMode]; | ||||||
|  |     }, | ||||||
|  |     headerButtons() { | ||||||
|  |       return { | ||||||
|  |         select: this.selectedCount > 0, | ||||||
|  |         upload: this.user.perm.create && this.selectedCount > 0, | ||||||
|  |         download: this.user.perm.download && this.selectedCount > 0, | ||||||
|  |         shell: this.user.perm.execute && enableExec, | ||||||
|  |         delete: this.selectedCount > 0 && this.user.perm.delete, | ||||||
|  |         rename: this.selectedCount === 1 && this.user.perm.rename, | ||||||
|  |         share: this.selectedCount === 1 && this.user.perm.share, | ||||||
|  |         move: this.selectedCount > 0 && this.user.perm.rename, | ||||||
|  |         copy: this.selectedCount > 0 && this.user.perm.create, | ||||||
|  |       }; | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   watch: { | ||||||
|  |     req: function () { | ||||||
|  |       // Reset the show value | ||||||
|  |       this.showLimit = 50; | ||||||
|  | 
 | ||||||
|  |       // Ensures that the listing is displayed | ||||||
|  |       Vue.nextTick(() => { | ||||||
|  |         // How much every listing item affects the window height | ||||||
|  |         this.setItemWeight(); | ||||||
|  | 
 | ||||||
|  |         // Fill and fit the window with listing items | ||||||
|  |         this.fillWindow(true); | ||||||
|  |       }); | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   mounted: function () { | ||||||
|  |     // Check the columns size for the first time. | ||||||
|  |     this.colunmsResize(); | ||||||
|  | 
 | ||||||
|  |     // How much every listing item affects the window height | ||||||
|  |     this.setItemWeight(); | ||||||
|  | 
 | ||||||
|  |     // Fill and fit the window with listing items | ||||||
|  |     this.fillWindow(true); | ||||||
|  | 
 | ||||||
|  |     // Add the needed event listeners to the window and document. | ||||||
|  |     window.addEventListener("keydown", this.keyEvent); | ||||||
|  |     window.addEventListener("scroll", this.scrollEvent); | ||||||
|  |     window.addEventListener("resize", this.windowsResize); | ||||||
|  | 
 | ||||||
|  |     if (!this.user.perm.create) return; | ||||||
|  |     document.addEventListener("dragover", this.preventDefault); | ||||||
|  |     document.addEventListener("dragenter", this.dragEnter); | ||||||
|  |     document.addEventListener("dragleave", this.dragLeave); | ||||||
|  |     document.addEventListener("drop", this.drop); | ||||||
|  |   }, | ||||||
|  |   beforeDestroy() { | ||||||
|  |     // Remove event listeners before destroying this page. | ||||||
|  |     window.removeEventListener("keydown", this.keyEvent); | ||||||
|  |     window.removeEventListener("scroll", this.scrollEvent); | ||||||
|  |     window.removeEventListener("resize", this.windowsResize); | ||||||
|  | 
 | ||||||
|  |     if (this.user && !this.user.perm.create) return; | ||||||
|  |     document.removeEventListener("dragover", this.preventDefault); | ||||||
|  |     document.removeEventListener("dragenter", this.dragEnter); | ||||||
|  |     document.removeEventListener("dragleave", this.dragLeave); | ||||||
|  |     document.removeEventListener("drop", this.drop); | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     action: function () { | ||||||
|  |       if (this.show) { | ||||||
|  |         this.$store.commit("showHover", this.show); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       this.$emit("action"); | ||||||
|  |     }, | ||||||
|  |     toggleSidebar() { | ||||||
|  |       if (this.$store.state.show == "sidebar") { | ||||||
|  |         this.$store.commit("closeHovers"); | ||||||
|  |       } else { | ||||||
|  |         this.$store.commit("showHover", "sidebar"); | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     ...mapMutations(["updateUser", "addSelected"]), | ||||||
|  |     base64: function (name) { | ||||||
|  |       return window.btoa(unescape(encodeURIComponent(name))); | ||||||
|  |     }, | ||||||
|  |     keyEvent(event) { | ||||||
|  |       // No prompts are shown | ||||||
|  |       if (this.show !== null) { | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // Esc! | ||||||
|  |       if (event.keyCode === 27) { | ||||||
|  |         // Reset files selection. | ||||||
|  |         this.$store.commit("resetSelected"); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // Del! | ||||||
|  |       if (event.keyCode === 46) { | ||||||
|  |         if (!this.user.perm.delete || this.selectedCount == 0) return; | ||||||
|  | 
 | ||||||
|  |         // Show delete prompt. | ||||||
|  |         this.$store.commit("showHover", "delete"); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // F2! | ||||||
|  |       if (event.keyCode === 113) { | ||||||
|  |         if (!this.user.perm.rename || this.selectedCount !== 1) return; | ||||||
|  | 
 | ||||||
|  |         // Show rename prompt. | ||||||
|  |         this.$store.commit("showHover", "rename"); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // Ctrl is pressed | ||||||
|  |       if (!event.ctrlKey && !event.metaKey) { | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       let key = String.fromCharCode(event.which).toLowerCase(); | ||||||
|  | 
 | ||||||
|  |       switch (key) { | ||||||
|  |         case "f": | ||||||
|  |           event.preventDefault(); | ||||||
|  |           this.$store.commit("showHover", "search"); | ||||||
|  |           break; | ||||||
|  |         case "c": | ||||||
|  |         case "x": | ||||||
|  |           this.copyCut(event, key); | ||||||
|  |           break; | ||||||
|  |         case "v": | ||||||
|  |           this.paste(event); | ||||||
|  |           break; | ||||||
|  |         case "a": | ||||||
|  |           event.preventDefault(); | ||||||
|  |           for (let file of this.items.files) { | ||||||
|  |             if (this.$store.state.selected.indexOf(file.index) === -1) { | ||||||
|  |               this.addSelected(file.index); | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |           for (let dir of this.items.dirs) { | ||||||
|  |             if (this.$store.state.selected.indexOf(dir.index) === -1) { | ||||||
|  |               this.addSelected(dir.index); | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |           break; | ||||||
|  |         case "s": | ||||||
|  |           event.preventDefault(); | ||||||
|  |           document.getElementById("download-button").click(); | ||||||
|  |           break; | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     switchView: async function () { | ||||||
|  |       this.$store.commit("closeHovers"); | ||||||
|  |       const modes = { | ||||||
|  |         list: "mosaic", | ||||||
|  |         mosaic: "mosaic gallery", | ||||||
|  |         "mosaic gallery": "list", | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       const data = { | ||||||
|  |         id: this.user.id, | ||||||
|  |         viewMode: modes[this.user.viewMode] || "list", | ||||||
|  |       }; | ||||||
|  |       //users.update(data, ["viewMode"]).catch(this.$showError); | ||||||
|  |       this.$store.commit("updateUser", data); | ||||||
|  | 
 | ||||||
|  |       //this.setItemWeight(); | ||||||
|  |       //this.fillWindow(); | ||||||
|  |     }, | ||||||
|  |     preventDefault(event) { | ||||||
|  |       // Wrapper around prevent default. | ||||||
|  |       event.preventDefault(); | ||||||
|  |     }, | ||||||
|  |     copyCut(event, key) { | ||||||
|  |       if (event.target.tagName.toLowerCase() === "input") { | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       let items = []; | ||||||
|  | 
 | ||||||
|  |       for (let i of this.selected) { | ||||||
|  |         items.push({ | ||||||
|  |           from: this.req.items[i].url, | ||||||
|  |           name: this.req.items[i].name, | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (items.length == 0) { | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       this.$store.commit("updateClipboard", { | ||||||
|  |         key: key, | ||||||
|  |         items: items, | ||||||
|  |         path: this.$route.path, | ||||||
|  |       }); | ||||||
|  |     }, | ||||||
|  |     paste(event) { | ||||||
|  |       if (event.target.tagName.toLowerCase() === "input") { | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       let items = []; | ||||||
|  | 
 | ||||||
|  |       for (let item of this.$store.state.clipboard.items) { | ||||||
|  |         const from = item.from.endsWith("/") ? item.from.slice(0, -1) : item.from; | ||||||
|  |         const to = this.$route.path + encodeURIComponent(item.name); | ||||||
|  |         items.push({ from, to, name: item.name }); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (items.length === 0) { | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       let action = (overwrite, rename) => { | ||||||
|  |         api | ||||||
|  |           .copy(items, overwrite, rename) | ||||||
|  |           .then(() => { | ||||||
|  |             this.$store.commit("setReload", true); | ||||||
|  |           }) | ||||||
|  |           .catch(this.$showError); | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       if (this.$store.state.clipboard.key === "x") { | ||||||
|  |         action = (overwrite, rename) => { | ||||||
|  |           api | ||||||
|  |             .move(items, overwrite, rename) | ||||||
|  |             .then(() => { | ||||||
|  |               this.$store.commit("resetClipboard"); | ||||||
|  |               this.$store.commit("setReload", true); | ||||||
|  |             }) | ||||||
|  |             .catch(this.$showError); | ||||||
|  |         }; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (this.$store.state.clipboard.path == this.$route.path) { | ||||||
|  |         action(false, true); | ||||||
|  | 
 | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       let conflict = upload.checkConflict(items, this.req.items); | ||||||
|  | 
 | ||||||
|  |       let overwrite = false; | ||||||
|  |       let rename = false; | ||||||
|  | 
 | ||||||
|  |       if (conflict) { | ||||||
|  |         this.$store.commit("showHover", { | ||||||
|  |           prompt: "replace-rename", | ||||||
|  |           confirm: (event, option) => { | ||||||
|  |             overwrite = option == "overwrite"; | ||||||
|  |             rename = option == "rename"; | ||||||
|  | 
 | ||||||
|  |             event.preventDefault(); | ||||||
|  |             this.$store.commit("closeHovers"); | ||||||
|  |             action(overwrite, rename); | ||||||
|  |           }, | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       action(overwrite, rename); | ||||||
|  |     }, | ||||||
|  |     colunmsResize() { | ||||||
|  |       // Update the columns size based on the window width. | ||||||
|  |       let columns = Math.floor( | ||||||
|  |         document.querySelector("main").offsetWidth / this.columnWidth | ||||||
|  |       ); | ||||||
|  |       let items = css(["#listing.mosaic .item", ".mosaic#listing .item"]); | ||||||
|  |       if (columns === 0) columns = 1; | ||||||
|  |       items.style.width = `calc(${100 / columns}% - 1em)`; | ||||||
|  |     }, | ||||||
|  |     scrollEvent: throttle(function () { | ||||||
|  |       const totalItems = this.req.numDirs + this.req.numFiles; | ||||||
|  | 
 | ||||||
|  |       // All items are displayed | ||||||
|  |       if (this.showLimit >= totalItems) return; | ||||||
|  | 
 | ||||||
|  |       const currentPos = window.innerHeight + window.scrollY; | ||||||
|  | 
 | ||||||
|  |       // Trigger at the 75% of the window height | ||||||
|  |       const triggerPos = document.body.offsetHeight - window.innerHeight * 0.25; | ||||||
|  | 
 | ||||||
|  |       if (currentPos > triggerPos) { | ||||||
|  |         // Quantity of items needed to fill 2x of the window height | ||||||
|  |         const showQuantity = Math.ceil((window.innerHeight * 2) / this.itemWeight); | ||||||
|  | 
 | ||||||
|  |         // Increase the number of displayed items | ||||||
|  |         this.showLimit += showQuantity; | ||||||
|  |       } | ||||||
|  |     }, 100), | ||||||
|  |     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; | ||||||
|  |       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.endsWith("/") | ||||||
|  |         ? this.$route.path | ||||||
|  |         : this.$route.path + "/"; | ||||||
|  | 
 | ||||||
|  |       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); | ||||||
|  |     }, | ||||||
|  |     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.endsWith("/") | ||||||
|  |         ? this.$route.path | ||||||
|  |         : this.$route.path + "/"; | ||||||
|  |       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; | ||||||
|  |       }); | ||||||
|  |     }, | ||||||
|  |     async sort(by) { | ||||||
|  |       let asc = false; | ||||||
|  | 
 | ||||||
|  |       if (by === "name") { | ||||||
|  |         if (this.nameIcon === "arrow_upward") { | ||||||
|  |           asc = true; | ||||||
|  |         } | ||||||
|  |       } else if (by === "size") { | ||||||
|  |         if (this.sizeIcon === "arrow_upward") { | ||||||
|  |           asc = true; | ||||||
|  |         } | ||||||
|  |       } else if (by === "modified") { | ||||||
|  |         if (this.modifiedIcon === "arrow_upward") { | ||||||
|  |           asc = true; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       try { | ||||||
|  |         await users.update({ id: this.user.id, sorting: { by, asc } }, ["sorting"]); | ||||||
|  |       } catch (e) { | ||||||
|  |         this.$showError(e); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       this.$store.commit("setReload", true); | ||||||
|  |     }, | ||||||
|  |     openSearch() { | ||||||
|  |       this.$store.commit("showHover", "search"); | ||||||
|  |     }, | ||||||
|  |     toggleMultipleSelection() { | ||||||
|  |       this.$store.commit("multiple", !this.multiple); | ||||||
|  |       this.$store.commit("closeHovers"); | ||||||
|  |     }, | ||||||
|  |     windowsResize: throttle(function () { | ||||||
|  |       this.colunmsResize(); | ||||||
|  |       this.width = window.innerWidth; | ||||||
|  | 
 | ||||||
|  |       // Listing element is not displayed | ||||||
|  |       if (this.$refs.listing == null) return; | ||||||
|  | 
 | ||||||
|  |       // How much every listing item affects the window height | ||||||
|  |       this.setItemWeight(); | ||||||
|  | 
 | ||||||
|  |       // Fill but not fit the window | ||||||
|  |       this.fillWindow(); | ||||||
|  |     }, 100), | ||||||
|  |     download() { | ||||||
|  |       if (this.selectedCount === 1 && !this.req.items[this.selected[0]].isDir) { | ||||||
|  |         api.download(null, this.req.items[this.selected[0]].url); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       this.$store.commit("showHover", { | ||||||
|  |         prompt: "download", | ||||||
|  |         confirm: (format) => { | ||||||
|  |           this.$store.commit("closeHovers"); | ||||||
|  |           let files = []; | ||||||
|  |           if (this.selectedCount > 0) { | ||||||
|  |             for (let i of this.selected) { | ||||||
|  |               files.push(this.req.items[i].url); | ||||||
|  |             } | ||||||
|  |           } else { | ||||||
|  |             files.push(this.$route.path); | ||||||
|  |           } | ||||||
|  | 
 | ||||||
|  |           api.download(format, ...files); | ||||||
|  |         }, | ||||||
|  |       }); | ||||||
|  |     }, | ||||||
|  | 
 | ||||||
|  |     upload: function () { | ||||||
|  |       if ( | ||||||
|  |         typeof window.DataTransferItem !== "undefined" && | ||||||
|  |         typeof DataTransferItem.prototype.webkitGetAsEntry !== "undefined" | ||||||
|  |       ) { | ||||||
|  |         this.$store.commit("showHover", "upload"); | ||||||
|  |       } else { | ||||||
|  |         document.getElementById("upload-input").click(); | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     setItemWeight() { | ||||||
|  |       // Listing element is not displayed | ||||||
|  |       if (this.$refs.listing == null) return; | ||||||
|  | 
 | ||||||
|  |       let itemQuantity = this.req.numDirs + this.req.numFiles; | ||||||
|  |       if (itemQuantity > this.showLimit) itemQuantity = this.showLimit; | ||||||
|  | 
 | ||||||
|  |       // How much every listing item affects the window height | ||||||
|  |       this.itemWeight = this.$refs.listing.offsetHeight / itemQuantity; | ||||||
|  |     }, | ||||||
|  |     fillWindow(fit = false) { | ||||||
|  |       const totalItems = this.req.numDirs + this.req.numFiles; | ||||||
|  | 
 | ||||||
|  |       // More items are displayed than the total | ||||||
|  |       if (this.showLimit >= totalItems && !fit) return; | ||||||
|  | 
 | ||||||
|  |       const windowHeight = window.innerHeight; | ||||||
|  | 
 | ||||||
|  |       // Quantity of items needed to fill 2x of the window height | ||||||
|  |       const showQuantity = Math.ceil((windowHeight + windowHeight * 2) / this.itemWeight); | ||||||
|  | 
 | ||||||
|  |       // Less items to display than current | ||||||
|  |       if (this.showLimit > showQuantity && !fit) return; | ||||||
|  | 
 | ||||||
|  |       // Set the number of displayed items | ||||||
|  |       this.showLimit = showQuantity > totalItems ? totalItems : showQuantity; | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  | </script> | ||||||
		Loading…
	
		Reference in New Issue