From 2289e2b8286fa28404469976599db6db26c07054 Mon Sep 17 00:00:00 2001 From: Jason Rudolph Date: Thu, 19 Oct 2017 08:42:20 -0400 Subject: [PATCH] Decaffeinate src/window-event-handler.coffee --- src/window-event-handler.coffee | 189 ------------------------ src/window-event-handler.js | 253 ++++++++++++++++++++++++++++++++ 2 files changed, 253 insertions(+), 189 deletions(-) delete mode 100644 src/window-event-handler.coffee create mode 100644 src/window-event-handler.js diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee deleted file mode 100644 index 6a277b612..000000000 --- a/src/window-event-handler.coffee +++ /dev/null @@ -1,189 +0,0 @@ -{Disposable, CompositeDisposable} = require 'event-kit' -listen = require './delegated-listener' - -# Handles low-level events related to the @window. -module.exports = -class WindowEventHandler - constructor: ({@atomEnvironment, @applicationDelegate}) -> - @reloadRequested = false - @subscriptions = new CompositeDisposable - - @handleNativeKeybindings() - - initialize: (@window, @document) -> - @subscriptions.add @atomEnvironment.commands.add @window, - 'window:toggle-full-screen': @handleWindowToggleFullScreen - 'window:close': @handleWindowClose - 'window:reload': @handleWindowReload - 'window:toggle-dev-tools': @handleWindowToggleDevTools - - if process.platform in ['win32', 'linux'] - @subscriptions.add @atomEnvironment.commands.add @window, - 'window:toggle-menu-bar': @handleWindowToggleMenuBar - - @subscriptions.add @atomEnvironment.commands.add @document, - 'core:focus-next': @handleFocusNext - 'core:focus-previous': @handleFocusPrevious - - @addEventListener(@window, 'beforeunload', @handleWindowBeforeunload) - @addEventListener(@window, 'focus', @handleWindowFocus) - @addEventListener(@window, 'blur', @handleWindowBlur) - - @addEventListener(@document, 'keyup', @handleDocumentKeyEvent) - @addEventListener(@document, 'keydown', @handleDocumentKeyEvent) - @addEventListener(@document, 'drop', @handleDocumentDrop) - @addEventListener(@document, 'dragover', @handleDocumentDragover) - @addEventListener(@document, 'contextmenu', @handleDocumentContextmenu) - @subscriptions.add listen(@document, 'click', 'a', @handleLinkClick) - @subscriptions.add listen(@document, 'submit', 'form', @handleFormSubmit) - - @subscriptions.add(@applicationDelegate.onDidEnterFullScreen(@handleEnterFullScreen)) - @subscriptions.add(@applicationDelegate.onDidLeaveFullScreen(@handleLeaveFullScreen)) - - # Wire commands that should be handled by Chromium for elements with the - # `.native-key-bindings` class. - handleNativeKeybindings: -> - bindCommandToAction = (command, action) => - @subscriptions.add @atomEnvironment.commands.add( - '.native-key-bindings', - command, - ((event) => @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: -> - @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))) - - handleDocumentKeyEvent: (event) => - @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 element in @document.querySelectorAll('[tabindex]') - continue if element.disabled - continue unless element.tabIndex >= 0 - callback(element, element.tabIndex) - return - - handleFocusNext: => - focusedTabIndex = @document.activeElement.tabIndex ? -Infinity - - nextElement = null - nextTabIndex = Infinity - lowestElement = null - lowestTabIndex = Infinity - @eachTabIndexedElement (element, tabIndex) -> - if tabIndex < lowestTabIndex - lowestTabIndex = tabIndex - lowestElement = element - - if focusedTabIndex < tabIndex < nextTabIndex - nextTabIndex = tabIndex - nextElement = element - - if nextElement? - nextElement.focus() - else if lowestElement? - lowestElement.focus() - - handleFocusPrevious: => - focusedTabIndex = @document.activeElement.tabIndex ? Infinity - - previousElement = null - previousTabIndex = -Infinity - highestElement = null - highestTabIndex = -Infinity - @eachTabIndexedElement (element, tabIndex) -> - if tabIndex > highestTabIndex - highestTabIndex = tabIndex - highestElement = element - - if focusedTabIndex > tabIndex > previousTabIndex - previousTabIndex = tabIndex - previousElement = element - - if previousElement? - previousElement.focus() - else if highestElement? - highestElement.focus() - - handleWindowFocus: -> - @document.body.classList.remove('is-blurred') - - handleWindowBlur: => - @document.body.classList.add('is-blurred') - @atomEnvironment.storeWindowDimensions() - - handleEnterFullScreen: => - @document.body.classList.add("fullscreen") - - handleLeaveFullScreen: => - @document.body.classList.remove("fullscreen") - - handleWindowBeforeunload: (event) => - if not @reloadRequested and not @atomEnvironment.inSpecMode() and @atomEnvironment.getCurrentWindow().isWebViewFocused() - @atomEnvironment.hide() - @reloadRequested = false - @atomEnvironment.storeWindowDimensions() - @atomEnvironment.unloadEditorWindow() - @atomEnvironment.destroy() - - handleWindowToggleFullScreen: => - @atomEnvironment.toggleFullScreen() - - handleWindowClose: => - @atomEnvironment.close() - - handleWindowReload: => - @reloadRequested = true - @atomEnvironment.reload() - - handleWindowToggleDevTools: => - @atomEnvironment.toggleDevTools() - - handleWindowToggleMenuBar: => - @atomEnvironment.config.set('core.autoHideMenuBar', not @atomEnvironment.config.get('core.autoHideMenuBar')) - - if @atomEnvironment.config.get('core.autoHideMenuBar') - detail = "To toggle, press the Alt key or execute the window:toggle-menu-bar command" - @atomEnvironment.notifications.addInfo('Menu bar hidden', {detail}) - - handleLinkClick: (event) => - event.preventDefault() - uri = event.currentTarget?.getAttribute('href') - if uri and uri[0] isnt '#' and /^https?:\/\//.test(uri) - @applicationDelegate.openExternal(uri) - - handleFormSubmit: (event) -> - # Prevent form submits from changing the current window's URL - event.preventDefault() - - handleDocumentContextmenu: (event) => - event.preventDefault() - @atomEnvironment.contextMenu.showForEvent(event) diff --git a/src/window-event-handler.js b/src/window-event-handler.js new file mode 100644 index 000000000..6d380819b --- /dev/null +++ b/src/window-event-handler.js @@ -0,0 +1,253 @@ +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.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.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() + } + + 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) + } +}