Remove Angular/Pug review panel code (#15935)

GitOrigin-RevId: de782d4b47d987f6434a34bea487568b269e8d85
This commit is contained in:
Alf Eaton 2023-11-28 11:23:55 +00:00 committed by Copybot
parent 9875e55a27
commit d40de2018c
28 changed files with 12 additions and 1732 deletions

View file

@ -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,

View file

@ -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)

View file

@ -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)

View file

@ -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")}

View file

@ -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"
)

View file

@ -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} />

View file

@ -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

View file

@ -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'))
}
})

View file

@ -134,5 +134,5 @@ export const createExtensions = (options: Record<string, any>): Extension[] => [
moduleExtensions.map(extension => extension()),
thirdPartyExtensions(),
effectListeners(),
geometryChangeEvent(options.reactReviewPanel),
geometryChangeEvent(),
]

View file

@ -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

View file

@ -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'

View file

@ -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))
},
])

View file

@ -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

View file

@ -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()
},
])

View file

@ -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 = ''
}
},
}
})

View file

@ -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)
)
},
}
},
])

View file

@ -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())
},
}
})

View file

@ -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)
)
},
}
},
])

View file

@ -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)
}
})
},
}
},
])

View file

@ -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)
)
},
}
})

View file

@ -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
})()
})
},
}
})

View file

@ -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)
}
}
}
)
},
}
},
])

View file

@ -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')
},
}
})

View file

@ -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>\
`,
}
})

View file

@ -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)
)

View file

@ -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
}
}
)

View file

@ -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
}
)

View file

@ -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()