mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #1626 from sharelatex/pr-history-drag-and-drop-selection
History drag and drop selection GitOrigin-RevId: d2bc0dfc2e2634553224b7bef2ac5d926d42bf01
This commit is contained in:
parent
ca9e6044c8
commit
9c5c6922b9
20 changed files with 843 additions and 472 deletions
|
@ -162,6 +162,9 @@ block requirejs
|
|||
"ace/keybinding-vim": {
|
||||
"deps": ["ace/ace"]
|
||||
},
|
||||
"libs/jquery.ui.touch-punch": {
|
||||
"deps": [ "libs/#{lib('jquery-layout')}" ]
|
||||
}
|
||||
},
|
||||
"config":{
|
||||
"moment":{
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
aside.change-list(
|
||||
ng-if="history.isV2 && history.viewMode === HistoryViewModes.POINT_IN_TIME"
|
||||
ng-if="history.isV2"
|
||||
ng-controller="HistoryV2ListController"
|
||||
)
|
||||
history-entries-list(
|
||||
ng-if="!history.showOnlyLabels && !history.error"
|
||||
entries="history.updates"
|
||||
range-selection-enabled="history.viewMode === HistoryViewModes.COMPARE"
|
||||
selected-history-version="history.selection.range.toV"
|
||||
selected-history-range="history.selection.range"
|
||||
current-user="user"
|
||||
current-user-is-owner="project.owner._id === user.id"
|
||||
users="projectUsers"
|
||||
|
@ -14,232 +16,23 @@ aside.change-list(
|
|||
load-initialize="ui.view == 'history'"
|
||||
is-loading="history.loading"
|
||||
free-history-limit-hit="history.freeHistoryLimitHit"
|
||||
on-entry-select="handleEntrySelect(selectedEntry)"
|
||||
on-version-select="handleVersionSelect(version)"
|
||||
on-range-select="handleRangeSelect(selectedToV, selectedFromV)"
|
||||
on-label-delete="handleLabelDelete(label)"
|
||||
)
|
||||
history-labels-list(
|
||||
ng-if="history.showOnlyLabels && !history.error"
|
||||
labels="history.labels"
|
||||
range-selection-enabled="history.viewMode === HistoryViewModes.COMPARE"
|
||||
selected-history-version="history.selection.range.toV"
|
||||
selected-history-range="history.selection.range"
|
||||
current-user="user"
|
||||
users="projectUsers"
|
||||
is-loading="history.loading"
|
||||
selected-label="history.selection.label"
|
||||
on-label-select="handleLabelSelect(label)"
|
||||
on-version-select="handleVersionSelect(version)"
|
||||
on-range-select="handleRangeSelect(selectedToV, selectedFromV)"
|
||||
on-label-delete="handleLabelDelete(label)"
|
||||
)
|
||||
aside.change-list.change-list-compare(
|
||||
ng-if="history.isV2 && history.viewMode === HistoryViewModes.COMPARE"
|
||||
ng-controller="HistoryCompareController"
|
||||
)
|
||||
div(
|
||||
ng-if="!history.showOnlyLabels && !history.error"
|
||||
)
|
||||
aside.change-list(
|
||||
infinite-scroll="loadMore()"
|
||||
infinite-scroll-disabled="history.loading || history.atEnd"
|
||||
infinite-scroll-initialize="ui.view == 'history' && history.viewMode === HistoryViewModes.COMPARE"
|
||||
)
|
||||
.infinite-scroll-inner
|
||||
ul.list-unstyled(
|
||||
ng-class="{\
|
||||
'hover-state': history.hoveringOverListSelectors\
|
||||
}"
|
||||
)
|
||||
li.change(
|
||||
ng-repeat="update in history.updates track by update.fromV"
|
||||
ng-class="{\
|
||||
'first-in-day': update.meta.first_in_day,\
|
||||
'selected': update.toV <= history.selection.range.toV && update.fromV >= history.selection.range.fromV,\
|
||||
'selected-to': update.toV === history.selection.range.toV,\
|
||||
'selected-from': update.fromV === history.selection.range.fromV,\
|
||||
'hover-selected': update.toV <= history.selection.hoveredRange.toV && update.fromV >= history.selection.hoveredRange.fromV,\
|
||||
'hover-selected-to': update.toV === history.selection.hoveredRange.toV,\
|
||||
'hover-selected-from': update.fromV === history.selection.hoveredRange.fromV,\
|
||||
}"
|
||||
)
|
||||
|
||||
div.day(ng-if="::update.meta.first_in_day") {{ ::update.meta.end_ts | relativeDate }}
|
||||
|
||||
div.selectors
|
||||
div.range
|
||||
form
|
||||
input.selector-from(
|
||||
type="radio"
|
||||
name="fromVersion"
|
||||
ng-model="history.selection.range.fromV"
|
||||
ng-value="update.fromV"
|
||||
ng-mouseover="setHoverFrom(update.fromV)"
|
||||
ng-mouseout="resetHover()"
|
||||
ng-show="update.fromV < history.selection.range.fromV || update.toV <= history.selection.range.toV && update.fromV >= history.selection.range.fromV"
|
||||
)
|
||||
form
|
||||
input.selector-to(
|
||||
type="radio"
|
||||
name="toVersion"
|
||||
ng-model="history.selection.range.toV"
|
||||
ng-value="update.toV"
|
||||
ng-mouseover="setHoverTo(update.toV)"
|
||||
ng-mouseout="resetHover()"
|
||||
ng-show="update.toV > history.selection.range.toV || update.toV <= history.selection.range.toV && update.fromV >= history.selection.range.fromV"
|
||||
)
|
||||
|
||||
div.description(ng-click="select(update.toV, update.fromV)")
|
||||
history-label(
|
||||
ng-repeat="label in update.labels track by label.id"
|
||||
label-text="label.comment"
|
||||
label-owner-name="getDisplayNameById(label.user_id)"
|
||||
label-creation-date-time="label.created_at"
|
||||
is-owned-by-current-user="label.user_id === user.id"
|
||||
on-label-delete="deleteLabel(label)"
|
||||
)
|
||||
div.time {{ ::update.meta.end_ts | formatDate:'h:mm a' }}
|
||||
div.action.action-edited(ng-if="::history.isV2 && update.pathnames.length > 0")
|
||||
| #{translate("file_action_edited")}
|
||||
div.docs(ng-repeat="pathname in ::update.pathnames")
|
||||
.doc {{ ::pathname }}
|
||||
div.docs(ng-repeat="project_op in ::update.project_ops")
|
||||
div(ng-if="::project_op.rename")
|
||||
.action #{translate("file_action_renamed")}
|
||||
.doc {{ ::project_op.rename.pathname }} → {{ ::project_op.rename.newPathname }}
|
||||
div(ng-if="::project_op.add")
|
||||
.action #{translate("file_action_created")}
|
||||
.doc {{ ::project_op.add.pathname }}
|
||||
div(ng-if="::project_op.remove")
|
||||
.action #{translate("file_action_deleted")}
|
||||
.doc {{ ::project_op.remove.pathname }}
|
||||
div.users
|
||||
div.user(ng-repeat="update_user in ::update.meta.users")
|
||||
.color-square(ng-if="::update_user != null", ng-style="::{'background-color': 'hsl({{ update_user.hue }}, 70%, 50%)'}")
|
||||
.color-square(ng-if="::update_user == null", ng-style="::{'background-color': 'hsl(100, 70%, 50%)'}")
|
||||
.name(ng-if="::update_user && update_user.id != user.id" ng-bind="getDisplayNameForUser(update_user)")
|
||||
.name(ng-if="::update_user && update_user.id == user.id") You
|
||||
.name(ng-if="::update_user == null") #{translate("anonymous")}
|
||||
div.user(ng-if="::update.meta.users.length == 0")
|
||||
.color-square(style="background-color: hsl(100, 100%, 50%)")
|
||||
span #{translate("anonymous")}
|
||||
|
||||
.loading(ng-show="history.loading")
|
||||
i.fa.fa-spin.fa-refresh
|
||||
| #{translate("loading")}...
|
||||
.history-entries-list-upgrade-prompt(
|
||||
ng-if="history.freeHistoryLimitHit && project.owner._id === user.id"
|
||||
ng-controller="FreeTrialModalController"
|
||||
)
|
||||
p #{translate("currently_seeing_only_24_hrs_history")}
|
||||
p: strong #{translate("upgrade_to_get_feature", {feature:"full Project History"})}
|
||||
ul.list-unstyled
|
||||
li
|
||||
i.fa.fa-check
|
||||
| #{translate("unlimited_projects")}
|
||||
|
||||
li
|
||||
i.fa.fa-check
|
||||
| #{translate("collabs_per_proj", {collabcount:'Multiple'})}
|
||||
|
||||
li
|
||||
i.fa.fa-check
|
||||
| #{translate("full_doc_history")}
|
||||
|
||||
li
|
||||
i.fa.fa-check
|
||||
| #{translate("sync_to_dropbox")}
|
||||
|
||||
li
|
||||
i.fa.fa-check
|
||||
| #{translate("sync_to_github")}
|
||||
|
||||
li
|
||||
i.fa.fa-check
|
||||
|#{translate("compile_larger_projects")}
|
||||
p.text-center
|
||||
a.btn.btn-success(
|
||||
href
|
||||
ng-class="buttonClass"
|
||||
ng-click="startFreeTrial('history')"
|
||||
) #{translate("start_free_trial")}
|
||||
p.small(ng-show="startedFreeTrial") #{translate("refresh_page_after_starting_free_trial")}
|
||||
.history-entries-list-upgrade-prompt(
|
||||
ng-if="history.freeHistoryLimitHit && !project.owner._id === user.id"
|
||||
)
|
||||
p #{translate("currently_seeing_only_24_hrs_history")}
|
||||
strong #{translate("ask_proj_owner_to_upgrade_for_full_history")}
|
||||
.history-labels-list-compare(
|
||||
ng-if="history.showOnlyLabels && !history.error"
|
||||
)
|
||||
ul.list-unstyled(
|
||||
ng-class="{\
|
||||
'hover-state': history.hoveringOverListSelectors\
|
||||
}"
|
||||
)
|
||||
li.change(
|
||||
ng-repeat="versionWithLabel in versionsWithLabels | orderBy:'-version' track by versionWithLabel.version"
|
||||
ng-class="{\
|
||||
'selected': versionWithLabel.version <= history.selection.range.toV && versionWithLabel.version >= history.selection.range.fromV,\
|
||||
'selected-to': versionWithLabel.version === history.selection.range.toV,\
|
||||
'selected-from': versionWithLabel.version === history.selection.range.fromV,\
|
||||
'hover-selected': versionWithLabel.version <= history.selection.hoveredRange.toV && versionWithLabel.version >= history.selection.hoveredRange.fromV,\
|
||||
'hover-selected-to': versionWithLabel.version === history.selection.hoveredRange.toV,\
|
||||
'hover-selected-from': versionWithLabel.version === history.selection.hoveredRange.fromV,\
|
||||
}"
|
||||
)
|
||||
div.selectors
|
||||
div.range
|
||||
form
|
||||
input.selector-from(
|
||||
type="radio"
|
||||
name="fromVersionForLabel"
|
||||
ng-model="history.selection.range.fromV"
|
||||
ng-value="versionWithLabel.version"
|
||||
ng-mouseover="setHoverFrom(versionWithLabel.version)"
|
||||
ng-mouseout="resetHover()"
|
||||
ng-show="versionWithLabel.version < history.selection.range.fromV || versionWithLabel.version <= history.selection.range.toV && versionWithLabel.version >= history.selection.range.fromV"
|
||||
)
|
||||
form
|
||||
input.selector-to(
|
||||
type="radio"
|
||||
name="toVersionForLabel"
|
||||
ng-model="history.selection.range.toV"
|
||||
ng-value="versionWithLabel.version"
|
||||
ng-mouseover="setHoverTo(versionWithLabel.version)"
|
||||
ng-mouseout="resetHover()"
|
||||
ng-show="versionWithLabel.version > history.selection.range.toV || versionWithLabel.version <= history.selection.range.toV && versionWithLabel.version >= history.selection.range.fromV"
|
||||
)
|
||||
|
||||
|
||||
.description(ng-click="addLabelVersionToSelection(versionWithLabel.version)")
|
||||
div(
|
||||
ng-repeat="label in versionWithLabel.labels track by label.id"
|
||||
)
|
||||
history-label(
|
||||
show-tooltip="false"
|
||||
label-text="label.comment"
|
||||
is-owned-by-current-user="label.user_id === user.id"
|
||||
is-pseudo-current-state-label="label.isPseudoCurrentStateLabel"
|
||||
on-label-delete="deleteLabel(label)"
|
||||
)
|
||||
.history-entry-label-metadata
|
||||
.history-entry-label-metadata-user(
|
||||
ng-if="!label.isPseudoCurrentStateLabel"
|
||||
ng-init="labelOwner = getUserById(label.user_id)"
|
||||
)
|
||||
| Saved by
|
||||
span.name(
|
||||
ng-if="::labelOwner && labelOwner._id !== user.id"
|
||||
ng-style="::{'color': 'hsl({{ hueForUser(label.user_id) }}, 70%, 50%)'}"
|
||||
) {{ ::getDisplayNameById(label.user_id) }}
|
||||
span.name(
|
||||
ng-if="labelOwner && labelOwner._id == user.id"
|
||||
ng-style="::{'color': 'hsl({{ hueForUser(label.user_id) }}, 70%, 50%)'}"
|
||||
) You
|
||||
span.name(
|
||||
ng-if="::labelOwner == null"
|
||||
ng-style="::{'color': 'hsl(100, 70%, 50%)'}"
|
||||
) #{translate("anonymous")}
|
||||
time.history-entry-label-metadata-time {{ ::label.created_at | formatDate }}
|
||||
|
||||
.loading(ng-show="history.loading")
|
||||
i.fa.fa-spin.fa-refresh
|
||||
| #{translate("loading")}...
|
||||
|
||||
script(type="text/ng-template", id="historyEntriesListTpl")
|
||||
.history-entries(
|
||||
|
@ -250,11 +43,15 @@ script(type="text/ng-template", id="historyEntriesListTpl")
|
|||
.infinite-scroll-inner
|
||||
history-entry(
|
||||
ng-repeat="entry in $ctrl.entries"
|
||||
range-selection-enabled="$ctrl.rangeSelectionEnabled"
|
||||
is-dragging="$ctrl.isDragging"
|
||||
selected-history-version="$ctrl.selectedHistoryVersion"
|
||||
selected-history-range="$ctrl.selectedHistoryRange"
|
||||
hovered-history-range="$ctrl.hoveredHistoryRange"
|
||||
entry="entry"
|
||||
current-user="$ctrl.currentUser"
|
||||
users="$ctrl.users"
|
||||
on-select="$ctrl.onEntrySelect({ selectedEntry: selectedEntry })"
|
||||
on-select="$ctrl.handleEntrySelect(selectedEntry)"
|
||||
on-label-delete="$ctrl.onLabelDelete({ label: label })"
|
||||
)
|
||||
.loading(ng-show="$ctrl.isLoading")
|
||||
|
@ -307,13 +104,30 @@ script(type="text/ng-template", id="historyEntryTpl")
|
|||
.history-entry(
|
||||
ng-class="{\
|
||||
'history-entry-first-in-day': $ctrl.entry.meta.first_in_day,\
|
||||
'history-entry-selected': $ctrl.entry.toV === $ctrl.selectedHistoryVersion,\
|
||||
'history-entry-selected': !$ctrl.isDragging && $ctrl.isEntrySelected(),\
|
||||
'history-entry-selected-to': $ctrl.rangeSelectionEnabled && !$ctrl.isDragging && $ctrl.selectedHistoryRange.toV === $ctrl.entry.toV,\
|
||||
'history-entry-selected-from': $ctrl.rangeSelectionEnabled && !$ctrl.isDragging && $ctrl.selectedHistoryRange.fromV === $ctrl.entry.fromV,\
|
||||
'history-entry-hover-selected': $ctrl.rangeSelectionEnabled && $ctrl.isDragging && $ctrl.isEntryHoverSelected(),\
|
||||
'history-entry-hover-selected-to': $ctrl.rangeSelectionEnabled && $ctrl.isDragging && $ctrl.hoveredHistoryRange.toV === $ctrl.entry.toV,\
|
||||
'history-entry-hover-selected-from': $ctrl.rangeSelectionEnabled && $ctrl.isDragging && $ctrl.hoveredHistoryRange.fromV === $ctrl.entry.fromV,\
|
||||
}"
|
||||
history-droppable-area
|
||||
history-droppable-area-on-drop="$ctrl.onDrop(boundary)"
|
||||
history-droppable-area-on-over="$ctrl.onOver(boundary)"
|
||||
)
|
||||
|
||||
time.history-entry-day(ng-if="::$ctrl.entry.meta.first_in_day") {{ ::$ctrl.entry.meta.end_ts | relativeDate }}
|
||||
|
||||
.history-entry-details(ng-click="$ctrl.onSelect({ selectedEntry: $ctrl.entry })")
|
||||
.history-entry-details(
|
||||
ng-click="$ctrl.onSelect({ selectedEntry: $ctrl.entry })"
|
||||
)
|
||||
.history-entry-toV-handle(
|
||||
ng-show="$ctrl.rangeSelectionEnabled && $ctrl.selectedHistoryRange && ((!$ctrl.isDragging && $ctrl.selectedHistoryRange.toV === $ctrl.entry.toV) || ($ctrl.isDragging && $ctrl.hoveredHistoryRange.toV === $ctrl.entry.toV))"
|
||||
history-draggable-boundary="toV"
|
||||
history-draggable-boundary-on-drag-start="$ctrl.onDraggingStart()"
|
||||
history-draggable-boundary-on-drag-stop="$ctrl.onDraggingStop(isValidDrop, boundary)"
|
||||
)
|
||||
|
||||
history-label(
|
||||
ng-repeat="label in $ctrl.entry.labels | orderBy : '-created_at'"
|
||||
label-text="label.comment"
|
||||
|
@ -342,7 +156,6 @@ script(type="text/ng-template", id="historyEntryTpl")
|
|||
ng-if="::project_op.remove"
|
||||
) #{translate("file_action_deleted")}
|
||||
span.history-entry-change-doc {{ ::$ctrl.getProjectOpDoc(project_op) }}
|
||||
|
||||
.history-entry-metadata
|
||||
time.history-entry-metadata-time {{ ::$ctrl.entry.meta.end_ts | formatDate:'h:mm a' }}
|
||||
span
|
||||
|
@ -368,39 +181,72 @@ script(type="text/ng-template", id="historyEntryTpl")
|
|||
ng-style="$ctrl.getUserCSSStyle();"
|
||||
) #{translate("anonymous")}
|
||||
|
||||
.history-entry-fromV-handle(
|
||||
ng-show="$ctrl.rangeSelectionEnabled && $ctrl.selectedHistoryRange && ((!$ctrl.isDragging && $ctrl.selectedHistoryRange.fromV === $ctrl.entry.fromV) || ($ctrl.isDragging && $ctrl.hoveredHistoryRange.fromV === $ctrl.entry.fromV))"
|
||||
history-draggable-boundary="fromV"
|
||||
history-draggable-boundary-on-drag-start="$ctrl.onDraggingStart()"
|
||||
history-draggable-boundary-on-drag-stop="$ctrl.onDraggingStop(isValidDrop, boundary)"
|
||||
)
|
||||
|
||||
script(type="text/ng-template", id="historyLabelsListTpl")
|
||||
.history-labels-list
|
||||
.history-entry-label(
|
||||
ng-repeat="label in $ctrl.labels track by label.id"
|
||||
ng-click="$ctrl.onLabelSelect({ label: label })"
|
||||
ng-class="{ 'history-entry-label-selected': label.id === $ctrl.selectedLabel.id }"
|
||||
.history-version-with-label(
|
||||
ng-repeat="versionWithLabel in $ctrl.versionsWithLabels | orderBy:'-version' track by versionWithLabel.version"
|
||||
ng-class="{\
|
||||
'history-version-with-label-selected': !$ctrl.isDragging && $ctrl.isVersionSelected(versionWithLabel.version),\
|
||||
'history-version-with-label-selected-to': !$ctrl.isDragging && $ctrl.selectedHistoryRange.toV === versionWithLabel.version,\
|
||||
'history-version-with-label-selected-from': !$ctrl.isDragging && $ctrl.selectedHistoryRange.fromV === versionWithLabel.version,\
|
||||
'history-version-with-label-hover-selected': $ctrl.isDragging && $ctrl.isVersionHoverSelected(versionWithLabel.version),\
|
||||
'history-version-with-label-hover-selected-to': $ctrl.isDragging && $ctrl.hoveredHistoryRange.toV === versionWithLabel.version,\
|
||||
'history-version-with-label-hover-selected-from': $ctrl.isDragging && $ctrl.hoveredHistoryRange.fromV === versionWithLabel.version,\
|
||||
}"
|
||||
ng-click="$ctrl.handleVersionSelect(versionWithLabel)"
|
||||
history-droppable-area
|
||||
history-droppable-area-on-drop="$ctrl.onDrop(boundary, versionWithLabel)"
|
||||
history-droppable-area-on-over="$ctrl.onOver(boundary, versionWithLabel)"
|
||||
)
|
||||
history-label(
|
||||
show-tooltip="false"
|
||||
label-text="label.comment"
|
||||
is-owned-by-current-user="label.user_id === $ctrl.currentUser.id"
|
||||
on-label-delete="$ctrl.onLabelDelete({ label: label })"
|
||||
is-pseudo-current-state-label="label.isPseudoCurrentStateLabel"
|
||||
.history-entry-toV-handle(
|
||||
ng-show="$ctrl.rangeSelectionEnabled && $ctrl.selectedHistoryRange && ((!$ctrl.isDragging && $ctrl.selectedHistoryRange.toV === versionWithLabel.version) || ($ctrl.isDragging && $ctrl.hoveredHistoryRange.toV === versionWithLabel.version))"
|
||||
history-draggable-boundary="toV"
|
||||
history-draggable-boundary-on-drag-start="$ctrl.onDraggingStart()"
|
||||
history-draggable-boundary-on-drag-stop="$ctrl.onDraggingStop(isValidDrop, boundary)"
|
||||
)
|
||||
.history-entry-label-metadata
|
||||
.history-entry-label-metadata-user(
|
||||
ng-if="!label.isPseudoCurrentStateLabel"
|
||||
ng-init="user = $ctrl.getUserById(label.user_id)"
|
||||
div(
|
||||
ng-repeat="label in versionWithLabel.labels track by label.id"
|
||||
)
|
||||
history-label(
|
||||
show-tooltip="false"
|
||||
label-text="label.comment"
|
||||
is-owned-by-current-user="label.user_id === $ctrl.currentUser.id"
|
||||
on-label-delete="$ctrl.onLabelDelete({ label: label })"
|
||||
is-pseudo-current-state-label="label.isPseudoCurrentStateLabel"
|
||||
)
|
||||
| Saved by
|
||||
span.name(
|
||||
ng-if="user && user._id !== $ctrl.currentUser.id"
|
||||
ng-style="$ctrl.getUserCSSStyle(user, label);"
|
||||
) {{ ::$ctrl.displayName(user) }}
|
||||
span.name(
|
||||
ng-if="user && user._id == $ctrl.currentUser.id"
|
||||
ng-style="$ctrl.getUserCSSStyle(user, label);"
|
||||
) You
|
||||
span.name(
|
||||
ng-if="user == null"
|
||||
ng-style="$ctrl.getUserCSSStyle(user, label);"
|
||||
) #{translate("anonymous")}
|
||||
time.history-entry-label-metadata-time {{ ::label.created_at | formatDate }}
|
||||
.history-entry-label-metadata
|
||||
.history-entry-label-metadata-user(
|
||||
ng-if="!label.isPseudoCurrentStateLabel"
|
||||
ng-init="user = $ctrl.getUserById(label.user_id)"
|
||||
)
|
||||
| Saved by
|
||||
span.name(
|
||||
ng-if="user && user._id !== $ctrl.currentUser.id"
|
||||
ng-style="$ctrl.getUserCSSStyle(user, versionWithLabel);"
|
||||
) {{ ::$ctrl.displayName(user) }}
|
||||
span.name(
|
||||
ng-if="user && user._id == $ctrl.currentUser.id"
|
||||
ng-style="$ctrl.getUserCSSStyle(user, versionWithLabel);"
|
||||
) You
|
||||
span.name(
|
||||
ng-if="user == null"
|
||||
ng-style="$ctrl.getUserCSSStyle(user, versionWithLabel);"
|
||||
) #{translate("anonymous")}
|
||||
time.history-entry-label-metadata-time {{ ::label.created_at | formatDate }}
|
||||
.history-entry-fromV-handle(
|
||||
ng-show="$ctrl.rangeSelectionEnabled && $ctrl.selectedHistoryRange && ((!$ctrl.isDragging && $ctrl.selectedHistoryRange.fromV === versionWithLabel.version) || ($ctrl.isDragging && $ctrl.hoveredHistoryRange.fromV === versionWithLabel.version))"
|
||||
history-draggable-boundary="fromV"
|
||||
history-draggable-boundary-on-drag-start="$ctrl.onDraggingStart()"
|
||||
history-draggable-boundary-on-drag-stop="$ctrl.onDraggingStop(isValidDrop, boundary)"
|
||||
)
|
||||
|
||||
.loading(ng-show="$ctrl.isLoading")
|
||||
i.fa.fa-spin.fa-refresh
|
||||
| #{translate("loading")}...
|
|
@ -2,7 +2,7 @@
|
|||
ng-if="history.isV2 && history.viewMode === HistoryViewModes.COMPARE"
|
||||
)
|
||||
.diff(
|
||||
ng-if="!!history.selection.diff && !history.selection.diff.loading && !history.selection.diff.error",
|
||||
ng-if="!!history.selection.diff && !isHistoryLoading() && !history.selection.diff.error",
|
||||
ng-class="{ 'diff-binary': history.selection.diff.binary }"
|
||||
)
|
||||
.diff-editor-v2.hide-ace-cursor(
|
||||
|
@ -19,10 +19,10 @@
|
|||
.alert.alert-info(ng-if="history.selection.diff.binary")
|
||||
| We're still working on showing image and binary changes, sorry. Stay tuned!
|
||||
|
||||
.loading-panel(ng-show="history.selection.diff.loading")
|
||||
.loading-panel(ng-show="isHistoryLoading()")
|
||||
i.fa.fa-spin.fa-refresh
|
||||
| #{translate("loading")}...
|
||||
.error-panel(ng-show="history.selection.diff.error")
|
||||
.error-panel(ng-show="history.selection.diff.error && !isHistoryLoading()")
|
||||
.alert.alert-danger #{translate("generic_something_went_wrong")}
|
||||
|
||||
.point-in-time-panel.full-size(
|
||||
|
@ -42,7 +42,7 @@
|
|||
)
|
||||
.alert.alert-info(ng-if="history.selection.file.binary")
|
||||
| We're still working on showing image and binary changes, sorry. Stay tuned!
|
||||
.loading-panel(ng-show="history.selection.file.loading")
|
||||
.loading-panel(ng-show="isHistoryLoading()")
|
||||
i.fa.fa-spin.fa-refresh
|
||||
| #{translate("loading")}...
|
||||
.error-panel(ng-show="history.error")
|
||||
|
|
|
@ -2,28 +2,32 @@
|
|||
ng-controller="HistoryV2ToolbarController"
|
||||
ng-if="ui.view == 'history' && history.isV2"
|
||||
)
|
||||
span.history-toolbar-selected-version(ng-show="history.loadingFileTree || history.selection.diff.loading")
|
||||
span.history-toolbar-selected-version(ng-show="history.loadingFileTree")
|
||||
i.fa.fa-spin.fa-refresh
|
||||
| #{translate("loading")}...
|
||||
|
||||
//- point-in-time mode info
|
||||
span.history-toolbar-selected-version(
|
||||
ng-show="!history.loadingFileTree && !history.showOnlyLabels && history.selection.update && !history.error"
|
||||
ng-show="!history.loadingFileTree && history.viewMode === HistoryViewModes.POINT_IN_TIME && !history.showOnlyLabels && currentUpdate && !history.error"
|
||||
) #{translate("browsing_project_as_of")}
|
||||
time.history-toolbar-time {{ history.selection.update.meta.end_ts | formatDate:'Do MMM YYYY, h:mm a' }}
|
||||
time.history-toolbar-time {{ currentUpdate.meta.end_ts | formatDate:'Do MMM YYYY, h:mm a' }}
|
||||
span.history-toolbar-selected-version(
|
||||
ng-show="!history.loadingFileTree && history.showOnlyLabels && history.selection.label && !history.error"
|
||||
ng-show="!history.loadingFileTree && history.viewMode === HistoryViewModes.POINT_IN_TIME && history.showOnlyLabels && currentUpdate && !history.error"
|
||||
)
|
||||
span(ng-if="history.selection.label.comment && !history.selection.label.isPseudoCurrentStateLabel")
|
||||
span(ng-if="currentUpdate.labels.length > 0")
|
||||
| #{translate("browsing_project_labelled")}
|
||||
span.history-toolbar-selected-label "{{ history.selection.label.comment }}"
|
||||
span.history-toolbar-selected-label(ng-if="history.selection.label.isPseudoCurrentStateLabel")
|
||||
span.history-toolbar-selected-label(
|
||||
ng-repeat="label in currentUpdate.labels"
|
||||
)
|
||||
| {{ label.comment }}
|
||||
span(ng-if="!$last") ,
|
||||
span.history-toolbar-selected-label(ng-if="currentUpdate.labels.length === 0 && history.labels[0].isPseudoCurrentStateLabel && currentUpdate.toV === history.labels[0].version")
|
||||
| #{translate("browsing_project_latest_for_pseudo_label")}
|
||||
|
||||
|
||||
|
||||
//- compare mode info
|
||||
span.history-toolbar-selected-version(ng-show="history.viewMode === HistoryViewModes.COMPARE && history.selection.diff && !history.selection.diff.binary && !history.selection.diff.loading && !history.selection.diff.error && !history.loadingFileTree")
|
||||
span.history-toolbar-selected-version(ng-if="history.viewMode === HistoryViewModes.COMPARE && history.selection.diff && !history.selection.diff.binary && !history.selection.diff.loading && !history.selection.diff.error && !history.loadingFileTree")
|
||||
| <strong>{{history.selection.diff.highlights.length}} </strong>
|
||||
ng-pluralize(
|
||||
count="history.selection.diff.highlights.length",
|
||||
|
@ -41,13 +45,13 @@
|
|||
button.history-toolbar-btn(
|
||||
ng-click="showAddLabelDialog();"
|
||||
ng-if="!history.showOnlyLabels"
|
||||
ng-disabled="history.loadingFileTree || history.selection.range.toV == null || history.selection.range.fromV == null"
|
||||
ng-disabled="isHistoryLoading() || history.selection.range.toV == null || history.selection.range.fromV == null"
|
||||
)
|
||||
i.fa.fa-tag
|
||||
| #{translate("history_label_this_version")}
|
||||
button.history-toolbar-btn(
|
||||
ng-click="toggleHistoryViewMode();"
|
||||
ng-disabled="history.loadingFileTree"
|
||||
ng-disabled="isHistoryLoading()"
|
||||
)
|
||||
i.fa.fa-exchange
|
||||
| #{translate("compare_to_another_version")}
|
||||
|
@ -68,6 +72,7 @@
|
|||
)
|
||||
button.history-toolbar-btn(
|
||||
ng-click="toggleHistoryViewMode();"
|
||||
ng-disabled="isHistoryLoading()"
|
||||
)
|
||||
i.fa
|
||||
| #{translate("view_single_version")}
|
||||
|
|
180
services/web/public/js/libs/jquery.ui.touch-punch.js
vendored
Normal file
180
services/web/public/js/libs/jquery.ui.touch-punch.js
vendored
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*!
|
||||
* jQuery UI Touch Punch 0.2.3
|
||||
*
|
||||
* Copyright 2011–2014, Dave Furfero
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
*
|
||||
* Depends:
|
||||
* jquery.ui.widget.js
|
||||
* jquery.ui.mouse.js
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
// Detect touch support
|
||||
$.support.touch = 'ontouchend' in document;
|
||||
|
||||
// Ignore browsers without touch support
|
||||
if (!$.support.touch) {
|
||||
return;
|
||||
}
|
||||
|
||||
var mouseProto = $.ui.mouse.prototype,
|
||||
_mouseInit = mouseProto._mouseInit,
|
||||
_mouseDestroy = mouseProto._mouseDestroy,
|
||||
touchHandled;
|
||||
|
||||
/**
|
||||
* Simulate a mouse event based on a corresponding touch event
|
||||
* @param {Object} event A touch event
|
||||
* @param {String} simulatedType The corresponding mouse event
|
||||
*/
|
||||
function simulateMouseEvent (event, simulatedType) {
|
||||
|
||||
// Ignore multi-touch events
|
||||
if (event.originalEvent.touches.length > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
var touch = event.originalEvent.changedTouches[0],
|
||||
simulatedEvent = document.createEvent('MouseEvents');
|
||||
|
||||
// Initialize the simulated mouse event using the touch event's coordinates
|
||||
simulatedEvent.initMouseEvent(
|
||||
simulatedType, // type
|
||||
true, // bubbles
|
||||
true, // cancelable
|
||||
window, // view
|
||||
1, // detail
|
||||
touch.screenX, // screenX
|
||||
touch.screenY, // screenY
|
||||
touch.clientX, // clientX
|
||||
touch.clientY, // clientY
|
||||
false, // ctrlKey
|
||||
false, // altKey
|
||||
false, // shiftKey
|
||||
false, // metaKey
|
||||
0, // button
|
||||
null // relatedTarget
|
||||
);
|
||||
|
||||
// Dispatch the simulated event to the target element
|
||||
event.target.dispatchEvent(simulatedEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the jQuery UI widget's touchstart events
|
||||
* @param {Object} event The widget element's touchstart event
|
||||
*/
|
||||
mouseProto._touchStart = function (event) {
|
||||
|
||||
var self = this;
|
||||
|
||||
// Ignore the event if another widget is already being handled
|
||||
if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the flag to prevent other widgets from inheriting the touch event
|
||||
touchHandled = true;
|
||||
|
||||
// Track movement to determine if interaction was a click
|
||||
self._touchMoved = false;
|
||||
|
||||
// Simulate the mouseover event
|
||||
simulateMouseEvent(event, 'mouseover');
|
||||
|
||||
// Simulate the mousemove event
|
||||
simulateMouseEvent(event, 'mousemove');
|
||||
|
||||
// Simulate the mousedown event
|
||||
simulateMouseEvent(event, 'mousedown');
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle the jQuery UI widget's touchmove events
|
||||
* @param {Object} event The document's touchmove event
|
||||
*/
|
||||
mouseProto._touchMove = function (event) {
|
||||
|
||||
// Ignore event if not handled
|
||||
if (!touchHandled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Interaction was not a click
|
||||
this._touchMoved = true;
|
||||
|
||||
// Simulate the mousemove event
|
||||
simulateMouseEvent(event, 'mousemove');
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle the jQuery UI widget's touchend events
|
||||
* @param {Object} event The document's touchend event
|
||||
*/
|
||||
mouseProto._touchEnd = function (event) {
|
||||
|
||||
// Ignore event if not handled
|
||||
if (!touchHandled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Simulate the mouseup event
|
||||
simulateMouseEvent(event, 'mouseup');
|
||||
|
||||
// Simulate the mouseout event
|
||||
simulateMouseEvent(event, 'mouseout');
|
||||
|
||||
// If the touch interaction did not move, it should trigger a click
|
||||
if (!this._touchMoved) {
|
||||
|
||||
// Simulate the click event
|
||||
simulateMouseEvent(event, 'click');
|
||||
}
|
||||
|
||||
// Unset the flag to allow other widgets to inherit the touch event
|
||||
touchHandled = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* A duck punch of the $.ui.mouse _mouseInit method to support touch events.
|
||||
* This method extends the widget with bound touch event handlers that
|
||||
* translate touch events to mouse events and pass them to the widget's
|
||||
* original mouse event handling methods.
|
||||
*/
|
||||
mouseProto._mouseInit = function () {
|
||||
|
||||
var self = this;
|
||||
|
||||
// Delegate the touch handlers to the widget's element
|
||||
self.element.bind({
|
||||
touchstart: $.proxy(self, '_touchStart'),
|
||||
touchmove: $.proxy(self, '_touchMove'),
|
||||
touchend: $.proxy(self, '_touchEnd')
|
||||
});
|
||||
|
||||
// Call the original $.ui.mouse init method
|
||||
_mouseInit.call(self);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the touch event handlers
|
||||
*/
|
||||
mouseProto._mouseDestroy = function () {
|
||||
|
||||
var self = this;
|
||||
|
||||
// Delegate the touch handlers to the widget's element
|
||||
self.element.unbind({
|
||||
touchstart: $.proxy(self, '_touchStart'),
|
||||
touchmove: $.proxy(self, '_touchMove'),
|
||||
touchend: $.proxy(self, '_touchEnd')
|
||||
});
|
||||
|
||||
// Call the original $.ui.mouse destroy method
|
||||
_mouseDestroy.call(self);
|
||||
};
|
||||
|
||||
})(jQuery);
|
|
@ -13,7 +13,7 @@
|
|||
* DS207: Consider shorter variations of null checks
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
define(['base', 'libs/jquery-layout'], App =>
|
||||
define(['base', 'libs/jquery-layout', 'libs/jquery.ui.touch-punch'], App =>
|
||||
App.directive('layout', [
|
||||
'$parse',
|
||||
'$compile',
|
||||
|
|
|
@ -19,7 +19,6 @@ define([
|
|||
'moment',
|
||||
'ide/colors/ColorManager',
|
||||
'ide/history/util/displayNameForUser',
|
||||
'ide/history/controllers/HistoryCompareController',
|
||||
'ide/history/controllers/HistoryListController',
|
||||
'ide/history/controllers/HistoryDiffController',
|
||||
'ide/history/directives/infiniteScroll'
|
||||
|
|
|
@ -28,6 +28,8 @@ define([
|
|||
'ide/history/controllers/HistoryV2AddLabelModalController',
|
||||
'ide/history/controllers/HistoryV2DeleteLabelModalController',
|
||||
'ide/history/directives/infiniteScroll',
|
||||
'ide/history/directives/historyDraggableBoundary',
|
||||
'ide/history/directives/historyDroppableArea',
|
||||
'ide/history/components/historyEntriesList',
|
||||
'ide/history/components/historyEntry',
|
||||
'ide/history/components/historyLabelsList',
|
||||
|
@ -57,6 +59,7 @@ define([
|
|||
$scope.project_id
|
||||
}`
|
||||
this._previouslySelectedPathname = null
|
||||
this._loadFileTreeRequestCanceller = null
|
||||
this.hardReset()
|
||||
|
||||
this.$scope.toggleHistory = () => {
|
||||
|
@ -71,23 +74,18 @@ define([
|
|||
}, 0)
|
||||
}
|
||||
|
||||
this.$scope.$watchGroup(
|
||||
['history.selection.range.toV', 'history.selection.range.fromV'],
|
||||
(newRange, prevRange) => {
|
||||
if (this.$scope.history.viewMode === HistoryViewModes.COMPARE) {
|
||||
let [newTo, newFrom] = newRange
|
||||
let [prevTo, prevFrom] = prevRange
|
||||
if (
|
||||
newTo != null &&
|
||||
newFrom != null &&
|
||||
newTo !== prevTo &&
|
||||
newFrom !== prevFrom
|
||||
) {
|
||||
this.loadFileTreeDiff(newTo, newFrom)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
this.$scope.isHistoryLoading = () => {
|
||||
let selection = this.$scope.history.selection
|
||||
return (
|
||||
this.$scope.history.loadingFileTree ||
|
||||
(this.$scope.history.viewMode === HistoryViewModes.POINT_IN_TIME &&
|
||||
selection.file &&
|
||||
selection.file.loading) ||
|
||||
(this.$scope.history.viewMode === HistoryViewModes.COMPARE &&
|
||||
selection.diff &&
|
||||
selection.diff.loading)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
show() {
|
||||
|
@ -151,8 +149,6 @@ define([
|
|||
},
|
||||
diff: null,
|
||||
files: [],
|
||||
update: null,
|
||||
label: null,
|
||||
file: null
|
||||
},
|
||||
error: null,
|
||||
|
@ -186,8 +182,6 @@ define([
|
|||
},
|
||||
diff: null, // When history.viewMode == HistoryViewModes.COMPARE
|
||||
files: [], // When history.viewMode == HistoryViewModes.COMPARE
|
||||
update: null, // When history.viewMode == HistoryViewModes.POINT_IN_TIME
|
||||
label: null, // When history.viewMode == HistoryViewModes.POINT_IN_TIME
|
||||
file: null
|
||||
}
|
||||
this.$scope.history.error = null
|
||||
|
@ -221,9 +215,9 @@ define([
|
|||
} else {
|
||||
// Point-in-time mode
|
||||
if (this.$scope.history.showOnlyLabels) {
|
||||
this.selectLabelFromUpdatesSelection()
|
||||
this.autoSelectLabelForPointInTime()
|
||||
} else {
|
||||
this.autoSelectLastVersionForPointInTime()
|
||||
this.autoSelectVersionForPointInTime()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -288,14 +282,23 @@ define([
|
|||
let selection = this.$scope.history.selection
|
||||
const query = [`from=${fromV}`, `to=${toV}`]
|
||||
url += `?${query.join('&')}`
|
||||
this.$scope.history.loadingFileTree = true
|
||||
|
||||
this.$scope.$applyAsync(
|
||||
() => (this.$scope.history.loadingFileTree = true)
|
||||
)
|
||||
|
||||
selection.file = null
|
||||
selection.pathname = null
|
||||
if (selection.diff) {
|
||||
selection.diff.loading = true
|
||||
|
||||
// If `this._loadFileTreeRequestCanceller` is not null, then we have a request inflight
|
||||
if (this._loadFileTreeRequestCanceller != null) {
|
||||
// Resolving it will cancel the inflight request (or, rather, ignore its result)
|
||||
this._loadFileTreeRequestCanceller.resolve()
|
||||
}
|
||||
this._loadFileTreeRequestCanceller = this.ide.$q.defer()
|
||||
|
||||
return this.ide.$http
|
||||
.get(url)
|
||||
.get(url, { timeout: this._loadFileTreeRequestCanceller.promise })
|
||||
.then(response => {
|
||||
this.$scope.history.selection.files = response.data.diff
|
||||
for (let file of this.$scope.history.selection.files) {
|
||||
|
@ -305,15 +308,15 @@ define([
|
|||
delete file.newPathname
|
||||
}
|
||||
}
|
||||
this._loadFileTreeRequestCanceller = null
|
||||
this.$scope.history.loadingFileTree = false
|
||||
this.autoSelectFile()
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
.finally(() => {
|
||||
this.$scope.history.loadingFileTree = false
|
||||
if (selection.diff) {
|
||||
selection.diff.loading = true
|
||||
if (err.status !== -1) {
|
||||
this._loadFileTreeRequestCanceller = null
|
||||
} else {
|
||||
this.$scope.history.loadingFileTree = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -380,7 +383,8 @@ define([
|
|||
return
|
||||
}
|
||||
|
||||
this.$scope.history.selection.range.toV = this.$scope.history.updates[0].toV
|
||||
let toV = this.$scope.history.updates[0].toV
|
||||
let fromV = null
|
||||
|
||||
let indexOfLastUpdateNotByMe = 0
|
||||
for (let i = 0; i < this.$scope.history.updates.length; i++) {
|
||||
|
@ -394,19 +398,24 @@ define([
|
|||
indexOfLastUpdateNotByMe = i
|
||||
}
|
||||
|
||||
this.$scope.history.selection.range.fromV = this.$scope.history.updates[
|
||||
indexOfLastUpdateNotByMe
|
||||
].fromV
|
||||
fromV = this.$scope.history.updates[indexOfLastUpdateNotByMe].fromV
|
||||
this.selectVersionsForCompare(toV, fromV)
|
||||
}
|
||||
|
||||
autoSelectLastVersionForPointInTime() {
|
||||
this.$scope.history.selection.label = null
|
||||
autoSelectVersionForPointInTime() {
|
||||
if (this.$scope.history.updates.length === 0) {
|
||||
return
|
||||
}
|
||||
return this.selectVersionForPointInTime(
|
||||
this.$scope.history.updates[0].toV
|
||||
)
|
||||
let versionToSelect = this.$scope.history.updates[0].toV
|
||||
let range = this.$scope.history.selection.range
|
||||
if (
|
||||
range.toV != null &&
|
||||
range.fromV != null &&
|
||||
range.toV === range.fromV
|
||||
) {
|
||||
versionToSelect = range.toV
|
||||
}
|
||||
this.selectVersionForPointInTime(versionToSelect)
|
||||
}
|
||||
|
||||
autoSelectLastLabel() {
|
||||
|
@ -429,14 +438,27 @@ define([
|
|||
|
||||
selectVersionForPointInTime(version) {
|
||||
let selection = this.$scope.history.selection
|
||||
selection.range.toV = version
|
||||
selection.range.fromV = version
|
||||
selection.update = this._getUpdateForVersion(version)
|
||||
this.loadFileTreeForVersion(version)
|
||||
if (
|
||||
selection.range.toV !== version &&
|
||||
selection.range.fromV !== version
|
||||
) {
|
||||
selection.range.toV = version
|
||||
selection.range.fromV = version
|
||||
this.loadFileTreeForVersion(version)
|
||||
}
|
||||
}
|
||||
|
||||
selectLabelFromUpdatesSelection() {
|
||||
const selectedUpdate = this._getUpdateForVersion(
|
||||
selectVersionsForCompare(toV, fromV) {
|
||||
let range = this.$scope.history.selection.range
|
||||
if (range.toV !== toV || range.fromV !== fromV) {
|
||||
range.toV = toV
|
||||
range.fromV = fromV
|
||||
this.loadFileTreeDiff(toV, fromV)
|
||||
}
|
||||
}
|
||||
|
||||
autoSelectLabelForPointInTime() {
|
||||
const selectedUpdate = this.getUpdateForVersion(
|
||||
this.$scope.history.selection.range.toV
|
||||
)
|
||||
let nSelectedLabels = 0
|
||||
|
@ -450,9 +472,7 @@ define([
|
|||
this.autoSelectLastLabel()
|
||||
// If the update has one label, select it
|
||||
} else if (nSelectedLabels === 1) {
|
||||
this.selectLabelForPointInTime(
|
||||
this.$scope.history.selection.update.labels[0]
|
||||
)
|
||||
this.selectLabelForPointInTime(selectedUpdate.labels[0])
|
||||
// If there are multiple labels for the update, select the latest
|
||||
} else if (nSelectedLabels > 1) {
|
||||
const sortedLabels = this.ide.$filter('orderBy')(
|
||||
|
@ -479,19 +499,17 @@ define([
|
|||
}
|
||||
}
|
||||
|
||||
this.$scope.history.selection.label = labelToSelect
|
||||
if (updateToSelect != null) {
|
||||
this.selectVersionForPointInTime(updateToSelect.toV)
|
||||
} else {
|
||||
let selection = this.$scope.history.selection
|
||||
selection.range.toV = labelToSelect.version
|
||||
selection.range.fromV = labelToSelect.version
|
||||
selection.update = null
|
||||
this.loadFileTreeForVersion(labelToSelect.version)
|
||||
}
|
||||
}
|
||||
|
||||
_getUpdateForVersion(version) {
|
||||
getUpdateForVersion(version) {
|
||||
for (let update of this.$scope.history.updates) {
|
||||
if (update.toV === version) {
|
||||
return update
|
||||
|
@ -501,17 +519,16 @@ define([
|
|||
|
||||
autoSelectLabelsForComparison() {
|
||||
let labels = this.$scope.history.labels
|
||||
let selection = this.$scope.history.selection
|
||||
let nLabels = 0
|
||||
if (Array.isArray(labels)) {
|
||||
nLabels = labels.length
|
||||
}
|
||||
if (nLabels === 1) {
|
||||
selection.range.toV = labels[0].version
|
||||
selection.range.fromV = labels[0].version
|
||||
if (nLabels === 0) {
|
||||
// TODO better handling
|
||||
} else if (nLabels === 1) {
|
||||
this.selectVersionsForCompare(labels[0].version, labels[0].version)
|
||||
} else if (nLabels > 1) {
|
||||
selection.range.toV = labels[0].version
|
||||
selection.range.fromV = labels[1].version
|
||||
this.selectVersionsForCompare(labels[0].version, labels[1].version)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -573,26 +590,27 @@ define([
|
|||
|
||||
_loadLabels(labels, lastUpdateToV) {
|
||||
let sortedLabels = this._sortLabelsByVersionAndDate(labels)
|
||||
let nLabels = sortedLabels.length
|
||||
let hasPseudoCurrentStateLabel = false
|
||||
let needsPseudoCurrentStateLabel = false
|
||||
if (sortedLabels.length > 0 && lastUpdateToV) {
|
||||
hasPseudoCurrentStateLabel = sortedLabels[0].isPseudoCurrentStateLabel
|
||||
if (lastUpdateToV) {
|
||||
hasPseudoCurrentStateLabel =
|
||||
nLabels > 0 ? sortedLabels[0].isPseudoCurrentStateLabel : false
|
||||
if (hasPseudoCurrentStateLabel) {
|
||||
needsPseudoCurrentStateLabel =
|
||||
sortedLabels.length > 1
|
||||
? sortedLabels[1].version !== lastUpdateToV
|
||||
: false
|
||||
nLabels > 1 ? sortedLabels[1].version !== lastUpdateToV : false
|
||||
} else {
|
||||
needsPseudoCurrentStateLabel =
|
||||
sortedLabels[0].version !== lastUpdateToV
|
||||
nLabels > 0 ? sortedLabels[0].version !== lastUpdateToV : true
|
||||
}
|
||||
if (needsPseudoCurrentStateLabel && !hasPseudoCurrentStateLabel) {
|
||||
sortedLabels.unshift({
|
||||
let pseudoCurrentStateLabel = {
|
||||
id: '1',
|
||||
isPseudoCurrentStateLabel: true,
|
||||
version: lastUpdateToV,
|
||||
created_at: new Date().toISOString()
|
||||
})
|
||||
}
|
||||
sortedLabels.unshift(pseudoCurrentStateLabel)
|
||||
} else if (
|
||||
!needsPseudoCurrentStateLabel &&
|
||||
hasPseudoCurrentStateLabel
|
||||
|
@ -638,8 +656,6 @@ define([
|
|||
|
||||
reloadDiff() {
|
||||
let { diff } = this.$scope.history.selection
|
||||
// const { updates } = this.$scope.history.selection
|
||||
// const { fromV, toV, pathname } = this._calculateDiffDataFromSelection()
|
||||
const { range, pathname } = this.$scope.history.selection
|
||||
const { fromV, toV } = range
|
||||
|
||||
|
@ -654,7 +670,7 @@ define([
|
|||
diff.fromV === fromV &&
|
||||
diff.toV === toV
|
||||
) {
|
||||
return this.ide.$q.when(true)
|
||||
return
|
||||
}
|
||||
|
||||
this.$scope.history.selection.diff = diff = {
|
||||
|
@ -732,8 +748,11 @@ define([
|
|||
}
|
||||
|
||||
_isLabelSelected(label) {
|
||||
if (this.$scope.history.selection.label) {
|
||||
return label.id === this.$scope.history.selection.label.id
|
||||
if (label) {
|
||||
return (
|
||||
label.version <= this.$scope.history.selection.range.toV &&
|
||||
label.version >= this.$scope.history.selection.range.fromV
|
||||
)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -11,15 +11,18 @@
|
|||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
define(['base'], function(App) {
|
||||
const historyEntriesListController = function($scope, $element, $attrs) {
|
||||
const historyEntriesListController = function($scope, $element, $attrs, _) {
|
||||
const ctrl = this
|
||||
ctrl.$entryListViewportEl = null
|
||||
ctrl.isDragging = false
|
||||
|
||||
const _isEntryElVisible = function($entryEl) {
|
||||
const entryElTop = $entryEl.offset().top
|
||||
const entryElBottom = entryElTop + $entryEl.outerHeight()
|
||||
const entryListViewportElTop = ctrl.$entryListViewportEl.offset().top
|
||||
const entryListViewportElBottom =
|
||||
entryListViewportElTop + ctrl.$entryListViewportEl.height()
|
||||
|
||||
return (
|
||||
entryElTop >= entryListViewportElTop &&
|
||||
entryElBottom <= entryListViewportElBottom
|
||||
|
@ -31,18 +34,86 @@ define(['base'], function(App) {
|
|||
}
|
||||
ctrl.onEntryLinked = function(entry, $entryEl) {
|
||||
if (
|
||||
entry.toV === ctrl.selectedHistoryVersion &&
|
||||
!_isEntryElVisible($entryEl)
|
||||
!ctrl.rangeSelectionEnabled &&
|
||||
entry.toV === ctrl.selectedHistoryVersion
|
||||
) {
|
||||
return $scope.$applyAsync(() =>
|
||||
ctrl.$entryListViewportEl.scrollTop(
|
||||
_getScrollTopPosForEntry($entryEl)
|
||||
)
|
||||
)
|
||||
$scope.$applyAsync(() => {
|
||||
if (!_isEntryElVisible($entryEl)) {
|
||||
ctrl.$entryListViewportEl.scrollTop(
|
||||
_getScrollTopPosForEntry($entryEl)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
ctrl.$onInit = () =>
|
||||
(ctrl.$entryListViewportEl = $element.find('> .history-entries'))
|
||||
ctrl.handleEntrySelect = entry => {
|
||||
if (ctrl.rangeSelectionEnabled) {
|
||||
ctrl.onRangeSelect({
|
||||
selectedToV: entry.toV,
|
||||
selectedFromV: entry.fromV
|
||||
})
|
||||
} else {
|
||||
ctrl.onVersionSelect({ version: entry.toV })
|
||||
}
|
||||
}
|
||||
ctrl.setRangeToV = toV => {
|
||||
if (toV > ctrl.selectedHistoryRange.fromV) {
|
||||
ctrl.onRangeSelect({
|
||||
selectedToV: toV,
|
||||
selectedFromV: ctrl.selectedHistoryRange.fromV
|
||||
})
|
||||
}
|
||||
}
|
||||
ctrl.setRangeFromV = fromV => {
|
||||
if (fromV < ctrl.selectedHistoryRange.toV) {
|
||||
ctrl.onRangeSelect({
|
||||
selectedToV: ctrl.selectedHistoryRange.toV,
|
||||
selectedFromV: fromV
|
||||
})
|
||||
}
|
||||
}
|
||||
ctrl.initHoveredRange = () => {
|
||||
ctrl.hoveredHistoryRange = {
|
||||
toV: ctrl.selectedHistoryRange.toV,
|
||||
fromV: ctrl.selectedHistoryRange.fromV
|
||||
}
|
||||
}
|
||||
ctrl.resetHoveredRange = () => {
|
||||
ctrl.hoveredHistoryRange = { toV: null, fromV: null }
|
||||
}
|
||||
ctrl.setHoveredRangeToV = toV => {
|
||||
if (toV > ctrl.hoveredHistoryRange.fromV) {
|
||||
$scope.$applyAsync(() => (ctrl.hoveredHistoryRange.toV = toV))
|
||||
}
|
||||
}
|
||||
ctrl.setHoveredRangeFromV = fromV => {
|
||||
if (fromV < ctrl.hoveredHistoryRange.toV) {
|
||||
$scope.$applyAsync(() => (ctrl.hoveredHistoryRange.fromV = fromV))
|
||||
}
|
||||
}
|
||||
ctrl.onDraggingStart = () => {
|
||||
$scope.$applyAsync(() => {
|
||||
ctrl.isDragging = true
|
||||
ctrl.initHoveredRange()
|
||||
})
|
||||
}
|
||||
ctrl.onDraggingStop = (isValidDrop, boundary) => {
|
||||
$scope.$applyAsync(() => {
|
||||
ctrl.isDragging = false
|
||||
if (!isValidDrop) {
|
||||
if (boundary === 'toV') {
|
||||
ctrl.setRangeToV(ctrl.hoveredHistoryRange.toV)
|
||||
} else if (boundary === 'fromV') {
|
||||
ctrl.setRangeFromV(ctrl.hoveredHistoryRange.fromV)
|
||||
}
|
||||
}
|
||||
ctrl.resetHoveredRange()
|
||||
})
|
||||
}
|
||||
ctrl.$onInit = () => {
|
||||
ctrl.$entryListViewportEl = $element.find('> .history-entries')
|
||||
ctrl.resetHoveredRange()
|
||||
}
|
||||
}
|
||||
|
||||
return App.component('historyEntriesList', {
|
||||
|
@ -56,8 +127,11 @@ define(['base'], function(App) {
|
|||
currentUser: '<',
|
||||
freeHistoryLimitHit: '<',
|
||||
currentUserIsOwner: '<',
|
||||
selectedHistoryVersion: '<',
|
||||
onEntrySelect: '&',
|
||||
rangeSelectionEnabled: '<',
|
||||
selectedHistoryVersion: '<?',
|
||||
selectedHistoryRange: '<?',
|
||||
onVersionSelect: '&',
|
||||
onRangeSelect: '&',
|
||||
onLabelDelete: '&'
|
||||
},
|
||||
controller: historyEntriesListController,
|
||||
|
|
|
@ -43,17 +43,67 @@ define([
|
|||
(user != null ? user._id : undefined) ||
|
||||
(user != null ? user.id : undefined)
|
||||
const hue = ColorManager.getHueForUserId(curUserId) || 100
|
||||
if (ctrl.entry.toV === ctrl.selectedHistoryVersion) {
|
||||
if (ctrl.isEntrySelected() || ctrl.isEntryHoverSelected()) {
|
||||
return { color: '#FFF' }
|
||||
} else {
|
||||
return { color: `hsl(${hue}, 70%, 50%)` }
|
||||
}
|
||||
}
|
||||
ctrl.$onInit = () =>
|
||||
ctrl.historyEntriesList.onEntryLinked(
|
||||
ctrl.entry,
|
||||
$element.find('> .history-entry')
|
||||
ctrl.isEntrySelected = function() {
|
||||
if (ctrl.rangeSelectionEnabled) {
|
||||
return (
|
||||
ctrl.entry.toV <= ctrl.selectedHistoryRange.toV &&
|
||||
ctrl.entry.fromV >= ctrl.selectedHistoryRange.fromV
|
||||
)
|
||||
} else {
|
||||
return ctrl.entry.toV === ctrl.selectedHistoryVersion
|
||||
}
|
||||
}
|
||||
|
||||
ctrl.isEntryHoverSelected = function() {
|
||||
return (
|
||||
ctrl.rangeSelectionEnabled &&
|
||||
ctrl.entry.toV <= ctrl.hoveredHistoryRange.toV &&
|
||||
ctrl.entry.fromV >= ctrl.hoveredHistoryRange.fromV
|
||||
)
|
||||
}
|
||||
|
||||
ctrl.onDraggingStart = () => {
|
||||
ctrl.historyEntriesList.onDraggingStart()
|
||||
}
|
||||
ctrl.onDraggingStop = (isValidDrop, boundary) =>
|
||||
ctrl.historyEntriesList.onDraggingStop(isValidDrop, boundary)
|
||||
|
||||
ctrl.onDrop = boundary => {
|
||||
if (boundary === 'toV') {
|
||||
$scope.$applyAsync(() =>
|
||||
ctrl.historyEntriesList.setRangeToV(ctrl.entry.toV)
|
||||
)
|
||||
} else if (boundary === 'fromV') {
|
||||
$scope.$applyAsync(() =>
|
||||
ctrl.historyEntriesList.setRangeFromV(ctrl.entry.fromV)
|
||||
)
|
||||
}
|
||||
}
|
||||
ctrl.onOver = boundary => {
|
||||
if (boundary === 'toV') {
|
||||
$scope.$applyAsync(() =>
|
||||
ctrl.historyEntriesList.setHoveredRangeToV(ctrl.entry.toV)
|
||||
)
|
||||
} else if (boundary === 'fromV') {
|
||||
$scope.$applyAsync(() =>
|
||||
ctrl.historyEntriesList.setHoveredRangeFromV(ctrl.entry.fromV)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ctrl.$onInit = () => {
|
||||
ctrl.$entryEl = $element.find('> .history-entry')
|
||||
ctrl.$entryDetailsEl = $element.find('.history-entry-details')
|
||||
ctrl.$toVHandleEl = $element.find('.history-entry-toV-handle')
|
||||
ctrl.$fromVHandleEl = $element.find('.history-entry-fromV-handle')
|
||||
ctrl.historyEntriesList.onEntryLinked(ctrl.entry, ctrl.$entryEl)
|
||||
}
|
||||
}
|
||||
|
||||
return App.component('historyEntry', {
|
||||
|
@ -61,7 +111,11 @@ define([
|
|||
entry: '<',
|
||||
currentUser: '<',
|
||||
users: '<',
|
||||
selectedHistoryVersion: '<',
|
||||
rangeSelectionEnabled: '<',
|
||||
isDragging: '<',
|
||||
selectedHistoryVersion: '<?',
|
||||
selectedHistoryRange: '<?',
|
||||
hoveredHistoryRange: '<?',
|
||||
onSelect: '&',
|
||||
onLabelDelete: '&'
|
||||
},
|
||||
|
|
|
@ -15,8 +15,125 @@ define([
|
|||
'ide/colors/ColorManager',
|
||||
'ide/history/util/displayNameForUser'
|
||||
], function(App, ColorManager, displayNameForUser) {
|
||||
const historyLabelsListController = function($scope, $element, $attrs) {
|
||||
const historyLabelsListController = function($scope, $element, $attrs, _) {
|
||||
const ctrl = this
|
||||
ctrl.isDragging = false
|
||||
ctrl.versionsWithLabels = []
|
||||
$scope.$watchCollection('$ctrl.labels', function(labels) {
|
||||
if (labels != null && labels.length > 0) {
|
||||
const groupedLabelsHash = _.groupBy(labels, 'version')
|
||||
ctrl.versionsWithLabels = _.map(
|
||||
groupedLabelsHash,
|
||||
(labels, version) => {
|
||||
return {
|
||||
version: parseInt(version, 10),
|
||||
labels
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
ctrl.initHoveredRange = () => {
|
||||
ctrl.hoveredHistoryRange = {
|
||||
toV: ctrl.selectedHistoryRange.toV,
|
||||
fromV: ctrl.selectedHistoryRange.fromV
|
||||
}
|
||||
}
|
||||
ctrl.resetHoveredRange = () => {
|
||||
ctrl.hoveredHistoryRange = { toV: null, fromV: null }
|
||||
}
|
||||
ctrl.setHoveredRangeToV = toV => {
|
||||
if (toV >= ctrl.hoveredHistoryRange.fromV) {
|
||||
ctrl.hoveredHistoryRange.toV = toV
|
||||
}
|
||||
}
|
||||
ctrl.setHoveredRangeFromV = fromV => {
|
||||
if (fromV <= ctrl.hoveredHistoryRange.toV) {
|
||||
ctrl.hoveredHistoryRange.fromV = fromV
|
||||
}
|
||||
}
|
||||
|
||||
ctrl.isVersionSelected = function(version) {
|
||||
if (ctrl.rangeSelectionEnabled) {
|
||||
return (
|
||||
version <= ctrl.selectedHistoryRange.toV &&
|
||||
version >= ctrl.selectedHistoryRange.fromV
|
||||
)
|
||||
} else {
|
||||
return version === ctrl.selectedHistoryVersion
|
||||
}
|
||||
}
|
||||
ctrl.isVersionHoverSelected = function(version) {
|
||||
return (
|
||||
ctrl.rangeSelectionEnabled &&
|
||||
version <= ctrl.hoveredHistoryRange.toV &&
|
||||
version >= ctrl.hoveredHistoryRange.fromV
|
||||
)
|
||||
}
|
||||
ctrl.onDraggingStart = () => {
|
||||
$scope.$applyAsync(() => {
|
||||
ctrl.isDragging = true
|
||||
ctrl.initHoveredRange()
|
||||
})
|
||||
}
|
||||
ctrl.onDraggingStop = (isValidDrop, boundary) => {
|
||||
$scope.$applyAsync(() => {
|
||||
if (!isValidDrop) {
|
||||
if (boundary === 'toV') {
|
||||
ctrl.setRangeToV(ctrl.hoveredHistoryRange.toV)
|
||||
} else if (boundary === 'fromV') {
|
||||
ctrl.setRangeFromV(ctrl.hoveredHistoryRange.fromV)
|
||||
}
|
||||
}
|
||||
ctrl.isDragging = false
|
||||
ctrl.resetHoveredRange()
|
||||
})
|
||||
}
|
||||
ctrl.onDrop = (boundary, versionWithLabel) => {
|
||||
if (boundary === 'toV') {
|
||||
$scope.$applyAsync(() => ctrl.setRangeToV(versionWithLabel.version))
|
||||
} else if (boundary === 'fromV') {
|
||||
$scope.$applyAsync(() => ctrl.setRangeFromV(versionWithLabel.version))
|
||||
}
|
||||
}
|
||||
ctrl.onOver = (boundary, versionWithLabel) => {
|
||||
if (boundary === 'toV') {
|
||||
$scope.$applyAsync(() =>
|
||||
ctrl.setHoveredRangeToV(versionWithLabel.version)
|
||||
)
|
||||
} else if (boundary === 'fromV') {
|
||||
$scope.$applyAsync(() =>
|
||||
ctrl.setHoveredRangeFromV(versionWithLabel.version)
|
||||
)
|
||||
}
|
||||
}
|
||||
ctrl.handleVersionSelect = versionWithLabel => {
|
||||
if (ctrl.rangeSelectionEnabled) {
|
||||
// TODO
|
||||
ctrl.onRangeSelect({
|
||||
selectedToV: versionWithLabel.version,
|
||||
selectedFromV: versionWithLabel.version
|
||||
})
|
||||
} else {
|
||||
ctrl.onVersionSelect({ version: versionWithLabel.version })
|
||||
}
|
||||
}
|
||||
ctrl.setRangeToV = version => {
|
||||
if (version >= ctrl.selectedHistoryRange.fromV) {
|
||||
ctrl.onRangeSelect({
|
||||
selectedToV: version,
|
||||
selectedFromV: ctrl.selectedHistoryRange.fromV
|
||||
})
|
||||
}
|
||||
}
|
||||
ctrl.setRangeFromV = version => {
|
||||
if (version <= ctrl.selectedHistoryRange.toV) {
|
||||
ctrl.onRangeSelect({
|
||||
selectedToV: ctrl.selectedHistoryRange.toV,
|
||||
selectedFromV: version
|
||||
})
|
||||
}
|
||||
}
|
||||
// This method (and maybe the one below) will be removed soon. User details data will be
|
||||
// injected into the history API responses, so we won't need to fetch user data from other
|
||||
// local data structures.
|
||||
|
@ -28,30 +145,37 @@ define([
|
|||
return curUserId === id
|
||||
})
|
||||
ctrl.displayName = displayNameForUser
|
||||
ctrl.getUserCSSStyle = function(user, label) {
|
||||
ctrl.getUserCSSStyle = function(user, versionWithLabel) {
|
||||
const curUserId =
|
||||
(user != null ? user._id : undefined) ||
|
||||
(user != null ? user.id : undefined)
|
||||
const hue = ColorManager.getHueForUserId(curUserId) || 100
|
||||
if (
|
||||
label.id ===
|
||||
(ctrl.selectedLabel != null ? ctrl.selectedLabel.id : undefined)
|
||||
ctrl.isVersionSelected(versionWithLabel.version) ||
|
||||
ctrl.isVersionHoverSelected(versionWithLabel.version)
|
||||
) {
|
||||
return { color: '#FFF' }
|
||||
} else {
|
||||
return { color: `hsl(${hue}, 70%, 50%)` }
|
||||
}
|
||||
}
|
||||
|
||||
ctrl.$onInit = () => {
|
||||
ctrl.resetHoveredRange()
|
||||
}
|
||||
}
|
||||
|
||||
return App.component('historyLabelsList', {
|
||||
bindings: {
|
||||
labels: '<',
|
||||
rangeSelectionEnabled: '<',
|
||||
users: '<',
|
||||
currentUser: '<',
|
||||
isLoading: '<',
|
||||
selectedLabel: '<',
|
||||
onLabelSelect: '&',
|
||||
selectedHistoryVersion: '<?',
|
||||
selectedHistoryRange: '<?',
|
||||
onVersionSelect: '&',
|
||||
onRangeSelect: '&',
|
||||
onLabelDelete: '&'
|
||||
},
|
||||
controller: historyLabelsListController,
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
/* eslint-disable
|
||||
camelcase,
|
||||
max-len,
|
||||
no-return-assign,
|
||||
no-undef,
|
||||
*/
|
||||
define(['base', 'ide/history/util/displayNameForUser'], function(
|
||||
App,
|
||||
displayNameForUser
|
||||
) {
|
||||
App.controller('HistoryCompareController', [
|
||||
'$scope',
|
||||
'$modal',
|
||||
'ide',
|
||||
'_',
|
||||
function($scope, $modal, ide, _) {
|
||||
$scope.projectUsers = []
|
||||
$scope.versionsWithLabels = []
|
||||
|
||||
$scope.$watch('project.members', function(newVal) {
|
||||
if (newVal != null) {
|
||||
$scope.projectUsers = newVal.concat($scope.project.owner)
|
||||
}
|
||||
})
|
||||
|
||||
$scope.$watchCollection('history.labels', function(labels) {
|
||||
if (labels != null && labels.length > 0) {
|
||||
const groupedLabelsHash = _.groupBy(labels, 'version')
|
||||
$scope.versionsWithLabels = _.map(
|
||||
groupedLabelsHash,
|
||||
(labels, version) => {
|
||||
return {
|
||||
version: parseInt(version, 10),
|
||||
labels
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
$scope.loadMore = () => ide.historyManager.fetchNextBatchOfUpdates()
|
||||
|
||||
$scope.setHoverFrom = fromV => ide.historyManager.setHoverFrom(fromV)
|
||||
|
||||
$scope.setHoverTo = toV => ide.historyManager.setHoverTo(toV)
|
||||
|
||||
$scope.resetHover = () => ide.historyManager.resetHover()
|
||||
|
||||
$scope.select = (toV, fromV) => {
|
||||
$scope.history.selection.range.toV = toV
|
||||
$scope.history.selection.range.fromV = fromV
|
||||
}
|
||||
|
||||
$scope.addLabelVersionToSelection = version => {
|
||||
ide.historyManager.expandSelectionToVersion(version)
|
||||
}
|
||||
|
||||
// This method (and maybe the one below) will be removed soon. User details data will be
|
||||
// injected into the history API responses, so we won't need to fetch user data from other
|
||||
// local data structures.
|
||||
$scope.getUserById = id =>
|
||||
_.find($scope.projectUsers, function(user) {
|
||||
let curUserId
|
||||
if (user) {
|
||||
curUserId = user._id || user.id
|
||||
}
|
||||
return curUserId === id
|
||||
})
|
||||
|
||||
$scope.getDisplayNameById = id =>
|
||||
displayNameForUser($scope.getUserById(id))
|
||||
|
||||
$scope.getDisplayNameForUser = user => displayNameForUser(user)
|
||||
|
||||
$scope.deleteLabel = labelDetails =>
|
||||
$modal.open({
|
||||
templateUrl: 'historyV2DeleteLabelModalTemplate',
|
||||
controller: 'HistoryV2DeleteLabelModalController',
|
||||
resolve: {
|
||||
labelDetails() {
|
||||
return labelDetails
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
])
|
||||
})
|
|
@ -35,11 +35,18 @@ define(['base', 'ide/history/util/displayNameForUser'], (
|
|||
return ide.historyManager.fetchNextBatchOfUpdates()
|
||||
}
|
||||
|
||||
$scope.handleEntrySelect = entry =>
|
||||
ide.historyManager.selectVersionForPointInTime(entry.toV)
|
||||
$scope.handleVersionSelect = version =>
|
||||
$scope.$applyAsync(() =>
|
||||
ide.historyManager.selectVersionForPointInTime(version)
|
||||
)
|
||||
|
||||
$scope.handleLabelSelect = label =>
|
||||
ide.historyManager.selectLabelForPointInTime(label)
|
||||
$scope.handleRangeSelect = (selectedToV, selectedFromV) =>
|
||||
$scope.$applyAsync(() =>
|
||||
ide.historyManager.selectVersionsForCompare(
|
||||
selectedToV,
|
||||
selectedFromV
|
||||
)
|
||||
)
|
||||
|
||||
return ($scope.handleLabelDelete = labelDetails =>
|
||||
$modal.open({
|
||||
|
|
|
@ -21,6 +21,9 @@ define(['base'], App =>
|
|||
($scope, $modal, ide, event_tracking, waitFor) => {
|
||||
let openEntity
|
||||
|
||||
$scope.currentUpdate = null
|
||||
$scope.currentLabel = null
|
||||
|
||||
$scope.restoreState = {
|
||||
inflight: false,
|
||||
error: false
|
||||
|
@ -50,6 +53,22 @@ define(['base'], App =>
|
|||
}
|
||||
})
|
||||
|
||||
$scope.$watch('history.viewMode', (newVal, oldVal) => {
|
||||
if (newVal != null && newVal !== oldVal) {
|
||||
$scope.currentUpdate = ide.historyManager.getUpdateForVersion(newVal)
|
||||
}
|
||||
})
|
||||
|
||||
$scope.$watch('history.selection.range.toV', (newVal, oldVal) => {
|
||||
if (
|
||||
newVal != null &&
|
||||
newVal !== oldVal &&
|
||||
$scope.history.viewMode === $scope.HistoryViewModes.POINT_IN_TIME
|
||||
) {
|
||||
$scope.currentUpdate = ide.historyManager.getUpdateForVersion(newVal)
|
||||
}
|
||||
})
|
||||
|
||||
$scope.toggleHistoryViewMode = () => {
|
||||
ide.historyManager.toggleHistoryViewMode()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
define(['base'], App =>
|
||||
App.directive('historyDraggableBoundary', () => ({
|
||||
scope: {
|
||||
historyDraggableBoundary: '@',
|
||||
historyDraggableBoundaryOnDragStart: '&',
|
||||
historyDraggableBoundaryOnDragStop: '&'
|
||||
},
|
||||
restrict: 'A',
|
||||
link(scope, element, attrs) {
|
||||
element.data('selectionBoundary', {
|
||||
boundary: scope.historyDraggableBoundary
|
||||
})
|
||||
element.draggable({
|
||||
axis: 'y',
|
||||
opacity: false,
|
||||
helper: 'clone',
|
||||
revert: true,
|
||||
scroll: true,
|
||||
cursor: 'row-resize',
|
||||
start(e, ui) {
|
||||
ui.helper.data('wasProperlyDropped', false)
|
||||
scope.historyDraggableBoundaryOnDragStart()
|
||||
},
|
||||
stop(e, ui) {
|
||||
scope.historyDraggableBoundaryOnDragStop({
|
||||
isValidDrop: ui.helper.data('wasProperlyDropped'),
|
||||
boundary: scope.historyDraggableBoundary
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})))
|
|
@ -0,0 +1,25 @@
|
|||
define(['base'], App =>
|
||||
App.directive('historyDroppableArea', () => ({
|
||||
scope: {
|
||||
historyDroppableAreaOnDrop: '&',
|
||||
historyDroppableAreaOnOver: '&',
|
||||
historyDroppableAreaOnOut: '&'
|
||||
},
|
||||
restrict: 'A',
|
||||
link(scope, element, attrs) {
|
||||
element.droppable({
|
||||
accept: e => '.history-entry-toV-handle, .history-entry-fromV-handle',
|
||||
drop: (e, ui) => {
|
||||
const draggedBoundary = ui.draggable.data('selectionBoundary')
|
||||
.boundary
|
||||
ui.helper.data('wasProperlyDropped', true)
|
||||
scope.historyDroppableAreaOnDrop({ boundary: draggedBoundary })
|
||||
},
|
||||
over: (e, ui) => {
|
||||
const draggedBoundary = ui.draggable.data('selectionBoundary')
|
||||
.boundary
|
||||
scope.historyDroppableAreaOnOver({ boundary: draggedBoundary })
|
||||
}
|
||||
})
|
||||
}
|
||||
})))
|
|
@ -69,6 +69,10 @@
|
|||
color: @history-base-color;
|
||||
height: 100%;
|
||||
background-color: @history-base-bg;
|
||||
position: relative;
|
||||
&.history-entries-dragging {
|
||||
cursor: row-resize;
|
||||
}
|
||||
}
|
||||
|
||||
.history-entry-day {
|
||||
|
@ -79,18 +83,82 @@
|
|||
line-height: 1;
|
||||
}
|
||||
|
||||
.history-entry-toV-handle,
|
||||
.history-entry-fromV-handle {
|
||||
position: absolute;
|
||||
background-color: @history-entry-handle-bg;
|
||||
height: @history-entry-handle-height;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
cursor: row-resize;
|
||||
|
||||
&.ui-draggable-dragging {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '\00b7\00b7\00b7\00b7';
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
width: 100%;
|
||||
font-size: 20px;
|
||||
color: #FFF;
|
||||
height: @history-entry-handle-height;
|
||||
line-height: @history-entry-handle-height / 2;
|
||||
}
|
||||
}
|
||||
|
||||
.history-entry-fromV-handle {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.history-entry-details {
|
||||
position: relative;
|
||||
background-color: #FFF;
|
||||
margin-bottom: 2px;
|
||||
border-bottom: solid 2px @history-base-bg;
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.history-entry-selected &,
|
||||
.history-entry-label-selected & {
|
||||
.history-version-with-label {
|
||||
.history-entry-details;
|
||||
padding: 7px 10px;
|
||||
}
|
||||
|
||||
.history-entry-selected .history-entry-details,
|
||||
.history-version-with-label-selected & {
|
||||
background-color: @history-entry-selected-bg;
|
||||
color: #FFF;
|
||||
}
|
||||
}
|
||||
|
||||
.history-entry-hover-selected .history-entry-details,
|
||||
.history-entry-hover-selected.history-entry-selected .history-entry-details,
|
||||
.history-version-with-label-hover-selected &,
|
||||
.history-version-with-label-hover-selected.history-entry-selected &, {
|
||||
background-color: tint(@history-entry-selected-bg, 20%);
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.history-entry-selected-to .history-entry-details,
|
||||
.history-entry-hover-selected-to .history-entry-details,
|
||||
.history-version-with-label-selected-to &,
|
||||
.history-version-with-label-hover-selected-to & {
|
||||
padding-top: @history-entry-handle-height + 5px;
|
||||
}
|
||||
|
||||
.history-entry-selected-from .history-entry-details,
|
||||
.history-entry-hover-selected-from .history-entry-details,
|
||||
.history-version-with-label-selected-from &,
|
||||
.history-version-with-label-hover-selected-from & {
|
||||
padding-bottom: @history-entry-handle-height + 5px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.history-label {
|
||||
display: inline-block;
|
||||
color: @history-entry-label-color;
|
||||
|
@ -99,12 +167,16 @@
|
|||
margin-right: 10px;
|
||||
white-space: nowrap;
|
||||
.history-entry-selected &,
|
||||
.history-entry-label-selected & {
|
||||
.history-entry-hover-selected &,
|
||||
.history-version-with-label-selected &,
|
||||
.history-version-with-label-hover-selected & {
|
||||
color: @history-entry-selected-label-color;
|
||||
}
|
||||
&.history-label-pseudo-current-state {
|
||||
.history-entry-selected &,
|
||||
.history-entry-label-selected & {
|
||||
.history-entry-hover-selected &,
|
||||
.history-version-with-label-selected &,
|
||||
.history-version-with-label-hover-selected & {
|
||||
color: @history-entry-selected-pseudo-label-color;
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +191,9 @@
|
|||
|
||||
}
|
||||
.history-entry-selected &,
|
||||
.history-entry-label-selected & {
|
||||
.history-entry-hover-selected &,
|
||||
.history-version-with-label-selected &,
|
||||
.history-version-with-label-hover-selected & {
|
||||
background-color: @history-entry-selected-label-bg-color;
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +216,9 @@
|
|||
&:hover {
|
||||
background-color: darken(@history-entry-label-bg-color, 8%);
|
||||
.history-entry-selected &,
|
||||
.history-entry-label-selected & {
|
||||
.history-entry-hover-selected &,
|
||||
.history-version-with-label-selected &,
|
||||
.history-version-with-label-hover-selected & {
|
||||
background-color: darken(@history-entry-selected-label-bg-color, 8%);
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +257,8 @@
|
|||
font-weight: bold;
|
||||
word-break: break-all;
|
||||
.history-entry-selected &,
|
||||
.history-entry-label-selected & {
|
||||
.history-entry-hover-selected &,
|
||||
.history-version-with-label-selected & {
|
||||
color: #FFF;
|
||||
}
|
||||
}
|
||||
|
@ -223,14 +300,6 @@
|
|||
.history-labels-list-compare {
|
||||
background-color: transparent;
|
||||
}
|
||||
.history-entry-label {
|
||||
.history-entry-details;
|
||||
padding: 7px 10px;
|
||||
&.history-entry-label-selected {
|
||||
background-color: @history-entry-selected-bg;
|
||||
color: #FFF;
|
||||
}
|
||||
}
|
||||
|
||||
.history-file-tree-inner {
|
||||
.full-size;
|
||||
|
|
|
@ -1030,6 +1030,8 @@
|
|||
@history-entry-selected-pseudo-label-color: @green;
|
||||
@history-entry-day-bg : @gray;
|
||||
@history-entry-selected-bg : @red;
|
||||
@history-entry-handle-bg : darken(@history-entry-selected-bg, 10%);
|
||||
@history-entry-handle-height : 8px;
|
||||
@history-base-color : @gray-light;
|
||||
@history-highlight-color : @gray;
|
||||
@history-toolbar-bg-color : @toolbar-alt-bg-color;
|
||||
|
|
|
@ -346,6 +346,8 @@
|
|||
@history-entry-selected-pseudo-label-color: @ol-green;
|
||||
@history-entry-day-bg : @ol-blue-gray-2;
|
||||
@history-entry-selected-bg : @ol-green;
|
||||
@history-entry-handle-bg : darken(@ol-green, 10%);
|
||||
@history-entry-handle-height : 8px;
|
||||
@history-base-color : @ol-blue-gray-2;
|
||||
@history-highlight-color : @ol-type-color;
|
||||
@history-toolbar-bg-color : @editor-toolbar-bg;
|
||||
|
|
|
@ -34,8 +34,6 @@ define(['ide/history/HistoryV2Manager'], HistoryV2Manager =>
|
|||
},
|
||||
diff: null,
|
||||
files: [],
|
||||
update: null,
|
||||
label: null,
|
||||
file: null
|
||||
},
|
||||
error: null,
|
||||
|
|
Loading…
Reference in a new issue