SafariScrollPatcher.js 4.1 KB

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