SafariScrollPatcher.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. /* eslint-disable
  2. max-len,
  3. no-return-assign,
  4. no-undef,
  5. no-unused-vars,
  6. */
  7. // TODO: This file was created by bulk-decaffeinate.
  8. // Fix any style issues and re-enable lint.
  9. /*
  10. * decaffeinate suggestions:
  11. * DS102: Remove unnecessary code created because of implicit returns
  12. * DS207: Consider shorter variations of null checks
  13. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  14. */
  15. define([], function() {
  16. let SafariScrollPatcher
  17. return (SafariScrollPatcher = class SafariScrollPatcher {
  18. constructor($scope) {
  19. this.isOverAce = false // Flag to control if the pointer is over Ace.
  20. this.pdfDiv = null
  21. this.aceDiv = null
  22. // Start listening to PDF wheel events when the pointer leaves the PDF region.
  23. // P.S. This is the problem in a nutshell: although the pointer is elsewhere,
  24. // wheel events keep being dispatched to the PDF.
  25. this.handlePdfDivMouseLeave = () => {
  26. return this.pdfDiv.addEventListener('wheel', this.dispatchToAce)
  27. }
  28. // Stop listening to wheel events when the pointer enters the PDF region. If
  29. // the pointer is over the PDF, native behaviour is adequate.
  30. this.handlePdfDivMouseEnter = () => {
  31. return this.pdfDiv.removeEventListener('wheel', this.dispatchToAce)
  32. }
  33. // Set the "pointer over Ace" flag as false, when the mouse leaves its area.
  34. this.handleAceDivMouseLeave = () => {
  35. return (this.isOverAce = false)
  36. }
  37. // Set the "pointer over Ace" flag as true, when the mouse enters its area.
  38. this.handleAceDivMouseEnter = () => {
  39. return (this.isOverAce = true)
  40. }
  41. // Grab the elements (pdfDiv, aceDiv) and set the "hover" event listeners.
  42. // If elements are already defined, clear existing event listeners and do
  43. // the process again (grab elements, set listeners).
  44. this.setListeners = () => {
  45. this.isOverAce = false
  46. // If elements aren't null, remove existing listeners.
  47. if (this.pdfDiv != null) {
  48. this.pdfDiv.removeEventListener(this.handlePdfDivMouseLeave)
  49. this.pdfDiv.removeEventListener(this.handlePdfDivMouseEnter)
  50. }
  51. if (this.aceDiv != null) {
  52. this.aceDiv.removeEventListener(this.handleAceDivMouseLeave)
  53. this.aceDiv.removeEventListener(this.handleAceDivMouseEnter)
  54. }
  55. // Grab elements.
  56. this.pdfDiv = document.querySelector('.pdfjs-viewer') // Grab the PDF div.
  57. this.aceDiv = document.querySelector('.ace_content') // Also the editor.
  58. // Set hover-related listeners.
  59. this.pdfDiv.addEventListener('mouseleave', this.handlePdfDivMouseLeave)
  60. this.pdfDiv.addEventListener('mouseenter', this.handlePdfDivMouseEnter)
  61. this.aceDiv.addEventListener('mouseleave', this.handleAceDivMouseLeave)
  62. return this.aceDiv.addEventListener(
  63. 'mouseenter',
  64. this.handleAceDivMouseEnter
  65. )
  66. }
  67. // Handler for wheel events on the PDF.
  68. // If the pointer is over Ace, grab the event, prevent default behaviour
  69. // and dispatch it to Ace.
  70. this.dispatchToAce = e => {
  71. if (this.isOverAce) {
  72. // If this is logged, the problem just happened: the event arrived
  73. // here (the PDF wheel handler), but it should've gone to Ace.
  74. // Small timeout - if we dispatch immediately, an exception is thrown.
  75. window.setTimeout(() => {
  76. // Dispatch the exact same event to Ace (this will keep values
  77. // values e.g. `wheelDelta` consistent with user interaction).
  78. return this.aceDiv.dispatchEvent(e)
  79. }, 1)
  80. // Avoid scrolling the PDF, as we assume this was intended to the
  81. // editor.
  82. return e.preventDefault()
  83. }
  84. }
  85. // "loaded" event is emitted from the pdfViewer controller $scope. This means
  86. // that the previous PDF DOM element was destroyed and a new one is available,
  87. // so we need to grab the elements and set the listeners again.
  88. $scope.$on('loaded', () => {
  89. return this.setListeners()
  90. })
  91. }
  92. })
  93. })