Show saving dialog based on whether there are inflight ops, and show a warning when leaving the page if there are

This commit is contained in:
James Allen 2014-04-07 12:55:57 +01:00
parent 6ad8566e24
commit a12716ab6b
5 changed files with 74 additions and 25 deletions

View file

@ -10,6 +10,11 @@ define [
@openDocs[doc_id] = new Document(ide, doc_id) @openDocs[doc_id] = new Document(ide, doc_id)
return @openDocs[doc_id] return @openDocs[doc_id]
@hasUnsavedChanges: () ->
for doc_id, doc of (@openDocs or {})
return true if doc.hasBufferedOps()
return false
constructor: (@ide, @doc_id) -> constructor: (@ide, @doc_id) ->
@connected = @ide.socket.socket.connected @connected = @ide.socket.socket.connected
@joined = false @joined = false
@ -25,8 +30,8 @@ define [
detachFromAce: () -> detachFromAce: () ->
@doc?.detachFromAce() @doc?.detachFromAce()
editorDoc = @ace.getSession().getDocument() editorDoc = @ace?.getSession().getDocument()
editorDoc.off "change", @_checkConsistency editorDoc?.off "change", @_checkConsistency
_checkConsistency: () -> _checkConsistency: () ->
editorValue = @ace?.getValue() editorValue = @ace?.getValue()
@ -40,6 +45,15 @@ define [
getType: () -> getType: () ->
@doc?.getType() @doc?.getType()
getInflightOp: () ->
@doc?.getInflightOp()
getPendingOp: () ->
@doc?.getPendingOp()
hasBufferedOps: () ->
@doc?.hasBufferedOps()
_bindToSocketEvents: () -> _bindToSocketEvents: () ->
@_onUpdateAppliedHandler = (update) => @_onUpdateApplied(update) @_onUpdateAppliedHandler = (update) => @_onUpdateApplied(update)
@ide.socket.on "otUpdateApplied", @_onUpdateAppliedHandler @ide.socket.on "otUpdateApplied", @_onUpdateAppliedHandler
@ -84,6 +98,25 @@ define [
else else
@_leaveDoc(callback) @_leaveDoc(callback)
pollSavedStatus: () ->
# returns false if doc has ops waiting to be acknowledged or
# sent that haven't changed since the last time we checked.
# Otherwise returns true.
inflightOp = @getInflightOp()
pendingOp = @getPendingOp()
if !inflightOp? and !pendingOp?
# there's nothing going on
saved = true
else if inflightOp == @oldInflightOp
saved = false
else if pendingOp?
saved = false
else
saved = true
@oldInflightOp = inflightOp
return saved
_cancelLeave: () -> _cancelLeave: () ->
if @_leaveCallbacks? if @_leaveCallbacks?
delete @_leaveCallbacks delete @_leaveCallbacks

View file

@ -210,11 +210,6 @@ define [
callback null, @document callback null, @document
_bindToDocumentEvents: (document) -> _bindToDocumentEvents: (document) ->
document.on "op:sent", () =>
@ide.savingAreaManager.saving()
document.on "op:acknowledged", () =>
@ide.savingAreaManager.saved()
document.on "remoteop", () => document.on "remoteop", () =>
@undoManager.nextUpdateIsRemote = true @undoManager.nextUpdateIsRemote = true
@ -364,3 +359,6 @@ define [
disable: () -> disable: () ->
@enabled = false @enabled = false
hasUnsavedChanges: () ->
Document.hasUnsavedChanges()

View file

@ -89,6 +89,9 @@ define [
hasBufferedOps: () -> hasBufferedOps: () ->
@_doc.inflightOp? or @_doc.pendingOp? @_doc.inflightOp? or @_doc.pendingOp?
getInflightOp: () -> @_doc.inflightOp
getPendingOp: () -> @_doc.pendingOp
attachToAce: (ace) -> @_doc.attach_ace(ace) attachToAce: (ace) -> @_doc.attach_ace(ace)
detachFromAce: () -> @_doc.detach_ace?() detachFromAce: () -> @_doc.detach_ace?()

View file

@ -11,6 +11,7 @@ define [
"ide/TabManager" "ide/TabManager"
"ide/LayoutManager" "ide/LayoutManager"
"ide/FileUploadManager" "ide/FileUploadManager"
"ide/SavingAreaManager"
"spelling/SpellingManager" "spelling/SpellingManager"
"search/SearchManager" "search/SearchManager"
"models/Project" "models/Project"
@ -45,6 +46,7 @@ define [
TabManager, TabManager,
LayoutManager, LayoutManager,
FileUploadManager, FileUploadManager,
SavingAreaManager,
SpellingManager, SpellingManager,
SearchManager, SearchManager,
Project, Project,
@ -205,22 +207,5 @@ define [
ide.tourManager = new IdeTour ide ide.tourManager = new IdeTour ide
ide.debugManager = new DebugManager(ide) ide.debugManager = new DebugManager(ide)
ide.savingAreaManager = ide.savingAreaManager = new SavingAreaManager(ide)
$savingArea : $('#saving-area')
timeOut: undefined
saved:->
@clearTimeout()
$("#savingProblems").hide()
saving:->
return if @timeOut?
@clearTimeout()
@timeOut = setTimeout((=>
ga?('send', 'event', 'editor-interaction', 'notification-shown', "saving")
$("#savingProblems").show()
), 3000)
clearTimeout:->
if @timeOut?
clearTimeout @timeOut
delete @timeOut

View file

@ -0,0 +1,30 @@
define [
], () ->
class SavingAreaManager
$el: $('#saving-area')
constructor: (@ide) ->
@unsavedSeconds = 0
setInterval () =>
@pollSavedStatus()
, 1000
$(window).bind 'beforeunload', () =>
@warnAboutUnsavedChanges()
pollSavedStatus: () ->
saved = @ide.editor.document.pollSavedStatus()
if saved
@unsavedSeconds = 0
else
@unsavedSeconds += 1
if @unsavedSeconds >= 4
$("#savingProblems").text("Saving... (#{@unsavedSeconds} seconds of unsaved changes)")
$("#savingProblems").show()
else
$("#savingProblems").hide()
warnAboutUnsavedChanges: () ->
if @ide.editor.hasUnsavedChanges()
return "You have unsaved changes. If you leave now they will not be saved."