keyboard2.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*!
  2. * (C) Ionic http://ionicframework.com - MIT License
  3. */
  4. import { K as Keyboard } from './keyboard.js';
  5. const KEYBOARD_DID_OPEN = 'ionKeyboardDidShow';
  6. const KEYBOARD_DID_CLOSE = 'ionKeyboardDidHide';
  7. const KEYBOARD_THRESHOLD = 150;
  8. // TODO(FW-2832): types
  9. let previousVisualViewport = {};
  10. let currentVisualViewport = {};
  11. let keyboardOpen = false;
  12. /**
  13. * This is only used for tests
  14. */
  15. const resetKeyboardAssist = () => {
  16. previousVisualViewport = {};
  17. currentVisualViewport = {};
  18. keyboardOpen = false;
  19. };
  20. const startKeyboardAssist = (win) => {
  21. const nativeEngine = Keyboard.getEngine();
  22. /**
  23. * If the native keyboard plugin is available
  24. * then we are running in a native environment. As a result
  25. * we should only listen on the native events instead of
  26. * using the Visual Viewport as the Ionic webview manipulates
  27. * how it resizes such that the Visual Viewport API is not
  28. * reliable here.
  29. */
  30. if (nativeEngine) {
  31. startNativeListeners(win);
  32. }
  33. else {
  34. if (!win.visualViewport) {
  35. return;
  36. }
  37. currentVisualViewport = copyVisualViewport(win.visualViewport);
  38. win.visualViewport.onresize = () => {
  39. trackViewportChanges(win);
  40. if (keyboardDidOpen() || keyboardDidResize(win)) {
  41. setKeyboardOpen(win);
  42. }
  43. else if (keyboardDidClose(win)) {
  44. setKeyboardClose(win);
  45. }
  46. };
  47. }
  48. };
  49. /**
  50. * Listen for events fired by native keyboard plugin
  51. * in Capacitor/Cordova so devs only need to listen
  52. * in one place.
  53. */
  54. const startNativeListeners = (win) => {
  55. win.addEventListener('keyboardDidShow', (ev) => setKeyboardOpen(win, ev));
  56. win.addEventListener('keyboardDidHide', () => setKeyboardClose(win));
  57. };
  58. const setKeyboardOpen = (win, ev) => {
  59. fireKeyboardOpenEvent(win, ev);
  60. keyboardOpen = true;
  61. };
  62. const setKeyboardClose = (win) => {
  63. fireKeyboardCloseEvent(win);
  64. keyboardOpen = false;
  65. };
  66. /**
  67. * Returns `true` if the `keyboardOpen` flag is not
  68. * set, the previous visual viewport width equal the current
  69. * visual viewport width, and if the scaled difference
  70. * of the previous visual viewport height minus the current
  71. * visual viewport height is greater than KEYBOARD_THRESHOLD
  72. *
  73. * We need to be able to accommodate users who have zooming
  74. * enabled in their browser (or have zoomed in manually) which
  75. * is why we take into account the current visual viewport's
  76. * scale value.
  77. */
  78. const keyboardDidOpen = () => {
  79. const scaledHeightDifference = (previousVisualViewport.height - currentVisualViewport.height) * currentVisualViewport.scale;
  80. return (!keyboardOpen &&
  81. previousVisualViewport.width === currentVisualViewport.width &&
  82. scaledHeightDifference > KEYBOARD_THRESHOLD);
  83. };
  84. /**
  85. * Returns `true` if the keyboard is open,
  86. * but the keyboard did not close
  87. */
  88. const keyboardDidResize = (win) => {
  89. return keyboardOpen && !keyboardDidClose(win);
  90. };
  91. /**
  92. * Determine if the keyboard was closed
  93. * Returns `true` if the `keyboardOpen` flag is set and
  94. * the current visual viewport height equals the
  95. * layout viewport height.
  96. */
  97. const keyboardDidClose = (win) => {
  98. return keyboardOpen && currentVisualViewport.height === win.innerHeight;
  99. };
  100. /**
  101. * Dispatch a keyboard open event
  102. */
  103. const fireKeyboardOpenEvent = (win, nativeEv) => {
  104. const keyboardHeight = nativeEv ? nativeEv.keyboardHeight : win.innerHeight - currentVisualViewport.height;
  105. const ev = new CustomEvent(KEYBOARD_DID_OPEN, {
  106. detail: { keyboardHeight },
  107. });
  108. win.dispatchEvent(ev);
  109. };
  110. /**
  111. * Dispatch a keyboard close event
  112. */
  113. const fireKeyboardCloseEvent = (win) => {
  114. const ev = new CustomEvent(KEYBOARD_DID_CLOSE);
  115. win.dispatchEvent(ev);
  116. };
  117. /**
  118. * Given a window object, create a copy of
  119. * the current visual and layout viewport states
  120. * while also preserving the previous visual and
  121. * layout viewport states
  122. */
  123. const trackViewportChanges = (win) => {
  124. previousVisualViewport = Object.assign({}, currentVisualViewport);
  125. currentVisualViewport = copyVisualViewport(win.visualViewport);
  126. };
  127. /**
  128. * Creates a deep copy of the visual viewport
  129. * at a given state
  130. */
  131. const copyVisualViewport = (visualViewport) => {
  132. return {
  133. width: Math.round(visualViewport.width),
  134. height: Math.round(visualViewport.height),
  135. offsetTop: visualViewport.offsetTop,
  136. offsetLeft: visualViewport.offsetLeft,
  137. pageTop: visualViewport.pageTop,
  138. pageLeft: visualViewport.pageLeft,
  139. scale: visualViewport.scale,
  140. };
  141. };
  142. export { KEYBOARD_DID_CLOSE, KEYBOARD_DID_OPEN, copyVisualViewport, keyboardDidClose, keyboardDidOpen, keyboardDidResize, resetKeyboardAssist, setKeyboardClose, setKeyboardOpen, startKeyboardAssist, trackViewportChanges };