322 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			322 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <!DOCTYPE html>
 | |
| <html>
 | |
|   <head>
 | |
|     <meta charset="utf-8">
 | |
|     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
 | |
|     <title>storage.clerie.de</title>
 | |
| 
 | |
|     <style>
 | |
|       * {
 | |
|         margin: 0;
 | |
|         padding: 0;
 | |
|       }
 | |
| 
 | |
|       body {
 | |
|         font-family: Roboto;
 | |
|         color: #222222;
 | |
|       }
 | |
| 
 | |
|       header {
 | |
|       }
 | |
| 
 | |
|       header > .title {
 | |
|         padding: 3em;
 | |
|         min-height: 3em;
 | |
|       }
 | |
| 
 | |
|       header > .title > h1 {
 | |
|         color: #222222;
 | |
|       }
 | |
| 
 | |
|       header > .menu {
 | |
|         padding: 1em 3em;
 | |
|       }
 | |
| 
 | |
|       header > .menu > button,
 | |
|       header > .menu > input {
 | |
|         height: 3em;
 | |
|         min-width: 3em;
 | |
|       }
 | |
| 
 | |
|       main {
 | |
|       }
 | |
| 
 | |
|       .listing {
 | |
|         display: flex;
 | |
|         width: 100%;
 | |
|         flex-direction: column;
 | |
|       }
 | |
| 
 | |
|       .listing-item {
 | |
|         padding: 1em 3em;
 | |
|         display: flex;
 | |
|         flex-direction: row;
 | |
|         flex-wrap: wrap;
 | |
|         min-height: 3em;
 | |
| 
 | |
|         border-top-style: solid;
 | |
|         border-width: 1px;
 | |
|         border-color: #F0F0F0;
 | |
|       }
 | |
| 
 | |
|       .listing-item:hover {
 | |
|         background-color: rgb(245, 245, 245);
 | |
|       }
 | |
| 
 | |
|       .listing-item > .detail {
 | |
|         flex: auto;
 | |
|       }
 | |
| 
 | |
|       .listing-item > .detail > a {
 | |
|         display: block;
 | |
|         height: 100%;
 | |
|         width: 100%;
 | |
|       }
 | |
| 
 | |
|       .listing-item button {
 | |
|         height: 3em;
 | |
|         min-width: 3em;
 | |
|       }
 | |
| 
 | |
|       button, input[type="file"] {
 | |
|         border-style: none;
 | |
|         background-color: transparent;
 | |
|         min-width: 3em;
 | |
|         height: 3em;
 | |
|         border-radius: 0.2em;
 | |
|       }
 | |
| 
 | |
|       button:hover {
 | |
|         background-color: #DDDDDD;
 | |
|       }
 | |
| 
 | |
|       .loading {
 | |
|         margin: auto;
 | |
|       }
 | |
|       @keyframes spinner {
 | |
|         0% {
 | |
|           transform: translate3d(-50%, -50%, 0) rotate(0deg);
 | |
|         }
 | |
|         100% {
 | |
|           transform: translate3d(-50%, -50%, 0) rotate(360deg);
 | |
|         }
 | |
|       }
 | |
|       .loading::before {
 | |
|         display: block;
 | |
|         animation: 1.5s linear infinite spinner;
 | |
|         animation-play-state: inherit;
 | |
|         border: solid 5px #cfd0d1;
 | |
|         border-bottom-color: #1c87c9;
 | |
|         border-radius: 50%;
 | |
|         content: "";
 | |
|         height: 40px;
 | |
|         width: 40px;
 | |
|         transform: translate3d(-50%, -50%, 0);
 | |
|         will-change: transform;
 | |
|       }
 | |
|     </style>
 | |
|   </head>
 | |
|   <body>
 | |
|     <header>
 | |
|       <div class="title">
 | |
|         <h1 id="path"></h1>
 | |
|       </div>
 | |
|       <div class="menu">
 | |
|         <button onclick="createDirectoryButton();">📁 +</button>
 | |
|         <input id="files" type="file" multiple> <button onclick="uploadFilesButton();">⭫</button>
 | |
|       </div>
 | |
|     </header>
 | |
|     <main>
 | |
|       <div id="listing"></div>
 | |
|     </main>
 | |
|     <script>
 | |
|       let path_field = document.getElementById("path");
 | |
|       let listing_field = document.getElementById("listing");
 | |
| 
 | |
|       let base_path = "/_";
 | |
| 
 | |
|       if (window.location.hash === "") {
 | |
|         window.location.hash = "#/";
 | |
|       }
 | |
| 
 | |
|       let current_path = window.location.hash.substring(1);
 | |
| 
 | |
|       function deleteFile(path) {
 | |
|         fetch(base_path + path, {
 | |
|           method: 'DELETE',
 | |
|         })
 | |
|         .then((response) => {
 | |
|           console.log(response);
 | |
|           if (!response.ok) {
 | |
|             throw new Error("Removing file failed");
 | |
|           }
 | |
|         })
 | |
|         .then(() => {
 | |
|           listFiles();
 | |
|         });
 | |
|       }
 | |
| 
 | |
