From 16e8cd7820108369d7544ea0bcf98792ce403fb6 Mon Sep 17 00:00:00 2001 From: Paulo Reis Date: Fri, 29 Jul 2016 17:45:50 +0100 Subject: [PATCH] Refactor Safari scroll patcher; ensure it works after PDF is reloaded. --- .../coffee/ide/SafariScrollPatcher.coffee | 119 ++++++++++-------- 1 file changed, 70 insertions(+), 49 deletions(-) diff --git a/services/web/public/coffee/ide/SafariScrollPatcher.coffee b/services/web/public/coffee/ide/SafariScrollPatcher.coffee index 4c77802926..c1535e3d27 100644 --- a/services/web/public/coffee/ide/SafariScrollPatcher.coffee +++ b/services/web/public/coffee/ide/SafariScrollPatcher.coffee @@ -2,58 +2,79 @@ define [ ], () -> class SafariScrollPatcher constructor: (ide, $scope) -> - @isBootstrapped = false - @isOverAce = false + @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 = () => + console.log "dispatching to ace enabled" + @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 = () => + console.log "dispatching to ace disabled" + @pdfDiv.removeEventListener "wheel", @dispatchToAce + + # Set the "pointer over Ace" flag as false, when the mouse leaves its area. + @handleAceDivMouseLeave = () => + @isOverAce = false + console.log 'is over ace = ' + @isOverAce + + # Set the "pointer over Ace" flag as true, when the mouse enters its area. + @handleAceDivMouseEnter = () => + @isOverAce = true + console.log 'is over ace = ' + @isOverAce + + # 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. + console.log "Event was bound to the PDF, dispatching 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 + , 5) + + # Avoid scrolling the PDF, as we assume this was intended to the + # editor. + e.preventDefault() + $scope.$on "loaded", () => - console.log this - if !@isBootstrapped - console.log "bootstrapping" - - @isBootstrapped = true; - @pdfDiv = document.querySelector ".pdfjs-viewer" # Grab the PDF div. - @aceDiv = document.querySelector ".ace_content" # Also the editor. - @isOverAce = false # Flag to control if the pointer is over Ace. - - # 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. - @pdfDiv.addEventListener "mouseleave", () => - @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. - @pdfDiv.addEventListener "mouseenter", () => - @pdfDiv.removeEventListener "wheel", dispatchToAce - - # Set the "pointer over Ace" flag as false, when the mouse leaves its area. - @aceDiv.addEventListener "mouseleave", () => - @isOverAce = false - - # Set the "pointer over Ace" flag as true, when the mouse enters its area. - @aceDiv.addEventListener "mouseenter", () => - @isOverAce = true - - # 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. - console.log "Event was bound to the PDF, dispatching 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 - , 5) - - # Avoid scrolling the PDF, as we assume this was intended to the - # editor. - e.preventDefault() + @setListeners()