Don’t use jQuery in window-event-handler or its spec

This commit is contained in:
Nathan Sobo
2015-09-03 19:42:34 -06:00
parent 938a8e5230
commit 9e59ab1e45
3 changed files with 255 additions and 244 deletions

View File

@@ -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)