diff --git a/docs/build-instructions/windows.md b/docs/build-instructions/windows.md index f54e1e049..600a7479d 100644 --- a/docs/build-instructions/windows.md +++ b/docs/build-instructions/windows.md @@ -20,7 +20,7 @@ * [Visual Studio Express 2013 or 2015 for Windows Desktop](http://www.visualstudio.com/en-us/downloads/download-visual-studio-vs#DownloadFamilies_2) * For VS 2015, be sure to customize the installation to include Visual C++. It's not installed by default. * Some have experienced issues with Node locating C++ on VS 2015. If so, try VS 2013. - * [node.js](http://nodejs.org/download/) (0.10.x or 0.12.x) or [io.js](https://iojs.org) (1.x or 2.x) + * [node.js](http://nodejs.org/download/) (0.10.x, 0.12.x or 4.x) or [io.js](https://iojs.org) (1.x or 2.x) * [Python](https://www.python.org/downloads/) v2.7.x (required by [node-gyp](https://github.com/TooTallNate/node-gyp)) * [GitHub Desktop](http://desktop.github.com/) diff --git a/package.json b/package.json index 394f05bda..b54222510 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "autocomplete-html": "0.7.2", "autocomplete-plus": "2.22.0", "autocomplete-snippets": "1.7.1", - "autoflow": "0.25.0", + "autoflow": "0.26.0", "autosave": "0.22.0", "background-tips": "0.26.0", "bookmarks": "0.38.0", @@ -103,7 +103,7 @@ "open-on-github": "0.38.0", "package-generator": "0.40.0", "release-notes": "0.53.0", - "settings-view": "0.225.0", + "settings-view": "0.229.0", "snippets": "0.100.0", "spell-check": "0.61.0", "status-bar": "0.79.0", @@ -111,20 +111,20 @@ "symbols-view": "0.109.0", "tabs": "0.84.0", "timecop": "0.33.0", - "tree-view": "0.189.0", + "tree-view": "0.190.0", "update-package-dependencies": "0.10.0", "welcome": "0.30.0", "whitespace": "0.31.0", "wrap-guide": "0.38.0", "language-c": "0.48.0", - "language-clojure": "0.17.0", + "language-clojure": "0.18.0", "language-coffee-script": "0.42.0", "language-csharp": "0.11.0", "language-css": "0.34.0", "language-gfm": "0.81.0", "language-git": "0.10.0", "language-go": "0.39.0", - "language-html": "0.41.3", + "language-html": "0.42.0", "language-hyperlink": "0.14.0", "language-java": "0.16.0", "language-javascript": "0.96.0", @@ -139,8 +139,8 @@ "language-python": "0.40.0", "language-ruby": "0.60.0", "language-ruby-on-rails": "0.23.0", - "language-sass": "0.41.0", - "language-shellscript": "0.17.0", + "language-sass": "0.42.0", + "language-shellscript": "0.19.0", "language-source": "0.9.0", "language-sql": "0.17.0", "language-text": "0.7.0", diff --git a/spec/pane-container-spec.coffee b/spec/pane-container-spec.coffee index 1442f24e4..34c38f535 100644 --- a/spec/pane-container-spec.coffee +++ b/spec/pane-container-spec.coffee @@ -139,6 +139,29 @@ describe "PaneContainer", -> pane2.activate() expect(observed).toEqual [pane1.itemAtIndex(0), pane2.itemAtIndex(0)] + describe "::onDidStopChangingActivePaneItem()", -> + [container, pane1, pane2, observed] = [] + + beforeEach -> + container = new PaneContainer(root: new Pane(items: [new Object, new Object])) + container.getRoot().splitRight(items: [new Object, new Object]) + [pane1, pane2] = container.getPanes() + + observed = [] + container.onDidStopChangingActivePaneItem (item) -> observed.push(item) + + it "invokes observers when the active item of the active pane stops changing", -> + pane2.activateNextItem() + pane2.activateNextItem() + advanceClock(100) + expect(observed).toEqual [pane2.itemAtIndex(0)] + + it "invokes observers when the active pane stops changing", -> + pane1.activate() + pane2.activate() + advanceClock(100) + expect(observed).toEqual [pane2.itemAtIndex(0)] + describe "::observePanes()", -> it "invokes observers with all current and future panes", -> container = new PaneContainer(params) diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index 39350392d..3be46b5fc 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -146,6 +146,8 @@ class AtomWindow when 0 then @browserWindow.destroy() when 1 then @browserWindow.restart() + @browserWindow.webContents.on 'will-navigate', (event) -> event.preventDefault() + @setupContextMenu() if @isSpec diff --git a/src/pane-container.coffee b/src/pane-container.coffee index 16a1274d6..94ae65757 100644 --- a/src/pane-container.coffee +++ b/src/pane-container.coffee @@ -9,6 +9,8 @@ module.exports = class PaneContainer extends Model serializationVersion: 1 root: null + stoppedChangingActivePaneItemDelay: 100 + stoppedChangingActivePaneItemTimeout: null constructor: (params) -> super @@ -73,6 +75,9 @@ class PaneContainer extends Model onDidChangeActivePaneItem: (fn) -> @emitter.on 'did-change-active-pane-item', fn + onDidStopChangingActivePaneItem: (fn) -> + @emitter.on 'did-stop-changing-active-pane-item', fn + observeActivePaneItem: (fn) -> fn(@getActivePaneItem()) @onDidChangeActivePaneItem(fn) @@ -180,12 +185,18 @@ class PaneContainer extends Model # Called by Model superclass when destroyed destroyed: -> + @cancelStoppedChangingActivePaneItemTimeout() pane.destroy() for pane in @getPanes() @subscriptions.dispose() @emitter.dispose() + cancelStoppedChangingActivePaneItemTimeout: -> + if @stoppedChangingActivePaneItemTimeout? + clearTimeout(@stoppedChangingActivePaneItemTimeout) + monitorActivePaneItem: -> childSubscription = null + @subscriptions.add @observeActivePane (activePane) => if childSubscription? @subscriptions.remove(childSubscription) @@ -193,6 +204,14 @@ class PaneContainer extends Model childSubscription = activePane.observeActiveItem (activeItem) => @emitter.emit 'did-change-active-pane-item', activeItem + @cancelStoppedChangingActivePaneItemTimeout() + stoppedChangingActivePaneItemCallback = => + @stoppedChangingActivePaneItemTimeout = null + @emitter.emit 'did-stop-changing-active-pane-item', activeItem + @stoppedChangingActivePaneItemTimeout = + setTimeout( + stoppedChangingActivePaneItemCallback, + @stoppedChangingActivePaneItemDelay) @subscriptions.add(childSubscription) diff --git a/src/workspace.coffee b/src/workspace.coffee index 6f0cc4ca1..37f4ac5a6 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -205,11 +205,34 @@ class Workspace extends Model # Essential: Invoke the given callback when the active pane item changes. # + # Because observers are invoked synchronously, it's important not to perform + # any expensive operations via this method. Consider + # {::onDidStopChangingActivePaneItem} to delay operations until after changes + # stop occurring. + # # * `callback` {Function} to be called when the active pane item changes. # * `item` The active pane item. # # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. - onDidChangeActivePaneItem: (callback) -> @paneContainer.onDidChangeActivePaneItem(callback) + onDidChangeActivePaneItem: (callback) -> + @paneContainer.onDidChangeActivePaneItem(callback) + + # Essential: Invoke the given callback when the active pane item stops + # changing. + # + # Observers are called asynchronously 100ms after the last active pane item + # change. Handling changes here rather than in the synchronous + # {::onDidChangeActivePaneItem} prevents unneeded work if the user is quickly + # changing or closing tabs and ensures critical UI feedback, like changing the + # highlighted tab, gets priority over work that can be done asynchronously. + # + # * `callback` {Function} to be called when the active pane item stopts + # changing. + # * `item` The active pane item. + # + # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + onDidStopChangingActivePaneItem: (callback) -> + @paneContainer.onDidStopChangingActivePaneItem(callback) # Essential: Invoke the given callback with the current active pane item and # with all future active pane items in the workspace.