pdf_presentation_mode.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * Javascript code in this page
  4. *
  5. * Copyright 2019 Mozilla Foundation
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. * @licend The above is the entire license notice for the
  20. * Javascript code in this page
  21. */
  22. "use strict";
  23. Object.defineProperty(exports, "__esModule", {
  24. value: true
  25. });
  26. exports.PDFPresentationMode = void 0;
  27. var _ui_utils = require("./ui_utils");
  28. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  29. function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
  30. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  31. var DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS = 1500;
  32. var DELAY_BEFORE_HIDING_CONTROLS = 3000;
  33. var ACTIVE_SELECTOR = 'pdfPresentationMode';
  34. var CONTROLS_SELECTOR = 'pdfPresentationModeControls';
  35. var MOUSE_SCROLL_COOLDOWN_TIME = 50;
  36. var PAGE_SWITCH_THRESHOLD = 0.1;
  37. var SWIPE_MIN_DISTANCE_THRESHOLD = 50;
  38. var SWIPE_ANGLE_THRESHOLD = Math.PI / 6;
  39. var PDFPresentationMode =
  40. /*#__PURE__*/
  41. function () {
  42. function PDFPresentationMode(_ref) {
  43. var _this = this;
  44. var container = _ref.container,
  45. _ref$viewer = _ref.viewer,
  46. viewer = _ref$viewer === void 0 ? null : _ref$viewer,
  47. pdfViewer = _ref.pdfViewer,
  48. eventBus = _ref.eventBus,
  49. _ref$contextMenuItems = _ref.contextMenuItems,
  50. contextMenuItems = _ref$contextMenuItems === void 0 ? null : _ref$contextMenuItems;
  51. _classCallCheck(this, PDFPresentationMode);
  52. this.container = container;
  53. this.viewer = viewer || container.firstElementChild;
  54. this.pdfViewer = pdfViewer;
  55. this.eventBus = eventBus;
  56. this.active = false;
  57. this.args = null;
  58. this.contextMenuOpen = false;
  59. this.mouseScrollTimeStamp = 0;
  60. this.mouseScrollDelta = 0;
  61. this.touchSwipeState = null;
  62. if (contextMenuItems) {
  63. contextMenuItems.contextFirstPage.addEventListener('click', function () {
  64. _this.contextMenuOpen = false;
  65. _this.eventBus.dispatch('firstpage', {
  66. source: _this
  67. });
  68. });
  69. contextMenuItems.contextLastPage.addEventListener('click', function () {
  70. _this.contextMenuOpen = false;
  71. _this.eventBus.dispatch('lastpage', {
  72. source: _this
  73. });
  74. });
  75. contextMenuItems.contextPageRotateCw.addEventListener('click', function () {
  76. _this.contextMenuOpen = false;
  77. _this.eventBus.dispatch('rotatecw', {
  78. source: _this
  79. });
  80. });
  81. contextMenuItems.contextPageRotateCcw.addEventListener('click', function () {
  82. _this.contextMenuOpen = false;
  83. _this.eventBus.dispatch('rotateccw', {
  84. source: _this
  85. });
  86. });
  87. }
  88. }
  89. _createClass(PDFPresentationMode, [{
  90. key: "request",
  91. value: function request() {
  92. if (this.switchInProgress || this.active || !this.viewer.hasChildNodes()) {
  93. return false;
  94. }
  95. this._addFullscreenChangeListeners();
  96. this._setSwitchInProgress();
  97. this._notifyStateChange();
  98. if (this.container.requestFullscreen) {
  99. this.container.requestFullscreen();
  100. } else if (this.container.mozRequestFullScreen) {
  101. this.container.mozRequestFullScreen();
  102. } else if (this.container.webkitRequestFullscreen) {
  103. this.container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
  104. } else if (this.container.msRequestFullscreen) {
  105. this.container.msRequestFullscreen();
  106. } else {
  107. return false;
  108. }
  109. this.args = {
  110. page: this.pdfViewer.currentPageNumber,
  111. previousScale: this.pdfViewer.currentScaleValue
  112. };
  113. return true;
  114. }
  115. }, {
  116. key: "_mouseWheel",
  117. value: function _mouseWheel(evt) {
  118. if (!this.active) {
  119. return;
  120. }
  121. evt.preventDefault();
  122. var delta = (0, _ui_utils.normalizeWheelEventDelta)(evt);
  123. var currentTime = new Date().getTime();
  124. var storedTime = this.mouseScrollTimeStamp;
  125. if (currentTime > storedTime && currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) {
  126. return;
  127. }
  128. if (this.mouseScrollDelta > 0 && delta < 0 || this.mouseScrollDelta < 0 && delta > 0) {
  129. this._resetMouseScrollState();
  130. }
  131. this.mouseScrollDelta += delta;
  132. if (Math.abs(this.mouseScrollDelta) >= PAGE_SWITCH_THRESHOLD) {
  133. var totalDelta = this.mouseScrollDelta;
  134. this._resetMouseScrollState();
  135. var success = totalDelta > 0 ? this._goToPreviousPage() : this._goToNextPage();
  136. if (success) {
  137. this.mouseScrollTimeStamp = currentTime;
  138. }
  139. }
  140. }
  141. }, {
  142. key: "_goToPreviousPage",
  143. value: function _goToPreviousPage() {
  144. var page = this.pdfViewer.currentPageNumber;
  145. if (page <= 1) {
  146. return false;
  147. }
  148. this.pdfViewer.currentPageNumber = page - 1;
  149. return true;
  150. }
  151. }, {
  152. key: "_goToNextPage",
  153. value: function _goToNextPage() {
  154. var page = this.pdfViewer.currentPageNumber;
  155. if (page >= this.pdfViewer.pagesCount) {
  156. return false;
  157. }
  158. this.pdfViewer.currentPageNumber = page + 1;
  159. return true;
  160. }
  161. }, {
  162. key: "_notifyStateChange",
  163. value: function _notifyStateChange() {
  164. this.eventBus.dispatch('presentationmodechanged', {
  165. source: this,
  166. active: this.active,
  167. switchInProgress: !!this.switchInProgress
  168. });
  169. }
  170. }, {
  171. key: "_setSwitchInProgress",
  172. value: function _setSwitchInProgress() {
  173. var _this2 = this;
  174. if (this.switchInProgress) {
  175. clearTimeout(this.switchInProgress);
  176. }
  177. this.switchInProgress = setTimeout(function () {
  178. _this2._removeFullscreenChangeListeners();
  179. delete _this2.switchInProgress;
  180. _this2._notifyStateChange();
  181. }, DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS);
  182. }
  183. }, {
  184. key: "_resetSwitchInProgress",
  185. value: function _resetSwitchInProgress() {
  186. if (this.switchInProgress) {
  187. clearTimeout(this.switchInProgress);
  188. delete this.switchInProgress;
  189. }
  190. }
  191. }, {
  192. key: "_enter",
  193. value: function _enter() {
  194. var _this3 = this;
  195. this.active = true;
  196. this._resetSwitchInProgress();
  197. this._notifyStateChange();
  198. this.container.classList.add(ACTIVE_SELECTOR);
  199. setTimeout(function () {
  200. _this3.pdfViewer.currentPageNumber = _this3.args.page;
  201. _this3.pdfViewer.currentScaleValue = 'page-fit';
  202. }, 0);
  203. this._addWindowListeners();
  204. this._showControls();
  205. this.contextMenuOpen = false;
  206. this.container.setAttribute('contextmenu', 'viewerContextMenu');
  207. window.getSelection().removeAllRanges();
  208. }
  209. }, {
  210. key: "_exit",
  211. value: function _exit() {
  212. var _this4 = this;
  213. var page = this.pdfViewer.currentPageNumber;
  214. this.container.classList.remove(ACTIVE_SELECTOR);
  215. setTimeout(function () {
  216. _this4.active = false;
  217. _this4._removeFullscreenChangeListeners();
  218. _this4._notifyStateChange();
  219. _this4.pdfViewer.currentScaleValue = _this4.args.previousScale;
  220. _this4.pdfViewer.currentPageNumber = page;
  221. _this4.args = null;
  222. }, 0);
  223. this._removeWindowListeners();
  224. this._hideControls();
  225. this._resetMouseScrollState();
  226. this.container.removeAttribute('contextmenu');
  227. this.contextMenuOpen = false;
  228. }
  229. }, {
  230. key: "_mouseDown",
  231. value: function _mouseDown(evt) {
  232. if (this.contextMenuOpen) {
  233. this.contextMenuOpen = false;
  234. evt.preventDefault();
  235. return;
  236. }
  237. if (evt.button === 0) {
  238. var isInternalLink = evt.target.href && evt.target.classList.contains('internalLink');
  239. if (!isInternalLink) {
  240. evt.preventDefault();
  241. if (evt.shiftKey) {
  242. this._goToPreviousPage();
  243. } else {
  244. this._goToNextPage();
  245. }
  246. }
  247. }
  248. }
  249. }, {
  250. key: "_contextMenu",
  251. value: function _contextMenu() {
  252. this.contextMenuOpen = true;
  253. }
  254. }, {
  255. key: "_showControls",
  256. value: function _showControls() {
  257. var _this5 = this;
  258. if (this.controlsTimeout) {
  259. clearTimeout(this.controlsTimeout);
  260. } else {
  261. this.container.classList.add(CONTROLS_SELECTOR);
  262. }
  263. this.controlsTimeout = setTimeout(function () {
  264. _this5.container.classList.remove(CONTROLS_SELECTOR);
  265. delete _this5.controlsTimeout;
  266. }, DELAY_BEFORE_HIDING_CONTROLS);
  267. }
  268. }, {
  269. key: "_hideControls",
  270. value: function _hideControls() {
  271. if (!this.controlsTimeout) {
  272. return;
  273. }
  274. clearTimeout(this.controlsTimeout);
  275. this.container.classList.remove(CONTROLS_SELECTOR);
  276. delete this.controlsTimeout;
  277. }
  278. }, {
  279. key: "_resetMouseScrollState",
  280. value: function _resetMouseScrollState() {
  281. this.mouseScrollTimeStamp = 0;
  282. this.mouseScrollDelta = 0;
  283. }
  284. }, {
  285. key: "_touchSwipe",
  286. value: function _touchSwipe(evt) {
  287. if (!this.active) {
  288. return;
  289. }
  290. if (evt.touches.length > 1) {
  291. this.touchSwipeState = null;
  292. return;
  293. }
  294. switch (evt.type) {
  295. case 'touchstart':
  296. this.touchSwipeState = {
  297. startX: evt.touches[0].pageX,
  298. startY: evt.touches[0].pageY,
  299. endX: evt.touches[0].pageX,
  300. endY: evt.touches[0].pageY
  301. };
  302. break;
  303. case 'touchmove':
  304. if (this.touchSwipeState === null) {
  305. return;
  306. }
  307. this.touchSwipeState.endX = evt.touches[0].pageX;
  308. this.touchSwipeState.endY = evt.touches[0].pageY;
  309. evt.preventDefault();
  310. break;
  311. case 'touchend':
  312. if (this.touchSwipeState === null) {
  313. return;
  314. }
  315. var delta = 0;
  316. var dx = this.touchSwipeState.endX - this.touchSwipeState.startX;
  317. var dy = this.touchSwipeState.endY - this.touchSwipeState.startY;
  318. var absAngle = Math.abs(Math.atan2(dy, dx));
  319. if (Math.abs(dx) > SWIPE_MIN_DISTANCE_THRESHOLD && (absAngle <= SWIPE_ANGLE_THRESHOLD || absAngle >= Math.PI - SWIPE_ANGLE_THRESHOLD)) {
  320. delta = dx;
  321. } else if (Math.abs(dy) > SWIPE_MIN_DISTANCE_THRESHOLD && Math.abs(absAngle - Math.PI / 2) <= SWIPE_ANGLE_THRESHOLD) {
  322. delta = dy;
  323. }
  324. if (delta > 0) {
  325. this._goToPreviousPage();
  326. } else if (delta < 0) {
  327. this._goToNextPage();
  328. }
  329. break;
  330. }
  331. }
  332. }, {
  333. key: "_addWindowListeners",
  334. value: function _addWindowListeners() {
  335. this.showControlsBind = this._showControls.bind(this);
  336. this.mouseDownBind = this._mouseDown.bind(this);
  337. this.mouseWheelBind = this._mouseWheel.bind(this);
  338. this.resetMouseScrollStateBind = this._resetMouseScrollState.bind(this);
  339. this.contextMenuBind = this._contextMenu.bind(this);
  340. this.touchSwipeBind = this._touchSwipe.bind(this);
  341. window.addEventListener('mousemove', this.showControlsBind);
  342. window.addEventListener('mousedown', this.mouseDownBind);
  343. window.addEventListener('wheel', this.mouseWheelBind);
  344. window.addEventListener('keydown', this.resetMouseScrollStateBind);
  345. window.addEventListener('contextmenu', this.contextMenuBind);
  346. window.addEventListener('touchstart', this.touchSwipeBind);
  347. window.addEventListener('touchmove', this.touchSwipeBind);
  348. window.addEventListener('touchend', this.touchSwipeBind);
  349. }
  350. }, {
  351. key: "_removeWindowListeners",
  352. value: function _removeWindowListeners() {
  353. window.removeEventListener('mousemove', this.showControlsBind);
  354. window.removeEventListener('mousedown', this.mouseDownBind);
  355. window.removeEventListener('wheel', this.mouseWheelBind);
  356. window.removeEventListener('keydown', this.resetMouseScrollStateBind);
  357. window.removeEventListener('contextmenu', this.contextMenuBind);
  358. window.removeEventListener('touchstart', this.touchSwipeBind);
  359. window.removeEventListener('touchmove', this.touchSwipeBind);
  360. window.removeEventListener('touchend', this.touchSwipeBind);
  361. delete this.showControlsBind;
  362. delete this.mouseDownBind;
  363. delete this.mouseWheelBind;
  364. delete this.resetMouseScrollStateBind;
  365. delete this.contextMenuBind;
  366. delete this.touchSwipeBind;
  367. }
  368. }, {
  369. key: "_fullscreenChange",
  370. value: function _fullscreenChange() {
  371. if (this.isFullscreen) {
  372. this._enter();
  373. } else {
  374. this._exit();
  375. }
  376. }
  377. }, {
  378. key: "_addFullscreenChangeListeners",
  379. value: function _addFullscreenChangeListeners() {
  380. this.fullscreenChangeBind = this._fullscreenChange.bind(this);
  381. window.addEventListener('fullscreenchange', this.fullscreenChangeBind);
  382. window.addEventListener('mozfullscreenchange', this.fullscreenChangeBind);
  383. window.addEventListener('webkitfullscreenchange', this.fullscreenChangeBind);
  384. window.addEventListener('MSFullscreenChange', this.fullscreenChangeBind);
  385. }
  386. }, {
  387. key: "_removeFullscreenChangeListeners",
  388. value: function _removeFullscreenChangeListeners() {
  389. window.removeEventListener('fullscreenchange', this.fullscreenChangeBind);
  390. window.removeEventListener('mozfullscreenchange', this.fullscreenChangeBind);
  391. window.removeEventListener('webkitfullscreenchange', this.fullscreenChangeBind);
  392. window.removeEventListener('MSFullscreenChange', this.fullscreenChangeBind);
  393. delete this.fullscreenChangeBind;
  394. }
  395. }, {
  396. key: "isFullscreen",
  397. get: function get() {
  398. return !!(document.fullscreenElement || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement);
  399. }
  400. }]);
  401. return PDFPresentationMode;
  402. }();
  403. exports.PDFPresentationMode = PDFPresentationMode;