file-tree.pug 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. aside.file-tree(ng-controller="FileTreeController", ng-class="{ 'multi-selected': multiSelectedCount > 0 }", ng-show="ui.view != 'history' || !history.isV2").full-size
  2. .toolbar.toolbar-filetree(ng-if="permissions.write")
  3. a(
  4. href,
  5. ng-click="openNewDocModal()",
  6. tooltip-html="'"+translate('new_file').replace(' ', '<br>')+"'",
  7. tooltip-placement="bottom"
  8. )
  9. i.fa.fa-fw.fa-file
  10. a(
  11. href,
  12. ng-click="openNewFolderModal()",
  13. tooltip-html="'"+translate('new_folder').replace(' ', '<br>')+"'",
  14. tooltip-placement="bottom"
  15. )
  16. i.fa.fa-fw.fa-folder
  17. a(
  18. href,
  19. ng-click="openUploadFileModal()",
  20. tooltip=translate('upload'),
  21. tooltip-placement="bottom"
  22. )
  23. i.fa.fa-fw.fa-upload
  24. .toolbar-right
  25. a(
  26. href,
  27. ng-click="startRenamingSelected()",
  28. tooltip=translate('rename'),
  29. tooltip-placement="bottom",
  30. ng-show="multiSelectedCount == 0"
  31. )
  32. i.fa.fa-fw.fa-pencil
  33. a(
  34. href,
  35. ng-click="openDeleteModalForSelected()",
  36. tooltip=translate('delete'),
  37. tooltip-placement="bottom",
  38. tooltip-append-to-body="true"
  39. )
  40. i.fa.fa-fw.fa-trash-o
  41. .file-tree-inner(
  42. ng-if="rootFolder",
  43. ng-controller="FileTreeRootFolderController",
  44. ng-class="{ 'no-toolbar': !permissions.write }"
  45. )
  46. ul.list-unstyled.file-tree-list(
  47. droppable="permissions.write"
  48. accept=".entity-name"
  49. on-drop-callback="onDrop"
  50. )
  51. li(
  52. ng-show="ui.pdfLayout == 'flat' && (ui.view == 'editor' || ui.view == 'pdf' || ui.view == 'file')"
  53. ng-class="{ 'selected': ui.view == 'pdf' }"
  54. ng-controller="PdfViewToggleController"
  55. )
  56. .entity
  57. .entity-name(
  58. ng-click="togglePdfView()"
  59. )
  60. i.fa.fa-fw.toggle
  61. i.fa.fa-fw.fa-file-pdf-o
  62. | PDF
  63. file-entity(
  64. entity="entity",
  65. permissions="permissions",
  66. ng-repeat="entity in rootFolder.children | orderBy:[orderByFoldersFirst, 'name']"
  67. )
  68. li(ng-show="deletedDocs.length > 0 && ui.view == 'history'")
  69. h3 #{translate("deleted_files")}
  70. li(
  71. ng-class="{ 'selected': entity.selected }",
  72. ng-repeat="entity in deletedDocs | orderBy:'name'",
  73. ng-controller="FileTreeEntityController",
  74. ng-show="ui.view == 'history'"
  75. )
  76. .entity
  77. .entity-name(
  78. ng-click="select($event)"
  79. )
  80. //- Just a spacer to align with folders
  81. i.fa.fa-fw.toggle
  82. i.fa.fa-fw.fa-file
  83. span {{ entity.name }}
  84. script(type='text/ng-template', id='entityListItemTemplate')
  85. li(
  86. ng-class="{ 'selected': entity.selected, 'multi-selected': entity.multiSelected }",
  87. ng-controller="FileTreeEntityController"
  88. )
  89. .entity(ng-if="entity.type != 'folder'")
  90. .entity-name(
  91. ng-click="select($event)"
  92. ng-dblclick="permissions.write && startRenaming()"
  93. draggable="permissions.write"
  94. draggable-helper="draggableHelper"
  95. context-menu
  96. data-target="context-menu-{{ entity.id }}"
  97. context-menu-container="body"
  98. context-menu-disabled="!permissions.write"
  99. )
  100. //- Just a spacer to align with folders
  101. i.fa.fa-fw.toggle(ng-if="entity.type != 'folder'")
  102. i.fa.fa-fw(ng-if="entity.type != 'folder'", ng-class="'fa-' + iconTypeFromName(entity.name)")
  103. i.fa.fa-external-link-square.fa-rotate-180.linked-file-highlight(
  104. ng-if="entity.linkedFileData.provider"
  105. )
  106. span(
  107. ng-hide="entity.renaming"
  108. ) {{ entity.renamingToName || entity.name }}
  109. span.rename-input
  110. input(
  111. ng-if="permissions.write",
  112. ng-show="entity.renaming",
  113. ng-model="inputs.name",
  114. ng-blur="finishRenaming()",
  115. select-name-when="entity.renaming",
  116. on-enter="finishRenaming()"
  117. valid-file
  118. )
  119. span.dropdown.entity-menu-toggle(
  120. dropdown,
  121. ng-if="permissions.write"
  122. )
  123. a.dropdown-toggle(href, dropdown-toggle, stop-propagation="click")
  124. i.fa.fa-chevron-down
  125. ul.dropdown-menu.dropdown-menu-right
  126. li
  127. a(
  128. href
  129. ng-click="startRenaming()"
  130. right-click="startRenaming()"
  131. ng-show="!entity.multiSelected"
  132. ) #{translate("rename")}
  133. li
  134. a(
  135. href
  136. ng-click="openDeleteModal()"
  137. right-click="openDeleteModal()"
  138. stop-propagation="click"
  139. ) #{translate("delete")}
  140. div.dropdown.context-menu(
  141. id="context-menu-{{ entity.id }}",
  142. ng-if="permissions.write"
  143. )
  144. ul.dropdown-menu
  145. li
  146. a(
  147. href
  148. ng-click="startRenaming()"
  149. right-click="startRenaming()"
  150. ng-show="!entity.multiSelected"
  151. ) #{translate("rename")}
  152. li
  153. a(
  154. href
  155. ng-click="openDeleteModal()"
  156. right-click="openDeleteModal()"
  157. stop-propagation="click"
  158. ) #{translate("delete")}
  159. .entity(ng-if="entity.type == 'folder'", ng-controller="FileTreeFolderController")
  160. .entity-name(
  161. ng-click="select($event)"
  162. ng-dblclick="permissions.write && startRenaming()"
  163. draggable="permissions.write"
  164. draggable-helper="draggableHelper"
  165. droppable="permissions.write"
  166. accept=".entity-name"
  167. on-drop-callback="onDrop"
  168. )
  169. div(
  170. context-menu
  171. data-target="context-menu-{{ entity.id }}"
  172. context-menu-container="body"
  173. context-menu-disabled="!permissions.write"
  174. )
  175. i.fa.fa-fw.toggle(
  176. ng-if="entity.type == 'folder'"
  177. ng-class="{'fa-chevron-right': !expanded, 'fa-chevron-down': expanded}"
  178. ng-click="toggleExpanded()"
  179. )
  180. i.fa.fa-fw(
  181. ng-if="entity.type == 'folder'"
  182. ng-class="{\
  183. 'fa-folder': !expanded, \
  184. 'fa-folder-open': expanded \
  185. }"
  186. ng-click="select($event)"
  187. )
  188. span(
  189. ng-hide="entity.renaming"
  190. ) {{ entity.renamingToName || entity.name }}
  191. span.rename-input
  192. input(
  193. ng-if="permissions.write",
  194. ng-show="entity.renaming",
  195. ng-model="inputs.name",
  196. ng-blur="finishRenaming()",
  197. select-name-when="entity.renaming",
  198. on-enter="finishRenaming()"
  199. valid-file
  200. )
  201. span.dropdown.entity-menu-toggle(
  202. dropdown,
  203. ng-if="permissions.write"
  204. )
  205. a.dropdown-toggle(href, dropdown-toggle, stop-propagation="click")
  206. i.fa.fa-chevron-down
  207. ul.dropdown-menu.dropdown-menu-right
  208. li
  209. a(
  210. href
  211. ng-click="startRenaming()"
  212. right-click="startRenaming()"
  213. ng-show="!entity.multiSelected"
  214. ) #{translate("rename")}
  215. li
  216. a(
  217. href
  218. ng-click="openDeleteModal()"
  219. right-click="openDeleteModal()"
  220. stop-propagation="click"
  221. ) #{translate("delete")}
  222. li.divider
  223. li
  224. a(
  225. href
  226. ng-click="openNewDocModal()"
  227. right-click="openNewDocModal()"
  228. ) #{translate("new_file")}
  229. li
  230. a(
  231. href
  232. ng-click="openNewFolderModal()"
  233. right-click="openNewFolderModal()"
  234. ) #{translate("new_folder")}
  235. li
  236. a(
  237. href
  238. ng-click="openUploadFileModal()"
  239. right-click="openUploadFileModal()"
  240. ) #{translate("upload_file")}
  241. .dropdown.context-menu(
  242. ng-if="permissions.write"
  243. id="context-menu-{{ entity.id }}"
  244. )
  245. ul.dropdown-menu
  246. li
  247. a(
  248. href
  249. ng-click="startRenaming()"
  250. right-click="startRenaming()"
  251. ng-show="!entity.multiSelected"
  252. ) #{translate("rename")}
  253. li
  254. a(
  255. href
  256. ng-click="openDeleteModal()"
  257. right-click="openDeleteModal()"
  258. stop-propagation="click"
  259. ) #{translate("delete")}
  260. li.divider
  261. li
  262. a(
  263. href
  264. ng-click="openNewDocModal()"
  265. right-click="openNewDocModal()"
  266. ) #{translate("new_file")}
  267. li
  268. a(
  269. href
  270. ng-click="openNewFolderModal()"
  271. right-click="openNewFolderModal()"
  272. ) #{translate("new_folder")}
  273. li
  274. a(
  275. href
  276. ng-click="openUploadFileModal()"
  277. right-click="openUploadFileModal()"
  278. ) #{translate("upload_file")}
  279. ul.list-unstyled(
  280. ng-if="entity.type == 'folder'"
  281. ng-show="expanded"
  282. droppable="permissions.write"
  283. accept=".entity-name"
  284. on-drop-callback="onDrop"
  285. )
  286. file-entity(
  287. entity="child",
  288. permissions="permissions",
  289. ng-repeat="child in entity.children | orderBy:[orderByFoldersFirst, 'name']"
  290. )
  291. script(type='text/ng-template', id='newDocModalTemplate')
  292. .modal-header
  293. h3 #{translate("new_file")}
  294. .modal-body
  295. form(novalidate, name="newDocForm")
  296. div.alert.alert-danger(ng-if="error")
  297. div(ng-switch="error")
  298. span(ng-switch-when="already exists") #{translate("file_already_exists")}
  299. span(ng-switch-default) {{error}}
  300. input.form-control(
  301. type="text",
  302. placeholder="File Name",
  303. required,
  304. ng-model="inputs.name",
  305. on-enter="create()",
  306. select-name-on="open",
  307. valid-file,
  308. name="name"
  309. )
  310. .text-danger.row-spaced-small(ng-show="newDocForm.name.$error.validFile")
  311. | #{translate('files_cannot_include_invalid_characters')}
  312. .modal-footer
  313. button.btn.btn-default(
  314. ng-disabled="state.inflight"
  315. ng-click="cancel()"
  316. ) #{translate("cancel")}
  317. button.btn.btn-primary(
  318. ng-disabled="newDocForm.$invalid || state.inflight"
  319. ng-click="create()"
  320. )
  321. span(ng-hide="state.inflight") #{translate("create")}
  322. span(ng-show="state.inflight") #{translate("creating")}...
  323. // Project Linked Files Modal
  324. script(type='text/ng-template', id='projectLinkedFileModalTemplate')
  325. .modal-header
  326. h3 New file from Project
  327. .modal-body
  328. div
  329. div.alert.alert-danger(ng-if="state.error") Error, something went wrong!
  330. div
  331. form
  332. .form-controls
  333. label(for="project-select") Select a Project
  334. span(ng-show="state.inFlight.projects")
  335. | &nbsp;
  336. i.fa.fa-spinner.fa-spin
  337. select.form-control(
  338. name="project-select"
  339. ng-model="data.selectedProjectId"
  340. ng-disabled="!shouldEnableProjectSelect()"
  341. )
  342. option(value="" disabled selected) - Please Select a Project
  343. option(
  344. ng-repeat="project in data.projects"
  345. value="{{ project._id }}"
  346. ) {{ project.name }}
  347. br
  348. .form-controls
  349. label(for="project-entity-select") Select a File
  350. span(ng-show="state.inFlight.entities")
  351. | &nbsp;
  352. i.fa.fa-spinner.fa-spin
  353. select.form-control(
  354. name="project-entity-select"
  355. ng-model="data.selectedProjectEntity"
  356. ng-disabled="!shouldEnableProjectEntitySelect()"
  357. )
  358. option(value="" disabled selected) - Please Select a File
  359. option(
  360. ng-repeat="projectEntity in data.projectEntities"
  361. value="{{ projectEntity.path }}"
  362. ) {{ projectEntity.path.slice(1) }}
  363. br
  364. .form-controls
  365. label(for="name") File Name In This Project
  366. input.form-control(
  367. type="text"
  368. placeholder="example.tex"
  369. required
  370. ng-model="data.name"
  371. name="name"
  372. )
  373. br
  374. .modal-footer
  375. span(ng-show="state.inFlight.create")
  376. i.fa.fa-spinner.fa-spin
  377. | &nbsp;
  378. button.btn.btn-default(
  379. ng-disabled="state.inflight"
  380. ng-click="cancel()"
  381. ) #{translate("cancel")}
  382. button.btn.btn-primary(
  383. ng-disabled="!shouldEnableCreateButton()"
  384. ng-click="create()"
  385. )
  386. span(ng-hide="state.inflight") #{translate("create")}
  387. span(ng-show="state.inflight") #{translate("creating")}...
  388. script(type='text/ng-template', id='linkedFileModalTemplate')
  389. .modal-header
  390. h3 New file from URL
  391. .modal-body
  392. form(novalidate, name="newLinkedFileForm")
  393. div.alert.alert-danger(ng-if="error")
  394. div(ng-switch="error")
  395. span(ng-switch-when="already exists") #{translate("file_already_exists")}
  396. span(ng-switch-default) {{error}}
  397. label(for="url") URL to fetch the file from
  398. input.form-control(
  399. type="text",
  400. placeholder="www.example.com/my_file",
  401. required,
  402. ng-model="inputs.url",
  403. focus-on="open",
  404. on-enter="create()",
  405. name="url"
  406. )
  407. .row-spaced
  408. label(for="name") File name in this project
  409. input.form-control(
  410. type="text",
  411. placeholder="my_file",
  412. required,
  413. ng-model="inputs.name",
  414. ng-change="nameChangedByUser = true"
  415. valid-file,
  416. on-enter="create()",
  417. name="name"
  418. )
  419. .text-danger.row-spaced-small(ng-show="newDocForm.name.$error.validFile")
  420. | #{translate('files_cannot_include_invalid_characters')}
  421. .modal-footer
  422. button.btn.btn-default(
  423. ng-disabled="state.inflight"
  424. ng-click="cancel()"
  425. ) #{translate("cancel")}
  426. button.btn.btn-primary(
  427. ng-disabled="newLinkedFileForm.$invalid || state.inflight"
  428. ng-click="create()"
  429. )
  430. span(ng-hide="state.inflight") #{translate("create")}
  431. span(ng-show="state.inflight") #{translate("creating")}...
  432. script(type='text/ng-template', id='newFolderModalTemplate')
  433. .modal-header
  434. h3 #{translate("new_folder")}
  435. .modal-body
  436. div.alert.alert-danger(ng-if="error")
  437. div(ng-switch="error")
  438. span(ng-switch-when="already exists") #{translate("file_already_exists")}
  439. span(ng-switch-default) {{error}}
  440. form(novalidate, name="newFolderForm")
  441. input.form-control(
  442. type="text",
  443. placeholder="Folder Name",
  444. required,
  445. ng-model="inputs.name",
  446. on-enter="create()",
  447. select-name-on="open",
  448. valid-file,
  449. name="name"
  450. )
  451. .text-danger.row-spaced-small(ng-show="newFolderForm.name.$error.validFile")
  452. | #{translate('files_cannot_include_invalid_characters')}
  453. .modal-footer
  454. button.btn.btn-default(
  455. ng-disabled="state.inflight"
  456. ng-click="cancel()"
  457. ) #{translate("cancel")}
  458. button.btn.btn-primary(
  459. ng-disabled="newFolderForm.$invalid || state.inflight"
  460. ng-click="create()"
  461. )
  462. span(ng-hide="state.inflight") #{translate("create")}
  463. span(ng-show="state.inflight") #{translate("creating")}...
  464. script(type="text/template", id="qq-file-uploader-template")
  465. div.qq-uploader-selector
  466. div(qq-hide-dropzone="").qq-upload-drop-area-selector.qq-upload-drop-area
  467. span.qq-upload-drop-area-text-selector #{translate('drop_files_here_to_upload')}
  468. div.qq-upload-button-selector.btn.btn-primary.btn-lg
  469. div #{translate('upload')}
  470. span.or.btn-lg #{translate('or')}
  471. span.drag-here.btn-lg #{translate('drag_here')}
  472. span.qq-drop-processing-selector
  473. span #{translate('processing')}
  474. span.qq-drop-processing-spinner-selector
  475. ul.qq-upload-list-selector
  476. li
  477. div.qq-progress-bar-container-selector
  478. div(
  479. role="progressbar"
  480. aria-valuenow="0"
  481. aria-valuemin="0"
  482. aria-valuemax="100"
  483. class="qq-progress-bar-selector qq-progress-bar"
  484. )
  485. span.qq-upload-file-selector.qq-upload-file
  486. span.qq-upload-size-selector.qq-upload-size
  487. a(type="button").qq-btn.qq-upload-cancel-selector.qq-upload-cancel #{translate('cancel')}
  488. button(type="button").qq-btn.qq-upload-retry-selector.qq-upload-retry #{translate('retry')}
  489. span(role="status").qq-upload-status-text-selector.qq-upload-status-text
  490. script(type="text/ng-template", id="uploadFileModalTemplate")
  491. .modal-header
  492. h3 #{translate("upload_files")}
  493. .alert.alert-warning.small.modal-alert(ng-if="tooManyFiles") #{translate("maximum_files_uploaded_together", {max:"{{max_files}}"})}
  494. .alert.alert-warning.small.modal-alert(ng-if="rateLimitHit") #{translate("too_many_files_uploaded_throttled_short_period")}
  495. .alert.alert-warning.small.modal-alert(ng-if="notLoggedIn") #{translate("session_expired_redirecting_to_login", {seconds:"{{secondsToRedirect}}"})}
  496. .alert.alert-warning.small.modal-alert(ng-if="conflicts.length > 0")
  497. p.text-center
  498. | The following files already exist in this project:
  499. ul.text-center.list-unstyled.row-spaced-small
  500. li(ng-repeat="conflict in conflicts"): strong {{ conflict }}
  501. p.text-center.row-spaced-small
  502. | Do you want to overwrite them?
  503. p.text-center
  504. a(href, ng-click="doUpload()").btn.btn-primary Overwrite
  505. | &nbsp;
  506. a(href, ng-click="cancel()").btn.btn-default Cancel
  507. .modal-body(
  508. fine-upload
  509. endpoint="/project/{{ project_id }}/upload"
  510. template-id="qq-file-uploader-template"
  511. multiple="true"
  512. auto-upload="false"
  513. on-complete-callback="onComplete"
  514. on-upload-callback="onUpload"
  515. on-validate-batch="onValidateBatch"
  516. on-error-callback="onError"
  517. on-submit-callback="onSubmit"
  518. on-cancel-callback="onCancel"
  519. control="control"
  520. params="{'folder_id': parent_folder_id}"
  521. )
  522. .modal-footer
  523. button.btn.btn-default(ng-click="cancel()") #{translate("cancel")}
  524. script(type='text/ng-template', id='deleteEntityModalTemplate')
  525. .modal-header
  526. h3 #{translate("delete")} {{ entity.name }}
  527. .modal-body
  528. p !{translate("sure_you_want_to_delete")}
  529. ul
  530. li(ng-repeat="entity in entities") {{entity.name}}
  531. .modal-footer
  532. button.btn.btn-default(
  533. ng-disabled="state.inflight"
  534. ng-click="cancel()"
  535. ) #{translate("cancel")}
  536. button.btn.btn-danger(
  537. ng-disabled="state.inflight"
  538. ng-click="delete()"
  539. )
  540. span(ng-hide="state.inflight") #{translate("delete")}
  541. span(ng-show="state.inflight") #{translate("deleting")}...
  542. script(type='text/ng-template', id='invalidFileNameModalTemplate')
  543. .modal-header
  544. h3 #{translate('invalid_file_name')}
  545. .modal-body
  546. p #{translate('files_cannot_include_invalid_characters')}
  547. .modal-footer
  548. button.btn.btn-default(
  549. ng-click="$close()"
  550. ) #{translate('ok')}