SafariScrollPatcher.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  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(this.handlePdfDivMouseLeave)
  47. this.pdfDiv.removeEventListener(this.handlePdfDivMouseEnter)
  48. }
  49. if (this.aceDiv != null) {
  50. this.aceDiv.removeEventListener(this.handleAceDivMouseLeave)
  51. this.aceDiv.removeEventListener(this.handleAceDivMouseEnter)
  52. }
  53. // Grab elements.
  54. this.pdfDiv = document.querySelector('.pdfjs-viewer') // Grab the PDF div.
  55. this.aceDiv = document.querySelector('.ace_content') // Also the editor.
  56. // Set hover-related listeners.
  57. this.pdfDiv.addEventListener('mouseleave', this.handlePdfDivMouseLeave)
  58. this.pdfDiv.addEventListener('mouseenter', this.handlePdfDivMouseEnter)
  59. this.aceDiv.addEventListener('mouseleave', this.handleAceDivMouseLeave)
  60. return this.aceDiv.addEventListener(
  61. 'mouseenter',
  62. this.handleAceDivMouseEnter
  63. )
  64. }
  65. // Handler for wheel events on the PDF.
  66. // If the pointer is over Ace, grab the event, prevent default behaviour
  67. // and dispatch it to Ace.
  68. this.dispatchToAce = e => {
  69. if (this.isOverAce) {
  70. // If this is logged, the problem just happened: the event arrived
  71. // here (the PDF wheel handler), but it should've gone to Ace.
  72. // Small timeout - if we dispatch immediately, an exception is thrown.
  73. window.setTimeout(() => {
  74. // Dispatch the exact same event to Ace (this will keep values
  75. // values e.g. `wheelDelta` consistent with user interaction).
  76. return this.aceDiv.dispatchEvent(e)
  77. }, 1)
  78. // Avoid scrolling the PDF, as we assume this was intended to the
  79. // editor.
  80. return e.preventDefault()
  81. }
  82. }
  83. // "loaded" event is emitted from the pdfViewer controller $scope. This means
  84. // that the previous PDF DOM element was destroyed and a new one is available,
  85. // so we need to grab the elements and set the listeners again.
  86. $scope.$on('loaded', () => {
  87. return this.setListeners()
  88. })
  89. }
  90. })