|       function deleteFileButton(path) {
 | |
|         if (confirm("Are you sure you wanna delete " + path + "?")) {
 | |
|           deleteFile(path);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       function createDirectory(path) {
 | |
|         fetch(base_path + path, {
 | |
|           method: 'MKCOL',
 | |
|         })
 | |
|         .then((response) => {
 | |
|           console.log(response);
 | |
|           if (!response.ok) {
 | |
|             throw new Error("Creating directory failed");
 | |
|           }
 | |
|         })
 | |
|         .then(() => {
 | |
|           listFiles();
 | |
|         });
 | |
|       }
 | |
| 
 | |
|       function createDirectoryButton() {
 | |
|         let dir_name = prompt("Directory name");
 | |
|         if (dir_name !== null) {
 | |
|           createDirectory(current_path + dir_name + "/");
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       function uploadFile(path, file) {
 | |
| 
 | |
|         fetch(base_path + path, {
 | |
|           method: 'PUT',
 | |
|           body: file,
 | |
|         })
 | |
|         .then((response) => {
 | |
|           console.log(response);
 | |
|           if (!response.ok) {
 | |
|             throw new Error("Upload failed");
 | |
|           }
 | |
|         })
 | |
|         .then(() => {
 | |
|           listFiles();
 | |
|         });
 | |
|       }
 | |
| 
 | |
|       function uploadFilesButton() {
 | |
|         let files = document.getElementById("files").files;
 | |
|         for (let i = 0; i < files.length; i++) {
 | |
|           uploadFile(current_path + files[i].name, files[i]);
 | |
|         }
 | |
|         document.getElementById("files").value = "";
 | |
|       }
 | |
| 
 | |
|       function moveFile(old_path, new_path) {
 | |
|         fetch(base_path + old_path, {
 | |
|           method: 'MOVE',
 | |
|           headers: {
 | |
|             'Destination': base_path + new_path,
 | |
|           },
 | |
|         })
 | |
|         .then((response) => {
 | |
|           console.log(response);
 | |
|           if (!response.ok) {   
 | |
|             throw new Error("Rename file failed");
 | |
|           }
 | |
|         })
 | |
|         .then(() => {
 | |
|           listFiles();
 | |
|         });
 | |
|       }
 | |
| 
 | |
|       function moveFileButton(path) {
 | |
|         let new_path = prompt("New file path", path);
 | |
|         moveFile(path, new_path);
 | |
|       }
 | |
| 
 | |
|       function renameFileButton(path) {
 | |
|         let new_name = prompt("New file name");
 | |
|         moveFile(path, current_path + new_name);
 | |
|       }
 | |
| 
 | |
|       function copyFile(path, new_path) {
 | |
|         fetch(base_path + path, {
 | |
|           method: 'COPY',
 | |
|           headers: {
 | |
|             'Destination': base_path + new_path,
 | |
|           },
 | |
|         })
 | |
|         .then((response) => {
 | |
|           console.log(response);
 | |
|           if (!response.ok) {
 | |
|             throw new Error("Copy file failed");
 | |
|           }
 | |
|         })
 | |
|         .then(() => {
 | |
|           listFiles();
 | |
|         });
 | |
|       }
 | |
| 
 | |
|       function duplicateFileButton(path) {
 | |
|         let new_path = prompt("New file path", path);
 | |
|         copyFile(path, new_path);
 | |
|       }
 | |
| 
 | |
|       function listFiles() {
 | |
|         listing_field.innerHTML = '<div class="loading"></div>';
 | |
| 
 | |
|         path_field.innerHTML = '<a href="#/">⌂</a>';
 | |
| 
 | |
|         let path_blocks = current_path.split('/').slice(1);
 | |
|         for (let i = 0; i < path_blocks.length; i++) {
 | |
|           path_field.innerHTML += ' / <a href="#/' + path_blocks.slice(0, i+1).join('/') + '/">' + path_blocks[i] + '</a>';
 | |
|         }
 | |
| 
 | |
|         fetch(base_path + current_path)
 | |
|         .then((response) => {
 | |
|           console.log(response);
 | |
|           if (!response.ok) {
 | |
|             throw new Error("Can't fetch directory");
 | |
|           }
 | |
|           return response.json();
 | |
|         })
 | |
|         .then((listing) => {
 | |
|           console.log(listing);
 | |
|           let out = '<div class="listing">';
 | |
|           for (let i = 0; i < listing.length; i++) {
 | |
|             let listing_path = current_path + encodeURIComponent(listing[i]["name"]);
 | |
|             let listing_link = "#";
 | |
|             let listing_icon = "";
 | |
|             if (listing[i]["type"] === "directory") {
 | |
|               listing_path += '/';
 | |
|               listing_link = '#' + listing_path;
 | |
|               listing_icon = "📁";
 | |
|             }
 | |
|             else {
 | |
|               listing_link = base_path + listing_path;
 | |
|             }
 | |
|             out += '<div class="listing-item">'
 | |
|                       + '<div class="detail">'
 | |
|                         + '<a href="' + listing_link + '">' + listing_icon + " " + listing[i]["name"] + '</a>'
 | |
|                       + '</div>'
 | |
|                       + '<div class="options">'
 | |
|                         + '<button onclick="renameFileButton(\'' + listing_path + '\');" alt="rename">✎</button>'
 | |
|                         + '<button onclick="duplicateFileButton(\'' + listing_path + '\');">●●</button>'
 | |
|                         + '<button onclick="moveFileButton(\'' + listing_path + '\');">⇨</button>'
 | |
|                         + '<button onclick="deleteFileButton(\'' + listing_path + '\');">❌</button>'
 | |
|                       + '</div>'
 | |
|                     + '</div>';
 | |
|           }
 | |
|           out += '</div>';
 | |
|           listing_field.innerHTML = out;
 | |
|         });
 | |
|       }
 | |
| 
 | |
|       listFiles();
 | |
| 
 | |
|       window.onhashchange = () => {
 | |
|         current_path = window.location.hash.substring(1);
 | |
|         listFiles();
 | |
|       }
 | |
|     </script>
 | |
|   </body>
 | |
| </html>
 |