mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Remove Angular/Pug review panel code (#15935)
GitOrigin-RevId: de782d4b47d987f6434a34bea487568b269e8d85
This commit is contained in:
parent
9875e55a27
commit
d40de2018c
28 changed files with 12 additions and 1732 deletions
|
@ -663,21 +663,6 @@ const ProjectController = {
|
|||
}
|
||||
)
|
||||
},
|
||||
reviewPanelAssignment(cb) {
|
||||
SplitTestHandler.getAssignment(
|
||||
req,
|
||||
res,
|
||||
'review-panel',
|
||||
(error, assignment) => {
|
||||
// do not fail editor load if assignment fails
|
||||
if (error) {
|
||||
cb(null, { variant: 'default' })
|
||||
} else {
|
||||
cb(null, assignment)
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
idePageAssignment(cb) {
|
||||
SplitTestHandler.getAssignment(
|
||||
req,
|
||||
|
@ -713,7 +698,6 @@ const ProjectController = {
|
|||
isInvitedMember,
|
||||
brandVariation,
|
||||
pdfjsAssignment,
|
||||
reviewPanelAssignment,
|
||||
idePageAssignment,
|
||||
personalAccessTokenAssignment,
|
||||
projectTags,
|
||||
|
@ -898,7 +882,6 @@ const ProjectController = {
|
|||
showUpgradePrompt,
|
||||
fixedSizeDocument: true,
|
||||
useOpenTelemetry: Settings.useOpenTelemetryClient,
|
||||
isReviewPanelReact: reviewPanelAssignment.variant === 'react',
|
||||
idePageReact,
|
||||
showPersonalAccessToken,
|
||||
optionalPersonalAccessToken,
|
||||
|
|
|
@ -45,10 +45,6 @@
|
|||
div(ng-controller="EditorLoaderController")
|
||||
|
||||
include ../../source-editor/source-editor
|
||||
|
||||
div(ng-if="!reviewPanel.isReact")
|
||||
if !isRestrictedTokenMember
|
||||
include ./review-panel
|
||||
|
||||
if moduleIncludesAvailable('editor:symbol-palette')
|
||||
.div(vertical-resizable-bottom)
|
||||
|
|
|
@ -32,7 +32,6 @@ meta(name="ol-showSupport", data-type="boolean" content=showSupport)
|
|||
meta(name="ol-showTemplatesServerPro", data-type="boolean" content=showTemplatesServerPro)
|
||||
meta(name="ol-showPersonalAccessToken", data-type="boolean" content=showPersonalAccessToken)
|
||||
meta(name="ol-optionalPersonalAccessToken", data-type="boolean" content=optionalPersonalAccessToken)
|
||||
meta(name="ol-isReviewPanelReact", data-type="boolean" content=isReviewPanelReact)
|
||||
meta(name="ol-hasTrackChangesFeature", data-type="boolean" content=hasTrackChangesFeature)
|
||||
meta(name="ol-mathJax3Path" content=mathJax3Path)
|
||||
meta(name="ol-completedTutorials", data-type="json" content=user.completedTutorials)
|
||||
|
|
|
@ -1,643 +0,0 @@
|
|||
#review-panel(
|
||||
ng-class="{ 'rp-collapsed-displaying-entry': reviewPanel.entryHover, 'rp-offset-widgets': true }"
|
||||
)
|
||||
.rp-in-editor-widgets
|
||||
a.rp-track-changes-indicator(
|
||||
href
|
||||
ng-if="editor.wantTrackChanges"
|
||||
ng-click="toggleReviewPanel();"
|
||||
ng-class="{ 'rp-track-changes-indicator-on-dark' : darkTheme }"
|
||||
) !{translate("track_changes_is_on")}
|
||||
a.rp-bulk-actions-btn(
|
||||
href
|
||||
ng-if="reviewPanel.nVisibleSelectedChanges > 1"
|
||||
ng-click="showBulkAcceptDialog();"
|
||||
)
|
||||
i.fa.fa-check
|
||||
| #{translate("accept_all")}
|
||||
| ({{ reviewPanel.nVisibleSelectedChanges }})
|
||||
a.rp-bulk-actions-btn(
|
||||
href
|
||||
ng-if="reviewPanel.nVisibleSelectedChanges > 1"
|
||||
ng-click="showBulkRejectDialog();"
|
||||
)
|
||||
i.fa.fa-times
|
||||
| #{translate("reject_all")}
|
||||
| ({{ reviewPanel.nVisibleSelectedChanges }})
|
||||
if hasFeature('track-changes')
|
||||
a.rp-add-comment-btn(
|
||||
href
|
||||
ng-if="reviewPanel.entries[editor.open_doc_id]['add-comment'] != null && permissions.comment"
|
||||
ng-mousedown="addNewComment($event);"
|
||||
)
|
||||
i.fa.fa-comment
|
||||
| #{translate("add_comment")}
|
||||
a.review-panel-toggler(
|
||||
href
|
||||
ng-click="handleTogglerClick($event);"
|
||||
)
|
||||
.review-panel-toolbar
|
||||
resolved-comments-dropdown(
|
||||
class="rp-flex-block"
|
||||
entries="reviewPanel.resolvedComments"
|
||||
threads="reviewPanel.commentThreads"
|
||||
resolved-ids="reviewPanel.resolvedThreadIds"
|
||||
docs="docs"
|
||||
on-open="refreshResolvedCommentsDropdown();"
|
||||
on-unresolve="unresolveComment(threadId);"
|
||||
on-delete="deleteThread(entryId, docId, threadId);"
|
||||
is-loading="reviewPanel.dropdown.loading"
|
||||
permissions="permissions"
|
||||
)
|
||||
span.review-panel-toolbar-label
|
||||
span.review-panel-toolbar-icon-on(
|
||||
ng-if="editor.wantTrackChanges === true"
|
||||
)
|
||||
i.fa.fa-circle
|
||||
span(ng-click="toggleFullTCStateCollapse();")
|
||||
span(ng-if="editor.wantTrackChanges === false") !{translate("track_changes_is_off")}
|
||||
span(ng-if="editor.wantTrackChanges === true") !{translate("track_changes_is_on")}
|
||||
span.rp-tc-state-collapse(
|
||||
ng-class="{ 'rp-tc-state-collapse-on': reviewPanel.fullTCStateCollapsed }"
|
||||
)
|
||||
i.fa.fa-angle-down
|
||||
ul.rp-tc-state(
|
||||
review-panel-collapse-height="reviewPanel.fullTCStateCollapsed"
|
||||
)
|
||||
li.rp-tc-state-item.rp-tc-state-item-everyone
|
||||
span.rp-tc-state-item-name(
|
||||
tooltip=translate('tc_switch_everyone_tip')
|
||||
tooltip-placement="left"
|
||||
tooltip-append-to-body="true"
|
||||
tooltip-popup-delay="1000"
|
||||
) !{translate("tc_everyone")}
|
||||
review-panel-toggle(
|
||||
description="Track changes for everyone"
|
||||
ng-model="reviewPanel.trackChangesOnForEveryone"
|
||||
on-toggle="toggleTrackChangesForEveryone(isOn);"
|
||||
is-disabled="!project.features.trackChanges || !permissions.write"
|
||||
)
|
||||
li.rp-tc-state-item(
|
||||
ng-repeat="member in reviewPanel.formattedProjectMembers"
|
||||
)
|
||||
span.rp-tc-state-item-name(
|
||||
ng-class="{ 'rp-tc-state-item-name-disabled' : reviewPanel.trackChangesOnForEveryone}"
|
||||
tooltip=translate('tc_switch_user_tip')
|
||||
tooltip-placement="left"
|
||||
tooltip-append-to-body="true"
|
||||
tooltip-popup-delay="1000"
|
||||
) {{ member.name }}
|
||||
review-panel-toggle(
|
||||
description="Track changes for {{ member.name }}"
|
||||
ng-model="reviewPanel.trackChangesState[member.id].value"
|
||||
on-toggle="toggleTrackChangesForUser(isOn, member.id);"
|
||||
is-disabled="reviewPanel.trackChangesOnForEveryone || !project.features.trackChanges || !permissions.write"
|
||||
)
|
||||
|
||||
li.rp-tc-state-separator
|
||||
li.rp-tc-state-item
|
||||
span.rp-tc-state-item-name(
|
||||
ng-class="{ 'rp-tc-state-item-name-disabled' : reviewPanel.trackChangesOnForEveryone}"
|
||||
tooltip=translate('tc_switch_guests_tip')
|
||||
tooltip-placement="left"
|
||||
tooltip-append-to-body="true"
|
||||
tooltip-popup-delay="1000"
|
||||
) !{translate("tc_guests")}
|
||||
review-panel-toggle(
|
||||
description="Track changes for guests"
|
||||
ng-model="reviewPanel.trackChangesOnForGuests"
|
||||
on-toggle="toggleTrackChangesForGuests(isOn);"
|
||||
is-disabled="reviewPanel.trackChangesOnForEveryone || !project.features.trackChanges || !permissions.write || !reviewPanel.trackChangesForGuestsAvailable"
|
||||
)
|
||||
|
||||
.rp-entry-list(
|
||||
review-panel-sorted
|
||||
ng-if="reviewPanel.subView === SubViews.CUR_FILE"
|
||||
)
|
||||
.rp-entry-list-inner
|
||||
.rp-entry-wrapper(
|
||||
ng-repeat="(entry_id, entry) in reviewPanel.entries[editor.open_doc_id]"
|
||||
ng-if="entry.visible"
|
||||
)
|
||||
div(ng-if="entry.type === 'insert' || entry.type === 'delete'")
|
||||
change-entry(
|
||||
entry="entry"
|
||||
user="users[entry.metadata.user_id]"
|
||||
on-reject="rejectChanges(entry.entry_ids);"
|
||||
on-accept="acceptChanges(entry.entry_ids);"
|
||||
on-indicator-click="toggleReviewPanel();"
|
||||
on-mouse-enter="mouseEnterIndicator()"
|
||||
on-mouse-leave="mouseLeaveIndicator()"
|
||||
on-body-click="gotoEntry(editor.open_doc_id, entry.offset)"
|
||||
permissions="permissions"
|
||||
)
|
||||
|
||||
div(ng-if="entry.type === 'aggregate-change'")
|
||||
aggregate-change-entry(
|
||||
entry="entry"
|
||||
user="users[entry.metadata.user_id]"
|
||||
on-reject="rejectChanges(entry.entry_ids);"
|
||||
on-accept="acceptChanges(entry.entry_ids);"
|
||||
on-indicator-click="toggleReviewPanel();"
|
||||
on-mouse-enter="mouseEnterIndicator()"
|
||||
on-mouse-leave="mouseLeaveIndicator()"
|
||||
on-body-click="gotoEntry(editor.open_doc_id, entry.offset)"
|
||||
permissions="permissions"
|
||||
)
|
||||
|
||||
div(ng-if="entry.type === 'comment'")
|
||||
comment-entry(
|
||||
entry="entry"
|
||||
threads="reviewPanel.commentThreads"
|
||||
on-resolve="resolveComment(editor.open_doc_id, entry_id)"
|
||||
on-reply="submitReply(entry, entry_id);"
|
||||
on-indicator-click="toggleReviewPanel();"
|
||||
on-mouse-enter="mouseEnterIndicator()"
|
||||
on-mouse-leave="mouseLeaveIndicator()"
|
||||
on-save-edit="saveEdit(entry.thread_id, comment.id, comment.content)"
|
||||
on-delete="deleteComment(entry.thread_id, comment.id)"
|
||||
on-body-click="gotoEntry(editor.open_doc_id, entry.offset)"
|
||||
permissions="permissions"
|
||||
ng-if="!loadingThreads"
|
||||
)
|
||||
|
||||
div(ng-if="entry.type === 'add-comment' && permissions.comment")
|
||||
add-comment-entry(
|
||||
on-start-new="startNewComment();"
|
||||
on-submit="submitNewComment(content);"
|
||||
on-cancel="cancelNewComment();"
|
||||
)
|
||||
div(ng-if="entry.type === 'bulk-actions'")
|
||||
bulk-actions-entry(
|
||||
on-bulk-accept="showBulkAcceptDialog();"
|
||||
on-bulk-reject="showBulkRejectDialog();"
|
||||
n-entries="reviewPanel.nVisibleSelectedChanges"
|
||||
)
|
||||
|
||||
.rp-entry-list(
|
||||
ng-if="reviewPanel.subView === SubViews.OVERVIEW"
|
||||
)
|
||||
.rp-loading(ng-if="reviewPanel.overview.loading")
|
||||
i.fa.fa-spinner.fa-spin
|
||||
.rp-overview-file(
|
||||
ng-repeat="doc in docs"
|
||||
ng-if="!reviewPanel.overview.loading"
|
||||
)
|
||||
.rp-overview-file-header(
|
||||
ng-if="(reviewPanel.entries[doc.doc.id] != null) && (reviewPanel.entries[doc.doc.id] | notEmpty)"
|
||||
ng-click="reviewPanel.overview.docsCollapsedState[doc.doc.id] = ! reviewPanel.overview.docsCollapsedState[doc.doc.id]"
|
||||
)
|
||||
span.rp-overview-file-header-collapse(
|
||||
ng-class="{ 'rp-overview-file-header-collapse-on': reviewPanel.overview.docsCollapsedState[doc.doc.id] }"
|
||||
)
|
||||
i.fa.fa-angle-down
|
||||
| {{ doc.path }}
|
||||
span.rp-overview-file-num-entries(
|
||||
ng-show="reviewPanel.overview.docsCollapsedState[doc.doc.id]"
|
||||
) ({{ reviewPanel.entries[doc.doc.id] | numKeys }})
|
||||
|
||||
.rp-overview-file-entries(
|
||||
review-panel-collapse-height="reviewPanel.overview.docsCollapsedState[doc.doc.id]"
|
||||
)
|
||||
.rp-entry-wrapper(
|
||||
ng-repeat="(entry_id, entry) in reviewPanel.entries[doc.doc.id] | orderOverviewEntries"
|
||||
ng-if="!(entry.type === 'comment' && reviewPanel.commentThreads[entry.thread_id].resolved === true)"
|
||||
)
|
||||
div(ng-if="entry.type === 'insert' || entry.type === 'delete'")
|
||||
change-entry(
|
||||
entry="entry"
|
||||
user="users[entry.metadata.user_id]"
|
||||
ng-click="gotoEntry(doc.doc.id, entry.offset)"
|
||||
permissions="permissions"
|
||||
)
|
||||
|
||||
div(ng-if="entry.type === 'aggregate-change'")
|
||||
aggregate-change-entry(
|
||||
entry="entry"
|
||||
user="users[entry.metadata.user_id]"
|
||||
ng-click="gotoEntry(doc.doc.id, entry.offset)"
|
||||
permissions="permissions"
|
||||
)
|
||||
|
||||
div(ng-if="entry.type === 'comment'")
|
||||
comment-entry(
|
||||
entry="entry"
|
||||
threads="reviewPanel.commentThreads"
|
||||
on-reply="submitReply(entry, entry_id);"
|
||||
on-save-edit="saveEdit(entry.thread_id, comment.id, comment.content)"
|
||||
on-delete="deleteComment(entry.thread_id, comment.id)"
|
||||
ng-click="gotoEntry(doc.doc.id, entry.offset)"
|
||||
permissions="permissions"
|
||||
)
|
||||
|
||||
.rp-nav
|
||||
a.rp-nav-item(
|
||||
href
|
||||
ng-click="setSubView(SubViews.CUR_FILE);"
|
||||
ng-class="{ 'rp-nav-item-active' : reviewPanel.subView === SubViews.CUR_FILE }"
|
||||
)
|
||||
i.fa.fa-file-text-o
|
||||
span.rp-nav-label #{translate("current_file")}
|
||||
a.rp-nav-item(
|
||||
href
|
||||
ng-click="setSubView(SubViews.OVERVIEW);"
|
||||
ng-class="{ 'rp-nav-item-active' : reviewPanel.subView === SubViews.OVERVIEW }"
|
||||
)
|
||||
i.fa.fa-list
|
||||
span.rp-nav-label #{translate("overview")}
|
||||
|
||||
.rp-unsupported-msg-wrapper
|
||||
.rp-unsupported-msg
|
||||
i.fa.fa-5x.fa-exclamation-triangle
|
||||
p.rp-unsupported-msg-title Join our #[a(href="/beta/participate") Beta program] to use Track Changes in Rich Text mode!
|
||||
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!
|
||||
|
||||
|
||||
script(type='text/ng-template', id='changeEntryTemplate')
|
||||
div(
|
||||
ng-mouseenter="onMouseEnter();"
|
||||
ng-mouseleave="onMouseLeave();"
|
||||
)
|
||||
.rp-entry-callout(
|
||||
ng-class="'rp-entry-callout-' + entry.type"
|
||||
)
|
||||
.rp-entry-indicator(
|
||||
ng-switch="entry.type"
|
||||
ng-class="{ 'rp-entry-indicator-focused': entry.focused }"
|
||||
ng-click="onIndicatorClick();"
|
||||
)
|
||||
i.fa.fa-pencil(ng-switch-when="insert")
|
||||
i.rp-icon-delete(ng-switch-when="delete")
|
||||
.rp-entry(
|
||||
ng-class="[ 'rp-entry-' + entry.type, (entry.focused ? 'rp-entry-focused' : '')]"
|
||||
)
|
||||
.rp-entry-body
|
||||
.rp-entry-action-icon(ng-switch="entry.type")
|
||||
i.fa.fa-pencil(ng-switch-when="insert")
|
||||
i.rp-icon-delete(ng-switch-when="delete")
|
||||
.rp-entry-details
|
||||
.rp-entry-description(ng-switch="entry.type")
|
||||
span(ng-switch-when="insert") #{translate("tracked_change_added")}
|
||||
ins.rp-content-highlight {{ entry.content | limitTo:(isCollapsed ? contentLimit : entry.content.length) }}
|
||||
a.rp-collapse-toggle(
|
||||
href
|
||||
ng-if="needsCollapsing"
|
||||
ng-click="toggleCollapse();"
|
||||
) {{ isCollapsed ? '… (#{translate("show_all")})' : ' (#{translate("show_less")})' }}
|
||||
span(ng-switch-when="delete") #{translate("tracked_change_deleted")}
|
||||
del.rp-content-highlight {{ entry.content | limitTo:(isCollapsed ? contentLimit : entry.content.length) }}
|
||||
a.rp-collapse-toggle(
|
||||
href
|
||||
ng-if="needsCollapsing"
|
||||
ng-click="toggleCollapse();"
|
||||
) {{ isCollapsed ? '… (#{translate("show_all")})' : ' (#{translate("show_less")})' }}
|
||||
.rp-entry-metadata
|
||||
| {{ entry.metadata.ts | date : 'MMM d, y h:mm a' }} •
|
||||
span.rp-entry-user(ng-switch="user.name" style="color: hsl({{ user.hue }}, 70%, 40%);")
|
||||
span(ng-switch-when="undefined") #{translate("anonymous")}
|
||||
span(ng-switch-default) {{ user.name }}
|
||||
.rp-entry-actions(ng-if="permissions.write")
|
||||
a.rp-entry-button(href, ng-click="onReject();")
|
||||
i.fa.fa-times
|
||||
| #{translate("reject")}
|
||||
a.rp-entry-button(href, ng-click="onAccept();")
|
||||
i.fa.fa-check
|
||||
| #{translate("accept")}
|
||||
|
||||
script(type='text/ng-template', id='aggregateChangeEntryTemplate')
|
||||
div(
|
||||
ng-mouseenter="onMouseEnter();"
|
||||
ng-mouseleave="onMouseLeave();"
|
||||
)
|
||||
.rp-entry-callout.rp-entry-callout-aggregate
|
||||
.rp-entry-indicator(
|
||||
ng-class="{ 'rp-entry-indicator-focused': entry.focused }"
|
||||
ng-click="onIndicatorClick();"
|
||||
)
|
||||
i.fa.fa-pencil
|
||||
.rp-entry.rp-entry-aggregate(
|
||||
ng-class="{ 'rp-entry-focused': entry.focused }"
|
||||
)
|
||||
.rp-entry-body
|
||||
.rp-entry-action-icon
|
||||
i.fa.fa-pencil
|
||||
.rp-entry-details
|
||||
.rp-entry-description
|
||||
| #{translate("aggregate_changed")}
|
||||
del.rp-content-highlight
|
||||
| {{ entry.metadata.replaced_content | limitTo:(isDeletionCollapsed ? contentLimit : entry.metadata.replaced_content.length) }}
|
||||
a.rp-collapse-toggle(
|
||||
href
|
||||
ng-if="deletionNeedsCollapsing"
|
||||
ng-click="toggleDeletionCollapse();"
|
||||
) {{ isDeletionCollapsed ? '… (#{translate("show_all")})' : ' (#{translate("show_less")})' }}
|
||||
| #{translate("aggregate_to")}
|
||||
ins.rp-content-highlight
|
||||
| {{ entry.content | limitTo:(isInsertionCollapsed ? contentLimit : entry.contentlength) }}
|
||||
a.rp-collapse-toggle(
|
||||
href
|
||||
ng-if="insertionNeedsCollapsing"
|
||||
ng-click="toggleInsertionCollapse();"
|
||||
) {{ isInsertionCollapsed ? '… (#{translate("show_all")})' : ' (#{translate("show_less")})' }}
|
||||
.rp-entry-metadata
|
||||
| {{ entry.metadata.ts | date : 'MMM d, y h:mm a' }} •
|
||||
span.rp-entry-user(ng-switch="user.name" style="color: hsl({{ user.hue }}, 70%, 40%);")
|
||||
span(ng-switch-when="undefined") #{translate("anonymous")}
|
||||
span(ng-switch-default) {{ user.name }}
|
||||
.rp-entry-actions(ng-if="permissions.write")
|
||||
a.rp-entry-button(href, ng-click="onReject();")
|
||||
i.fa.fa-times
|
||||
| #{translate("reject")}
|
||||
a.rp-entry-button(href, ng-click="onAccept();")
|
||||
i.fa.fa-check
|
||||
| #{translate("accept")}
|
||||
|
||||
script(type='text/ng-template', id='commentEntryTemplate')
|
||||
.rp-comment-wrapper(
|
||||
ng-class="{ 'rp-comment-wrapper-resolving': state.animating }"
|
||||
ng-mouseenter="onMouseEnter();"
|
||||
ng-mouseleave="onMouseLeave();"
|
||||
)
|
||||
.rp-entry-callout.rp-entry-callout-comment
|
||||
.rp-entry-indicator(
|
||||
ng-class="{ 'rp-entry-indicator-focused': entry.focused }"
|
||||
ng-click="onIndicatorClick();"
|
||||
)
|
||||
i.fa.fa-comment
|
||||
.rp-entry.rp-entry-comment(
|
||||
ng-class="{ 'rp-entry-focused': entry.focused, 'rp-entry-comment-resolving': state.animating }"
|
||||
)
|
||||
|
||||
.rp-loading(ng-if="!threads[entry.thread_id].submitting && (!threads[entry.thread_id] || threads[entry.thread_id].messages.length == 0)")
|
||||
| #{translate("no_comments")}
|
||||
.rp-comment-loaded
|
||||
.rp-comment(
|
||||
ng-repeat="comment in threads[entry.thread_id].messages track by comment.id"
|
||||
)
|
||||
p.rp-comment-content
|
||||
span(ng-if="!comment.editing")
|
||||
span.rp-entry-user(
|
||||
style="color: hsl({{ comment.user.hue }}, 70%, 40%);",
|
||||
) {{ comment.user.name }}:
|
||||
span(ng-bind-html="comment.content | linky:'_blank':{rel: 'noreferrer noopener'}")
|
||||
textarea.rp-comment-input(
|
||||
expandable-text-area
|
||||
ng-if="comment.editing"
|
||||
ng-model="comment.content"
|
||||
ng-keypress="saveEditOnEnter($event, comment);"
|
||||
ng-blur="saveEdit(comment)"
|
||||
autofocus
|
||||
stop-propagation="click"
|
||||
)
|
||||
.rp-entry-metadata(ng-if="!comment.editing")
|
||||
span(ng-if="!comment.deleting") {{ comment.timestamp | date : 'MMM d, y h:mm a' }}
|
||||
span.rp-comment-actions(ng-if="comment.user.isSelf && !comment.deleting")
|
||||
| •
|
||||
a(href, ng-click="startEditing(comment)") #{translate("edit")}
|
||||
span(ng-if="threads[entry.thread_id].messages.length > 1")
|
||||
| •
|
||||
a(href, ng-click="confirmDelete(comment)") #{translate("delete")}
|
||||
span.rp-confim-delete(ng-if="comment.user.isSelf && comment.deleting")
|
||||
| #{translate("are_you_sure")}
|
||||
| •
|
||||
a(href, ng-click="doDelete(comment)") #{translate("delete")}
|
||||
| •
|
||||
a(href, ng-click="cancelDelete(comment)") #{translate("cancel")}
|
||||
|
||||
.rp-loading(ng-if="threads[entry.thread_id].submitting")
|
||||
i.fa.fa-spinner.fa-spin
|
||||
.rp-comment-reply(ng-if="permissions.comment")
|
||||
textarea.rp-comment-input(
|
||||
expandable-text-area
|
||||
ng-model="entry.replyContent"
|
||||
ng-keypress="handleCommentReplyKeyPress($event);"
|
||||
stop-propagation="click"
|
||||
placeholder=translate("hit_enter_to_reply")
|
||||
)
|
||||
.rp-entry-actions
|
||||
button.rp-entry-button(
|
||||
ng-click="animateAndCallOnResolve();"
|
||||
ng-if="permissions.comment && permissions.write"
|
||||
)
|
||||
i.fa.fa-inbox
|
||||
| #{translate("resolve")}
|
||||
button.rp-entry-button(
|
||||
ng-click="onReply();"
|
||||
ng-if="permissions.comment"
|
||||
ng-disabled="!entry.replyContent.length"
|
||||
)
|
||||
i.fa.fa-reply
|
||||
| #{translate("reply")}
|
||||
|
||||
script(type='text/ng-template', id='resolvedCommentEntryTemplate')
|
||||
.rp-resolved-comment
|
||||
div
|
||||
.rp-resolved-comment-context
|
||||
| #{translate("quoted_text_in")}
|
||||
span.rp-resolved-comment-context-file {{ thread.docName }}
|
||||
p.rp-resolved-comment-context-quote
|
||||
span {{ thread.content | limitTo:(isCollapsed ? contentLimit : thread.content.length)}}
|
||||
a.rp-collapse-toggle(
|
||||
href
|
||||
ng-if="needsCollapsing"
|
||||
ng-click="toggleCollapse();"
|
||||
) {{ isCollapsed ? '… (#{translate("show_all")})' : ' (#{translate("show_less")})' }}
|
||||
.rp-comment(
|
||||
ng-repeat="comment in thread.messages track by comment.id"
|
||||
)
|
||||
p.rp-comment-content
|
||||
span.rp-entry-user(
|
||||
style="color: hsl({{ comment.user.hue }}, 70%, 40%);"
|
||||
ng-if="$first || comment.user.id !== thread.messages[$index - 1].user.id"
|
||||
) {{ comment.user.name }}:
|
||||
span(ng-bind-html="comment.content | linky:'_blank':{rel: 'noreferrer noopener'}")
|
||||
.rp-entry-metadata
|
||||
| {{ comment.timestamp | date : 'MMM d, y h:mm a' }}
|
||||
.rp-comment.rp-comment-resolver
|
||||
p.rp-comment-resolver-content
|
||||
span.rp-entry-user(
|
||||
style="color: hsl({{ thread.resolved_by_user.hue }}, 70%, 40%);"
|
||||
) {{ thread.resolved_by_user.name }}:
|
||||
| #{translate("mark_as_resolved")}.
|
||||
.rp-entry-metadata
|
||||
| {{ thread.resolved_at | date : 'MMM d, y h:mm a' }}
|
||||
|
||||
.rp-entry-actions(ng-if="permissions.comment && permissions.write")
|
||||
a.rp-entry-button(
|
||||
href
|
||||
ng-click="onUnresolve({ 'threadId': thread.threadId });"
|
||||
)
|
||||
| #{translate("reopen")}
|
||||
a.rp-entry-button(
|
||||
href
|
||||
ng-click="onDelete({ 'entryId': thread.entryId, 'docId': thread.docId, 'threadId': thread.threadId });"
|
||||
)
|
||||
| #{translate("delete")}
|
||||
|
||||
|
||||
script(type='text/ng-template', id='addCommentEntryTemplate')
|
||||
div
|
||||
.rp-entry-callout.rp-entry-callout-add-comment
|
||||
.rp-entry.rp-entry-add-comment(
|
||||
ng-class="[ (state.isAdding ? 'rp-entry-adding-comment' : ''), (entry.focused ? 'rp-entry-focused' : '')]"
|
||||
)
|
||||
a.rp-add-comment-btn(
|
||||
href
|
||||
ng-if="!state.isAdding"
|
||||
ng-click="startNewComment();"
|
||||
)
|
||||
i.fa.fa-comment
|
||||
| #{translate("add_comment")}
|
||||
div(ng-if="state.isAdding")
|
||||
.rp-new-comment
|
||||
textarea.rp-comment-input(
|
||||
expandable-text-area
|
||||
ng-model="state.content"
|
||||
ng-keypress="handleCommentKeyPress($event);"
|
||||
ng-keydown="handleCommentKeyDown($event);"
|
||||
placeholder=translate("add_your_comment_here")
|
||||
focus-on="comment:new:open"
|
||||
)
|
||||
.rp-entry-actions
|
||||
button.rp-entry-button.rp-entry-button-cancel(
|
||||
ng-click="cancelNewComment();"
|
||||
)
|
||||
i.fa.fa-times
|
||||
| #{translate("cancel")}
|
||||
button.rp-entry-button(
|
||||
ng-click="submitNewComment()"
|
||||
ng-disabled="!state.content.length"
|
||||
)
|
||||
i.fa.fa-comment
|
||||
| #{translate("comment")}
|
||||
|
||||
script(type='text/ng-template', id='bulkActionsEntryTemplate')
|
||||
div(ng-if="nEntries > 1")
|
||||
.rp-entry-callout.rp-entry-callout-bulk-actions
|
||||
.rp-entry.rp-entry-bulk-actions
|
||||
a.rp-bulk-actions-btn(
|
||||
href
|
||||
ng-click="bulkReject();"
|
||||
)
|
||||
i.fa.fa-times
|
||||
| #{translate("reject_all")}
|
||||
| ({{ nEntries }})
|
||||
a.rp-bulk-actions-btn(
|
||||
href
|
||||
ng-click="bulkAccept();"
|
||||
)
|
||||
i.fa.fa-check
|
||||
| #{translate("accept_all")}
|
||||
| ({{ nEntries }})
|
||||
|
||||
script(type='text/ng-template', id='resolvedCommentsDropdownTemplate')
|
||||
.resolved-comments
|
||||
.resolved-comments-backdrop(
|
||||
ng-class="{ 'resolved-comments-backdrop-visible' : state.isOpen }"
|
||||
ng-click="state.isOpen = false"
|
||||
)
|
||||
a.resolved-comments-toggle(
|
||||
href
|
||||
ng-click="toggleOpenState();"
|
||||
tooltip=translate("resolved_comments")
|
||||
tooltip-placement="bottom"
|
||||
tooltip-append-to-body="true"
|
||||
)
|
||||
i.fa.fa-inbox
|
||||
.resolved-comments-dropdown(
|
||||
ng-class="{ 'resolved-comments-dropdown-open' : state.isOpen }"
|
||||
)
|
||||
.rp-loading(ng-if="isLoading")
|
||||
i.fa.fa-spinner.fa-spin
|
||||
.resolved-comments-scroller(
|
||||
ng-if="!isLoading"
|
||||
)
|
||||
resolved-comment-entry(
|
||||
ng-repeat="thread in resolvedComments | orderBy:'resolved_at':true"
|
||||
thread="thread"
|
||||
on-unresolve="handleUnresolve(threadId);"
|
||||
on-delete="handleDelete(entryId, docId, threadId);"
|
||||
permissions="permissions"
|
||||
)
|
||||
.rp-loading(ng-if="!resolvedComments.length")
|
||||
| #{translate("no_resolved_threads")}.
|
||||
|
||||
script(type="text/ng-template", id="trackChangesUpgradeModalTemplate")
|
||||
.modal-header
|
||||
button.close(
|
||||
type="button"
|
||||
data-dismiss="modal"
|
||||
ng-click="cancel()"
|
||||
aria-label="Close"
|
||||
)
|
||||
span(aria-hidden="true") ×
|
||||
h3 #{translate("upgrade_to_track_changes")}
|
||||
.modal-body
|
||||
.teaser-video-container
|
||||
video.teaser-video(autoplay, loop)
|
||||
source(ng-src="{{ '/img/teasers/track-changes/teaser-track-changes.mp4' }}", type="video/mp4")
|
||||
img(src="/img/teasers/track-changes/teaser-track-changes.gif")
|
||||
|
||||
h4.teaser-title #{translate("see_changes_in_your_documents_live")}
|
||||
|
||||
p.small(ng-show="startedFreeTrial")
|
||||
| #{translate("refresh_page_after_starting_free_trial")}
|
||||
|
||||
.row
|
||||
.col-md-10.col-md-offset-1
|
||||
ul.list-unstyled
|
||||
li
|
||||
i.fa.fa-check
|
||||
| #{translate("track_any_change_in_real_time")}
|
||||
|
||||
li
|
||||
i.fa.fa-check
|
||||
| #{translate("review_your_peers_work")}
|
||||
|
||||
li
|
||||
i.fa.fa-check
|
||||
| #{translate("accept_or_reject_each_changes_individually")}
|
||||
|
||||
.row.text-center
|
||||
div(ng-show="user.allowedFreeTrial" ng-controller="FreeTrialModalController")
|
||||
a.btn.btn-primary(
|
||||
href
|
||||
ng-click="startFreeTrial('track-changes')"
|
||||
ng-show="project.owner._id == user.id"
|
||||
) #{translate("try_it_for_free")}
|
||||
div(ng-show="!user.allowedFreeTrial" ng-controller="UpgradeModalController")
|
||||
a.btn.btn-primary(
|
||||
href
|
||||
ng-click="upgradePlan('project-sharing')"
|
||||
ng-show="project.owner._id == user.id"
|
||||
) #{translate("upgrade")}
|
||||
p(ng-show="project.owner._id != user.id"): strong #{translate("please_ask_the_project_owner_to_upgrade_to_track_changes")}
|
||||
|
||||
.modal-footer()
|
||||
button.btn.btn-secondary(
|
||||
ng-click="cancel()"
|
||||
)
|
||||
span #{translate("close")}
|
||||
|
||||
script(type="text/ng-template", id="bulkActionsModalTemplate")
|
||||
.modal-header
|
||||
button.close(
|
||||
type="button"
|
||||
data-dismiss="modal"
|
||||
ng-click="cancel()"
|
||||
aria-label="Close"
|
||||
)
|
||||
span(aria-hidden="true") ×
|
||||
h3 {{ isAccept ? '#{translate("accept_all")}' : '#{translate("reject_all")}' }}
|
||||
.modal-body
|
||||
p(ng-if="isAccept") #{translate("bulk_accept_confirm", { nChanges: "{{ nChanges }}"})}
|
||||
p(ng-if="!isAccept") #{translate("bulk_reject_confirm", { nChanges: "{{ nChanges }}"})}
|
||||
.modal-footer()
|
||||
button.btn.btn-secondary(
|
||||
ng-click="cancel()"
|
||||
)
|
||||
span #{translate("cancel")}
|
||||
button.btn.btn-primary(
|
||||
ng-click="confirm()"
|
||||
)
|
||||
span #{translate("ok")}
|
|
@ -1,4 +1,3 @@
|
|||
source-editor#editor(
|
||||
ng-class="{ 'review-panel-react': reviewPanel.isReact }"
|
||||
source-editor.review-panel-react#editor(
|
||||
ng-show="!!editor.sharejs_doc && !editor.opening && multiSelectedCount === 0 && !editor.error_state"
|
||||
)
|
||||
|
|
|
@ -19,8 +19,6 @@ import { dispatchTimer } from '../../../infrastructure/cm6-performance'
|
|||
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
|
||||
import { FigureModal } from './figure-modal/figure-modal'
|
||||
import ReviewPanel from './review-panel/review-panel'
|
||||
import getMeta from '../../../utils/meta'
|
||||
import { useIdeContext } from '@/shared/context/ide-context'
|
||||
|
||||
const sourceEditorComponents = importOverleafModules(
|
||||
'sourceEditorComponents'
|
||||
|
@ -33,8 +31,6 @@ function CodeMirrorEditor() {
|
|||
})
|
||||
|
||||
const isMounted = useIsMounted()
|
||||
const isReviewPanelReact = getMeta('ol-isReviewPanelReact')
|
||||
const { isReactIde } = useIdeContext()
|
||||
|
||||
// create the view using the initial state and intercept transactions
|
||||
const viewRef = useRef<EditorView | null>(null)
|
||||
|
@ -64,7 +60,7 @@ function CodeMirrorEditor() {
|
|||
<CodeMirrorSearch />
|
||||
<CodeMirrorToolbar />
|
||||
<CodeMirrorCommandTooltip />
|
||||
{(isReviewPanelReact || isReactIde) && <ReviewPanel />}
|
||||
<ReviewPanel />
|
||||
{sourceEditorComponents.map(
|
||||
({ import: { default: Component }, path }) => (
|
||||
<Component key={path} />
|
||||
|
|
|
@ -11,11 +11,6 @@ import { EditorView, ViewUpdate } from '@codemirror/view'
|
|||
import { CurrentDoc } from '../../../../../../types/current-doc'
|
||||
import { fullHeightCoordsAtPos } from '../../utils/layer'
|
||||
import { debounce } from 'lodash'
|
||||
import getMeta from '../../../../utils/meta'
|
||||
|
||||
// If a toolbar row sits alongside the review panel, the review panel entries need to be shifted down by 32px.
|
||||
// Once the review panel is always inside the editor, this offset can be removed.
|
||||
const offsetTop = getMeta('ol-isReviewPanelReact') ? 0 : 32
|
||||
|
||||
// With less than this number of entries, don't bother culling to avoid
|
||||
// little UI jumps when scrolling.
|
||||
|
@ -123,7 +118,7 @@ export const createChangeManager = (
|
|||
visibilityChanged = true
|
||||
}
|
||||
|
||||
entry.screenPos = { y: y + offsetTop, height, editorPaddingTop }
|
||||
entry.screenPos = { y, height, editorPaddingTop }
|
||||
entry.inViewport = true
|
||||
} else {
|
||||
entry.inViewport = false
|
||||
|
|
|
@ -5,11 +5,9 @@ import { EditorView } from '@codemirror/view'
|
|||
* changes. This is used to synchronize the editor content and review panel
|
||||
* height in "Current file" mode.
|
||||
*/
|
||||
export const geometryChangeEvent = (reactReviewPanel: boolean) =>
|
||||
reactReviewPanel
|
||||
? EditorView.updateListener.of(update => {
|
||||
if (update.geometryChanged) {
|
||||
window.dispatchEvent(new CustomEvent('editor:geometry-change'))
|
||||
}
|
||||
})
|
||||
: []
|
||||
export const geometryChangeEvent = () =>
|
||||
EditorView.updateListener.of(update => {
|
||||
if (update.geometryChanged) {
|
||||
window.dispatchEvent(new CustomEvent('editor:geometry-change'))
|
||||
}
|
||||
})
|
||||
|
|
|
@ -134,5 +134,5 @@ export const createExtensions = (options: Record<string, any>): Extension[] => [
|
|||
moduleExtensions.map(extension => extension()),
|
||||
thirdPartyExtensions(),
|
||||
effectListeners(),
|
||||
geometryChangeEvent(options.reactReviewPanel),
|
||||
geometryChangeEvent(),
|
||||
]
|
||||
|
|
|
@ -44,7 +44,6 @@ import { EditorView } from '@codemirror/view'
|
|||
import { CurrentDoc } from '../../../../../types/current-doc'
|
||||
import { useErrorHandler } from 'react-error-boundary'
|
||||
import { setVisual } from '../extensions/visual/visual'
|
||||
import getMeta from '../../../utils/meta'
|
||||
import { useFileTreePathContext } from '@/features/file-tree/contexts/file-tree-path'
|
||||
import { useUserSettingsContext } from '@/shared/context/user-settings-context'
|
||||
|
||||
|
@ -87,7 +86,6 @@ function useCodeMirrorScope(view: EditorView) {
|
|||
)
|
||||
|
||||
const [visual] = useScopeValue<boolean>('editor.showVisual')
|
||||
const reactReviewPanel: boolean = getMeta('ol-isReviewPanelReact')
|
||||
|
||||
const [references] = useScopeValue<{ keys: string[] }>('$root._references')
|
||||
|
||||
|
@ -272,7 +270,6 @@ function useCodeMirrorScope(view: EditorView) {
|
|||
visual: visualRef.current,
|
||||
changeManager: createChangeManager(view, currentDoc),
|
||||
handleError,
|
||||
reactReviewPanel,
|
||||
}),
|
||||
})
|
||||
view.setState(state)
|
||||
|
@ -302,7 +299,7 @@ function useCodeMirrorScope(view: EditorView) {
|
|||
}
|
||||
// IMPORTANT: This effect must not depend on anything variable apart from currentDoc,
|
||||
// as the editor state is recreated when the effect runs.
|
||||
}, [view, currentDoc, handleError, reactReviewPanel])
|
||||
}, [view, currentDoc, handleError])
|
||||
|
||||
useEffect(() => {
|
||||
visualRef.current.visual = visual
|
||||
|
|
|
@ -1,18 +1 @@
|
|||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
import './controllers/ReviewPanelController'
|
||||
import './controllers/TrackChangesUpgradeModalController'
|
||||
import './controllers/BulkActionsModalController'
|
||||
import './directives/reviewPanelSorted'
|
||||
import './directives/reviewPanelToggle'
|
||||
import './directives/changeEntry'
|
||||
import './directives/aggregateChangeEntry'
|
||||
import './directives/commentEntry'
|
||||
import './directives/addCommentEntry'
|
||||
import './directives/bulkActionsEntry'
|
||||
import './directives/resolvedCommentEntry'
|
||||
import './directives/resolvedCommentsDropdown'
|
||||
import './directives/reviewPanelCollapseHeight'
|
||||
import './filters/notEmpty'
|
||||
import './filters/numKeys'
|
||||
import './filters/orderOverviewEntries'
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
/* eslint-disable
|
||||
max-len,
|
||||
no-return-assign,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
import App from '../../../base'
|
||||
|
||||
export default App.controller('BulkActionsModalController', [
|
||||
'$scope',
|
||||
'$modalInstance',
|
||||
'isAccept',
|
||||
'nChanges',
|
||||
function ($scope, $modalInstance, isAccept, nChanges) {
|
||||
$scope.isAccept = isAccept
|
||||
$scope.nChanges = nChanges
|
||||
$scope.cancel = () => $modalInstance.dismiss()
|
||||
return ($scope.confirm = () => $modalInstance.close(isAccept))
|
||||
},
|
||||
])
|
|
@ -111,7 +111,6 @@ export default App.controller('ReviewPanelController', [
|
|||
// as only one.
|
||||
nVisibleSelectedChanges: 0,
|
||||
entryHover: false,
|
||||
isReact: getMeta('ol-splitTestVariants')?.['review-panel'] === 'react',
|
||||
}
|
||||
|
||||
ide.$scope.loadingThreads = true
|
||||
|
@ -731,38 +730,6 @@ export default App.controller('ReviewPanelController', [
|
|||
})
|
||||
}
|
||||
|
||||
ide.$scope.showBulkAcceptDialog = () => showBulkActionsDialog(true)
|
||||
|
||||
ide.$scope.showBulkRejectDialog = () => showBulkActionsDialog(false)
|
||||
|
||||
const showBulkActionsDialog = isAccept =>
|
||||
$modal
|
||||
.open({
|
||||
templateUrl: 'bulkActionsModalTemplate',
|
||||
controller: 'BulkActionsModalController',
|
||||
resolve: {
|
||||
isAccept() {
|
||||
return isAccept
|
||||
},
|
||||
nChanges() {
|
||||
return ide.$scope.reviewPanel.nVisibleSelectedChanges
|
||||
},
|
||||
},
|
||||
scope: $scope.$new(),
|
||||
})
|
||||
.result.then(function (isAccept) {
|
||||
if (isAccept) {
|
||||
return ide.$scope.bulkAcceptActions()
|
||||
} else {
|
||||
return ide.$scope.bulkRejectActions()
|
||||
}
|
||||
})
|
||||
|
||||
$scope.handleTogglerClick = function (e) {
|
||||
e.target.blur()
|
||||
return $scope.toggleReviewPanel()
|
||||
}
|
||||
|
||||
ide.$scope.addNewComment = function (e) {
|
||||
e.preventDefault()
|
||||
ide.$scope.$broadcast('comment:start_adding')
|
||||
|
@ -819,19 +786,13 @@ export default App.controller('ReviewPanelController', [
|
|||
eventTracking.sendMB('rp-new-comment', { size: content.length })
|
||||
}
|
||||
|
||||
if (ide.$scope.reviewPanel.isReact === false) {
|
||||
emitCommentAdd()
|
||||
}
|
||||
|
||||
return $http
|
||||
.post(`/project/${$scope.project_id}/thread/${thread_id}/messages`, {
|
||||
content,
|
||||
_csrf: window.csrfToken,
|
||||
})
|
||||
.then(() => {
|
||||
if (ide.$scope.reviewPanel.isReact) {
|
||||
emitCommentAdd()
|
||||
}
|
||||
emitCommentAdd()
|
||||
})
|
||||
.catch(() => {
|
||||
ide.showGenericMessageModal(
|
||||
|
@ -1008,27 +969,6 @@ export default App.controller('ReviewPanelController', [
|
|||
ide.$scope.gotoEntry = (doc_id, entry_offset) =>
|
||||
ide.editorManager.openDocId(doc_id, { gotoOffset: entry_offset })
|
||||
|
||||
$scope.toggleFullTCStateCollapse = function () {
|
||||
if ($scope.project.features.trackChanges) {
|
||||
return (ide.$scope.reviewPanel.fullTCStateCollapsed =
|
||||
!ide.$scope.reviewPanel.fullTCStateCollapsed)
|
||||
} else {
|
||||
_sendAnalytics()
|
||||
return $scope.openTrackChangesUpgradeModal()
|
||||
}
|
||||
}
|
||||
|
||||
const _sendAnalytics = () => {
|
||||
eventTracking.send(
|
||||
'subscription-funnel',
|
||||
'editor-click-feature',
|
||||
'real-time-track-changes'
|
||||
)
|
||||
eventTracking.sendMB('paywall-prompt', {
|
||||
'paywall-type': 'track-changes',
|
||||
})
|
||||
}
|
||||
|
||||
const _setUserTCState = function (userId, newValue, isLocal) {
|
||||
if (isLocal == null) {
|
||||
isLocal = false
|
||||
|
@ -1339,13 +1279,6 @@ export default App.controller('ReviewPanelController', [
|
|||
}
|
||||
}
|
||||
|
||||
$scope.openTrackChangesUpgradeModal = () =>
|
||||
$modal.open({
|
||||
templateUrl: 'trackChangesUpgradeModalTemplate',
|
||||
controller: 'TrackChangesUpgradeModalController',
|
||||
scope: $scope.$new(),
|
||||
})
|
||||
|
||||
// listen for events from the CodeMirror 6 track changes extension
|
||||
window.addEventListener('editor:event', event => {
|
||||
const { type, payload } = event.detail
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
/* eslint-disable
|
||||
max-len,
|
||||
no-return-assign,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
import App from '../../../base'
|
||||
|
||||
export default App.controller('TrackChangesUpgradeModalController', [
|
||||
'$scope',
|
||||
'$modalInstance',
|
||||
function ($scope, $modalInstance) {
|
||||
$scope.cancel = () => $modalInstance.dismiss()
|
||||
},
|
||||
])
|
|
@ -1,62 +0,0 @@
|
|||
import App from '../../../base'
|
||||
let content = ''
|
||||
App.directive('addCommentEntry', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
templateUrl: 'addCommentEntryTemplate',
|
||||
scope: {
|
||||
onStartNew: '&',
|
||||
onSubmit: '&',
|
||||
onCancel: '&',
|
||||
},
|
||||
link(scope, element, attrs) {
|
||||
scope.state = {
|
||||
isAdding: false,
|
||||
content,
|
||||
}
|
||||
|
||||
scope.$on('comment:start_adding', () => scope.startNewComment())
|
||||
scope.$on('$destroy', function () {
|
||||
content = scope.state.content
|
||||
})
|
||||
|
||||
scope.startNewComment = function () {
|
||||
scope.state.isAdding = true
|
||||
scope.onStartNew()
|
||||
setTimeout(() => scope.$broadcast('comment:new:open'))
|
||||
}
|
||||
|
||||
scope.cancelNewComment = function () {
|
||||
scope.state.isAdding = false
|
||||
scope.state.content = ''
|
||||
scope.onCancel()
|
||||
}
|
||||
|
||||
const ignoreKeysInTextAreas = ['PageDown', 'PageUp']
|
||||
|
||||
scope.handleCommentKeyDown = function (ev) {
|
||||
if (ignoreKeysInTextAreas.includes(ev.key)) {
|
||||
if (ev.target.closest('textarea')) {
|
||||
ev.preventDefault()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope.handleCommentKeyPress = function (ev) {
|
||||
if (ev.keyCode === 13 && !ev.shiftKey && !ev.ctrlKey && !ev.metaKey) {
|
||||
ev.preventDefault()
|
||||
if (scope.state.content.length > 0) {
|
||||
scope.submitNewComment()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope.submitNewComment = function (event) {
|
||||
scope.onSubmit({ content: scope.state.content })
|
||||
content = scope.state.content
|
||||
scope.state.isAdding = false
|
||||
scope.state.content = ''
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
|
@ -1,74 +0,0 @@
|
|||
/* eslint-disable
|
||||
max-len,
|
||||
no-return-assign,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
import App from '../../../base'
|
||||
|
||||
export default App.directive('aggregateChangeEntry', [
|
||||
'$timeout',
|
||||
function ($timeout) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
templateUrl: 'aggregateChangeEntryTemplate',
|
||||
scope: {
|
||||
entry: '=',
|
||||
user: '=',
|
||||
permissions: '=',
|
||||
onAccept: '&',
|
||||
onReject: '&',
|
||||
onIndicatorClick: '&',
|
||||
onMouseEnter: '&',
|
||||
onMouseLeave: '&',
|
||||
onBodyClick: '&',
|
||||
},
|
||||
link(scope, element, attrs) {
|
||||
scope.contentLimit = 17
|
||||
scope.isDeletionCollapsed = true
|
||||
scope.isInsertionCollapsed = true
|
||||
scope.deletionNeedsCollapsing = false
|
||||
scope.insertionNeedsCollapsing = false
|
||||
|
||||
element.on('click', function (e) {
|
||||
if (
|
||||
$(e.target).is(
|
||||
'.rp-entry, .rp-entry-description, .rp-entry-body, .rp-entry-action-icon i'
|
||||
)
|
||||
) {
|
||||
return scope.onBodyClick()
|
||||
}
|
||||
})
|
||||
|
||||
scope.toggleDeletionCollapse = function () {
|
||||
scope.isDeletionCollapsed = !scope.isDeletionCollapsed
|
||||
return $timeout(() => scope.$emit('review-panel:layout'))
|
||||
}
|
||||
|
||||
scope.toggleInsertionCollapse = function () {
|
||||
scope.isInsertionCollapsed = !scope.isInsertionCollapsed
|
||||
return $timeout(() => scope.$emit('review-panel:layout'))
|
||||
}
|
||||
|
||||
scope.$watch(
|
||||
'entry.metadata.replaced_content.length',
|
||||
deletionContentLength =>
|
||||
(scope.deletionNeedsCollapsing =
|
||||
deletionContentLength > scope.contentLimit)
|
||||
)
|
||||
|
||||
return scope.$watch(
|
||||
'entry.content.length',
|
||||
insertionContentLength =>
|
||||
(scope.insertionNeedsCollapsing =
|
||||
insertionContentLength > scope.contentLimit)
|
||||
)
|
||||
},
|
||||
}
|
||||
},
|
||||
])
|
|
@ -1,27 +0,0 @@
|
|||
/* eslint-disable
|
||||
no-return-assign,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
import App from '../../../base'
|
||||
|
||||
export default App.directive('bulkActionsEntry', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
templateUrl: 'bulkActionsEntryTemplate',
|
||||
scope: {
|
||||
onBulkAccept: '&',
|
||||
onBulkReject: '&',
|
||||
nEntries: '=',
|
||||
},
|
||||
link(scope, element, attrs) {
|
||||
scope.bulkAccept = () => scope.onBulkAccept()
|
||||
return (scope.bulkReject = () => scope.onBulkReject())
|
||||
},
|
||||
}
|
||||
})
|
|
@ -1,59 +0,0 @@
|
|||
/* eslint-disable
|
||||
max-len,
|
||||
no-return-assign,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
import App from '../../../base'
|
||||
|
||||
export default App.directive('changeEntry', [
|
||||
'$timeout',
|
||||
function ($timeout) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
templateUrl: 'changeEntryTemplate',
|
||||
scope: {
|
||||
entry: '=',
|
||||
user: '=',
|
||||
permissions: '=',
|
||||
onAccept: '&',
|
||||
onReject: '&',
|
||||
onIndicatorClick: '&',
|
||||
onMouseEnter: '&',
|
||||
onMouseLeave: '&',
|
||||
onBodyClick: '&',
|
||||
},
|
||||
link(scope, element, attrs) {
|
||||
scope.contentLimit = 40
|
||||
scope.isCollapsed = true
|
||||
scope.needsCollapsing = false
|
||||
|
||||
element.on('click', function (e) {
|
||||
if (
|
||||
$(e.target).is(
|
||||
'.rp-entry, .rp-entry-description, .rp-entry-body, .rp-entry-action-icon i'
|
||||
)
|
||||
) {
|
||||
return scope.onBodyClick()
|
||||
}
|
||||
})
|
||||
|
||||
scope.toggleCollapse = function () {
|
||||
scope.isCollapsed = !scope.isCollapsed
|
||||
return $timeout(() => scope.$emit('review-panel:layout'))
|
||||
}
|
||||
|
||||
return scope.$watch(
|
||||
'entry.content.length',
|
||||
contentLength =>
|
||||
(scope.needsCollapsing = contentLength > scope.contentLimit)
|
||||
)
|
||||
},
|
||||
}
|
||||
},
|
||||
])
|
|
@ -1,97 +0,0 @@
|
|||
/* eslint-disable
|
||||
max-len,
|
||||
no-return-assign,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
import App from '../../../base'
|
||||
|
||||
export default App.directive('commentEntry', [
|
||||
'$timeout',
|
||||
function ($timeout) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
templateUrl: 'commentEntryTemplate',
|
||||
scope: {
|
||||
entry: '=',
|
||||
threads: '=',
|
||||
permissions: '=',
|
||||
onResolve: '&',
|
||||
onReply: '&',
|
||||
onIndicatorClick: '&',
|
||||
onMouseEnter: '&',
|
||||
onMouseLeave: '&',
|
||||
onSaveEdit: '&',
|
||||
onDelete: '&',
|
||||
onBodyClick: '&',
|
||||
},
|
||||
link(scope, element, attrs) {
|
||||
scope.state = { animating: false }
|
||||
|
||||
element.on('click', function (e) {
|
||||
if (
|
||||
$(e.target).is(
|
||||
'.rp-entry, .rp-comment-loaded, .rp-comment-content, .rp-comment-reply, .rp-entry-metadata'
|
||||
)
|
||||
) {
|
||||
return scope.onBodyClick()
|
||||
}
|
||||
})
|
||||
|
||||
scope.handleCommentReplyKeyPress = function (ev) {
|
||||
if (ev.keyCode === 13 && !ev.shiftKey && !ev.ctrlKey && !ev.metaKey) {
|
||||
ev.preventDefault()
|
||||
if (scope.entry.replyContent.length > 0) {
|
||||
ev.target.blur()
|
||||
return scope.onReply()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope.animateAndCallOnResolve = function () {
|
||||
scope.state.animating = true
|
||||
element.find('.rp-entry').css('top', 0)
|
||||
$timeout(() => scope.onResolve(), 350)
|
||||
return true
|
||||
}
|
||||
|
||||
scope.startEditing = function (comment) {
|
||||
comment.editing = true
|
||||
return setTimeout(() => scope.$emit('review-panel:layout'))
|
||||
}
|
||||
|
||||
scope.saveEdit = function (comment) {
|
||||
comment.editing = false
|
||||
return scope.onSaveEdit({ comment })
|
||||
}
|
||||
|
||||
scope.confirmDelete = function (comment) {
|
||||
comment.deleting = true
|
||||
return setTimeout(() => scope.$emit('review-panel:layout'))
|
||||
}
|
||||
|
||||
scope.cancelDelete = function (comment) {
|
||||
comment.deleting = false
|
||||
return setTimeout(() => scope.$emit('review-panel:layout'))
|
||||
}
|
||||
|
||||
scope.doDelete = function (comment) {
|
||||
comment.deleting = false
|
||||
return scope.onDelete({ comment })
|
||||
}
|
||||
|
||||
return (scope.saveEditOnEnter = function (ev, comment) {
|
||||
if (ev.keyCode === 13 && !ev.shiftKey && !ev.ctrlKey && !ev.metaKey) {
|
||||
ev.preventDefault()
|
||||
return scope.saveEdit(comment)
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
},
|
||||
])
|
|
@ -1,38 +0,0 @@
|
|||
/* eslint-disable
|
||||
max-len,
|
||||
no-return-assign,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
import App from '../../../base'
|
||||
|
||||
export default App.directive('resolvedCommentEntry', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
templateUrl: 'resolvedCommentEntryTemplate',
|
||||
scope: {
|
||||
thread: '=',
|
||||
permissions: '=',
|
||||
onUnresolve: '&',
|
||||
onDelete: '&',
|
||||
},
|
||||
link(scope, element, attrs) {
|
||||
scope.contentLimit = 40
|
||||
scope.needsCollapsing = false
|
||||
scope.isCollapsed = true
|
||||
|
||||
scope.toggleCollapse = () => (scope.isCollapsed = !scope.isCollapsed)
|
||||
|
||||
return scope.$watch(
|
||||
'thread.content.length',
|
||||
contentLength =>
|
||||
(scope.needsCollapsing = contentLength > scope.contentLimit)
|
||||
)
|
||||
},
|
||||
}
|
||||
})
|
|
@ -1,111 +0,0 @@
|
|||
import _ from 'lodash'
|
||||
/* eslint-disable
|
||||
max-len,
|
||||
no-return-assign,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS205: Consider reworking code to avoid use of IIFEs
|
||||
* DS207: Consider shorter variations of null checks
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
import App from '../../../base'
|
||||
|
||||
export default App.directive('resolvedCommentsDropdown', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
templateUrl: 'resolvedCommentsDropdownTemplate',
|
||||
scope: {
|
||||
entries: '=',
|
||||
threads: '=',
|
||||
resolvedIds: '=',
|
||||
docs: '=',
|
||||
permissions: '=',
|
||||
onOpen: '&',
|
||||
onUnresolve: '&',
|
||||
onDelete: '&',
|
||||
isLoading: '=',
|
||||
},
|
||||
|
||||
link(scope, element, attrs) {
|
||||
let filterResolvedComments
|
||||
scope.state = { isOpen: false }
|
||||
|
||||
scope.toggleOpenState = function () {
|
||||
scope.state.isOpen = !scope.state.isOpen
|
||||
if (scope.state.isOpen) {
|
||||
return scope.onOpen().then(() => filterResolvedComments())
|
||||
}
|
||||
}
|
||||
|
||||
scope.resolvedComments = []
|
||||
|
||||
scope.handleUnresolve = function (threadId) {
|
||||
scope.onUnresolve({ threadId })
|
||||
return (scope.resolvedComments = scope.resolvedComments.filter(
|
||||
c => c.threadId !== threadId
|
||||
))
|
||||
}
|
||||
|
||||
scope.handleDelete = function (entryId, docId, threadId) {
|
||||
scope.onDelete({ entryId, docId, threadId })
|
||||
return (scope.resolvedComments = scope.resolvedComments.filter(
|
||||
c => c.threadId !== threadId
|
||||
))
|
||||
}
|
||||
|
||||
const getDocNameById = function (docId) {
|
||||
const doc = _.find(scope.docs, doc => doc.doc.id === docId)
|
||||
if (doc != null) {
|
||||
return doc.path
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
return (filterResolvedComments = function () {
|
||||
scope.resolvedComments = []
|
||||
|
||||
return (() => {
|
||||
const result = []
|
||||
for (const docId in scope.entries) {
|
||||
const docEntries = scope.entries[docId]
|
||||
result.push(
|
||||
(() => {
|
||||
const result1 = []
|
||||
for (const entryId in docEntries) {
|
||||
const entry = docEntries[entryId]
|
||||
if (
|
||||
entry.type === 'comment' &&
|
||||
(scope.threads[entry.thread_id] != null
|
||||
? scope.threads[entry.thread_id].resolved
|
||||
: undefined) != null
|
||||
) {
|
||||
const resolvedComment = angular.copy(
|
||||
scope.threads[entry.thread_id]
|
||||
)
|
||||
|
||||
resolvedComment.content = entry.content
|
||||
resolvedComment.threadId = entry.thread_id
|
||||
resolvedComment.entryId = entryId
|
||||
resolvedComment.docId = docId
|
||||
resolvedComment.docName = getDocNameById(docId)
|
||||
|
||||
result1.push(scope.resolvedComments.push(resolvedComment))
|
||||
} else {
|
||||
result1.push(undefined)
|
||||
}
|
||||
}
|
||||
return result1
|
||||
})()
|
||||
)
|
||||
}
|
||||
return result
|
||||
})()
|
||||
})
|
||||
},
|
||||
}
|
||||
})
|
|
@ -1,39 +0,0 @@
|
|||
/* eslint-disable
|
||||
max-len,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
import App from '../../../base'
|
||||
|
||||
export default App.directive('reviewPanelCollapseHeight', [
|
||||
'$parse',
|
||||
function ($parse) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link(scope, element, attrs) {
|
||||
return scope.$watch(
|
||||
() => $parse(attrs.reviewPanelCollapseHeight)(scope),
|
||||
function (shouldCollapse) {
|
||||
const neededHeight = element.prop('scrollHeight')
|
||||
if (neededHeight > 0) {
|
||||
if (shouldCollapse) {
|
||||
return element.animate({ height: 0 }, 150)
|
||||
} else {
|
||||
return element.animate({ height: neededHeight }, 150)
|
||||
}
|
||||
} else {
|
||||
if (shouldCollapse) {
|
||||
return element.height(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
}
|
||||
},
|
||||
])
|
|
@ -1,294 +0,0 @@
|
|||
/* eslint-disable
|
||||
camelcase,
|
||||
max-len,
|
||||
no-return-assign,
|
||||
no-unused-vars,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS101: Remove unnecessary use of Array.from
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS207: Consider shorter variations of null checks
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
import App from '../../../base'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
|
||||
export default App.directive('reviewPanelSorted', function () {
|
||||
return {
|
||||
link(scope, element, attrs) {
|
||||
let previous_focused_entry_index = 0
|
||||
|
||||
const applyEntryVisibility = function (entry) {
|
||||
const visible = entry.scope.entry.screenPos
|
||||
if (visible) {
|
||||
entry.$wrapper_el.removeClass('rp-entry-hidden')
|
||||
} else {
|
||||
entry.$wrapper_el.addClass('rp-entry-hidden')
|
||||
}
|
||||
return visible
|
||||
}
|
||||
|
||||
const layout = function (animate) {
|
||||
let entry,
|
||||
height,
|
||||
i,
|
||||
original_top,
|
||||
overflowTop,
|
||||
screenPosHeight,
|
||||
OVERVIEW_TOGGLE_HEIGHT,
|
||||
PADDING,
|
||||
TOOLBAR_HEIGHT,
|
||||
top
|
||||
if (animate == null) {
|
||||
animate = true
|
||||
}
|
||||
if (animate) {
|
||||
element.removeClass('no-animate')
|
||||
} else {
|
||||
element.addClass('no-animate')
|
||||
}
|
||||
if (scope.ui.reviewPanelOpen) {
|
||||
PADDING = 8
|
||||
TOOLBAR_HEIGHT = 38
|
||||
OVERVIEW_TOGGLE_HEIGHT = 57
|
||||
} else {
|
||||
PADDING = 4
|
||||
TOOLBAR_HEIGHT = 4
|
||||
OVERVIEW_TOGGLE_HEIGHT = 0
|
||||
}
|
||||
|
||||
const entries = []
|
||||
for (const el of Array.from(element.find('.rp-entry-wrapper'))) {
|
||||
entry = {
|
||||
$wrapper_el: $(el),
|
||||
$indicator_el: $(el).find('.rp-entry-indicator'),
|
||||
$box_el: $(el).find('.rp-entry'),
|
||||
$callout_el: $(el).find('.rp-entry-callout'),
|
||||
scope: angular.element(el).scope(),
|
||||
}
|
||||
if (scope.ui.reviewPanelOpen) {
|
||||
entry.$layout_el = entry.$box_el
|
||||
} else {
|
||||
entry.$layout_el = entry.$indicator_el
|
||||
}
|
||||
entry.height = entry.$layout_el.height() // Do all of our DOM reads first for performance, see http://wilsonpage.co.uk/preventing-layout-thrashing/
|
||||
entries.push(entry)
|
||||
}
|
||||
entries.sort((a, b) => a.scope.entry.offset - b.scope.entry.offset)
|
||||
|
||||
if (entries.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const line_height = scope.reviewPanel.rendererData.lineHeight
|
||||
|
||||
let focused_entry_index = Math.min(
|
||||
previous_focused_entry_index,
|
||||
entries.length - 1
|
||||
)
|
||||
for (i = 0; i < entries.length; i++) {
|
||||
entry = entries[i]
|
||||
if (entry.scope.entry.focused) {
|
||||
focused_entry_index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const focused_entry = entries[focused_entry_index]
|
||||
const focusedEntryVisible = applyEntryVisibility(focused_entry)
|
||||
|
||||
// If the focused entry has no screenPos, we can't position other entries
|
||||
// relative to it, so we position all other entries as though the focused
|
||||
// entry is at the top and they all follow it
|
||||
const entries_after = focusedEntryVisible
|
||||
? entries.slice(focused_entry_index + 1)
|
||||
: [...entries]
|
||||
const entries_before = focusedEntryVisible
|
||||
? entries.slice(0, focused_entry_index)
|
||||
: []
|
||||
previous_focused_entry_index = focused_entry_index
|
||||
|
||||
debugConsole.log('focused_entry_index', focused_entry_index)
|
||||
|
||||
const positionLayoutEl = function (
|
||||
$callout_el,
|
||||
original_top,
|
||||
top,
|
||||
height
|
||||
) {
|
||||
if (original_top <= top) {
|
||||
$callout_el.removeClass('rp-entry-callout-inverted')
|
||||
return $callout_el.css({
|
||||
top: original_top + height - 1,
|
||||
height: top - original_top,
|
||||
})
|
||||
} else {
|
||||
$callout_el.addClass('rp-entry-callout-inverted')
|
||||
return $callout_el.css({
|
||||
top: top + height,
|
||||
height: original_top - top,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Put the focused entry as close to where it wants to be as possible
|
||||
let focused_entry_top = 0
|
||||
let previousBottom = 0
|
||||
|
||||
if (focusedEntryVisible) {
|
||||
const focusedEntryScreenPos = focused_entry.scope.entry.screenPos
|
||||
focused_entry_top = Math.max(focusedEntryScreenPos.y, TOOLBAR_HEIGHT)
|
||||
focused_entry.$box_el.css({
|
||||
top: focused_entry_top,
|
||||
// The entry element is invisible by default, to avoid flickering when positioning for
|
||||
// the first time. Here we make sure it becomes visible after having a "top" value.
|
||||
visibility: 'visible',
|
||||
})
|
||||
focused_entry.$indicator_el.css({ top: focused_entry_top })
|
||||
// use screenPos.height if set
|
||||
screenPosHeight = focusedEntryScreenPos.height ?? line_height
|
||||
positionLayoutEl(
|
||||
focused_entry.$callout_el,
|
||||
focusedEntryScreenPos.y,
|
||||
focused_entry_top,
|
||||
screenPosHeight
|
||||
)
|
||||
previousBottom = focused_entry_top + focused_entry.$layout_el.height()
|
||||
}
|
||||
|
||||
for (entry of entries_after) {
|
||||
const entryVisible = applyEntryVisibility(entry)
|
||||
if (entryVisible) {
|
||||
original_top = entry.scope.entry.screenPos.y
|
||||
// use screenPos.height if set
|
||||
screenPosHeight = entry.scope.entry.screenPos.height ?? line_height
|
||||
;({ height } = entry)
|
||||
top = Math.max(original_top, previousBottom + PADDING)
|
||||
previousBottom = top + height
|
||||
entry.$box_el.css({
|
||||
top,
|
||||
// The entry element is invisible by default, to avoid flickering when positioning for
|
||||
// the first time. Here we make sure it becomes visible after having a "top" value.
|
||||
visibility: 'visible',
|
||||
})
|
||||
entry.$indicator_el.css({ top })
|
||||
positionLayoutEl(
|
||||
entry.$callout_el,
|
||||
original_top,
|
||||
top,
|
||||
screenPosHeight
|
||||
)
|
||||
}
|
||||
debugConsole.log('ENTRY', { entry: entry.scope.entry, top })
|
||||
}
|
||||
|
||||
let previousTop = focused_entry_top
|
||||
entries_before.reverse() // Work through backwards, starting with the one just above
|
||||
for (entry of entries_before) {
|
||||
const entryVisible = applyEntryVisibility(entry)
|
||||
if (entryVisible) {
|
||||
original_top = entry.scope.entry.screenPos.y
|
||||
// use screenPos.height if set
|
||||
screenPosHeight = entry.scope.entry.screenPos.height ?? line_height
|
||||
;({ height } = entry)
|
||||
const original_bottom = original_top + height
|
||||
const bottom = Math.min(original_bottom, previousTop - PADDING)
|
||||
top = bottom - height
|
||||
previousTop = top
|
||||
entry.$box_el.css({
|
||||
top,
|
||||
// The entry element is invisible by default, to avoid flickering when positioning for
|
||||
// the first time. Here we make sure it becomes visible after having a "top" value.
|
||||
visibility: 'visible',
|
||||
})
|
||||
entry.$indicator_el.css({ top })
|
||||
positionLayoutEl(
|
||||
entry.$callout_el,
|
||||
original_top,
|
||||
top,
|
||||
screenPosHeight
|
||||
)
|
||||
}
|
||||
debugConsole.log('ENTRY', { entry: entry.scope.entry, top })
|
||||
}
|
||||
|
||||
const lastTop = top
|
||||
if (lastTop < TOOLBAR_HEIGHT) {
|
||||
overflowTop = -lastTop + TOOLBAR_HEIGHT
|
||||
} else {
|
||||
overflowTop = 0
|
||||
}
|
||||
|
||||
return scope.$emit('review-panel:sizes', {
|
||||
overflowTop,
|
||||
height: previousBottom + OVERVIEW_TOGGLE_HEIGHT,
|
||||
})
|
||||
}
|
||||
|
||||
scope.$applyAsync(() => layout())
|
||||
|
||||
scope.$on('review-panel:layout', function (e, animate) {
|
||||
if (animate == null) {
|
||||
animate = true
|
||||
}
|
||||
return scope.$applyAsync(() => layout(animate))
|
||||
})
|
||||
|
||||
scope.$watch('reviewPanel.rendererData.lineHeight', () => layout())
|
||||
|
||||
// # Scroll lock with Ace
|
||||
const scroller = element
|
||||
const list = element.find('.rp-entry-list-inner')
|
||||
|
||||
// If we listen for scroll events in the review panel natively, then with a Mac trackpad
|
||||
// the scroll is very smooth (natively done I'd guess), but we don't get polled regularly
|
||||
// enough to keep Ace in step, and it noticeably lags. If instead, we borrow the manual
|
||||
// mousewheel/trackpad scrolling behaviour from Ace, and turn mousewheel events into
|
||||
// scroll events ourselves, then it makes the review panel slightly less smooth (barely)
|
||||
// noticeable, but keeps it perfectly in step with Ace.
|
||||
scroller[0].addEventListener('wheel', e => {
|
||||
// FIXME (or remove this): https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
|
||||
const deltaY = e.wheelY
|
||||
const old_top = parseInt(list.css('top'))
|
||||
const top = old_top - deltaY * 4
|
||||
dispatchScrollEvent(deltaY * 4)
|
||||
return e.preventDefault()
|
||||
})
|
||||
|
||||
// We always scroll by telling Ace to scroll and then updating the
|
||||
// review panel. This lets Ace manage the size of the scroller and
|
||||
// when it overflows.
|
||||
let ignoreNextAceEvent = false
|
||||
|
||||
const scrollPanel = function (scrollTop, height) {
|
||||
if (ignoreNextAceEvent) {
|
||||
return (ignoreNextAceEvent = false)
|
||||
} else {
|
||||
list.height(height)
|
||||
return list.css({ top: -scrollTop })
|
||||
}
|
||||
}
|
||||
|
||||
// receive the scroll position from the CodeMirror 6 track changes extension
|
||||
window.addEventListener('editor:scroll', event => {
|
||||
const { scrollTop, height, paddingTop } = event.detail
|
||||
|
||||
scrollPanel(scrollTop - paddingTop, height)
|
||||
})
|
||||
|
||||
// Send scroll delta to the CodeMirror 6 track changes extension
|
||||
const dispatchScrollEvent = scrollTopDelta => {
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('review-panel:event', {
|
||||
detail: { type: 'scroll', payload: scrollTopDelta },
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
return scope.reviewPanelEventsBridge.emit('refreshScrollPosition')
|
||||
},
|
||||
}
|
||||
})
|
|
@ -1,53 +0,0 @@
|
|||
/* eslint-disable
|
||||
max-len,
|
||||
no-return-assign,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS207: Consider shorter variations of null checks
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
import App from '../../../base'
|
||||
|
||||
export default App.directive('reviewPanelToggle', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
onToggle: '&',
|
||||
ngModel: '=',
|
||||
valWhenUndefined: '=?',
|
||||
isDisabled: '=?',
|
||||
onDisabledClick: '&?',
|
||||
description: '@',
|
||||
},
|
||||
link(scope) {
|
||||
if (scope.disabled == null) {
|
||||
scope.disabled = false
|
||||
}
|
||||
scope.onChange = (...args) => scope.onToggle({ isOn: scope.localModel })
|
||||
scope.handleClick = function () {
|
||||
if (scope.disabled && scope.onDisabledClick != null) {
|
||||
return scope.onDisabledClick()
|
||||
}
|
||||
}
|
||||
scope.localModel = scope.ngModel
|
||||
return scope.$watch('ngModel', function (value) {
|
||||
if (scope.valWhenUndefined != null && value == null) {
|
||||
value = scope.valWhenUndefined
|
||||
}
|
||||
return (scope.localModel = value)
|
||||
})
|
||||
},
|
||||
|
||||
template: `\
|
||||
<fieldset class="input-switch" ng-click="handleClick();">
|
||||
<legend class="sr-only">{{description}}</legend>
|
||||
<input id="input-switch-{{$id}}" ng-disabled="isDisabled" type="checkbox" class="input-switch-hidden-input" ng-model="localModel" ng-change="onChange()" />
|
||||
<label for="input-switch-{{$id}}" class="input-switch-btn"></label>
|
||||
</fieldset>\
|
||||
`,
|
||||
}
|
||||
})
|
|
@ -1,12 +0,0 @@
|
|||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
import App from '../../../base'
|
||||
export default App.filter(
|
||||
'notEmpty',
|
||||
() => object => !angular.equals({}, object)
|
||||
)
|
|
@ -1,21 +0,0 @@
|
|||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS207: Consider shorter variations of null checks
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
import App from '../../../base'
|
||||
|
||||
export default App.filter(
|
||||
'numKeys',
|
||||
() =>
|
||||
function (object) {
|
||||
if (object != null) {
|
||||
return Object.keys(object).length
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
)
|
|
@ -1,23 +0,0 @@
|
|||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
import App from '../../../base'
|
||||
|
||||
export default App.filter(
|
||||
'orderOverviewEntries',
|
||||
() =>
|
||||
function (items) {
|
||||
const array = []
|
||||
for (const key in items) {
|
||||
const value = items[key]
|
||||
value.entry_id = key
|
||||
array.push(value)
|
||||
}
|
||||
array.sort((a, b) => a.offset - b.offset)
|
||||
return array
|
||||
}
|
||||
)
|
|
@ -13,7 +13,6 @@ function Container(props: ContainerProps) {
|
|||
|
||||
describe('<ReviewPanel />', function () {
|
||||
beforeEach(function () {
|
||||
window.metaAttributesCache.set('ol-isReviewPanelReact', true)
|
||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||
|
||||
cy.interceptEvents()
|
||||
|
|
Loading…
Reference in a new issue