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.

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