Files
atom/src/window-event-handler.js
Xavier Fontes 0a9437bef2 🐛 Add event handler for window resizing.
Added event handler to solve issues about saving the window dimensions
2017-11-29 15:38:47 +00:00

260 lines
8.6 KiB
JavaScript

const {Disposable, CompositeDisposable} = require('event-kit')
const listen = require('./delegated-listener')
// Handles low-level events related to the `window`.
module.exports =
class WindowEventHandler {
constructor ({atomEnvironment, applicationDelegate}) {
this.handleDocumentKeyEvent = this.handleDocumentKeyEvent.bind(this)
this.handleFocusNext = this.handleFocusNext.bind(this)
this.handleFocusPrevious = this.handleFocusPrevious.bind(this)
this.handleWindowBlur = this.handleWindowBlur.bind(this)
this.handleWindowResize = this.handleWindowResize.bind(this)
this.handleEnterFullScreen = this.handleEnterFullScreen.bind(this)
this.handleLeaveFullScreen = this.handleLeaveFullScreen.bind(this)
this.handleWindowBeforeunload = this.handleWindowBeforeunload.bind(this)
this.handleWindowToggleFullScreen = this.handleWindowToggleFullScreen.bind(this)
this.handleWindowClose = this.handleWindowClose.bind(this)
this.handleWindowReload = this.handleWindowReload.bind(this)
this.handleWindowToggleDevTools = this.handleWindowToggleDevTools.bind(this)
this.handleWindowToggleMenuBar = this.handleWindowToggleMenuBar.bind(this)
this.handleLinkClick = this.handleLinkClick.bind(this)
this.handleDocumentContextmenu = this.handleDocumentContextmenu.bind(this)
this.atomEnvironment = atomEnvironment
this.applicationDelegate = applicationDelegate
this.reloadRequested = false
this.subscriptions = new CompositeDisposable()
this.handleNativeKeybindings()
}
initialize (window, document) {
this.window = window
this.document = document
this.subscriptions.add(this.atomEnvironment.commands.add(this.window, {
'window:toggle-full-screen': this.handleWindowToggleFullScreen,
'window:close': this.handleWindowClose,
'window:reload': this.handleWindowReload,
'window:toggle-dev-tools': this.handleWindowToggleDevTools
}))
if (['win32', 'linux'].includes(process.platform)) {
this.subscriptions.add(this.atomEnvironment.commands.add(this.window,
{'window:toggle-menu-bar': this.handleWindowToggleMenuBar})
)
}
this.subscriptions.add(this.atomEnvironment.commands.add(this.document, {
'core:focus-next': this.handleFocusNext,
'core:focus-previous': this.handleFocusPrevious
}))
this.addEventListener(this.window, 'beforeunload', this.handleWindowBeforeunload)
this.addEventListener(this.window, 'focus', this.handleWindowFocus)
this.addEventListener(this.window, 'blur', this.handleWindowBlur)
this.addEventListener(this.window, 'resize', this.handleWindowResize)
this.addEventListener(this.document, 'keyup', this.handleDocumentKeyEvent)
this.addEventListener(this.document, 'keydown', this.handleDocumentKeyEvent)
this.addEventListener(this.document, 'drop', this.handleDocumentDrop)
this.addEventListener(this.document, 'dragover', this.handleDocumentDragover)
this.addEventListener(this.document, 'contextmenu', this.handleDocumentContextmenu)
this.subscriptions.add(listen(this.document, 'click', 'a', this.handleLinkClick))
this.subscriptions.add(listen(this.document, 'submit', 'form', this.handleFormSubmit))
this.subscriptions.add(this.applicationDelegate.onDidEnterFullScreen(this.handleEnterFullScreen))
this.subscriptions.add(this.applicationDelegate.onDidLeaveFullScreen(this.handleLeaveFullScreen))
}
// Wire commands that should be handled by Chromium for elements with the
// `.native-key-bindings` class.
handleNativeKeybindings () {
const bindCommandToAction = (command, action) => {
this.subscriptions.add(
this.atomEnvironment.commands.add(
'.native-key-bindings',
command,
event => this.applicationDelegate.getCurrentWindow().webContents[action](),
false
)
)
}
bindCommandToAction('core:copy', 'copy')
bindCommandToAction('core:paste', 'paste')
bindCommandToAction('core:undo', 'undo')
bindCommandToAction('core:redo', 'redo')
bindCommandToAction('core:select-all', 'selectAll')
bindCommandToAction('core:cut', 'cut')
}
unsubscribe () {
this.subscriptions.dispose()
}
on (target, eventName, handler) {
target.on(eventName, handler)
this.subscriptions.add(new Disposable(function () {
target.removeListener(eventName, handler)
}))
}
addEventListener (target, eventName, handler) {
target.addEventListener(eventName, handler)
this.subscriptions.add(new Disposable(function () {
target.removeEventListener(eventName, handler)
}))
}
handleDocumentKeyEvent (event) {
this.atomEnvironment.keymaps.handleKeyboardEvent(event)
event.stopImmediatePropagation()
}
handleDrop (event) {
event.preventDefault()
event.stopPropagation()
}
handleDragover (event) {
event.preventDefault()
event.stopPropagation()
event.dataTransfer.dropEffect = 'none'
}
eachTabIndexedElement (callback) {
for (let element of this.document.querySelectorAll('[tabindex]')) {
if (element.disabled) { continue }
if (!(element.tabIndex >= 0)) { continue }
callback(element, element.tabIndex)
}
}
handleFocusNext () {
const focusedTabIndex = this.document.activeElement.tabIndex != null ? this.document.activeElement.tabIndex : -Infinity
let nextElement = null
let nextTabIndex = Infinity
let lowestElement = null
let lowestTabIndex = Infinity
this.eachTabIndexedElement(function (element, tabIndex) {
if (tabIndex < lowestTabIndex) {
lowestTabIndex = tabIndex
lowestElement = element
}
if (focusedTabIndex < tabIndex && tabIndex < nextTabIndex) {
nextTabIndex = tabIndex
nextElement = element
}
})
if (nextElement != null) {
nextElement.focus()
} else if (lowestElement != null) {
lowestElement.focus()
}
}
handleFocusPrevious () {
const focusedTabIndex = this.document.activeElement.tabIndex != null ? this.document.activeElement.tabIndex : Infinity
let previousElement = null
let previousTabIndex = -Infinity
let highestElement = null
let highestTabIndex = -Infinity
this.eachTabIndexedElement(function (element, tabIndex) {
if (tabIndex > highestTabIndex) {
highestTabIndex = tabIndex
highestElement = element
}
if (focusedTabIndex > tabIndex && tabIndex > previousTabIndex) {
previousTabIndex = tabIndex
previousElement = element
}
})
if (previousElement != null) {
previousElement.focus()
} else if (highestElement != null) {
highestElement.focus()
}
}
handleWindowFocus () {
this.document.body.classList.remove('is-blurred')
}
handleWindowBlur () {
this.document.body.classList.add('is-blurred')
this.atomEnvironment.storeWindowDimensions()
}
handleWindowResize () {
this.atomEnvironment.storeWindowDimensions()
}
handleEnterFullScreen () {
this.document.body.classList.add('fullscreen')
}
handleLeaveFullScreen () {
this.document.body.classList.remove('fullscreen')
}
handleWindowBeforeunload (event) {
if (!this.reloadRequested && !this.atomEnvironment.inSpecMode() && this.atomEnvironment.getCurrentWindow().isWebViewFocused()) {
this.atomEnvironment.hide()
}
this.reloadRequested = false
this.atomEnvironment.storeWindowDimensions()
this.atomEnvironment.unloadEditorWindow()
this.atomEnvironment.destroy()
}
handleWindowToggleFullScreen () {
this.atomEnvironment.toggleFullScreen()
}
handleWindowClose () {
this.atomEnvironment.close()
}
handleWindowReload () {
this.reloadRequested = true
this.atomEnvironment.reload()
}
handleWindowToggleDevTools () {
this.atomEnvironment.toggleDevTools()
}
handleWindowToggleMenuBar () {
this.atomEnvironment.config.set('core.autoHideMenuBar', !this.atomEnvironment.config.get('core.autoHideMenuBar'))
if (this.atomEnvironment.config.get('core.autoHideMenuBar')) {
const detail = 'To toggle, press the Alt key or execute the window:toggle-menu-bar command'
this.atomEnvironment.notifications.addInfo('Menu bar hidden', {detail})
}
}
handleLinkClick (event) {
event.preventDefault()
const uri = event.currentTarget && event.currentTarget.getAttribute('href')
if (uri && (uri[0] !== '#') && /^https?:\/\//.test(uri)) {
this.applicationDelegate.openExternal(uri)
}
}
handleFormSubmit (event) {
// Prevent form submits from changing the current window's URL
event.preventDefault()
}
handleDocumentContextmenu (event) {
event.preventDefault()
this.atomEnvironment.contextMenu.showForEvent(event)
}
}