define [ ], () -> class SafariScrollPatcher constructor: ($scope) -> @isOverAce = false # Flag to control if the pointer is over Ace. @pdfDiv = null @aceDiv = null # Start listening to PDF wheel events when the pointer leaves the PDF region. # P.S. This is the problem in a nutshell: although the pointer is elsewhere, # wheel events keep being dispatched to the PDF. @handlePdfDivMouseLeave = () => @pdfDiv.addEventListener "wheel", @dispatchToAce # Stop listening to wheel events when the pointer enters the PDF region. If # the pointer is over the PDF, native behaviour is adequate. @handlePdfDivMouseEnter = () => @pdfDiv.removeEventListener "wheel", @dispatchToAce # Set the "pointer over Ace" flag as false, when the mouse leaves its area. @handleAceDivMouseLeave = () => @isOverAce = false # Set the "pointer over Ace" flag as true, when the mouse enters its area. @handleAceDivMouseEnter = () => @isOverAce = true # Grab the elements (pdfDiv, aceDiv) and set the "hover" event listeners. # If elements are already defined, clear existing event listeners and do # the process again (grab elements, set listeners). @setListeners = () => @isOverAce = false # If elements aren't null, remove existing listeners. if @pdfDiv? @pdfDiv.removeEventListener @handlePdfDivMouseLeave @pdfDiv.removeEventListener @handlePdfDivMouseEnter if @aceDiv? @aceDiv.removeEventListener @handleAceDivMouseLeave @aceDiv.removeEventListener @handleAceDivMouseEnter # Grab elements. @pdfDiv = document.querySelector ".pdfjs-viewer" # Grab the PDF div. @aceDiv = document.querySelector ".ace_content" # Also the editor. # Set hover-related listeners. @pdfDiv.addEventListener "mouseleave", @handlePdfDivMouseLeave @pdfDiv.addEventListener "mouseenter", @handlePdfDivMouseEnter @aceDiv.addEventListener "mouseleave", @handleAceDivMouseLeave @aceDiv.addEventListener "mouseenter", @handleAceDivMouseEnter # Handler for wheel events on the PDF. # If the pointer is over Ace, grab the event, prevent default behaviour # and dispatch it to Ace. @dispatchToAce = (e) => if @isOverAce # If this is logged, the problem just happened: the event arrived # here (the PDF wheel handler), but it should've gone to Ace. # Small timeout - if we dispatch immediately, an exception is thrown. window.setTimeout(() => # Dispatch the exact same event to Ace (this will keep values # values e.g. `wheelDelta` consistent with user interaction). @aceDiv.dispatchEvent e , 1) # Avoid scrolling the PDF, as we assume this was intended to the # editor. e.preventDefault() # "loaded" event is emitted from the pdfViewer controller $scope. This means # that the previous PDF DOM element was destroyed and a new one is available, # so we need to grab the elements and set the listeners again. $scope.$on "loaded", () => @setListeners()