listdir_components.mako 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354
  1. ## Licensed to Cloudera, Inc. under one
  2. ## or more contributor license agreements. See the NOTICE file
  3. ## distributed with this work for additional information
  4. ## regarding copyright ownership. Cloudera, Inc. licenses this file
  5. ## to you under the Apache License, Version 2.0 (the
  6. ## "License"); you may not use this file except in compliance
  7. ## with the License. You may obtain a copy of the License at
  8. ##
  9. ## http://www.apache.org/licenses/LICENSE-2.0
  10. ##
  11. ## Unless required by applicable law or agreed to in writing, software
  12. ## distributed under the License is distributed on an "AS IS" BASIS,
  13. ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. ## See the License for the specific language governing permissions and
  15. ## limitations under the License.
  16. <%!
  17. import datetime
  18. import md5
  19. from django.template.defaultfilters import urlencode, stringformat, filesizeformat, date, time, escape
  20. from desktop.lib.django_util import reverse_with_get, extract_field_data
  21. from django.utils.encoding import smart_str
  22. from django.utils.translation import ugettext as _
  23. %>
  24. <%namespace name="edit" file="editor_components.mako" />
  25. <%def name="list_table_chooser(files, path, current_request_path)">
  26. ${_table(files, path, current_request_path, 'chooser')}
  27. </%def>
  28. <%def name="list_table_browser(files, path, current_request_path, cwd_set=True)">
  29. ${_table(files, path, current_request_path, 'view')}
  30. </%def>
  31. <%def name="_table(files, path, current_request_path, view)">
  32. <script src="/static/ext/js/jquery/plugins/jquery.cookie.js"></script>
  33. <script src="/static/ext/js/knockout-2.1.0.js" type="text/javascript" charset="utf-8"></script>
  34. <script src="/static/ext/js/moment.min.js" type="text/javascript" charset="utf-8"></script>
  35. <script src="/static/ext/js/datatables-paging-0.1.js" type="text/javascript" charset="utf-8"></script>
  36. <style type="text/css">
  37. .fixed {
  38. position: fixed;
  39. top: 40px;
  40. filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);
  41. -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
  42. -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
  43. box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
  44. }
  45. .pull-right {
  46. margin: 4px;
  47. }
  48. .sortable {
  49. cursor: pointer;
  50. }
  51. .file-row {
  52. height: 37px;
  53. }
  54. .fileChooserModal {
  55. padding: 14px;
  56. }
  57. .fileChooserModal .hueBreadcrumb {
  58. margin: 0 0 18px !important;
  59. }
  60. .fieldError {
  61. border-color: #B94A48 !important;
  62. }
  63. .pagination {
  64. position: fixed;
  65. left: 0;
  66. bottom: 0;
  67. width: 100%;
  68. background-color: #f5f5f5;
  69. margin: 0;
  70. border-top: 1px solid #e3e3e3;
  71. -webkit-box-shadow: 0px -1px 3px rgba(50, 50, 50, 0.1);
  72. -moz-box-shadow: 0px -1px 3px rgba(50, 50, 50, 0.1);
  73. box-shadow: 0px -1px 3px rgba(50, 50, 50, 0.1);
  74. padding-bottom: 16px;
  75. }
  76. .pagination p {
  77. padding-top: 10px;
  78. padding-left: 10px;
  79. }
  80. .pagination ul {
  81. margin-bottom: 10px;
  82. margin-right: 20px;
  83. }
  84. .btn-group {
  85. font-size: 14px;
  86. vertical-align: baseline;
  87. }
  88. #delete-dropdown {
  89. margin-left: -11px;
  90. }
  91. .actionbar {
  92. padding-top: 6px;
  93. background-color: #FFFFFF;
  94. }
  95. .shadow {
  96. -webkit-box-shadow: 0px 2px 3px rgba(50, 50, 50, 0.1);
  97. -moz-box-shadow: 0px 2px 3px rgba(50, 50, 50, 0.1);
  98. box-shadow: 0px 1px 2px rgba(50, 50, 50, 0.1);
  99. }
  100. .scrollable {
  101. margin-bottom: 80px;
  102. }
  103. </style>
  104. <table class="table table-striped table-condensed datatables tablescroller-disable">
  105. <thead>
  106. <tr>
  107. <th width="1%"><div data-bind="click: selectAll, css: {hueCheckbox: true, 'icon-ok': allSelected}"></div></th>
  108. <th class="sortable sorting" data-sort="type" width="4%" data-bind="click: sort">Type</th>
  109. <th class="sortable sorting" data-sort="name" data-bind="click: sort">${_('Name')}</th>
  110. <th class="sortable sorting" data-sort="size" width="10%" data-bind="click: sort">${_('Size')}</th>
  111. <th class="sortable sorting" data-sort="user" width="10%" data-bind="click: sort">${_('User')}</th>
  112. <th class="sortable sorting" data-sort="group" width="10%" data-bind="click: sort">${_('Group')}</th>
  113. <th width="10%">${_('Permissions')}</th>
  114. <th class="sortable sorting" data-sort="mtime" width="15%" data-bind="click: sort">${_('Date')}</th>
  115. </tr>
  116. </thead>
  117. <tbody id="files" data-bind="template: {name: 'fileTemplate', foreach: files}">
  118. </tbody>
  119. <tfoot>
  120. <tr data-bind="visible: isLoading()">
  121. <td colspan="8" class="left">
  122. <img src="/static/art/spinner.gif" />
  123. </td>
  124. </tr>
  125. <tr data-bind="visible: files().length == 0 && !isLoading()">
  126. <td colspan="8">
  127. <div class="alert">
  128. There are no files matching the search criteria.
  129. </div>
  130. </td>
  131. </tr>
  132. </tfoot>
  133. </table>
  134. <script id="fileTemplate" type="text/html">
  135. <tr style="cursor: pointer" data-bind="event: { mouseover: toggleHover, mouseout: toggleHover}">
  136. <td class="center" data-bind="click: handleSelect" style="cursor: default">
  137. <div data-bind="visible: name != '.' && name != '..', css: {hueCheckbox: name != '.' && name != '..', 'icon-ok': selected}"></div>
  138. </td>
  139. <td data-bind="click: $root.viewFile" class="left"><i data-bind="css: {'icon-file-alt': type == 'file', 'icon-folder-close': type != 'file', 'icon-folder-open': type != 'file' && hovered}"></i></td>
  140. <td data-bind="click: $root.viewFile, attr: {'title': tooltip}" rel="tooltip">
  141. <strong><a href="#" data-bind="click: $root.viewFile, text: name"></a></strong>
  142. </td>
  143. <td data-bind="click: $root.viewFile">
  144. <span data-bind="visible: type=='file', text: stats.size"></span>
  145. </td>
  146. <td data-bind="click: $root.viewFile, text: stats.user"></td>
  147. <td data-bind="click: $root.viewFile, text: stats.group"></td>
  148. <td data-bind="click: $root.viewFile, text: permissions"></td>
  149. <td data-bind="click: $root.viewFile, text: stats.mtime" style="white-space: nowrap;"></td>
  150. </tr>
  151. </script>
  152. <div class="pagination" data-bind="visible: !isLoading()">
  153. <ul class="pull-right">
  154. <!-- ko if: page().number > 1 -->
  155. <li class="prev"><a href="#" data-bind="click: firstPage" title="${_('Beginning of List')}">&larr; ${_('Beginning of List')}</a></li>
  156. <li><a href="#" data-bind="click: previousPage" title="${_('Previous Page')}">${_('Previous Page')}</a></li>
  157. <!-- /ko -->
  158. <!-- ko if: page().number < page().num_pages -->
  159. <li><a href="#" data-bind="click: nextPage" title="${_('Next page')}">${_('Next Page')}</a></li>
  160. <li class="next"><a href="#" data-bind="click: lastPage" title="${_('End of List')}">${_('End of List')} &rarr;</a></li>
  161. <!-- /ko -->
  162. </ul>
  163. <p>${_('Show')}
  164. <select class="input-mini" data-bind="options: recordsPerPageChoices, value: recordsPerPage"></select>
  165. ${_('items per page')}.
  166. ${_('Showing')} <span data-bind="text: page().start_index"></span> ${_('to')} <span data-bind="text: page().end_index"></span> ${_('of')} <span data-bind="text: page().total_count"></span> ${_('items, page')}
  167. <span data-bind="text: page().number"></span> ${_('of')} <span data-bind="text: page().num_pages"></span>.</p>
  168. </div>
  169. <!-- delete modal -->
  170. <div id="deleteModal" class="modal hide fade">
  171. <div class="modal-header">
  172. <a href="#" class="close" data-dismiss="modal">&times;</a>
  173. <h3>${_('Confirm Delete')}</h3>
  174. </div>
  175. <div class="modal-body">
  176. <p>${_('Are you sure you want to delete these files?')}</p>
  177. </div>
  178. <div class="modal-footer">
  179. <form id="deleteForm" action="/filebrowser/rmtree" method="POST" enctype="multipart/form-data" class="form-stacked">
  180. <a class="btn" data-dismiss="modal">${_('No')}</a>
  181. <input type="submit" value="${_('Yes')}" class="btn btn-danger" />
  182. </form>
  183. </div>
  184. </div>
  185. <!-- restore modal -->
  186. <div id="restoreTrashModal" class="modal hide fade">
  187. <div class="modal-header">
  188. <a href="#" class="close" data-dismiss="modal">&times;</a>
  189. <h3>${_('Confirm Restore')}</h3>
  190. </div>
  191. <div class="modal-body">
  192. <p>${_('Are you sure you want to restore these files?')}</p>
  193. </div>
  194. <div class="modal-footer">
  195. <form id="restoreTrashForm" action="/filebrowser/trash/restore" method="POST" enctype="multipart/form-data" class="form-stacked">
  196. <a class="btn" data-dismiss="modal">${_('No')}</a>
  197. <input type="submit" value="${_('Yes')}" class="btn btn-primary" />
  198. </form>
  199. </div>
  200. </div>
  201. <!-- purge modal -->
  202. <div id="purgeTrashModal" class="modal hide fade">
  203. <div class="modal-header">
  204. <a href="#" class="close" data-dismiss="modal">&times;</a>
  205. <h3>${_('Confirm Empty Trash')}</h3>
  206. </div>
  207. <div class="modal-body">
  208. <p>${_('Are you sure you want to permanently delete all your trash?')}</p>
  209. </div>
  210. <div class="modal-footer">
  211. <form id="purgeTrashForm" action="/filebrowser/trash/purge" method="POST" enctype="multipart/form-data" class="form-stacked">
  212. <a class="btn" data-dismiss="modal">${_('Cancel')}</a>
  213. <input type="submit" value="${_('Delete')}" class="btn btn-primary" />
  214. </form>
  215. </div>
  216. </div>
  217. <!-- rename modal -->
  218. <div id="renameModal" class="modal hide fade">
  219. <form id="renameForm" action="/filebrowser/rename?next=${current_request_path}" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix">
  220. <div class="modal-header">
  221. <a href="#" class="close" data-dismiss="modal">&times;</a>
  222. <h3>${_('Renaming:')} <span id="renameFileName">file name</span></h3>
  223. </div>
  224. <div class="modal-body">
  225. <label>${_('New name')} <input id="newNameInput" name="dest_path" value="" type="text" class="input-xlarge"/></label>
  226. </div>
  227. <div class="modal-footer">
  228. <div id="renameNameRequiredAlert" class="hide" style="position: absolute; left: 10;">
  229. <span class="label label-important">${_('Name is required.')}</span>
  230. </div>
  231. <div id="renameNameExistsAlert" class="hide" style="position: absolute; left: 10;">
  232. <span class="label label-important"><span class="newName"></span> ${_('already exists.')}</span>
  233. </div>
  234. <input id="renameSrcPath" type="hidden" name="src_path" type="text">
  235. <a class="btn" data-dismiss="modal">${_('Cancel')}</a>
  236. <input type="submit" value="${_('Submit')}" class="btn btn-primary" />
  237. </div>
  238. </form>
  239. </div>
  240. <!-- chown modal -->
  241. % if is_superuser:
  242. <div id="changeOwnerModal" class="modal hide fade">
  243. <%
  244. select_filter = is_superuser and 'SelectWithOther' or ''
  245. %>
  246. <form id="chownForm" action="/filebrowser/chown" method="POST" enctype="multipart/form-data" class="form-stacked form-padding-fix">
  247. <div class="modal-header">
  248. <a href="#" class="close" data-dismiss="modal">&times;</a>
  249. <h3>${_('Change Owner / Group')}</h3>
  250. </div>
  251. <div class="modal-body change-owner-modal-body clearfix" >
  252. <div class="alert alert-message block-message info">${_('Note: Only the Hadoop superuser, "%(superuser)s" on this file system, may change the owner of a file.') % dict(superuser=superuser)}</div>
  253. <div style="padding-left: 15px; padding-bottom: 10px;">
  254. <label>${_('User')}</label>
  255. ${ edit.selection("user", users, user.username, "user_other") }
  256. <label>${_('Group')}</label>
  257. ${ edit.selection("group", groups, 'supergroup', "group_other") }
  258. <br />
  259. <label style="display: inline;">${_('Recursive')}</label><input type="checkbox" name="recursive">
  260. </div>
  261. </div>
  262. <div class="modal-footer" style="padding-top: 10px;">
  263. <div id="chownRequired" class="hide" style="position: absolute; left: 10;">
  264. <span class="label label-important">${_('Name is required.')}</span>
  265. </div>
  266. <a class="btn" onclick="$('#changeOwnerModal').modal('hide');">${_('Cancel')}</a>
  267. <input class="btn btn-primary" type="submit" value="${_('Submit')}" />
  268. </div>
  269. </form>
  270. </div>
  271. % endif
  272. <!-- chmod modal -->
  273. <div id="changePermissionModal" class="modal hide fade">
  274. <form action="/filebrowser/chmod" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix" id="chmodForm">
  275. <div class="modal-header">
  276. <a href="#" class="close" data-dismiss="modal">&times;</a>
  277. <h3>${_('Change Permissions:')} </h3>
  278. </div>
  279. <div class="modal-body table-margin">
  280. <table class="table table-striped">
  281. <thead>
  282. <tr>
  283. <th>&nbsp;</th>
  284. <th class="center">${_('User')}</th>
  285. <th class="center">${_('Group')}</th>
  286. <th class="center">${_('Other')}</th>
  287. <th class="center">&nbsp;</th>
  288. <th width="120">&nbsp</th>
  289. </tr>
  290. </thead>
  291. <tbody>
  292. <tr>
  293. <td><strong>${_('Read')}</strong></td>
  294. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="user_read"></td>
  295. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="group_read"></td>
  296. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="other_read"></td>
  297. <td colspan="2">&nbsp;</td>
  298. </tr>
  299. <tr>
  300. <td><strong>${_('Write')}</strong></td>
  301. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="user_write"></td>
  302. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="group_write"></td>
  303. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="other_write"></td>
  304. <td colspan="2">&nbsp;</td>
  305. </tr>
  306. <tr>
  307. <td><strong>${_('Execute')}</strong></td>
  308. <td class="center"><input type="checkbox" checked="" name="user_execute"></td>
  309. <td class="center"><input type="checkbox" checked="" name="group_execute"></td>
  310. <td class="center"><input type="checkbox" checked="" name="other_execute"></td>
  311. <td colspan="2">&nbsp;</td>
  312. </tr>
  313. <tr>
  314. <td><strong>${_('Sticky')}</strong></td>
  315. <td colspan="3">&nbsp;</td>
  316. <td class="center"><input type="checkbox" name="sticky"></td>
  317. <td>&nbsp;</td>
  318. </tr>
  319. <tr>
  320. <td><strong>${_('Recursive')}</strong></td>
  321. <td colspan="3">&nbsp;</td>
  322. <td class="center"><input type="checkbox" name="recursive"></td>
  323. <td>&nbsp;</td>
  324. </tbody>
  325. </table>
  326. </div>
  327. <div class="modal-footer" style="padding-top: 10px;">
  328. <a class="btn" onclick="$('#changePermissionModal').modal('hide');">${_('Cancel')}</a>
  329. <input class="btn btn-primary" type="submit" value="${_('Submit')}"/>
  330. </div>
  331. </form>
  332. </div>
  333. <!-- move modal -->
  334. <div id="moveModal" class="modal hide fade">
  335. <form id="moveForm" action="/filebrowser/move" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix">
  336. <div class="modal-header">
  337. <a href="#" class="close" data-dismiss="modal">&times;</a>
  338. <h3>${_('Move:')}</h3>
  339. </div>
  340. <div class="modal-body">
  341. <div style="padding-left: 15px;">
  342. <label for="moveDestination">${_('Destination')}</label>
  343. <input type="text" class="input-xlarge pathChooser" value="" name="dest_path" id="moveDestination" /><a class="btn fileChooserBtn" href="#" data-filechooser-destination="dest_path">..</a>
  344. </div>
  345. <br/>
  346. <div class="fileChooserModal" class="hide">
  347. </div>
  348. </div>
  349. <div class="modal-footer">
  350. <div id="moveNameRequiredAlert" class="hide" style="position: absolute; left: 10;">
  351. <span class="label label-important">${_('Name is required.')}</span>
  352. </div>
  353. <a class="btn" onclick="$('#moveModal').modal('hide');">${_('Cancel')}</a>
  354. <input class="btn btn-primary" type="submit" value="${_('Submit')}"/>
  355. </div>
  356. </form>
  357. </div>
  358. <!-- copy modal -->
  359. <div id="copyModal" class="modal hide fade">
  360. <form id="copyForm" action="/filebrowser/copy" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix">
  361. <div class="modal-header">
  362. <a href="#" class="close" data-dismiss="modal">&times;</a>
  363. <h3>${_('Copy:')}</h3>
  364. </div>
  365. <div class="modal-body">
  366. <div style="padding-left: 15px;">
  367. <label for="copyDestination">${_('Destination')}</label>
  368. <input type="text" class="input-xlarge pathChooser" value="" name="dest_path" id="copyDestination" /><a class="btn fileChooserBtn" href="#" data-filechooser-destination="dest_path">..</a>
  369. </div>
  370. <br/>
  371. <div class="fileChooserModal" class="hide">
  372. </div>
  373. </div>
  374. <div class="modal-footer">
  375. <div id="copyNameRequiredAlert" class="hide" style="position: absolute; left: 10;">
  376. <span class="label label-important">${_('Name is required.')}</span>
  377. </div>
  378. <a class="btn" onclick="$('#copyModal').modal('hide');">${_('Cancel')}</a>
  379. <input class="btn btn-primary" type="submit" value="${_('Submit')}"/>
  380. </div>
  381. </form>
  382. </div>
  383. <!-- upload file modal -->
  384. <div id="uploadFileModal" class="modal hide fade">
  385. <div class="modal-header">
  386. <a href="#" class="close" data-dismiss="modal">&times;</a>
  387. <h3>${_('Uploading to:')} <span id="uploadDirName" data-bind="text: currentPath"></span></h3>
  388. </div>
  389. <div class="modal-body form-inline">
  390. <div id="fileUploader" class="uploader">
  391. <noscript>
  392. <p>${_('Enable JavaScript to use the file uploader.')}</p>
  393. </noscript>
  394. </div>
  395. </div>
  396. <div class="modal-footer"></div>
  397. </div>
  398. <!-- upload archive modal -->
  399. <div id="uploadArchiveModal" class="modal hide fade">
  400. <div class="modal-header">
  401. <a href="#" class="close" data-dismiss="modal">&times;</a>
  402. <h3>${_('Uploading to:')} <span id="uploadDirName" data-bind="text: currentPath"></span></h3>
  403. <p>${_('The file will then be extracted in the path specified above.')}</p>
  404. </div>
  405. <div class="modal-body form-inline">
  406. <div id="archiveUploader" class="uploader">
  407. <noscript>
  408. <p>${_('Enable JavaScript to use the file uploader.')}</p>
  409. </noscript>
  410. </div>
  411. </div>
  412. <div class="modal-footer"></div>
  413. </div>
  414. <!-- new directory modal -->
  415. <div id="createDirectoryModal" class="modal hide fade">
  416. <form id="createDirectoryForm" data-bind="submit: createDirectory" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix">
  417. <div class="modal-header">
  418. <a href="#" class="close" data-dismiss="modal">&times;</a>
  419. <h3>${_('Create Directory')}</h3>
  420. </div>
  421. <div class="modal-body">
  422. <label>${_('Directory Name')} <input id="newDirectoryNameInput" name="name" value="" type="text" class="input-xlarge"/></label>
  423. <input type="hidden" name="path" type="text" data-bind="value: currentPath"/>
  424. </div>
  425. <div class="modal-footer">
  426. <div id="directoryNameRequiredAlert" class="hide" style="position: absolute; left: 10;">
  427. <span class="label label-important">${_('Directory name is required.')}</span>
  428. </div>
  429. <div id="directoryNameExistsAlert" class="hide" style="position: absolute; left: 10;">
  430. <span class="label label-important"><span class="newName"></span> ${_('already exists.')}</span>
  431. </div>
  432. <a class="btn" href="#" data-dismiss="modal">${_('Cancel')}</a>
  433. <input class="btn btn-primary" type="submit" value="${_('Submit')}" />
  434. </div>
  435. </form>
  436. </div>
  437. <!-- new directory modal -->
  438. <div id="createFileModal" class="modal hide fade">
  439. <form id="createFileForm" data-bind="submit: createFile" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix">
  440. <div class="modal-header">
  441. <a href="#" class="close" data-dismiss="modal">&times;</a>
  442. <h3>${_('Create File')}</h3>
  443. </div>
  444. <div class="modal-body">
  445. <label>${_('File Name')} <input id="newFileNameInput" name="name" value="" type="text" class="input-xlarge"/></label>
  446. <input type="hidden" name="path" type="text" data-bind="value: currentPath"/>
  447. </div>
  448. <div class="modal-footer">
  449. <div id="fileNameRequiredAlert" class="alert-message error hide" style="position: absolute; left: 10;">
  450. <span class="label label-important">${_('File name is required.')}</span>
  451. </div>
  452. <div id="fileNameExistsAlert" class="hide" style="position: absolute; left: 10;">
  453. <span class="label label-important"><span class="newName"></span> ${_('already exists.')}</span>
  454. </div>
  455. <a class="btn" href="#" data-dismiss="modal">${_('Cancel')}</a>
  456. <input class="btn btn-primary" type="submit" value="${_('Submit')}" />
  457. </div>
  458. </form>
  459. </div>
  460. <script type="text/javascript" charset="utf-8">
  461. // ajax modal windows
  462. function openChownWindow(path, user, group, next) {
  463. $.ajax({
  464. url:"/filebrowser/chown",
  465. data:{"path":path, "user":user, "group":group, "next":next},
  466. beforeSend:function (xhr) {
  467. xhr.setRequestHeader("X-Requested-With", "Hue");
  468. },
  469. dataType:"html",
  470. success:function (data) {
  471. $("#changeOwnerModal").html(data);
  472. $("#changeOwnerModal").modal({
  473. keyboard:true,
  474. show:true
  475. });
  476. }
  477. });
  478. }
  479. // Modal file chooser
  480. // The file chooser should be at least 2 levels deeper than the modal container
  481. $(".fileChooserBtn").on('click', function (e) {
  482. e.preventDefault();
  483. var _destination = $(this).attr("data-filechooser-destination");
  484. var fileChooser = $(this).parent().parent().find(".fileChooserModal");
  485. fileChooser.jHueFileChooser({
  486. initialPath:$("input[name='" + _destination + "']").val(),
  487. onFolderChange:function (folderPath) {
  488. $("input[name='" + _destination + "']").val(folderPath);
  489. },
  490. onFolderChoose:function (folderPath) {
  491. $("input[name='" + _destination + "']").val(folderPath);
  492. fileChooser.slideUp();
  493. },
  494. selectFolder:true,
  495. createFolder:true,
  496. uploadFile:false
  497. });
  498. fileChooser.slideDown();
  499. });
  500. $(document).ready(function () {
  501. $("#chownForm select[name='user']").change(function () {
  502. if ($(this).val() == "__other__") {
  503. $("input[name='user_other']").show();
  504. }
  505. else {
  506. $("input[name='user_other']").hide();
  507. }
  508. });
  509. $("#chownForm select[name='group']").change(function () {
  510. if ($(this).val() == "__other__") {
  511. $("input[name='group_other']").show();
  512. }
  513. else {
  514. $("input[name='group_other']").hide();
  515. }
  516. });
  517. $("#chownForm").submit(function () {
  518. if ($("#chownForm select[name='user']").val() == null) {
  519. $("#chownRequired").find(".label").text("${_('User is required.')}");
  520. $("#chownRequired").show();
  521. resetPrimaryButtonsStatus(); //globally available
  522. return false;
  523. }
  524. else if ($("#chownForm select[name='group']").val() == null) {
  525. $("#chownRequired").find(".label").text("${_('Group is required.')}");
  526. $("#chownRequired").show();
  527. resetPrimaryButtonsStatus(); //globally available
  528. return false;
  529. }
  530. else {
  531. if ($("#chownForm select[name='group']").val() == "__other__" && $("input[name='group_other']").val() == "") {
  532. $("#chownRequired").find(".label").text("${_('Specify another group.')}");
  533. $("#chownForm input[name='group_other']").addClass("fieldError");
  534. $("#chownRequired").show();
  535. resetPrimaryButtonsStatus(); //globally available
  536. return false;
  537. }
  538. if ($("#chownForm select[name='user']").val() == "__other__" && $("input[name='user_other']").val() == "") {
  539. $("#chownRequired").find(".label").text("${_('Specify another user.')}");
  540. $("#chownForm input[name='user_other']").addClass("fieldError");
  541. $("#chownRequired").show();
  542. return false;
  543. resetPrimaryButtonsStatus(); //globally available
  544. }
  545. return true;
  546. }
  547. });
  548. $("#renameForm").submit(function () {
  549. if ($("#newNameInput").val() == "") {
  550. $("#renameNameRequiredAlert").show();
  551. $("#newNameInput").addClass("fieldError");
  552. resetPrimaryButtonsStatus(); //globally available
  553. return false;
  554. }
  555. if (fileExists($("#newNameInput").val())) {
  556. $("#renameNameExistsAlert").find(".newName").text($("#newNameInput").val());
  557. $("#renameNameExistsAlert").show();
  558. $("#newNameInput").addClass("fieldError");
  559. resetPrimaryButtonsStatus(); //globally available
  560. return false;
  561. }
  562. return true;
  563. });
  564. $("#newNameInput").focus(function () {
  565. $("#renameNameRequiredAlert").hide();
  566. $("#renameNameExistsAlert").hide();
  567. $("#newNameInput").removeClass("fieldError");
  568. });
  569. $("#moveForm").live("submit", function () {
  570. if ($.trim($("#moveForm").find("input.pathChooser").val()) == "") {
  571. $("#moveNameRequiredAlert").show();
  572. $("#moveForm").find("input[name='*dest_path']").addClass("fieldError");
  573. resetPrimaryButtonsStatus(); //globally available
  574. return false;
  575. }
  576. return true;
  577. });
  578. $("#moveForm").find("input[name='dest_path']").live("focus", function () {
  579. $("#moveNameRequiredAlert").hide();
  580. $("#moveForm").find("input[name='dest_path']").removeClass("fieldError");
  581. });
  582. $("#copyForm").on("submit", function () {
  583. if ($.trim($("#copyForm").find("input.pathChooser").val()) == "") {
  584. $("#copyNameRequiredAlert").show();
  585. $("#copyForm").find("input[name='*dest_path']").addClass("fieldError");
  586. resetPrimaryButtonsStatus(); //globally available
  587. return false;
  588. }
  589. return true;
  590. });
  591. $("#copyForm").find("input[name='dest_path']").on("focus", function () {
  592. $("#copyNameRequiredAlert").hide();
  593. $("#copyForm").find("input[name='dest_path']").removeClass("fieldError");
  594. });
  595. $(".create-directory-link").click(function () {
  596. $("#createDirectoryModal").modal({
  597. keyboard:true,
  598. show:true
  599. });
  600. });
  601. $(".create-file-link").click(function () {
  602. $("#createFileModal").modal({
  603. keyboard:true,
  604. show:true
  605. });
  606. });
  607. $("#createDirectoryForm").submit(function () {
  608. if ($.trim($("#newDirectoryNameInput").val()) == "") {
  609. $("#directoryNameRequiredAlert").show();
  610. $("#newDirectoryNameInput").addClass("fieldError");
  611. resetPrimaryButtonsStatus(); //globally available
  612. return false;
  613. }
  614. if (fileExists($("#newDirectoryNameInput").val())) {
  615. $("#directoryNameExistsAlert").find(".newName").text($("#newDirectoryNameInput").val());
  616. $("#directoryNameExistsAlert").show();
  617. $("#newDirectoryNameInput").addClass("fieldError");
  618. resetPrimaryButtonsStatus(); //globally available
  619. return false;
  620. }
  621. return true;
  622. });
  623. $("#newDirectoryNameInput").focus(function () {
  624. $("#newDirectoryNameInput").removeClass("fieldError");
  625. $("#directoryNameRequiredAlert").hide();
  626. $("#directoryNameExistsAlert").hide();
  627. });
  628. $("#createFileForm").submit(function () {
  629. if ($.trim($("#newFileNameInput").val()) == "") {
  630. $("#fileNameRequiredAlert").show();
  631. $("#newFileNameInput").addClass("fieldError");
  632. resetPrimaryButtonsStatus(); //globally available
  633. return false;
  634. }
  635. if (fileExists($("#newFileNameInput").val())) {
  636. $("#fileNameExistsAlert").find(".newName").text($("#newFileNameInput").val());
  637. $("#fileNameExistsAlert").show();
  638. $("#newFileNameInput").addClass("fieldError");
  639. resetPrimaryButtonsStatus(); //globally available
  640. return false;
  641. }
  642. return true;
  643. });
  644. $("#newFileNameInput").focus(function () {
  645. $("#newFileNameInput").removeClass("fieldError");
  646. $("#fileNameRequiredAlert").hide();
  647. $("#fileNameExistsAlert").hide();
  648. });
  649. $(".pathChooser").click(function () {
  650. var self = this;
  651. $("#fileChooserRename").jHueFileChooser({
  652. initialPath:$(self).val(),
  653. onFileChoose:function (filePath) {
  654. $(self).val(filePath);
  655. },
  656. onFolderChange:function (folderPath) {
  657. $(self).val(folderPath);
  658. },
  659. createFolder:false,
  660. uploadFile:false
  661. });
  662. $("#fileChooserRename").slideDown();
  663. });
  664. function fileExists(newName) {
  665. if (viewModel) {
  666. var files = viewModel.files();
  667. for (var i = 0; i < files.length; i++) {
  668. if (files[i].name == newName) {
  669. return true;
  670. }
  671. }
  672. }
  673. return false;
  674. }
  675. $("*[rel='tooltip']").tooltip({ placement:"bottom" });
  676. if (window.location.hash != null && window.location.hash.length > 1) {
  677. viewModel.targetPath("${url('filebrowser.views.view', path=urlencode('/'))}" + stripHashes(window.location.hash.substring(2)));
  678. }
  679. viewModel.retrieveData();
  680. var filterTimeout = -1;
  681. $(".search-query").keyup(function () {
  682. window.clearTimeout(filterTimeout);
  683. filterTimeout = window.setTimeout(function () {
  684. viewModel.searchQuery($(".search-query").val());
  685. viewModel.filter();
  686. }, 500);
  687. });
  688. $("#editBreadcrumb").click(function () {
  689. $(this).hide();
  690. $(".hueBreadcrumb").hide();
  691. $("#hueBreadcrumbText").show().focus();
  692. });
  693. $("#hueBreadcrumbText").keyup(function (e) {
  694. if (e.keyCode == 13) {
  695. var _el = $(this);
  696. viewModel.targetPath("${url('filebrowser.views.view', path=urlencode('/'))}" + stripHashes(_el.val().substring(1)));
  697. viewModel.getStats(function (data) {
  698. if (data.type != null && data.type == "file") {
  699. location.href = data.url;
  700. return false;
  701. }
  702. else {
  703. window.location.hash = stripHashes(_el.val());
  704. }
  705. });
  706. }
  707. });
  708. $("#hueBreadcrumbText").blur(function () {
  709. $(this).hide();
  710. $(".hueBreadcrumb").show();
  711. $("#editBreadcrumb").show();
  712. });
  713. $.ajaxSetup({
  714. error:function (x, e) {
  715. if (x.status == 500) {
  716. $.jHueNotify.error("${_('There was a problem with your request.')}");
  717. $("#hueBreadcrumbText").blur();
  718. }
  719. }
  720. });
  721. $(window).bind("hashchange", function () {
  722. var target = "";
  723. var hash = window.location.hash.substring(1);
  724. if (hash != null && hash != "") {
  725. target = "${url('filebrowser.views.view', path=urlencode('/'))}" + stripHashes(hash.substring(1));
  726. }
  727. if (window.location.href.indexOf("#") == -1) {
  728. target = "${current_request_path}";
  729. }
  730. if (target != "") {
  731. viewModel.targetPath(target);
  732. viewModel.retrieveData();
  733. }
  734. });
  735. $(".actionbar").data("originalWidth", $(".actionbar").width());
  736. $(".actionbarGhost").height($(".actionbar").outerHeight() + 20);
  737. resetActionbar();
  738. $(window).scroll(function () {
  739. if ($(window).scrollTop() > 95) {
  740. $(".actionbar").width($(".actionbar").data("originalWidth"));
  741. $(".actionbar").css("position", "fixed").css("top", "40px");
  742. $(".actionbarGhost").removeClass("hide");
  743. }
  744. else {
  745. resetActionbar();
  746. }
  747. });
  748. });
  749. function resetActionbar() {
  750. $(".actionbar").attr("style", "");
  751. $(".actionbar").data("originalWidth", $(".actionbar").width());
  752. $(".actionbarGhost").addClass("hide");
  753. }
  754. function stripHashes(str) {
  755. return str.replace(/#/gi, encodeURIComponent("#"));
  756. }
  757. var Page = function (page) {
  758. if (page != null) {
  759. return {
  760. number:page.number,
  761. num_pages:page.num_pages,
  762. previous_page_number:page.previous_page_number,
  763. next_page_number:page.next_page_number,
  764. start_index:page.start_index,
  765. end_index:page.end_index,
  766. total_count:page.total_count
  767. }
  768. }
  769. return {
  770. }
  771. }
  772. var File = function (file) {
  773. file.tooltip = "";
  774. if (file.name == "."){
  775. file.tooltip = "${_('This folder')}";
  776. }
  777. if (file.name == ".."){
  778. file.tooltip = "${_('One level up')}";
  779. }
  780. return {
  781. name:file.name,
  782. path:file.path,
  783. url:file.url,
  784. type:file.type,
  785. permissions:file.rwx,
  786. mode:file.mode,
  787. stats:{
  788. size:file.humansize,
  789. user:file.stats.user,
  790. group:file.stats.group,
  791. mtime:moment.unix(file.stats.mtime).format("MMMM DD, YYYY hh:mm a")
  792. },
  793. selected:ko.observable(false),
  794. handleSelect:function (row, e) {
  795. this.selected(!this.selected());
  796. },
  797. hovered:ko.observable(false),
  798. toggleHover:function (row, e) {
  799. this.hovered(!this.hovered());
  800. },
  801. tooltip:file.tooltip
  802. }
  803. }
  804. var Breadcrumb = function (breadcrumb) {
  805. return {
  806. url:breadcrumb.url,
  807. label:breadcrumb.label,
  808. show:function () {
  809. if (this.url == null || this.url == "") {
  810. // forcing root on empty breadcrumb url
  811. this.url = "/";
  812. }
  813. viewModel.targetPath("${url('filebrowser.views.view', path=urlencode('/'))}" + stripHashes(this.url));
  814. window.location.hash = this.url;
  815. }
  816. }
  817. }
  818. var FileBrowserModel = function (files, page, breadcrumbs, currentDirPath) {
  819. var self = this;
  820. if (!$.cookie("hueFilebrowserRecordsPerPage")){
  821. $.cookie("hueFilebrowserRecordsPerPage", "45");
  822. }
  823. self.page = ko.observable(new Page(page));
  824. self.recordsPerPageChoices = ["15", "30", "45", "60", "100", "200"],
  825. self.recordsPerPage = ko.observable($.cookie("hueFilebrowserRecordsPerPage"));
  826. self.targetPageNum = ko.observable(1);
  827. self.targetPath = ko.observable("${current_request_path}");
  828. self.trashEnabled = ko.observable(${ trash_enabled and "true" or "false" });
  829. self.sortBy = ko.observable("name");
  830. self.sortDescending = ko.observable(false);
  831. self.searchQuery = ko.observable("");
  832. self.files = ko.observableArray(ko.utils.arrayMap(files, function (file) {
  833. return new File(file);
  834. }));
  835. self.breadcrumbs = ko.observableArray(ko.utils.arrayMap(breadcrumbs, function (breadcrumb) {
  836. return new Breadcrumb(breadcrumb);
  837. }));
  838. self.sort = function (viewModel, event) {
  839. var el = $(event.currentTarget);
  840. el.siblings(".sortable").attr("class", "sortable sorting");
  841. self.sortBy(el.data("sort"))
  842. el.removeClass("sorting");
  843. if (el.hasClass("sorting_asc")) {
  844. self.sortDescending(true);
  845. }
  846. else {
  847. self.sortDescending(false);
  848. }
  849. el.attr("class", "sortable");
  850. if (self.sortDescending() == true) {
  851. el.addClass("sorting_desc");
  852. }
  853. else {
  854. el.addClass("sorting_asc");
  855. }
  856. self.retrieveData();
  857. }
  858. self.isLoading = ko.observable(true);
  859. self.allSelected = ko.observable(false);
  860. self.selectedFiles = ko.computed(function () {
  861. return ko.utils.arrayFilter(self.files(), function (file) {
  862. return file.selected();
  863. });
  864. }, self);
  865. self.selectedFile = ko.computed(function () {
  866. return self.selectedFiles()[0];
  867. }, self);
  868. self.currentPath = ko.observable(currentDirPath);
  869. self.inTrash = ko.computed(function() {
  870. return self.currentPath().match(/^\/user\/.+?\/\.Trash/) && self.trashEnabled();
  871. });
  872. self.inRestorableTrash = ko.computed(function() {
  873. return self.currentPath().match(/^\/user\/.+?\/\.Trash\/.+?/) && self.trashEnabled();
  874. });
  875. self.getStats = function (callback) {
  876. $.getJSON(self.targetPath() + "?pagesize=1&format=json", callback);
  877. }
  878. self.retrieveData = function () {
  879. self.isLoading(true);
  880. $.getJSON(self.targetPath() + "?pagesize=" + self.recordsPerPage() + "&pagenum=" + self.targetPageNum() + "&filter=" + self.searchQuery() + "&sortby=" + self.sortBy() + "&descending=" + self.sortDescending() + "&format=json", function (data) {
  881. if (data.error){
  882. $.jHueNotify.error(data.error);
  883. self.isLoading(false);
  884. return false;
  885. }
  886. if (data.type != null && data.type == "file") {
  887. location.href = data.url;
  888. return false;
  889. }
  890. self.updateFileList(data.files, data.page, data.breadcrumbs, data.current_dir_path);
  891. if ($("#hueBreadcrumbText").is(":visible")) {
  892. $(".hueBreadcrumb").show();
  893. $("#hueBreadcrumbText").hide();
  894. $("#editBreadcrumb").show();
  895. }
  896. });
  897. };
  898. self.updateFileList = function (files, page, breadcrumbs, currentDirPath) {
  899. $(".tooltip").hide();
  900. self.page(new Page(page));
  901. self.files(ko.utils.arrayMap(files, function (file) {
  902. return new File(file);
  903. }));
  904. self.breadcrumbs(ko.utils.arrayMap(breadcrumbs, function (breadcrumb) {
  905. return new Breadcrumb(breadcrumb);
  906. }));
  907. self.currentPath(currentDirPath);
  908. $('.uploader').trigger('fb:updatePath', {dest:self.currentPath()});
  909. self.isLoading(false);
  910. $("*[rel='tooltip']").tooltip({ placement:"left" });
  911. $(window).scrollTop(0);
  912. resetActionbar();;
  913. };
  914. self.recordsPerPage.subscribe(function (newValue) {
  915. $.cookie("hueFilebrowserRecordsPerPage", newValue);
  916. self.retrieveData();
  917. });
  918. self.goToPage = function (pageNumber) {
  919. self.targetPageNum(pageNumber);
  920. self.retrieveData();
  921. };
  922. self.firstPage = function () {
  923. self.goToPage(1)
  924. };
  925. self.previousPage = function () {
  926. self.goToPage(self.page().previous_page_number)
  927. };
  928. self.nextPage = function () {
  929. self.goToPage(self.page().next_page_number)
  930. };
  931. self.lastPage = function () {
  932. self.goToPage(self.page().num_pages)
  933. };
  934. self.selectAll = function () {
  935. self.allSelected(!self.allSelected());
  936. ko.utils.arrayForEach(self.files(), function (file) {
  937. if (file.name != "." && file.name != "..") {
  938. file.selected(self.allSelected());
  939. }
  940. });
  941. return true;
  942. };
  943. self.searchQuery.subscribe(function (newValue) {
  944. self.filter();
  945. });
  946. self.filter = function () {
  947. self.targetPageNum(1);
  948. self.retrieveData();
  949. };
  950. self.viewFile = function (file) {
  951. if (file.type == "dir") {
  952. // Reset page number so that we don't hit a page that doesn't exist
  953. self.targetPageNum(1);
  954. self.targetPath("${url('filebrowser.views.view', path=urlencode('/'))}" + "." + stripHashes(file.path));
  955. window.location.hash = stripHashes(file.path);
  956. }
  957. else {
  958. location.href = "${url('filebrowser.views.view', path=urlencode('/'))}" + stripHashes(file.path);
  959. }
  960. };
  961. self.editFile = function () {
  962. location.href = "${url('filebrowser.views.edit', path=urlencode('/'))}" + self.selectedFile().path;
  963. };
  964. self.downloadFile = function () {
  965. location.href = "${url('filebrowser.views.download', path=urlencode('/'))}" + self.selectedFile().path;
  966. };
  967. self.renameFile = function () {
  968. $("#renameSrcPath").attr("value", self.selectedFile().path);
  969. $("#renameFileName").text(self.selectedFile().path);
  970. $("#newNameInput").val(self.selectedFile().name);
  971. $("#renameForm").attr("action", "/filebrowser/rename?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
  972. $("#renameModal").modal({
  973. keyboard:true,
  974. show:true
  975. });
  976. };
  977. self.move = function () {
  978. var paths = [];
  979. $(self.selectedFiles()).each(function (index, file) {
  980. paths.push(file.path);
  981. });
  982. hiddenFields($("#moveForm"), "src_path", paths);
  983. $("#moveForm").attr("action", "/filebrowser/move?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
  984. $("#moveModal").modal({
  985. keyboard:true,
  986. show:true
  987. });
  988. };
  989. self.copy = function () {
  990. var paths = [];
  991. $(self.selectedFiles()).each(function (index, file) {
  992. paths.push(file.path);
  993. });
  994. hiddenFields($("#copyForm"), "src_path", paths);
  995. $("#copyForm").attr("action", "/filebrowser/copy?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
  996. $("#copyModal").modal({
  997. keyboard:true,
  998. show:true
  999. });
  1000. };
  1001. self.changeOwner = function () {
  1002. var paths = [];
  1003. $(self.selectedFiles()).each(function (index, file) {
  1004. paths.push(file.path);
  1005. });
  1006. hiddenFields($("#chownForm"), 'path', paths);
  1007. $("#chownForm").attr("action", "/filebrowser/chown?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
  1008. $("select[name=user]").val(self.selectedFile().stats.user);
  1009. if ($("select[name=group] option:contains('" + self.selectedFile().stats.group + "')").length > 0) {
  1010. $("select[name=group]").val(self.selectedFile().stats.group);
  1011. } else{
  1012. $("select[name=group]").val("__other__");
  1013. $("input[name=group_other]").val(self.selectedFile().stats.group);
  1014. }
  1015. $("select[name=group]").change();
  1016. $("#changeOwnerModal").modal({
  1017. keyboard:true,
  1018. show:true
  1019. });
  1020. };
  1021. self.changePermissions = function () {
  1022. var paths = [];
  1023. var allFileType = true;
  1024. $(self.selectedFiles()).each(function (index, file) {
  1025. if ("dir" == file.type){
  1026. allFileType = false;
  1027. }
  1028. paths.push(file.path);
  1029. });
  1030. hiddenFields($("#chmodForm"), 'path', paths);
  1031. $("#chmodForm").attr("action", "/filebrowser/chmod?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
  1032. $("#changePermissionModal").modal({
  1033. keyboard:true,
  1034. show:true
  1035. });
  1036. // Initial values for form
  1037. var permissions = ["sticky", "user_read", "user_write", "user_execute", "group_read", "group_write", "group_execute", "other_read", "other_write", "other_execute"].reverse();
  1038. var mode = octal(self.selectedFile().mode) & 01777;
  1039. for (var i = 0; i < permissions.length; i++) {
  1040. if (mode & 1) {
  1041. $("#chmodForm input[name=" + permissions[i] + "]").attr("checked", true);
  1042. } else {
  1043. $("#chmodForm input[name=" + permissions[i] + "]").attr("checked", false);
  1044. }
  1045. mode >>>= 1;
  1046. }
  1047. if (allFileType){
  1048. $("#chmodForm input[name='user_execute']").attr("disabled", "disabled");
  1049. $("#chmodForm input[name='group_execute']").attr("disabled", "disabled");
  1050. $("#chmodForm input[name='other_execute']").attr("disabled", "disabled");
  1051. }
  1052. else {
  1053. $("#chmodForm input[name='user_execute']").removeAttr("disabled");
  1054. $("#chmodForm input[name='group_execute']").removeAttr("disabled");
  1055. $("#chmodForm input[name='other_execute']").removeAttr("disabled");
  1056. }
  1057. };
  1058. var deleteSelected = function(skip_trash) {
  1059. var paths = [];
  1060. $(self.selectedFiles()).each(function (index, file) {
  1061. paths.push(file.path);
  1062. });
  1063. hiddenFields($("#deleteForm"), 'path', paths);
  1064. $("#deleteForm").attr("action", "/filebrowser/rmtree" + "?" +
  1065. (skip_trash ? "skip_trash=true&" : "") +
  1066. "next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
  1067. $("#deleteModal").modal({
  1068. keyboard:true,
  1069. show:true
  1070. });
  1071. }
  1072. self.deleteSelected = function () {
  1073. deleteSelected(true);
  1074. };
  1075. self.trashSelected = function () {
  1076. deleteSelected();
  1077. };
  1078. self.createDirectory = function (formElement) {
  1079. $(formElement).attr("action", "/filebrowser/mkdir?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
  1080. return true;
  1081. };
  1082. self.createFile = function (formElement) {
  1083. $(formElement).attr("action", "/filebrowser/touch?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
  1084. return true;
  1085. };
  1086. self.restoreTrashSelected = function(formElement) {
  1087. var paths = [];
  1088. $(self.selectedFiles()).each(function (index, file) {
  1089. paths.push(file.path);
  1090. });
  1091. hiddenFields($("#restoreTrashForm"), 'path', paths);
  1092. $("#restoreTrashForm").attr("action", "/filebrowser/trash/restore?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
  1093. $("#restoreTrashModal").modal({
  1094. keyboard:true,
  1095. show:true
  1096. });
  1097. };
  1098. self.purgeTrash = function(formElement) {
  1099. var paths = [];
  1100. $(self.selectedFiles()).each(function (index, file) {
  1101. paths.push(file.path);
  1102. });
  1103. hiddenFields($("#purgeTrashForm"), 'path', paths);
  1104. $("#purgeTrashForm").attr("action", "/filebrowser/trash/purge?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
  1105. $("#purgeTrashModal").modal({
  1106. keyboard:true,
  1107. show:true
  1108. });
  1109. };
  1110. self.uploadFile = (function () {
  1111. var num_of_pending_uploads = 0;
  1112. var action = "/filebrowser/upload/file";
  1113. var uploader = new qq.FileUploader({
  1114. element:document.getElementById("fileUploader"),
  1115. action:action,
  1116. template:'<div class="qq-uploader">' +
  1117. '<div class="qq-upload-drop-area"><span>${_('Drop files here to upload')}</span></div>' +
  1118. '<div class="qq-upload-button">${_('Select files')}</div>' +
  1119. '<ul class="qq-upload-list"></ul>' +
  1120. '</div>',
  1121. fileTemplate:'<li>' +
  1122. '<span class="qq-upload-file"></span>' +
  1123. '<span class="qq-upload-spinner"></span>' +
  1124. '<span class="qq-upload-size"></span>' +
  1125. '<a class="qq-upload-cancel" href="#">${_('Cancel')}</a>' +
  1126. '<span class="qq-upload-failed-text">${_('Failed')}</span>' +
  1127. '</li>',
  1128. params:{
  1129. dest:self.currentPath(),
  1130. fileFieldLabel:"hdfs_file"
  1131. },
  1132. onComplete:function (id, fileName, response) {
  1133. num_of_pending_uploads--;
  1134. if (response.status != 0) {
  1135. $.jHueNotify.error("${ _('Error: ') }" + (response['data'] ? response['data'] : "${ _('Check file permissions') }"));
  1136. } else if (num_of_pending_uploads == 0) {
  1137. window.location = "/filebrowser/view" + self.currentPath();
  1138. }
  1139. },
  1140. onSubmit:function (id, fileName, responseJSON) {
  1141. num_of_pending_uploads++;
  1142. },
  1143. debug:false
  1144. });
  1145. $("#fileUploader").on('fb:updatePath', function (e, options) {
  1146. uploader.setParams({
  1147. dest:options.dest,
  1148. fileFieldLabel:"hdfs_file"
  1149. });
  1150. });
  1151. return function () {
  1152. $("#uploadFileModal").modal({
  1153. keyboard:true,
  1154. show:true
  1155. });
  1156. };
  1157. })();
  1158. self.uploadArchive = (function () {
  1159. var num_of_pending_uploads = 0;
  1160. var uploader = new qq.FileUploader({
  1161. element:document.getElementById("archiveUploader"),
  1162. action:"/filebrowser/upload/archive",
  1163. template:'<div class="qq-uploader">' +
  1164. '<div class="qq-upload-drop-area"><span>${_('Drop files here to upload')}</span></div>' +
  1165. '<div class="qq-upload-button">${_('Upload a zip file')}</div>' +
  1166. '<ul class="qq-upload-list"></ul>' +
  1167. '</div>',
  1168. fileTemplate:'<li>' +
  1169. '<span class="qq-upload-file"></span>' +
  1170. '<span class="qq-upload-spinner"></span>' +
  1171. '<span class="qq-upload-size"></span>' +
  1172. '<a class="qq-upload-cancel" href="#">${_('Cancel')}</a>' +
  1173. '<span class="qq-upload-failed-text">${_('Failed')}</span>' +
  1174. '</li>',
  1175. params:{
  1176. dest:self.currentPath(),
  1177. fileFieldLabel:"archive"
  1178. },
  1179. onComplete:function (id, fileName, responseJSON) {
  1180. num_of_pending_uploads--;
  1181. if (num_of_pending_uploads == 0) {
  1182. window.location = "/filebrowser/view" + self.currentPath();
  1183. }
  1184. },
  1185. onSubmit:function (id, fileName, responseJSON) {
  1186. num_of_pending_uploads++;
  1187. },
  1188. debug:false
  1189. });
  1190. $("#archiveUploader").on('fb:updatePath', function (e, options) {
  1191. uploader.setParams({
  1192. dest:options.dest,
  1193. fileFieldLabel:"archive"
  1194. });
  1195. });
  1196. return function () {
  1197. $("#uploadArchiveModal").modal({
  1198. keyboard:true,
  1199. show:true
  1200. });
  1201. };
  1202. })();
  1203. // Place all values into hidden fields under parent element.
  1204. // Looks for managed hidden fields and handles sizing appropriately.
  1205. var hiddenFields = function (parentEl, name, values) {
  1206. parentEl = $(parentEl);
  1207. parentEl.find("input.hidden-field").remove();
  1208. $(values).each(function (index, value) {
  1209. var field = $("<input type='hidden' />");
  1210. field.attr("name", name);
  1211. field.attr("class", "hidden-field")
  1212. field.val(value);
  1213. parentEl.append(field);
  1214. });
  1215. }
  1216. var octal = function (strInt) {
  1217. return parseInt("0" + strInt, 8);
  1218. }
  1219. };
  1220. var viewModel = new FileBrowserModel([], null, [], "/");
  1221. ko.applyBindings(viewModel);
  1222. </script>
  1223. </%def>