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.

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