You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

299 lines
8.6 KiB

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>SeaweedFS Filer</title>
  5. <meta name="viewport" content="width=device-width, initial-scale=1">
  6. <link rel="stylesheet" href="/seaweedfsstatic/bootstrap/3.3.1/css/bootstrap.min.css">
  7. <style>
  8. body {
  9. padding-bottom: 128px;
  10. }
  11. #drop-area {
  12. border: 1px transparent;
  13. }
  14. #drop-area.highlight {
  15. border-color: purple;
  16. border: 2px dashed #ccc;
  17. }
  18. .button {
  19. display: inline-block;
  20. padding: 2px;
  21. background: #ccc;
  22. cursor: pointer;
  23. border-radius: 2px;
  24. border: 1px solid #ccc;
  25. float: right;
  26. margin-left: 5px;
  27. }
  28. .button:hover {
  29. background: #ddd;
  30. }
  31. #fileElem {
  32. display: none;
  33. }
  34. .danger {
  35. color: red;
  36. background: #fff;
  37. border: 1px solid #fff;
  38. border-radius: 2px;
  39. }
  40. .footer {
  41. position: absolute;
  42. bottom: 10px;
  43. right: 10%;
  44. min-width: 30%;
  45. }
  46. .progress-table {
  47. width: 100%;
  48. }
  49. .progress-table-file-name {
  50. text-align: right;
  51. }
  52. .progress-table-percent {
  53. width: 60px;
  54. text-align: right;
  55. }
  56. </style>
  57. </head>
  58. <body>
  59. <div class="container">
  60. <div class="page-header">
  61. <h1>
  62. <a href="https://github.com/chrislusf/seaweedfs"><img src="/seaweedfsstatic/seaweed50x50.png"></img></a>
  63. SeaweedFS Filer
  64. </h1>
  65. </div>
  66. <div class="row">
  67. <div>
  68. {{ range $entry := .Breadcrumbs }}
  69. <a href="{{ printpath $entry.Link }}">
  70. {{ $entry.Name }}
  71. </a>
  72. {{ end }}
  73. <label class="button" for="fileElem">Upload</label>
  74. <label class="button" onclick="handleCreateDir()">New Folder</label>
  75. </div>
  76. </div>
  77. <div class="row" id="drop-area">
  78. <form class="upload-form">
  79. <input type="file" id="fileElem" multiple onchange="handleFiles(this.files)">
  80. <table width="86%">
  81. {{$path := .Path }}
  82. {{ range $entry_index, $entry := .Entries }}
  83. <tr>
  84. <td>
  85. {{if $entry.IsDirectory}}
  86. <img src="/seaweedfsstatic/images/folder.gif" width="20" height="23">
  87. <a href="{{ printpath $path "/" $entry.Name "/"}}" >
  88. {{ $entry.Name }}
  89. </a>
  90. {{else}}
  91. <a href="{{ printpath $path "/" $entry.Name }}" >
  92. {{ $entry.Name }}
  93. </a>
  94. {{end}}
  95. </td>
  96. <td align="right" nowrap>
  97. {{if $entry.IsDirectory}}
  98. {{else}}
  99. {{ $entry.Mime }}&nbsp;
  100. {{end}}
  101. </td>
  102. <td align="right" nowrap>
  103. {{if $entry.IsDirectory}}
  104. {{else}}
  105. {{ $entry.Size | humanizeBytes }}&nbsp;
  106. {{end}}
  107. </td>
  108. <td align="right" nowrap>
  109. {{ $entry.Timestamp.Format "2006-01-02 15:04" }}
  110. </td>
  111. <td>
  112. {{if $entry.IsDirectory}}
  113. <label class="button danger" onclick="handleDelete('{{ printpath $path "/" $entry.Name "/" }}')">Delete</label>
  114. {{else}}
  115. <label class="button danger" onclick="handleDelete('{{ printpath $path "/" $entry.Name }}')">Delete</label>
  116. {{end}}
  117. </td>
  118. </tr>
  119. {{ end }}
  120. </table>
  121. </form>
  122. </div>
  123. {{if .ShouldDisplayLoadMore}}
  124. <div class="row">
  125. <a href={{ print .Path "?limit=" .Limit "&lastFileName=" .LastFileName}} >
  126. Load more
  127. </a>
  128. </div>
  129. {{end}}
  130. <br/>
  131. <br/>
  132. <div id="progress-area" class="footer" style="display: none;">
  133. </div>
  134. </div>
  135. </body>
  136. <script type="text/javascript">
  137. // ************************ Drag and drop ***************** //
  138. let dropArea = document.getElementById("drop-area");
  139. let progressArea = document.getElementById("progress-area");
  140. // Prevent default drag behaviors
  141. ;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
  142. dropArea.addEventListener(eventName, preventDefaults, false);
  143. document.body.addEventListener(eventName, preventDefaults, false);
  144. });
  145. // Highlight drop area when item is dragged over it
  146. ;['dragenter', 'dragover'].forEach(eventName => {
  147. dropArea.addEventListener(eventName, highlight, false);
  148. });
  149. ;['dragleave', 'drop'].forEach(eventName => {
  150. dropArea.addEventListener(eventName, unhighlight, false);
  151. });
  152. // Handle dropped files
  153. dropArea.addEventListener('drop', handleDrop, false);
  154. function preventDefaults(e) {
  155. e.preventDefault();
  156. e.stopPropagation();
  157. }
  158. function highlight(e) {
  159. dropArea.classList.add('highlight');
  160. }
  161. function unhighlight(e) {
  162. dropArea.classList.remove('highlight');
  163. }
  164. function handleDrop(e) {
  165. var dt = e.dataTransfer;
  166. var files = dt.files;
  167. handleFiles(files);
  168. }
  169. var uploadList = {};
  170. function handleFiles(files) {
  171. files = [...files];
  172. files.forEach(startUpload);
  173. renderProgress();
  174. files.forEach(uploadFile);
  175. }
  176. function startUpload(file, i) {
  177. uploadList[file.name] = {'name': file.name, 'percent': 0, 'finish': false};
  178. }
  179. function renderProgress() {
  180. var values = Object.values(uploadList);
  181. var html = '<table class="progress-table">\n';
  182. for (let i of values) {
  183. html += '<tr>\n<td class="progress-table-file-name">' + i.name + '</td>\n';
  184. html += '<td class="progress-table-percent">' + i.percent + '% </td>\n</tr>\n';
  185. }
  186. html += '</table>\n';
  187. progressArea.innerHTML = html;
  188. if (values.length > 0) {
  189. progressArea.attributes.style.value = '';
  190. }
  191. console.log('Render Progress', values);
  192. }
  193. function reportProgress(file, percent) {
  194. var item = uploadList[file]
  195. item.percent = percent;
  196. renderProgress();
  197. }
  198. function finishUpload(file) {
  199. uploadList[file]['finish'] = true;
  200. renderProgress();
  201. var allFinish = true;
  202. for (let i of Object.values(uploadList)) {
  203. if (!i.finish) {
  204. allFinish = false;
  205. break;
  206. }
  207. }
  208. if (allFinish) {
  209. console.log('All Finish');
  210. window.location.reload();
  211. }
  212. }
  213. function uploadFile(file, i) {
  214. var url = window.location.href;
  215. var xhr = new XMLHttpRequest();
  216. var fileName = file.name;
  217. xhr.upload.addEventListener('progress', function(e) {
  218. if (e.lengthComputable) {
  219. var percent = Math.ceil((e.loaded / e.total) * 100);
  220. reportProgress(fileName, percent)
  221. }
  222. });
  223. xhr.upload.addEventListener('loadend', function(e) {
  224. finishUpload(fileName);
  225. });
  226. var formData = new FormData();
  227. xhr.open('POST', url, true);
  228. formData.append('file', file);
  229. xhr.send(formData);
  230. }
  231. function handleCreateDir() {
  232. var dirName = prompt('Directory Name:', '');
  233. dirName = dirName.trim();
  234. if (dirName == null && dirName == '') {
  235. return;
  236. }
  237. var baseUrl = window.location.href;
  238. if (!baseUrl.endsWith('/')) {
  239. baseUrl += '/';
  240. }
  241. var url = baseUrl + dirName;
  242. if (!url.endsWith('/')) {
  243. url += '/';
  244. }
  245. var xhr = new XMLHttpRequest();
  246. xhr.open('POST', url, false);
  247. xhr.setRequestHeader('Content-Type', '');
  248. xhr.send();
  249. window.location.reload();
  250. }
  251. function handleDelete(path) {
  252. if (!confirm('Are you sure to delete ' + path + '?')) {
  253. return;
  254. }
  255. var url = path;
  256. if (url.endsWith('/')) {
  257. url += '?recursive=true';
  258. }
  259. var xhr = new XMLHttpRequest();
  260. xhr.open('DELETE', url, false);
  261. xhr.send();
  262. window.location.reload();
  263. }
  264. </script>
  265. </html>