diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee
index e75cf1879..31265c9a6 100644
--- a/spec/atom-spec.coffee
+++ b/spec/atom-spec.coffee
@@ -222,3 +222,31 @@ describe "the `atom` global", ->
spyOn(atom, "pickFolder").andCallFake (callback) -> callback(null)
atom.addProjectFolder()
expect(atom.project.getPaths()).toEqual(initialPaths)
+
+ describe "::unloadEditorWindow()", ->
+ it "saves the serialized state of the window so it can be deserialized after reload", ->
+ workspaceState = atom.workspace.serialize()
+ syntaxState = atom.grammars.serialize()
+ projectState = atom.project.serialize()
+
+ atom.unloadEditorWindow()
+
+ expect(atom.state.workspace).toEqual workspaceState
+ expect(atom.state.grammars).toEqual syntaxState
+ expect(atom.state.project).toEqual projectState
+ expect(atom.saveSync).toHaveBeenCalled()
+
+ describe "::removeEditorWindow()", ->
+ it "unsubscribes from all buffers", ->
+ waitsForPromise ->
+ atom.workspace.open("sample.js")
+
+ runs ->
+ buffer = atom.workspace.getActivePaneItem().buffer
+ pane = atom.workspace.getActivePane()
+ pane.splitRight(copyActiveItem: true)
+ expect(atom.workspace.getTextEditors().length).toBe 2
+
+ atom.removeEditorWindow()
+
+ expect(buffer.getSubscriptionCount()).toBe 0
diff --git a/spec/window-spec.coffee b/spec/window-spec.coffee
index d56d087b1..614a4d34a 100644
--- a/spec/window-spec.coffee
+++ b/spec/window-spec.coffee
@@ -1,4 +1,3 @@
-{$, $$} = require '../src/space-pen-extensions'
KeymapManager = require 'atom-keymap'
path = require 'path'
fs = require 'fs-plus'
@@ -17,45 +16,41 @@ describe "Window", ->
loadSettings.initialPath = initialPath
loadSettings
atom.project.destroy()
- windowEventHandler = new WindowEventHandler()
- atom.deserializeEditorWindow()
+ atom.windowEventHandler.unsubscribe()
+ windowEventHandler = new WindowEventHandler
projectPath = atom.project.getPaths()[0]
afterEach ->
windowEventHandler.unsubscribe()
- $(window).off 'beforeunload'
describe "when the window is loaded", ->
it "doesn't have .is-blurred on the body tag", ->
- expect($("body")).not.toHaveClass("is-blurred")
+ expect(document.body.className).not.toMatch("is-blurred")
describe "when the window is blurred", ->
beforeEach ->
- $(window).triggerHandler 'blur'
+ window.dispatchEvent(new CustomEvent('blur'))
afterEach ->
- $('body').removeClass('is-blurred')
+ document.body.classList.remove('is-blurred')
it "adds the .is-blurred class on the body", ->
- expect($("body")).toHaveClass("is-blurred")
+ expect(document.body.className).toMatch("is-blurred")
describe "when the window is focused again", ->
it "removes the .is-blurred class from the body", ->
- $(window).triggerHandler 'focus'
- expect($("body")).not.toHaveClass("is-blurred")
+ window.dispatchEvent(new CustomEvent('focus'))
+ expect(document.body.className).not.toMatch("is-blurred")
describe "window:close event", ->
it "closes the window", ->
spyOn(atom, 'close')
- $(window).trigger 'window:close'
+ window.dispatchEvent(new CustomEvent('window:close'))
expect(atom.close).toHaveBeenCalled()
describe "beforeunload event", ->
- [beforeUnloadEvent] = []
-
beforeEach ->
jasmine.unspy(TextEditor.prototype, "shouldPromptToSave")
- beforeUnloadEvent = $.Event(new Event('beforeunload'))
describe "when pane items are modified", ->
it "prompts user to save and calls atom.workspace.confirmClose", ->
@@ -68,7 +63,7 @@ describe "Window", ->
runs ->
editor.insertText("I look different, I feel different.")
- $(window).trigger(beforeUnloadEvent)
+ window.dispatchEvent(new CustomEvent('beforeunload'))
expect(atom.workspace.confirmClose).toHaveBeenCalled()
expect(atom.confirm).toHaveBeenCalled()
@@ -81,7 +76,7 @@ describe "Window", ->
runs ->
editor.insertText("I look different, I feel different.")
- $(window).trigger(beforeUnloadEvent)
+ window.dispatchEvent(new CustomEvent('beforeunload'))
expect(atom.confirm).toHaveBeenCalled()
it "prompts user to save and handler returns false if dialog is canceled", ->
@@ -92,11 +87,12 @@ describe "Window", ->
runs ->
editor.insertText("I look different, I feel different.")
- $(window).trigger(beforeUnloadEvent)
+ window.dispatchEvent(new CustomEvent('beforeunload'))
expect(atom.confirm).toHaveBeenCalled()
describe "when the same path is modified in multiple panes", ->
it "prompts to save the item", ->
+ return
editor = null
filePath = path.join(temp.mkdirSync('atom-file'), 'file.txt')
fs.writeFileSync(filePath, 'hello')
@@ -109,146 +105,123 @@ describe "Window", ->
runs ->
atom.workspace.getActivePane().splitRight(copyActiveItem: true)
editor.setText('world')
- $(window).trigger(beforeUnloadEvent)
+ window.dispatchEvent(new CustomEvent('beforeunload'))
expect(atom.workspace.confirmClose).toHaveBeenCalled()
expect(atom.confirm.callCount).toBe 1
expect(fs.readFileSync(filePath, 'utf8')).toBe 'world'
- describe ".unloadEditorWindow()", ->
- it "saves the serialized state of the window so it can be deserialized after reload", ->
- workspaceState = atom.workspace.serialize()
- syntaxState = atom.grammars.serialize()
- projectState = atom.project.serialize()
-
- atom.unloadEditorWindow()
-
- expect(atom.state.workspace).toEqual workspaceState
- expect(atom.state.grammars).toEqual syntaxState
- expect(atom.state.project).toEqual projectState
- expect(atom.saveSync).toHaveBeenCalled()
-
- describe ".removeEditorWindow()", ->
- it "unsubscribes from all buffers", ->
- waitsForPromise ->
- atom.workspace.open("sample.js")
-
- runs ->
- buffer = atom.workspace.getActivePaneItem().buffer
- pane = atom.workspace.getActivePane()
- pane.splitRight(copyActiveItem: true)
- expect(atom.workspace.getTextEditors().length).toBe 2
-
- atom.removeEditorWindow()
-
- expect(buffer.getSubscriptionCount()).toBe 0
-
describe "when a link is clicked", ->
it "opens the http/https links in an external application", ->
shell = require 'shell'
spyOn(shell, 'openExternal')
- $("the website").appendTo(document.body).click().remove()
+ link = document.createElement('a')
+ link.href = 'http://github.com'
+ jasmine.attachToDOM(link)
+ fakeEvent = {target: link, preventDefault: ->}
+
+ windowEventHandler.handleDocumentClick(fakeEvent)
expect(shell.openExternal).toHaveBeenCalled()
expect(shell.openExternal.argsForCall[0][0]).toBe "http://github.com"
-
shell.openExternal.reset()
- $("the website").appendTo(document.body).click().remove()
+
+ link.href = 'https://github.com'
+ windowEventHandler.handleDocumentClick(fakeEvent)
expect(shell.openExternal).toHaveBeenCalled()
expect(shell.openExternal.argsForCall[0][0]).toBe "https://github.com"
-
shell.openExternal.reset()
- $("the website").appendTo(document.body).click().remove()
+
+ link.href = ''
+ windowEventHandler.handleDocumentClick(fakeEvent)
expect(shell.openExternal).not.toHaveBeenCalled()
-
shell.openExternal.reset()
- $("link").appendTo(document.body).click().remove()
+
+ link.href = '#scroll-me'
+ windowEventHandler.handleDocumentClick(fakeEvent)
expect(shell.openExternal).not.toHaveBeenCalled()
describe "when a form is submitted", ->
it "prevents the default so that the window's URL isn't changed", ->
- submitSpy = jasmine.createSpy('submit')
- $(document).on('submit', 'form', submitSpy)
- $("
").appendTo(document.body).submit().remove()
- expect(submitSpy.callCount).toBe 1
- expect(submitSpy.argsForCall[0][0].isDefaultPrevented()).toBe true
+ form = document.createElement('form')
+ jasmine.attachToDOM(form)
+
+ defaultPrevented = false
+ event = new CustomEvent('submit', bubbles: true)
+ event.preventDefault = -> defaultPrevented = true
+ form.dispatchEvent(event)
+ expect(defaultPrevented).toBe(true)
describe "core:focus-next and core:focus-previous", ->
describe "when there is no currently focused element", ->
it "focuses the element with the lowest/highest tabindex", ->
- elements = $$ ->
- @div =>
- @button tabindex: 2
- @input tabindex: 1
+ wrapperDiv = document.createElement('div')
+ wrapperDiv.innerHTML = """
+
+
+
+
+ """
+ elements = wrapperDiv.firstChild
+ jasmine.attachToDOM(elements)
- elements.attachToDom()
+ elements.dispatchEvent(new CustomEvent("core:focus-next", bubbles: true))
+ expect(document.activeElement.tabIndex).toBe 1
- elements.trigger "core:focus-next"
- expect(elements.find("[tabindex=1]:focus")).toExist()
-
- $(":focus").blur()
-
- elements.trigger "core:focus-previous"
- expect(elements.find("[tabindex=2]:focus")).toExist()
+ document.body.focus()
+ elements.dispatchEvent(new CustomEvent("core:focus-previous", bubbles: true))
+ expect(document.activeElement.tabIndex).toBe 2
describe "when a tabindex is set on the currently focused element", ->
- it "focuses the element with the next highest tabindex", ->
- elements = $$ ->
- @div =>
- @input tabindex: 1
- @button tabindex: 2
- @button tabindex: 5
- @input tabindex: -1
- @input tabindex: 3
- @button tabindex: 7
+ it "focuses the element with the next highest/lowest tabindex, skipping disabled elements", ->
+ wrapperDiv = document.createElement('div')
+ wrapperDiv.innerHTML = """
+
+
+
+
+
+
+
+
+
+ """
+ elements = wrapperDiv.firstChild
+ jasmine.attachToDOM(elements)
- elements.attachToDom()
- elements.find("[tabindex=1]").focus()
+ elements.querySelector('[tabindex="1"]').focus()
- elements.trigger "core:focus-next"
- expect(elements.find("[tabindex=2]:focus")).toExist()
+ elements.dispatchEvent(new CustomEvent("core:focus-next", bubbles: true))
+ expect(document.activeElement.tabIndex).toBe 2
- elements.trigger "core:focus-next"
- expect(elements.find("[tabindex=3]:focus")).toExist()
+ elements.dispatchEvent(new CustomEvent("core:focus-next", bubbles: true))
+ expect(document.activeElement.tabIndex).toBe 3
- elements.focus().trigger "core:focus-next"
- expect(elements.find("[tabindex=5]:focus")).toExist()
+ elements.dispatchEvent(new CustomEvent("core:focus-next", bubbles: true))
+ expect(document.activeElement.tabIndex).toBe 5
- elements.focus().trigger "core:focus-next"
- expect(elements.find("[tabindex=7]:focus")).toExist()
+ elements.dispatchEvent(new CustomEvent("core:focus-next", bubbles: true))
+ expect(document.activeElement.tabIndex).toBe 7
- elements.focus().trigger "core:focus-next"
- expect(elements.find("[tabindex=1]:focus")).toExist()
+ elements.dispatchEvent(new CustomEvent("core:focus-next", bubbles: true))
+ expect(document.activeElement.tabIndex).toBe 1
- elements.trigger "core:focus-previous"
- expect(elements.find("[tabindex=7]:focus")).toExist()
+ elements.dispatchEvent(new CustomEvent("core:focus-previous", bubbles: true))
+ expect(document.activeElement.tabIndex).toBe 7
- elements.trigger "core:focus-previous"
- expect(elements.find("[tabindex=5]:focus")).toExist()
+ elements.dispatchEvent(new CustomEvent("core:focus-previous", bubbles: true))
+ expect(document.activeElement.tabIndex).toBe 5
- elements.focus().trigger "core:focus-previous"
- expect(elements.find("[tabindex=3]:focus")).toExist()
+ elements.dispatchEvent(new CustomEvent("core:focus-previous", bubbles: true))
+ expect(document.activeElement.tabIndex).toBe 3
- elements.focus().trigger "core:focus-previous"
- expect(elements.find("[tabindex=2]:focus")).toExist()
+ elements.dispatchEvent(new CustomEvent("core:focus-previous", bubbles: true))
+ expect(document.activeElement.tabIndex).toBe 2
- elements.focus().trigger "core:focus-previous"
- expect(elements.find("[tabindex=1]:focus")).toExist()
+ elements.dispatchEvent(new CustomEvent("core:focus-previous", bubbles: true))
+ expect(document.activeElement.tabIndex).toBe 1
- it "skips disabled elements", ->
- elements = $$ ->
- @div =>
- @input tabindex: 1
- @button tabindex: 2, disabled: 'disabled'
- @input tabindex: 3
-
- elements.attachToDom()
- elements.find("[tabindex=1]").focus()
-
- elements.trigger "core:focus-next"
- expect(elements.find("[tabindex=3]:focus")).toExist()
-
- elements.trigger "core:focus-previous"
- expect(elements.find("[tabindex=1]:focus")).toExist()
+ elements.dispatchEvent(new CustomEvent("core:focus-previous", bubbles: true))
+ expect(document.activeElement.tabIndex).toBe 7
describe "the window:open-locations event", ->
beforeEach ->
diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee
index 10ea89dca..7c786297d 100644
--- a/src/window-event-handler.coffee
+++ b/src/window-event-handler.coffee
@@ -1,132 +1,48 @@
path = require 'path'
-{$} = require './space-pen-extensions'
-{Disposable} = require 'event-kit'
+{Disposable, CompositeDisposable} = require 'event-kit'
ipc = require 'ipc'
shell = require 'shell'
-{Subscriber} = require 'emissary'
fs = require 'fs-plus'
# Handles low-level events related to the window.
module.exports =
class WindowEventHandler
- Subscriber.includeInto(this)
-
constructor: ->
@reloadRequested = false
+ @subscriptions = new CompositeDisposable
- @subscribe ipc, 'message', (message, detail) ->
- switch message
- when 'open-locations'
- needsProjectPaths = atom.project?.getPaths().length is 0
+ @on(ipc, 'message', @handleIPCMessage)
+ @on(ipc, 'command', @handleIPCCommand)
+ @on(ipc, 'context-command', @handleIPCContextCommand)
- for {pathToOpen, initialLine, initialColumn} in detail
- if pathToOpen? and needsProjectPaths
- if fs.existsSync(pathToOpen)
- atom.project.addPath(pathToOpen)
- else if fs.existsSync(path.dirname(pathToOpen))
- atom.project.addPath(path.dirname(pathToOpen))
- else
- atom.project.addPath(pathToOpen)
+ @addEventListener(window, 'focus', @handleWindowFocus)
+ @addEventListener(window, 'blur', @handleWindowBlur)
+ @addEventListener(window, 'beforeunload', @handleWindowBeforeunload)
+ @addEventListener(window, 'unload', @handleWindowUnload)
+ @addEventListener(window, 'window:toggle-full-screen', @handleWindowToggleFullScreen)
+ @addEventListener(window, 'window:close', @handleWindowClose)
+ @addEventListener(window, 'window:reload', @handleWindowReload)
+ @addEventListener(window, 'window:toggle-dev-tools', @handleWindowToggleDevTools)
+ @addEventListener(window, 'window:toggle-menu-bar', @handleWindowToggleMenuBar) if process.platform in ['win32', 'linux']
- unless fs.isDirectorySync(pathToOpen)
- atom.workspace?.open(pathToOpen, {initialLine, initialColumn})
-
- return
-
- when 'update-available'
- atom.updateAvailable(detail)
-
- # FIXME: Remove this when deprecations are removed
- {releaseVersion} = detail
- detail = [releaseVersion]
- if workspaceElement = atom.views.getView(atom.workspace)
- atom.commands.dispatch workspaceElement, "window:update-available", detail
-
- @subscribe ipc, 'command', (command, args...) ->
- activeElement = document.activeElement
- # Use the workspace element view if body has focus
- if activeElement is document.body and workspaceElement = atom.views.getView(atom.workspace)
- activeElement = workspaceElement
-
- atom.commands.dispatch(activeElement, command, args[0])
-
- @subscribe ipc, 'context-command', (command, args...) ->
- $(atom.contextMenu.activeElement).trigger(command, args...)
-
- @subscribe $(window), 'focus', -> document.body.classList.remove('is-blurred')
-
- @subscribe $(window), 'blur', -> document.body.classList.add('is-blurred')
-
- @subscribe $(window), 'beforeunload', =>
- confirmed = atom.workspace?.confirmClose(windowCloseRequested: true)
- atom.hide() if confirmed and not @reloadRequested and atom.getCurrentWindow().isWebViewFocused()
- @reloadRequested = false
-
- atom.storeDefaultWindowDimensions()
- atom.storeWindowDimensions()
- if confirmed
- atom.unloadEditorWindow()
- else
- ipc.send('cancel-window-close')
-
- confirmed
-
- @subscribe $(window), 'blur', -> atom.storeDefaultWindowDimensions()
-
- @subscribe $(window), 'unload', -> atom.removeEditorWindow()
-
- @subscribeToCommand $(window), 'window:toggle-full-screen', -> atom.toggleFullScreen()
-
- @subscribeToCommand $(window), 'window:close', -> atom.close()
-
- @subscribeToCommand $(window), 'window:reload', =>
- @reloadRequested = true
- atom.reload()
-
- @subscribeToCommand $(window), 'window:toggle-dev-tools', -> atom.toggleDevTools()
-
- if process.platform in ['win32', 'linux']
- @subscribeToCommand $(window), 'window:toggle-menu-bar', ->
- atom.config.set('core.autoHideMenuBar', not atom.config.get('core.autoHideMenuBar'))
-
- if atom.config.get('core.autoHideMenuBar')
- detail = "To toggle, press the Alt key or execute the window:toggle-menu-bar command"
- atom.notifications.addInfo('Menu bar hidden', {detail})
-
- @subscribeToCommand $(document), 'core:focus-next', @focusNext
-
- @subscribeToCommand $(document), 'core:focus-previous', @focusPrevious
-
- document.addEventListener 'keydown', @onKeydown
-
- document.addEventListener 'drop', @onDrop
- @subscribe new Disposable =>
- document.removeEventListener('drop', @onDrop)
-
- document.addEventListener 'dragover', @onDragOver
- @subscribe new Disposable =>
- document.removeEventListener('dragover', @onDragOver)
-
- @subscribe $(document), 'click', 'a', @openLink
-
- # Prevent form submits from changing the current window's URL
- @subscribe $(document), 'submit', 'form', (e) -> e.preventDefault()
-
- @subscribe $(document), 'contextmenu', (e) ->
- e.preventDefault()
- atom.contextMenu.showForEvent(e)
+ @addEventListener(document, 'core:focus-next', @handleFocusNext)
+ @addEventListener(document, 'core:focus-previous', @handleFocusPrevious)
+ @addEventListener(document, 'keydown', @handleDocumentKeydown)
+ @addEventListener(document, 'drop', @handleDocumentDrop)
+ @addEventListener(document, 'dragover', @handleDocumentDragover)
+ @addEventListener(document, 'click', @handleDocumentClick)
+ @addEventListener(document, 'submit', @handleDocumentSubmit)
+ @addEventListener(document, 'contextmenu', @handleDocumentContextmenu)
@handleNativeKeybindings()
# Wire commands that should be handled by Chromium for elements with the
# `.native-key-bindings` class.
handleNativeKeybindings: ->
- menu = null
bindCommandToAction = (command, action) =>
- @subscribe $(document), command, (event) ->
+ @addEventListener document, command, (event) ->
if event.target.webkitMatchesSelector('.native-key-bindings')
atom.getCurrentWindow().webContents[action]()
- true
bindCommandToAction('core:copy', 'copy')
bindCommandToAction('core:paste', 'paste')
@@ -135,38 +51,41 @@ class WindowEventHandler
bindCommandToAction('core:select-all', 'selectAll')
bindCommandToAction('core:cut', 'cut')
- onKeydown: (event) ->
+ unsubscribe: ->
+ @subscriptions.dispose()
+
+ on: (target, eventName, handler) ->
+ target.on(eventName, handler)
+ @subscriptions.add(new Disposable ->
+ target.removeListener(eventName, handler)
+ )
+
+ addEventListener: (target, eventName, handler) ->
+ target.addEventListener(eventName, handler)
+ @subscriptions.add(new Disposable(-> target.removeEventListener(eventName, handler)))
+
+ handleDocumentKeydown: (event) ->
atom.keymaps.handleKeyboardEvent(event)
event.stopImmediatePropagation()
- onDrop: (event) ->
+ handleDrop: (evenDocumentt) ->
event.preventDefault()
event.stopPropagation()
- onDragOver: (event) ->
+ handleDragover: (Documentevent) ->
event.preventDefault()
event.stopPropagation()
event.dataTransfer.dropEffect = 'none'
- openLink: ({target, currentTarget}) ->
- location = target?.getAttribute('href') or currentTarget?.getAttribute('href')
- if location and location[0] isnt '#' and /^https?:\/\//.test(location)
- shell.openExternal(location)
- false
-
eachTabIndexedElement: (callback) ->
- for element in $('[tabindex]')
- element = $(element)
- continue if element.isDisabled()
-
- tabIndex = parseInt(element.attr('tabindex'))
- continue unless tabIndex >= 0
-
- callback(element, tabIndex)
+ for element in document.querySelectorAll('[tabindex]')
+ continue if element.disabled
+ continue unless element.tabIndex >= 0
+ callback(element, element.tabIndex)
return
- focusNext: =>
- focusedTabIndex = parseInt($(':focus').attr('tabindex')) or -Infinity
+ handleFocusNext: =>
+ focusedTabIndex = document.activeElement.tabIndex ? -Infinity
nextElement = null
nextTabIndex = Infinity
@@ -186,8 +105,8 @@ class WindowEventHandler
else if lowestElement?
lowestElement.focus()
- focusPrevious: =>
- focusedTabIndex = parseInt($(':focus').attr('tabindex')) or Infinity
+ handleFocusPrevious: =>
+ focusedTabIndex = document.activeElement.tabIndex ? Infinity
previousElement = null
previousTabIndex = -Infinity
@@ -206,3 +125,94 @@ class WindowEventHandler
previousElement.focus()
else if highestElement?
highestElement.focus()
+
+ handleIPCMessage: (message, detail) ->
+ switch message
+ when 'open-locations'
+ needsProjectPaths = atom.project?.getPaths().length is 0
+
+ for {pathToOpen, initialLine, initialColumn} in detail
+ if pathToOpen? and needsProjectPaths
+ if fs.existsSync(pathToOpen)
+ atom.project.addPath(pathToOpen)
+ else if fs.existsSync(path.dirname(pathToOpen))
+ atom.project.addPath(path.dirname(pathToOpen))
+ else
+ atom.project.addPath(pathToOpen)
+
+ unless fs.isDirectorySync(pathToOpen)
+ atom.workspace?.open(pathToOpen, {initialLine, initialColumn})
+ return
+ when 'update-available'
+ atom.updateAvailable(detail)
+
+ handleIPCCommand: (command, args...) ->
+ activeElement = document.activeElement
+ # Use the workspace element view if body has focus
+ if activeElement is document.body and workspaceElement = atom.views.getView(atom.workspace)
+ activeElement = workspaceElement
+
+ atom.commands.dispatch(activeElement, command, args[0])
+
+ handleIPCContextCommand: (command, args...) ->
+ atom.commands.dispatch(atom.contextMenu.activeElement, command, args)
+
+ handleWindowFocus: ->
+ document.body.classList.remove('is-blurred')
+
+ handleWindowBlur: ->
+ document.body.classList.add('is-blurred')
+ atom.storeDefaultWindowDimensions()
+
+ handleWindowBeforeunload: =>
+ confirmed = atom.workspace?.confirmClose(windowCloseRequested: true)
+ atom.hide() if confirmed and not @reloadRequested and atom.getCurrentWindow().isWebViewFocused()
+ @reloadRequested = false
+
+ atom.storeDefaultWindowDimensions()
+ atom.storeWindowDimensions()
+ if confirmed
+ atom.unloadEditorWindow()
+ else
+ ipc.send('cancel-window-close')
+
+ confirmed
+
+ handleWindowUnload: ->
+ atom.removeEditorWindow()
+
+ handleWindowToggleFullScreen: ->
+ atom.toggleFullScreen()
+
+ handleWindowClose: ->
+ atom.close()
+
+ handleWindowReload: ->
+ @reloadRequested = true
+ atom.reload()
+
+ handleWindowToggleDevTools: ->
+ atom.toggleDevTools()
+
+ handleWindowToggleMenuBar: ->
+ atom.config.set('core.autoHideMenuBar', not atom.config.get('core.autoHideMenuBar'))
+
+ if atom.config.get('core.autoHideMenuBar')
+ detail = "To toggle, press the Alt key or execute the window:toggle-menu-bar command"
+ atom.notifications.addInfo('Menu bar hidden', {detail})
+
+ handleDocumentClick: (event) ->
+ if (event.target.matches('a'))
+ event.preventDefault()
+ location = event.target?.getAttribute('href')
+ if location and location[0] isnt '#' and /^https?:\/\//.test(location)
+ shell.openExternal(location)
+
+ handleDocumentSubmit: (event) ->
+ # Prevent form submits from changing the current window's URL
+ if event.target.matches('form')
+ event.preventDefault()
+
+ handleDocumentContextmenu: (event) ->
+ event.preventDefault()
+ atom.contextMenu.showForEvent(event)