diff --git a/services/web/public/coffee/editor/Document.coffee b/services/web/public/coffee/editor/Document.coffee index e1380dba8e..62987c07e5 100644 --- a/services/web/public/coffee/editor/Document.coffee +++ b/services/web/public/coffee/editor/Document.coffee @@ -10,6 +10,11 @@ define [ @openDocs[doc_id] = new Document(ide, 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) -> @connected = @ide.socket.socket.connected @joined = false @@ -25,8 +30,8 @@ define [ detachFromAce: () -> @doc?.detachFromAce() - editorDoc = @ace.getSession().getDocument() - editorDoc.off "change", @_checkConsistency + editorDoc = @ace?.getSession().getDocument() + editorDoc?.off "change", @_checkConsistency _checkConsistency: () -> editorValue = @ace?.getValue() @@ -40,6 +45,15 @@ define [ getType: () -> @doc?.getType() + getInflightOp: () -> + @doc?.getInflightOp() + + getPendingOp: () -> + @doc?.getPendingOp() + + hasBufferedOps: () -> + @doc?.hasBufferedOps() + _bindToSocketEvents: () -> @_onUpdateAppliedHandler = (update) => @_onUpdateApplied(update) @ide.socket.on "otUpdateApplied", @_onUpdateAppliedHandler @@ -84,6 +98,25 @@ define [ else @_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: () -> if @_leaveCallbacks? delete @_leaveCallbacks diff --git a/services/web/public/coffee/editor/Editor.coffee b/services/web/public/coffee/editor/Editor.coffee index de2860c6d4..b0909e1ac3 100644 --- a/services/web/public/coffee/editor/Editor.coffee +++ b/services/web/public/coffee/editor/Editor.coffee @@ -210,11 +210,6 @@ define [ callback null, @document _bindToDocumentEvents: (document) -> - document.on "op:sent", () => - @ide.savingAreaManager.saving() - document.on "op:acknowledged", () => - @ide.savingAreaManager.saved() - document.on "remoteop", () => @undoManager.nextUpdateIsRemote = true @@ -364,3 +359,6 @@ define [ disable: () -> @enabled = false + + hasUnsavedChanges: () -> + Document.hasUnsavedChanges() diff --git a/services/web/public/coffee/editor/ShareJsDoc.coffee b/services/web/public/coffee/editor/ShareJsDoc.coffee index 04485c9602..f264fe6a9c 100644 --- a/services/web/public/coffee/editor/ShareJsDoc.coffee +++ b/services/web/public/coffee/editor/ShareJsDoc.coffee @@ -89,6 +89,9 @@ define [ hasBufferedOps: () -> @_doc.inflightOp? or @_doc.pendingOp? + getInflightOp: () -> @_doc.inflightOp + getPendingOp: () -> @_doc.pendingOp + attachToAce: (ace) -> @_doc.attach_ace(ace) detachFromAce: () -> @_doc.detach_ace?() diff --git a/services/web/public/coffee/ide.coffee b/services/web/public/coffee/ide.coffee index 2dec585952..5bfdcc0c4d 100644 --- a/services/web/public/coffee/ide.coffee +++ b/services/web/public/coffee/ide.coffee @@ -11,6 +11,7 @@ define [ "ide/TabManager" "ide/LayoutManager" "ide/FileUploadManager" + "ide/SavingAreaManager" "spelling/SpellingManager" "search/SearchManager" "models/Project" @@ -45,6 +46,7 @@ define [ TabManager, LayoutManager, FileUploadManager, + SavingAreaManager, SpellingManager, SearchManager, Project, @@ -205,22 +207,5 @@ define [ ide.tourManager = new IdeTour ide ide.debugManager = new DebugManager(ide) - ide.savingAreaManager = - $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 + ide.savingAreaManager = new SavingAreaManager(ide) diff --git a/services/web/public/coffee/ide/SavingAreaManager.coffee b/services/web/public/coffee/ide/SavingAreaManager.coffee new file mode 100644 index 0000000000..9006eced0a --- /dev/null +++ b/services/web/public/coffee/ide/SavingAreaManager.coffee @@ -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."