review-panel.pug 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. #review-panel(
  2. ng-class="{ 'rp-collapsed-displaying-entry': reviewPanel.entryHover, 'rp-offset-widgets': editor.showVisual }"
  3. )
  4. .rp-in-editor-widgets
  5. a.rp-track-changes-indicator(
  6. href
  7. ng-if="editor.wantTrackChanges"
  8. ng-click="toggleReviewPanel();"
  9. ng-class="{ 'rp-track-changes-indicator-on-dark' : darkTheme }"
  10. ) !{translate("track_changes_is_on")}
  11. a.rp-bulk-actions-btn(
  12. href
  13. ng-if="reviewPanel.nVisibleSelectedChanges > 1"
  14. ng-click="showBulkAcceptDialog();"
  15. )
  16. i.fa.fa-check
  17. |  #{translate("accept_all")}
  18. | ({{ reviewPanel.nVisibleSelectedChanges }})
  19. a.rp-bulk-actions-btn(
  20. href
  21. ng-if="reviewPanel.nVisibleSelectedChanges > 1"
  22. ng-click="showBulkRejectDialog();"
  23. )
  24. i.fa.fa-times
  25. |  #{translate("reject_all")}
  26. | ({{ reviewPanel.nVisibleSelectedChanges }})
  27. if hasFeature('track-changes')
  28. a.rp-add-comment-btn(
  29. href
  30. ng-if="reviewPanel.entries[editor.open_doc_id]['add-comment'] != null && permissions.comment"
  31. ng-mousedown="addNewComment($event);"
  32. )
  33. i.fa.fa-comment
  34. |  #{translate("add_comment")}
  35. a.review-panel-toggler(
  36. href
  37. ng-click="handleTogglerClick($event);"
  38. )
  39. .review-panel-toolbar
  40. resolved-comments-dropdown(
  41. class="rp-flex-block"
  42. entries="reviewPanel.resolvedComments"
  43. threads="reviewPanel.commentThreads"
  44. resolved-ids="reviewPanel.resolvedThreadIds"
  45. docs="docs"
  46. on-open="refreshResolvedCommentsDropdown();"
  47. on-unresolve="unresolveComment(threadId);"
  48. on-delete="deleteThread(entryId, docId, threadId);"
  49. is-loading="reviewPanel.dropdown.loading"
  50. permissions="permissions"
  51. )
  52. span.review-panel-toolbar-label
  53. span.review-panel-toolbar-icon-on(
  54. ng-if="editor.wantTrackChanges === true"
  55. )
  56. i.fa.fa-circle
  57. span(ng-click="toggleFullTCStateCollapse();")
  58. span(ng-if="editor.wantTrackChanges === false") !{translate("track_changes_is_off")}
  59. span(ng-if="editor.wantTrackChanges === true") !{translate("track_changes_is_on")}
  60. span.rp-tc-state-collapse(
  61. ng-class="{ 'rp-tc-state-collapse-on': reviewPanel.fullTCStateCollapsed }"
  62. )
  63. i.fa.fa-angle-down
  64. ul.rp-tc-state(
  65. review-panel-collapse-height="reviewPanel.fullTCStateCollapsed"
  66. )
  67. li.rp-tc-state-item.rp-tc-state-item-everyone
  68. span.rp-tc-state-item-name(
  69. tooltip=translate('tc_switch_everyone_tip')
  70. tooltip-placement="left"
  71. tooltip-append-to-body="true"
  72. tooltip-popup-delay="1000"
  73. ) !{translate("tc_everyone")}
  74. review-panel-toggle(
  75. description="Track changes for everyone"
  76. ng-model="reviewPanel.trackChangesOnForEveryone"
  77. on-toggle="toggleTrackChangesForEveryone(isOn);"
  78. is-disabled="!project.features.trackChanges || !permissions.write"
  79. )
  80. li.rp-tc-state-item(
  81. ng-repeat="member in reviewPanel.formattedProjectMembers"
  82. )
  83. span.rp-tc-state-item-name(
  84. ng-class="{ 'rp-tc-state-item-name-disabled' : reviewPanel.trackChangesOnForEveryone}"
  85. tooltip=translate('tc_switch_user_tip')
  86. tooltip-placement="left"
  87. tooltip-append-to-body="true"
  88. tooltip-popup-delay="1000"
  89. ) {{ member.name }}
  90. review-panel-toggle(
  91. description="Track changes for {{ member.name }}"
  92. ng-model="reviewPanel.trackChangesState[member.id].value"
  93. on-toggle="toggleTrackChangesForUser(isOn, member.id);"
  94. is-disabled="reviewPanel.trackChangesOnForEveryone || !project.features.trackChanges || !permissions.write"
  95. )
  96. li.rp-tc-state-separator
  97. li.rp-tc-state-item
  98. span.rp-tc-state-item-name(
  99. ng-class="{ 'rp-tc-state-item-name-disabled' : reviewPanel.trackChangesOnForEveryone}"
  100. tooltip=translate('tc_switch_guests_tip')
  101. tooltip-placement="left"
  102. tooltip-append-to-body="true"
  103. tooltip-popup-delay="1000"
  104. ) !{translate("tc_guests")}
  105. review-panel-toggle(
  106. description="Track changes for guests"
  107. ng-model="reviewPanel.trackChangesOnForGuests"
  108. on-toggle="toggleTrackChangesForGuests(isOn);"
  109. is-disabled="reviewPanel.trackChangesOnForEveryone || !project.features.trackChanges || !permissions.write || !reviewPanel.trackChangesForGuestsAvailable"
  110. )
  111. .rp-entry-list(
  112. review-panel-sorted
  113. ng-if="reviewPanel.subView === SubViews.CUR_FILE"
  114. )
  115. .rp-entry-list-inner
  116. .rp-entry-wrapper(
  117. ng-repeat="(entry_id, entry) in reviewPanel.entries[editor.open_doc_id]"
  118. ng-if="entry.visible"
  119. )
  120. div(ng-if="entry.type === 'insert' || entry.type === 'delete'")
  121. change-entry(
  122. entry="entry"
  123. user="users[entry.metadata.user_id]"
  124. on-reject="rejectChanges(entry.entry_ids);"
  125. on-accept="acceptChanges(entry.entry_ids);"
  126. on-indicator-click="toggleReviewPanel();"
  127. on-mouse-enter="mouseEnterIndicator()"
  128. on-mouse-leave="mouseLeaveIndicator()"
  129. on-body-click="gotoEntry(editor.open_doc_id, entry.offset)"
  130. permissions="permissions"
  131. )
  132. div(ng-if="entry.type === 'aggregate-change'")
  133. aggregate-change-entry(
  134. entry="entry"
  135. user="users[entry.metadata.user_id]"
  136. on-reject="rejectChanges(entry.entry_ids);"
  137. on-accept="acceptChanges(entry.entry_ids);"
  138. on-indicator-click="toggleReviewPanel();"
  139. on-mouse-enter="mouseEnterIndicator()"
  140. on-mouse-leave="mouseLeaveIndicator()"
  141. on-body-click="gotoEntry(editor.open_doc_id, entry.offset)"
  142. permissions="permissions"
  143. )
  144. div(ng-if="entry.type === 'comment'")
  145. comment-entry(
  146. entry="entry"
  147. threads="reviewPanel.commentThreads"
  148. on-resolve="resolveComment(editor.open_doc_id, entry_id)"
  149. on-reply="submitReply(entry, entry_id);"
  150. on-indicator-click="toggleReviewPanel();"
  151. on-mouse-enter="mouseEnterIndicator()"
  152. on-mouse-leave="mouseLeaveIndicator()"
  153. on-save-edit="saveEdit(entry.thread_id, comment.id, comment.content)"
  154. on-delete="deleteComment(entry.thread_id, comment.id)"
  155. on-body-click="gotoEntry(editor.open_doc_id, entry.offset)"
  156. permissions="permissions"
  157. ng-if="!loadingThreads"
  158. )
  159. div(ng-if="entry.type === 'add-comment' && permissions.comment")
  160. add-comment-entry(
  161. on-start-new="startNewComment();"
  162. on-submit="submitNewComment(content);"
  163. on-cancel="cancelNewComment();"
  164. )
  165. div(ng-if="entry.type === 'bulk-actions'")
  166. bulk-actions-entry(
  167. on-bulk-accept="showBulkAcceptDialog();"
  168. on-bulk-reject="showBulkRejectDialog();"
  169. n-entries="reviewPanel.nVisibleSelectedChanges"
  170. )
  171. .rp-entry-list(
  172. ng-if="reviewPanel.subView === SubViews.OVERVIEW"
  173. )
  174. .rp-loading(ng-if="reviewPanel.overview.loading")
  175. i.fa.fa-spinner.fa-spin
  176. .rp-overview-file(
  177. ng-repeat="doc in docs"
  178. ng-if="!reviewPanel.overview.loading"
  179. )
  180. .rp-overview-file-header(
  181. ng-if="(reviewPanel.entries[doc.doc.id] != null) && (reviewPanel.entries[doc.doc.id] | notEmpty)"
  182. ng-click="reviewPanel.overview.docsCollapsedState[doc.doc.id] = ! reviewPanel.overview.docsCollapsedState[doc.doc.id]"
  183. )
  184. span.rp-overview-file-header-collapse(
  185. ng-class="{ 'rp-overview-file-header-collapse-on': reviewPanel.overview.docsCollapsedState[doc.doc.id] }"
  186. )
  187. i.fa.fa-angle-down
  188. | {{ doc.path }}
  189. span.rp-overview-file-num-entries(
  190. ng-show="reviewPanel.overview.docsCollapsedState[doc.doc.id]"
  191. )  ({{ reviewPanel.entries[doc.doc.id] | numKeys }})
  192. .rp-overview-file-entries(
  193. review-panel-collapse-height="reviewPanel.overview.docsCollapsedState[doc.doc.id]"
  194. )
  195. .rp-entry-wrapper(
  196. ng-repeat="(entry_id, entry) in reviewPanel.entries[doc.doc.id] | orderOverviewEntries"
  197. ng-if="!(entry.type === 'comment' && reviewPanel.commentThreads[entry.thread_id].resolved === true)"
  198. )
  199. div(ng-if="entry.type === 'insert' || entry.type === 'delete'")
  200. change-entry(
  201. entry="entry"
  202. user="users[entry.metadata.user_id]"
  203. ng-click="gotoEntry(doc.doc.id, entry.offset)"
  204. permissions="permissions"
  205. )
  206. div(ng-if="entry.type === 'aggregate-change'")
  207. aggregate-change-entry(
  208. entry="entry"
  209. user="users[entry.metadata.user_id]"
  210. ng-click="gotoEntry(doc.doc.id, entry.offset)"
  211. permissions="permissions"
  212. )
  213. div(ng-if="entry.type === 'comment'")
  214. comment-entry(
  215. entry="entry"
  216. threads="reviewPanel.commentThreads"
  217. on-reply="submitReply(entry, entry_id);"
  218. on-save-edit="saveEdit(entry.thread_id, comment.id, comment.content)"
  219. on-delete="deleteComment(entry.thread_id, comment.id)"
  220. ng-click="gotoEntry(doc.doc.id, entry.offset)"
  221. permissions="permissions"
  222. )
  223. .rp-nav
  224. a.rp-nav-item(
  225. href
  226. ng-click="setSubView(SubViews.CUR_FILE);"
  227. ng-class="{ 'rp-nav-item-active' : reviewPanel.subView === SubViews.CUR_FILE }"
  228. )
  229. i.fa.fa-file-text-o
  230. span.rp-nav-label #{translate("current_file")}
  231. a.rp-nav-item(
  232. href
  233. ng-click="setSubView(SubViews.OVERVIEW);"
  234. ng-class="{ 'rp-nav-item-active' : reviewPanel.subView === SubViews.OVERVIEW }"
  235. )
  236. i.fa.fa-list
  237. span.rp-nav-label #{translate("overview")}
  238. .rp-unsupported-msg-wrapper
  239. .rp-unsupported-msg
  240. i.fa.fa-5x.fa-exclamation-triangle
  241. p.rp-unsupported-msg-title Join our #[a(href="/beta/participate") Beta program] to use Track Changes in Rich Text mode!
  242. p You can #[a(href="/beta/participate") sign up] instantly to test and give feedback on our new version that includes comments and track changes!
  243. script(type='text/ng-template', id='changeEntryTemplate')
  244. div(
  245. ng-mouseenter="onMouseEnter();"
  246. ng-mouseleave="onMouseLeave();"
  247. )
  248. .rp-entry-callout(
  249. ng-class="'rp-entry-callout-' + entry.type"
  250. )
  251. .rp-entry-indicator(
  252. ng-switch="entry.type"
  253. ng-class="{ 'rp-entry-indicator-focused': entry.focused }"
  254. ng-click="onIndicatorClick();"
  255. )
  256. i.fa.fa-pencil(ng-switch-when="insert")
  257. i.rp-icon-delete(ng-switch-when="delete")
  258. .rp-entry(
  259. ng-class="[ 'rp-entry-' + entry.type, (entry.focused ? 'rp-entry-focused' : '')]"
  260. )
  261. .rp-entry-body
  262. .rp-entry-action-icon(ng-switch="entry.type")
  263. i.fa.fa-pencil(ng-switch-when="insert")
  264. i.rp-icon-delete(ng-switch-when="delete")
  265. .rp-entry-details
  266. .rp-entry-description(ng-switch="entry.type")
  267. span(ng-switch-when="insert") #{translate("tracked_change_added")} 
  268. ins.rp-content-highlight {{ entry.content | limitTo:(isCollapsed ? contentLimit : entry.content.length) }}
  269. a.rp-collapse-toggle(
  270. href
  271. ng-if="needsCollapsing"
  272. ng-click="toggleCollapse();"
  273. ) {{ isCollapsed ? '… (#{translate("show_all")})' : ' (#{translate("show_less")})' }}
  274. span(ng-switch-when="delete") #{translate("tracked_change_deleted")} 
  275. del.rp-content-highlight {{ entry.content | limitTo:(isCollapsed ? contentLimit : entry.content.length) }}
  276. a.rp-collapse-toggle(
  277. href
  278. ng-if="needsCollapsing"
  279. ng-click="toggleCollapse();"
  280. ) {{ isCollapsed ? '… (#{translate("show_all")})' : ' (#{translate("show_less")})' }}
  281. .rp-entry-metadata
  282. | {{ entry.metadata.ts | date : 'MMM d, y h:mm a' }} • 
  283. span.rp-entry-user(ng-switch="user.name" style="color: hsl({{ user.hue }}, 70%, 40%);")
  284. span(ng-switch-when="undefined") #{translate("anonymous")}
  285. span(ng-switch-default) {{ user.name }}
  286. .rp-entry-actions(ng-if="permissions.write")
  287. a.rp-entry-button(href, ng-click="onReject();")
  288. i.fa.fa-times
  289. |  #{translate("reject")}
  290. a.rp-entry-button(href, ng-click="onAccept();")
  291. i.fa.fa-check
  292. |  #{translate("accept")}
  293. script(type='text/ng-template', id='aggregateChangeEntryTemplate')
  294. div(
  295. ng-mouseenter="onMouseEnter();"
  296. ng-mouseleave="onMouseLeave();"
  297. )
  298. .rp-entry-callout.rp-entry-callout-aggregate
  299. .rp-entry-indicator(
  300. ng-class="{ 'rp-entry-indicator-focused': entry.focused }"
  301. ng-click="onIndicatorClick();"
  302. )
  303. i.fa.fa-pencil
  304. .rp-entry.rp-entry-aggregate(
  305. ng-class="{ 'rp-entry-focused': entry.focused }"
  306. )
  307. .rp-entry-body
  308. .rp-entry-action-icon
  309. i.fa.fa-pencil
  310. .rp-entry-details
  311. .rp-entry-description
  312. | #{translate("aggregate_changed")} 
  313. del.rp-content-highlight
  314. | {{ entry.metadata.replaced_content | limitTo:(isDeletionCollapsed ? contentLimit : entry.metadata.replaced_content.length) }}
  315. a.rp-collapse-toggle(
  316. href
  317. ng-if="deletionNeedsCollapsing"
  318. ng-click="toggleDeletionCollapse();"
  319. ) {{ isDeletionCollapsed ? '… (#{translate("show_all")})' : ' (#{translate("show_less")})' }}
  320. | #{translate("aggregate_to")} 
  321. ins.rp-content-highlight
  322. | {{ entry.content | limitTo:(isInsertionCollapsed ? contentLimit : entry.contentlength) }}
  323. a.rp-collapse-toggle(
  324. href
  325. ng-if="insertionNeedsCollapsing"
  326. ng-click="toggleInsertionCollapse();"
  327. ) {{ isInsertionCollapsed ? '… (#{translate("show_all")})' : ' (#{translate("show_less")})' }}
  328. .rp-entry-metadata
  329. | {{ entry.metadata.ts | date : 'MMM d, y h:mm a' }} • 
  330. span.rp-entry-user(ng-switch="user.name" style="color: hsl({{ user.hue }}, 70%, 40%);")
  331. span(ng-switch-when="undefined") #{translate("anonymous")}
  332. span(ng-switch-default) {{ user.name }}
  333. .rp-entry-actions(ng-if="permissions.write")
  334. a.rp-entry-button(href, ng-click="onReject();")
  335. i.fa.fa-times
  336. |  #{translate("reject")}
  337. a.rp-entry-button(href, ng-click="onAccept();")
  338. i.fa.fa-check
  339. |  #{translate("accept")}
  340. script(type='text/ng-template', id='commentEntryTemplate')
  341. .rp-comment-wrapper(
  342. ng-class="{ 'rp-comment-wrapper-resolving': state.animating }"
  343. ng-mouseenter="onMouseEnter();"
  344. ng-mouseleave="onMouseLeave();"
  345. )
  346. .rp-entry-callout.rp-entry-callout-comment
  347. .rp-entry-indicator(
  348. ng-class="{ 'rp-entry-indicator-focused': entry.focused }"
  349. ng-click="onIndicatorClick();"
  350. )
  351. i.fa.fa-comment
  352. .rp-entry.rp-entry-comment(
  353. ng-class="{ 'rp-entry-focused': entry.focused, 'rp-entry-comment-resolving': state.animating }"
  354. )
  355. .rp-loading(ng-if="!threads[entry.thread_id].submitting && (!threads[entry.thread_id] || threads[entry.thread_id].messages.length == 0)")
  356. | #{translate("no_comments")}
  357. .rp-comment-loaded
  358. .rp-comment(
  359. ng-repeat="comment in threads[entry.thread_id].messages track by comment.id"
  360. )
  361. p.rp-comment-content
  362. span(ng-if="!comment.editing")
  363. span.rp-entry-user(
  364. style="color: hsl({{ comment.user.hue }}, 70%, 40%);",
  365. ) {{ comment.user.name }}: 
  366. span(ng-bind-html="comment.content | linky:'_blank':{rel: 'noreferrer noopener'}")
  367. textarea.rp-comment-input(
  368. expandable-text-area
  369. ng-if="comment.editing"
  370. ng-model="comment.content"
  371. ng-keypress="saveEditOnEnter($event, comment);"
  372. ng-blur="saveEdit(comment)"
  373. autofocus
  374. stop-propagation="click"
  375. )
  376. .rp-entry-metadata(ng-if="!comment.editing")
  377. span(ng-if="!comment.deleting") {{ comment.timestamp | date : 'MMM d, y h:mm a' }}
  378. span.rp-comment-actions(ng-if="comment.user.isSelf && !comment.deleting")
  379. |  • 
  380. a(href, ng-click="startEditing(comment)") #{translate("edit")}
  381. span(ng-if="threads[entry.thread_id].messages.length > 1")
  382. |  • 
  383. a(href, ng-click="confirmDelete(comment)") #{translate("delete")}
  384. span.rp-confim-delete(ng-if="comment.user.isSelf && comment.deleting")
  385. | #{translate("are_you_sure")}
  386. | • 
  387. a(href, ng-click="doDelete(comment)") #{translate("delete")}
  388. |  • 
  389. a(href, ng-click="cancelDelete(comment)") #{translate("cancel")}
  390. .rp-loading(ng-if="threads[entry.thread_id].submitting")
  391. i.fa.fa-spinner.fa-spin
  392. .rp-comment-reply(ng-if="permissions.comment")
  393. textarea.rp-comment-input(
  394. expandable-text-area
  395. ng-model="entry.replyContent"
  396. ng-keypress="handleCommentReplyKeyPress($event);"
  397. stop-propagation="click"
  398. placeholder=translate("hit_enter_to_reply")
  399. )
  400. .rp-entry-actions
  401. button.rp-entry-button(
  402. ng-click="animateAndCallOnResolve();"
  403. ng-if="permissions.comment && permissions.write"
  404. )
  405. i.fa.fa-inbox
  406. |  #{translate("resolve")}
  407. button.rp-entry-button(
  408. ng-click="onReply();"
  409. ng-if="permissions.comment"
  410. ng-disabled="!entry.replyContent.length"
  411. )
  412. i.fa.fa-reply
  413. |  #{translate("reply")}
  414. script(type='text/ng-template', id='resolvedCommentEntryTemplate')
  415. .rp-resolved-comment
  416. div
  417. .rp-resolved-comment-context
  418. | #{translate("quoted_text_in")} 
  419. span.rp-resolved-comment-context-file {{ thread.docName }}
  420. p.rp-resolved-comment-context-quote
  421. span {{ thread.content | limitTo:(isCollapsed ? contentLimit : thread.content.length)}}
  422. a.rp-collapse-toggle(
  423. href
  424. ng-if="needsCollapsing"
  425. ng-click="toggleCollapse();"
  426. )  {{ isCollapsed ? '… (#{translate("show_all")})' : ' (#{translate("show_less")})' }}
  427. .rp-comment(
  428. ng-repeat="comment in thread.messages track by comment.id"
  429. )
  430. p.rp-comment-content
  431. span.rp-entry-user(
  432. style="color: hsl({{ comment.user.hue }}, 70%, 40%);"
  433. ng-if="$first || comment.user.id !== thread.messages[$index - 1].user.id"
  434. ) {{ comment.user.name }}: 
  435. span(ng-bind-html="comment.content | linky:'_blank':{rel: 'noreferrer noopener'}")
  436. .rp-entry-metadata
  437. | {{ comment.timestamp | date : 'MMM d, y h:mm a' }}
  438. .rp-comment.rp-comment-resolver
  439. p.rp-comment-resolver-content
  440. span.rp-entry-user(
  441. style="color: hsl({{ thread.resolved_by_user.hue }}, 70%, 40%);"
  442. ) {{ thread.resolved_by_user.name }}: 
  443. | #{translate("mark_as_resolved")}.
  444. .rp-entry-metadata
  445. | {{ thread.resolved_at | date : 'MMM d, y h:mm a' }}
  446. .rp-entry-actions(ng-if="permissions.comment && permissions.write")
  447. a.rp-entry-button(
  448. href
  449. ng-click="onUnresolve({ 'threadId': thread.threadId });"
  450. )
  451. |  #{translate("reopen")}
  452. a.rp-entry-button(
  453. href
  454. ng-click="onDelete({ 'entryId': thread.entryId, 'docId': thread.docId, 'threadId': thread.threadId });"
  455. )
  456. |  #{translate("delete")}
  457. script(type='text/ng-template', id='addCommentEntryTemplate')
  458. div
  459. .rp-entry-callout.rp-entry-callout-add-comment
  460. .rp-entry.rp-entry-add-comment(
  461. ng-class="[ (state.isAdding ? 'rp-entry-adding-comment' : ''), (entry.focused ? 'rp-entry-focused' : '')]"
  462. )
  463. a.rp-add-comment-btn(
  464. href
  465. ng-if="!state.isAdding"
  466. ng-click="startNewComment();"
  467. )
  468. i.fa.fa-comment
  469. |  #{translate("add_comment")}
  470. div(ng-if="state.isAdding")
  471. .rp-new-comment
  472. textarea.rp-comment-input(
  473. expandable-text-area
  474. ng-model="state.content"
  475. ng-keypress="handleCommentKeyPress($event);"
  476. ng-keydown="handleCommentKeyDown($event);"
  477. placeholder=translate("add_your_comment_here")
  478. focus-on="comment:new:open"
  479. )
  480. .rp-entry-actions
  481. button.rp-entry-button.rp-entry-button-cancel(
  482. ng-click="cancelNewComment();"
  483. )
  484. i.fa.fa-times
  485. |  #{translate("cancel")}
  486. button.rp-entry-button(
  487. ng-click="submitNewComment()"
  488. ng-disabled="!state.content.length"
  489. )
  490. i.fa.fa-comment
  491. |  #{translate("comment")}
  492. script(type='text/ng-template', id='bulkActionsEntryTemplate')
  493. div(ng-if="nEntries > 1")
  494. .rp-entry-callout.rp-entry-callout-bulk-actions
  495. .rp-entry.rp-entry-bulk-actions
  496. a.rp-bulk-actions-btn(
  497. href
  498. ng-click="bulkReject();"
  499. )
  500. i.fa.fa-times
  501. |  #{translate("reject_all")}
  502. | ({{ nEntries }})
  503. a.rp-bulk-actions-btn(
  504. href
  505. ng-click="bulkAccept();"
  506. )
  507. i.fa.fa-check
  508. |  #{translate("accept_all")}
  509. | ({{ nEntries }})
  510. script(type='text/ng-template', id='resolvedCommentsDropdownTemplate')
  511. .resolved-comments
  512. .resolved-comments-backdrop(
  513. ng-class="{ 'resolved-comments-backdrop-visible' : state.isOpen }"
  514. ng-click="state.isOpen = false"
  515. )
  516. a.resolved-comments-toggle(
  517. href
  518. ng-click="toggleOpenState();"
  519. tooltip=translate("resolved_comments")
  520. tooltip-placement="bottom"
  521. tooltip-append-to-body="true"
  522. )
  523. i.fa.fa-inbox
  524. .resolved-comments-dropdown(
  525. ng-class="{ 'resolved-comments-dropdown-open' : state.isOpen }"
  526. )
  527. .rp-loading(ng-if="isLoading")
  528. i.fa.fa-spinner.fa-spin
  529. .resolved-comments-scroller(
  530. ng-if="!isLoading"
  531. )
  532. resolved-comment-entry(
  533. ng-repeat="thread in resolvedComments | orderBy:'resolved_at':true"
  534. thread="thread"
  535. on-unresolve="handleUnresolve(threadId);"
  536. on-delete="handleDelete(entryId, docId, threadId);"
  537. permissions="permissions"
  538. )
  539. .rp-loading(ng-if="!resolvedComments.length")
  540. | #{translate("no_resolved_threads")}.
  541. script(type="text/ng-template", id="trackChangesUpgradeModalTemplate")
  542. .modal-header
  543. button.close(
  544. type="button"
  545. data-dismiss="modal"
  546. ng-click="cancel()"
  547. aria-label="Close"
  548. )
  549. span(aria-hidden="true") ×
  550. h3 #{translate("upgrade_to_track_changes")}
  551. .modal-body
  552. .teaser-video-container
  553. video.teaser-video(autoplay, loop)
  554. source(ng-src="{{ '/img/teasers/track-changes/teaser-track-changes.mp4' }}", type="video/mp4")
  555. img(src="/img/teasers/track-changes/teaser-track-changes.gif")
  556. h4.teaser-title #{translate("see_changes_in_your_documents_live")}
  557. p.small(ng-show="startedFreeTrial")
  558. | #{translate("refresh_page_after_starting_free_trial")}
  559. .row
  560. .col-md-10.col-md-offset-1
  561. ul.list-unstyled
  562. li
  563. i.fa.fa-check  
  564. | #{translate("track_any_change_in_real_time")}
  565. li
  566. i.fa.fa-check  
  567. | #{translate("review_your_peers_work")}
  568. li
  569. i.fa.fa-check  
  570. | #{translate("accept_or_reject_each_changes_individually")}
  571. .row.text-center
  572. div(ng-show="user.allowedFreeTrial" ng-controller="FreeTrialModalController")
  573. a.btn.btn-primary(
  574. href
  575. ng-click="startFreeTrial('track-changes')"
  576. ng-show="project.owner._id == user.id"
  577. ) #{translate("try_it_for_free")}
  578. div(ng-show="!user.allowedFreeTrial" ng-controller="UpgradeModalController")
  579. a.btn.btn-primary(
  580. href
  581. ng-click="upgradePlan('project-sharing')"
  582. ng-show="project.owner._id == user.id"
  583. ) #{translate("upgrade")}
  584. p(ng-show="project.owner._id != user.id"): strong #{translate("please_ask_the_project_owner_to_upgrade_to_track_changes")}
  585. .modal-footer()
  586. button.btn.btn-secondary(
  587. ng-click="cancel()"
  588. )
  589. span #{translate("close")}
  590. script(type="text/ng-template", id="bulkActionsModalTemplate")
  591. .modal-header
  592. button.close(
  593. type="button"
  594. data-dismiss="modal"
  595. ng-click="cancel()"
  596. aria-label="Close"
  597. )
  598. span(aria-hidden="true") ×
  599. h3 {{ isAccept ? '#{translate("accept_all")}' : '#{translate("reject_all")}' }}
  600. .modal-body
  601. p(ng-if="isAccept") #{translate("bulk_accept_confirm", { nChanges: "{{ nChanges }}"})}
  602. p(ng-if="!isAccept") #{translate("bulk_reject_confirm", { nChanges: "{{ nChanges }}"})}
  603. .modal-footer()
  604. button.btn.btn-secondary(
  605. ng-click="cancel()"
  606. )
  607. span #{translate("cancel")}
  608. button.btn.btn-primary(
  609. ng-click="confirm()"
  610. )
  611. span #{translate("ok")}