mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-08 07:52:06 +00:00
Merge pull request #321 from sharelatex/ja-recompile-tweaks
Animate toolbar for auto-compile and consolidate trigger logic
This commit is contained in:
commit
a7fabb8e43
9 changed files with 173 additions and 54 deletions
|
@ -6,21 +6,21 @@ aside.file-tree(ng-controller="FileTreeController", ng-class="{ 'multi-selected'
|
|||
tooltip-html="'"+translate('new_file').replace(' ', '<br>')+"'",
|
||||
tooltip-placement="bottom"
|
||||
)
|
||||
i.fa.fa-file
|
||||
i.fa.fa-fw.fa-file
|
||||
a(
|
||||
href,
|
||||
ng-click="openNewFolderModal()",
|
||||
tooltip-html="'"+translate('new_folder').replace(' ', '<br>')+"'",
|
||||
tooltip-placement="bottom"
|
||||
)
|
||||
i.fa.fa-folder
|
||||
i.fa.fa-fw.fa-folder
|
||||
a(
|
||||
href,
|
||||
ng-click="openUploadFileModal()",
|
||||
tooltip=translate('upload'),
|
||||
tooltip-placement="bottom"
|
||||
)
|
||||
i.fa.fa-upload
|
||||
i.fa.fa-fw.fa-upload
|
||||
|
||||
.toolbar-right
|
||||
a(
|
||||
|
@ -30,7 +30,7 @@ aside.file-tree(ng-controller="FileTreeController", ng-class="{ 'multi-selected'
|
|||
tooltip-placement="bottom",
|
||||
ng-show="multiSelectedCount == 0"
|
||||
)
|
||||
i.fa.fa-pencil
|
||||
i.fa.fa-fw.fa-pencil
|
||||
a(
|
||||
href,
|
||||
ng-click="openDeleteModalForSelected()",
|
||||
|
@ -38,7 +38,7 @@ aside.file-tree(ng-controller="FileTreeController", ng-class="{ 'multi-selected'
|
|||
tooltip-placement="bottom",
|
||||
tooltip-append-to-body="true"
|
||||
)
|
||||
i.fa.fa-trash-o
|
||||
i.fa.fa-fw.fa-trash-o
|
||||
|
||||
|
||||
.file-tree-inner(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
div.full-size.pdf(ng-controller="PdfController")
|
||||
.toolbar.toolbar-pdf
|
||||
.toolbar.toolbar-pdf(ng-class="{ 'uncompiled-changes': uncompiledChanges && !autoCompileLintingError }")
|
||||
.btn-group.btn-recompile-group#recompile(
|
||||
dropdown,
|
||||
tooltip-html="'"+translate('recompile_pdf')+" <span class=\"keyboard-shortcut\">({{modifierKey}} + Enter)</span>'"
|
||||
|
@ -65,7 +65,7 @@ div.full-size.pdf(ng-controller="PdfController")
|
|||
tooltip=translate('stop_compile')
|
||||
tooltip-placement="bottom"
|
||||
)
|
||||
i.fa.fa-stop()
|
||||
i.fa.fa-fw.fa-stop()
|
||||
a.log-btn(
|
||||
href
|
||||
ng-click="toggleLogs()"
|
||||
|
@ -73,7 +73,7 @@ div.full-size.pdf(ng-controller="PdfController")
|
|||
tooltip=translate('logs_and_output_files')
|
||||
tooltip-placement="bottom"
|
||||
)
|
||||
i.fa.fa-file-text-o
|
||||
i.fa.fa-fw.fa-file-text-o
|
||||
span.label(
|
||||
ng-show="pdf.logEntries.warnings.length + pdf.logEntries.errors.length > 0"
|
||||
ng-class="{\
|
||||
|
@ -89,9 +89,21 @@ div.full-size.pdf(ng-controller="PdfController")
|
|||
tooltip=translate('download_pdf')
|
||||
tooltip-placement="bottom"
|
||||
)
|
||||
i.fa.fa-download
|
||||
i.fa.fa-fw.fa-download
|
||||
|
||||
.toolbar-right
|
||||
span.auto-compile-status.small(
|
||||
ng-show="uncompiledChanges && !compiling && !autoCompileLintingError"
|
||||
) #{translate('uncompiled_changes')}
|
||||
span.auto-compile-status.auto-compile-error.small(
|
||||
ng-show="autoCompileLintingError"
|
||||
tooltip-placement="bottom"
|
||||
tooltip=translate("code_check_failed_explanation")
|
||||
tooltip-append-to-body="true"
|
||||
)
|
||||
i.fa.fa-fw.fa-exclamation-triangle
|
||||
|
|
||||
| #{translate("code_check_failed")}
|
||||
a(
|
||||
href,
|
||||
ng-click="switchToFlatLayout()"
|
||||
|
|
|
@ -352,8 +352,13 @@ define [
|
|||
v: version
|
||||
@doc.on "change", (ops, oldSnapshot, msg) =>
|
||||
@_applyOpsToRanges(ops, oldSnapshot, msg)
|
||||
@ide.$scope.$emit "doc:changed",
|
||||
doc_id: @doc_id
|
||||
@doc.on "flipped_pending_to_inflight", () =>
|
||||
@trigger "flipped_pending_to_inflight"
|
||||
@doc.on "saved", () =>
|
||||
@ide.$scope.$emit "doc:saved",
|
||||
doc_id: @doc_id
|
||||
|
||||
_onError: (error, meta = {}) ->
|
||||
meta.doc_id = @doc_id
|
||||
|
|
|
@ -46,6 +46,8 @@ define [
|
|||
@trigger "remoteop", args...
|
||||
@_doc.on "flipped_pending_to_inflight", () =>
|
||||
@trigger "flipped_pending_to_inflight"
|
||||
@_doc.on "saved", () =>
|
||||
@trigger "saved"
|
||||
@_doc.on "error", (e) =>
|
||||
@_handleError(e)
|
||||
|
||||
|
|
|
@ -164,6 +164,9 @@ class Doc
|
|||
@inflightOp = null
|
||||
@inflightSubmittedIds.length = 0
|
||||
|
||||
if @pendingOp == null # All ops are acked
|
||||
@emit 'saved'
|
||||
|
||||
error = msg.error
|
||||
if error
|
||||
# The server has rejected an op from the client for some reason.
|
||||
|
|
|
@ -5,8 +5,12 @@ define [
|
|||
"libs/bib-log-parser"
|
||||
"services/log-hints-feedback"
|
||||
], (App, Ace, HumanReadableLogs, BibLogParser) ->
|
||||
AUTO_COMPILE_TIMEOUT = 5000
|
||||
OP_ACKNOWLEDGEMENT_TIMEOUT = 1100
|
||||
AUTO_COMPILE_MAX_WAIT = 5000
|
||||
# We add a 1 second debounce to sending user changes to server if they aren't
|
||||
# collaborating with anyone. This needs to be higher than that, and allow for
|
||||
# client to server latency, otherwise we compile before the op reaches the server
|
||||
# and then again on ack.
|
||||
AUTO_COMPILE_DEBOUNCE = 2000
|
||||
|
||||
App.controller "PdfController", ($scope, $http, ide, $modal, synctex, event_tracking, logHintsFeedback, localStorage) ->
|
||||
# enable per-user containers by default
|
||||
|
@ -75,38 +79,102 @@ define [
|
|||
$scope.pdf.view = 'errors'
|
||||
$scope.pdf.renderingError = true
|
||||
|
||||
autoCompileTimeout = null
|
||||
autoCompileInterval = null
|
||||
autoCompileIfReady = () ->
|
||||
if $scope.pdf.compiling
|
||||
return
|
||||
|
||||
# Only checking linting if syntaxValidation is on and visible to the user
|
||||
autoCompileLintingError = ide.$scope.hasLintingError and ide.$scope.settings.syntaxValidation
|
||||
if $scope.autoCompileLintingError != autoCompileLintingError
|
||||
$scope.$apply () ->
|
||||
$scope.autoCompileLintingError = autoCompileLintingError
|
||||
# We've likely been waiting a while until the user fixed the linting, but we
|
||||
# don't want to compile as soon as it is fixed, so reset the timeout.
|
||||
$scope.startedTryingAutoCompileAt = Date.now()
|
||||
$scope.docLastChangedAt = Date.now()
|
||||
if autoCompileLintingError
|
||||
return
|
||||
|
||||
# If there's a longish compile, don't compile immediately after if user is still typing
|
||||
startedTryingAt = Math.max($scope.startedTryingAutoCompileAt, $scope.lastFinishedCompileAt || 0)
|
||||
|
||||
timeSinceStartedTrying = Date.now() - startedTryingAt
|
||||
timeSinceLastChange = Date.now() - $scope.docLastChangedAt
|
||||
|
||||
shouldCompile = false
|
||||
if timeSinceLastChange > AUTO_COMPILE_DEBOUNCE # Don't compile in the middle of the user typing
|
||||
shouldCompile = true
|
||||
else if timeSinceStartedTrying > AUTO_COMPILE_MAX_WAIT # Unless they type for a long time
|
||||
shouldCompile = true
|
||||
else if timeSinceStartedTrying < 0 or timeSinceLastChange < 0
|
||||
# If time is non-monotonic, assume that the user's system clock has been
|
||||
# changed and continue with compile
|
||||
shouldCompile = true
|
||||
|
||||
if shouldCompile
|
||||
triggerAutoCompile()
|
||||
|
||||
triggerAutoCompile = () ->
|
||||
return if autoCompileTimeout or $scope.ui.pdfHidden
|
||||
$scope.recompile(isAutoCompileOnChange: true)
|
||||
|
||||
timeSinceLastCompile = Date.now() - $scope.recompiledAt
|
||||
# If time is non-monotonic, assume that the user's system clock has been
|
||||
# changed and continue with recompile
|
||||
isTimeNonMonotonic = timeSinceLastCompile < 0
|
||||
startTryingAutoCompile = () ->
|
||||
return if autoCompileInterval?
|
||||
$scope.startedTryingAutoCompileAt = Date.now()
|
||||
autoCompileInterval = setInterval autoCompileIfReady, 200
|
||||
|
||||
if isTimeNonMonotonic || timeSinceLastCompile >= AUTO_COMPILE_TIMEOUT
|
||||
# If user has code check disabled, it is likely because they have
|
||||
# linting errors that they are ignoring. Therefore it doesn't make sense
|
||||
# to block auto compiles. It also causes problems where server-provided
|
||||
# linting errors aren't cleared after typing
|
||||
if (ide.$scope.settings.syntaxValidation and !ide.$scope.hasLintingError)
|
||||
$scope.recompile(isAutoCompileOnChange: true) # compile if no linting errors
|
||||
else if !ide.$scope.settings.syntaxValidation
|
||||
$scope.recompile(isAutoCompileOnChange: true) # always recompile
|
||||
stopTryingAutoCompile = () ->
|
||||
clearInterval autoCompileInterval
|
||||
autoCompileInterval = null
|
||||
|
||||
$scope.$watch "uncompiledChanges", (uncompiledChanges) ->
|
||||
if uncompiledChanges
|
||||
startTryingAutoCompile()
|
||||
else
|
||||
# Extend remainder of timeout
|
||||
autoCompileTimeout = setTimeout () ->
|
||||
autoCompileTimeout = null
|
||||
triggerAutoCompile()
|
||||
, AUTO_COMPILE_TIMEOUT - timeSinceLastCompile
|
||||
stopTryingAutoCompile()
|
||||
|
||||
autoCompileListener = null
|
||||
$scope.uncompiledChanges = false
|
||||
recalculateUncompiledChanges = () ->
|
||||
if $scope.ui.pdfHidden
|
||||
# Don't bother auto-compiling if pdf isn't visible
|
||||
$scope.uncompiledChanges = false
|
||||
else if !$scope.docLastChangedAt?
|
||||
$scope.uncompiledChanges = false
|
||||
else if !$scope.lastStartedCompileAt? or $scope.docLastChangedAt > $scope.lastStartedCompileAt
|
||||
$scope.uncompiledChanges = true
|
||||
else
|
||||
$scope.uncompiledChanges = false
|
||||
|
||||
_updateDocLastChangedAt = () ->
|
||||
$scope.docLastChangedAt = Date.now()
|
||||
recalculateUncompiledChanges()
|
||||
|
||||
onDocChanged = () ->
|
||||
$scope.autoCompileLintingError = false
|
||||
_updateDocLastChangedAt()
|
||||
|
||||
onDocSaved = () ->
|
||||
# We use the save as a trigger too, to account for the delay between the client
|
||||
# and server. Otherwise, we might have compiled after the user made
|
||||
# the change on the client, but before the server had it.
|
||||
_updateDocLastChangedAt()
|
||||
|
||||
onCompilingStateChanged = (compiling) ->
|
||||
recalculateUncompiledChanges()
|
||||
|
||||
autoCompileListeners = []
|
||||
toggleAutoCompile = (enabling) ->
|
||||
if enabling
|
||||
autoCompileListener = ide.$scope.$on "ide:opAcknowledged", _.debounce(triggerAutoCompile, OP_ACKNOWLEDGEMENT_TIMEOUT)
|
||||
autoCompileListeners = [
|
||||
ide.$scope.$on "doc:changed", onDocChanged
|
||||
ide.$scope.$on "doc:saved", onDocSaved
|
||||
$scope.$watch "pdf.compiling", onCompilingStateChanged
|
||||
]
|
||||
else
|
||||
autoCompileListener() if autoCompileListener
|
||||
autoCompileListener = null
|
||||
for unbind in autoCompileListeners
|
||||
unbind()
|
||||
autoCompileListeners = []
|
||||
$scope.autoCompileLintingError = false
|
||||
|
||||
$scope.autocompile_enabled = localStorage("autocompile_enabled:#{$scope.project_id}") or false
|
||||
$scope.$watch "autocompile_enabled", (newValue, oldValue) ->
|
||||
|
@ -428,6 +496,7 @@ define [
|
|||
|
||||
event_tracking.sendMBSampled "editor-recompile-sampled", options
|
||||
|
||||
$scope.lastStartedCompileAt = Date.now()
|
||||
$scope.pdf.compiling = true
|
||||
$scope.pdf.isAutoCompileOnLoad = options?.isAutoCompileOnLoad # initial autocompile
|
||||
|
||||
|
@ -460,7 +529,7 @@ define [
|
|||
$scope.pdf.error = true
|
||||
$scope.pdf.view = 'errors'
|
||||
.finally () ->
|
||||
$scope.recompiledAt = Date.now()
|
||||
$scope.lastFinishedCompileAt = Date.now()
|
||||
|
||||
# This needs to be public.
|
||||
ide.$scope.recompile = $scope.recompile
|
||||
|
|
|
@ -1,13 +1,34 @@
|
|||
@stripe-width: 20px;
|
||||
@keyframes pdf-toolbar-stripes {
|
||||
from { background-position: 0 0; }
|
||||
to { background-position: @stripe-width 0; }
|
||||
}
|
||||
|
||||
.pdf .toolbar.toolbar-pdf when (@is-overleaf = true) {
|
||||
.toolbar-small-mixin;
|
||||
.toolbar-alt-mixin;
|
||||
border-bottom: 0;
|
||||
padding-right: 5px;
|
||||
&.uncompiled-changes {
|
||||
#gradient > .striped(@color: rgba(255,255,255,.10), @angle: -45deg);
|
||||
background-size: @stripe-width @stripe-width;
|
||||
.animation(pdf-toolbar-stripes 2s linear infinite);
|
||||
}
|
||||
.auto-compile-status {
|
||||
color: white;
|
||||
margin-right: (@line-height-computed / 2);
|
||||
i {
|
||||
color: @brand-danger;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pdf .toolbar.toolbar-pdf when (@is-overleaf = false) {
|
||||
.toolbar-tall-mixin;
|
||||
padding: 0 (@line-height-computed / 2);
|
||||
.auto-compile-status {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.pdf {
|
||||
|
@ -31,29 +52,30 @@
|
|||
|
||||
.btn-recompile-group when (@is-overleaf = true) {
|
||||
align-self: stretch;
|
||||
margin-right: 5px;
|
||||
margin-right: 6px;
|
||||
.btn-recompile {
|
||||
height: 100%;
|
||||
.btn-primary;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
&:first-child {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
&[disabled] {
|
||||
background-color: mix(@btn-primary-bg, @toolbar-alt-bg-color, 65%);
|
||||
.opacity(1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-recompile-group when (@is-overleaf = false) {
|
||||
margin-right: (@line-height-computed / 2);
|
||||
}
|
||||
|
||||
|
||||
.btn-recompile when (@is-overleaf = true) {
|
||||
height: 100%;
|
||||
.btn-primary;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
&:first-child {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
.btn-recompile {
|
||||
.btn-info;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-recompile when (@is-overleaf = false) {
|
||||
.btn-info;
|
||||
}
|
||||
|
||||
.btn-split-screen when (@is-overleaf = false) {
|
||||
.fa {
|
||||
display: none;
|
||||
|
@ -146,7 +168,6 @@
|
|||
width: 16px;
|
||||
height: 16px;
|
||||
border: 1px solid @gray-light;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
i.full-screen {
|
||||
|
|
|
@ -25,7 +25,9 @@
|
|||
.toolbar-right > a:not(.btn) {
|
||||
display: inline-block;
|
||||
color: @toolbar-icon-btn-color;
|
||||
padding: 0 5px;
|
||||
padding: 4px 2px;
|
||||
line-height: 1;
|
||||
height: 24px;
|
||||
border-radius: @border-radius-small;
|
||||
&.toolbar-header-back-projects {
|
||||
padding: 5px 10px 4px;
|
||||
|
@ -49,6 +51,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.toolbar-pdf > a:not(.btn) {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.btn-full-height {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
border-top: @caret-width-base solid;
|
||||
border-right: @caret-width-base solid transparent;
|
||||
border-left: @caret-width-base solid transparent;
|
||||
margin-top: -@caret-width-base/2;
|
||||
}
|
||||
|
||||
// The dropdown wrapper (div)
|
||||
|
|
Loading…
Add table
Reference in a new issue