mouse.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. 'use strict';
  2. require('../../event/behavior/click.js');
  3. require('../../event/behavior/cut.js');
  4. require('../../event/behavior/keydown.js');
  5. require('../../event/behavior/keypress.js');
  6. require('../../event/behavior/keyup.js');
  7. require('../../event/behavior/paste.js');
  8. require('@testing-library/dom');
  9. require('../../utils/dataTransfer/Clipboard.js');
  10. var isDisabled = require('../../utils/misc/isDisabled.js');
  11. var getTreeDiff = require('../../utils/misc/getTreeDiff.js');
  12. var focus = require('../../event/focus.js');
  13. var setSelectionPerMouse = require('../../event/selection/setSelectionPerMouse.js');
  14. var modifySelectionPerMouse = require('../../event/selection/modifySelectionPerMouse.js');
  15. var buttons = require('./buttons.js');
  16. var shared = require('./shared.js');
  17. function _define_property(obj, key, value) {
  18. if (key in obj) {
  19. Object.defineProperty(obj, key, {
  20. value: value,
  21. enumerable: true,
  22. configurable: true,
  23. writable: true
  24. });
  25. } else {
  26. obj[key] = value;
  27. }
  28. return obj;
  29. }
  30. /**
  31. * This object is the single "virtual" mouse that might be controlled by multiple different pointer devices.
  32. */ class Mouse {
  33. move(instance, position, /** Whether `preventDefault()` has been called on the `pointerdown` event */ isPrevented) {
  34. const prevPosition = this.position;
  35. const prevTarget = this.getTarget(instance);
  36. this.position = position;
  37. if (!shared.isDifferentPointerPosition(prevPosition, position)) {
  38. return;
  39. }
  40. const nextTarget = this.getTarget(instance);
  41. const init = this.getEventInit('mousemove');
  42. const [leave, enter] = getTreeDiff.getTreeDiff(prevTarget, nextTarget);
  43. return {
  44. leave: ()=>{
  45. if (prevTarget !== nextTarget) {
  46. instance.dispatchUIEvent(prevTarget, 'mouseout', init);
  47. leave.forEach((el)=>instance.dispatchUIEvent(el, 'mouseleave', init));
  48. }
  49. },
  50. enter: ()=>{
  51. if (prevTarget !== nextTarget) {
  52. instance.dispatchUIEvent(nextTarget, 'mouseover', init);
  53. enter.forEach((el)=>instance.dispatchUIEvent(el, 'mouseenter', init));
  54. }
  55. },
  56. move: ()=>{
  57. if (isPrevented) {
  58. return;
  59. }
  60. instance.dispatchUIEvent(nextTarget, 'mousemove', init);
  61. this.modifySelecting(instance);
  62. }
  63. };
  64. }
  65. down(instance, keyDef, /** Whether `preventDefault()` has been called on the `pointerdown` event */ isPrevented) {
  66. const button = this.buttons.down(keyDef);
  67. if (button === undefined) {
  68. return;
  69. }
  70. const target = this.getTarget(instance);
  71. this.buttonDownTarget[button] = target;
  72. const init = this.getEventInit('mousedown', keyDef.button);
  73. const disabled = isDisabled.isDisabled(target);
  74. if (!isPrevented && (disabled || instance.dispatchUIEvent(target, 'mousedown', init))) {
  75. this.startSelecting(instance, init.detail);
  76. focus.focusElement(target);
  77. }
  78. if (!disabled && buttons.getMouseEventButton(keyDef.button) === 2) {
  79. instance.dispatchUIEvent(target, 'contextmenu', this.getEventInit('contextmenu', keyDef.button));
  80. }
  81. }
  82. up(instance, keyDef, /** Whether `preventDefault()` has been called on the `pointerdown` event */ isPrevented) {
  83. const button = this.buttons.up(keyDef);
  84. if (button === undefined) {
  85. return;
  86. }
  87. const target = this.getTarget(instance);
  88. if (!isDisabled.isDisabled(target)) {
  89. if (!isPrevented) {
  90. const mouseUpInit = this.getEventInit('mouseup', keyDef.button);
  91. instance.dispatchUIEvent(target, 'mouseup', mouseUpInit);
  92. this.endSelecting();
  93. }
  94. const clickTarget = getTreeDiff.getTreeDiff(this.buttonDownTarget[button], target)[2][0];
  95. if (clickTarget) {
  96. const init = this.getEventInit('click', keyDef.button);
  97. if (init.detail) {
  98. instance.dispatchUIEvent(clickTarget, init.button === 0 ? 'click' : 'auxclick', init);
  99. if (init.button === 0 && init.detail === 2) {
  100. instance.dispatchUIEvent(clickTarget, 'dblclick', {
  101. ...this.getEventInit('dblclick', keyDef.button),
  102. detail: init.detail
  103. });
  104. }
  105. }
  106. }
  107. }
  108. }
  109. resetClickCount() {
  110. this.clickCount.reset();
  111. }
  112. getEventInit(type, button) {
  113. const init = {
  114. ...this.position.coords
  115. };
  116. init.button = buttons.getMouseEventButton(button);
  117. init.buttons = this.buttons.getButtons();
  118. if (type === 'mousedown') {
  119. init.detail = this.clickCount.getOnDown(init.button);
  120. } else if (type === 'mouseup') {
  121. init.detail = this.clickCount.getOnUp(init.button);
  122. } else if (type === 'click' || type === 'auxclick') {
  123. init.detail = this.clickCount.incOnClick(init.button);
  124. }
  125. return init;
  126. }
  127. getTarget(instance) {
  128. var _this_position_target;
  129. return (_this_position_target = this.position.target) !== null && _this_position_target !== undefined ? _this_position_target : instance.config.document.body;
  130. }
  131. startSelecting(instance, clickCount) {
  132. var _this_position_caret, _this_position_caret1;
  133. // TODO: support extending range (shift)
  134. this.selecting = setSelectionPerMouse.setSelectionPerMouseDown({
  135. document: instance.config.document,
  136. target: this.getTarget(instance),
  137. node: (_this_position_caret = this.position.caret) === null || _this_position_caret === undefined ? undefined : _this_position_caret.node,
  138. offset: (_this_position_caret1 = this.position.caret) === null || _this_position_caret1 === undefined ? undefined : _this_position_caret1.offset,
  139. clickCount
  140. });
  141. }
  142. modifySelecting(instance) {
  143. var _this_position_caret, _this_position_caret1;
  144. if (!this.selecting) {
  145. return;
  146. }
  147. modifySelectionPerMouse.modifySelectionPerMouseMove(this.selecting, {
  148. document: instance.config.document,
  149. target: this.getTarget(instance),
  150. node: (_this_position_caret = this.position.caret) === null || _this_position_caret === undefined ? undefined : _this_position_caret.node,
  151. offset: (_this_position_caret1 = this.position.caret) === null || _this_position_caret1 === undefined ? undefined : _this_position_caret1.offset
  152. });
  153. }
  154. endSelecting() {
  155. this.selecting = undefined;
  156. }
  157. constructor(){
  158. _define_property(this, "position", {});
  159. _define_property(this, "buttons", new buttons.Buttons());
  160. _define_property(this, "selecting", undefined);
  161. _define_property(this, "buttonDownTarget", {});
  162. // According to spec the `detail` on click events should be the number
  163. // of *consecutive* clicks with a specific button.
  164. // On `mousedown` and `mouseup` it should be this number increased by one.
  165. // But the browsers don't implement it this way.
  166. // If another button is pressed,
  167. // in Webkit: the `mouseup` on the previously pressed button has `detail: 0` and no `click`/`auxclick`.
  168. // in Gecko: the `mouseup` and click events have the same detail as the `mousedown`.
  169. // If there is a delay while a button is pressed,
  170. // the `mouseup` and `click` are normal, but a following `mousedown` starts a new click count.
  171. // We'll follow the minimal implementation of Webkit.
  172. _define_property(this, "clickCount", new class {
  173. incOnClick(button) {
  174. const current = this.down[button] === undefined ? undefined : Number(this.down[button]) + 1;
  175. this.count = this.count[button] === undefined ? {} : {
  176. [button]: Number(this.count[button]) + 1
  177. };
  178. return current;
  179. }
  180. getOnDown(button) {
  181. var _this_count_button;
  182. this.down = {
  183. [button]: (_this_count_button = this.count[button]) !== null && _this_count_button !== undefined ? _this_count_button : 0
  184. };
  185. var _this_count_button1;
  186. this.count = {
  187. [button]: (_this_count_button1 = this.count[button]) !== null && _this_count_button1 !== undefined ? _this_count_button1 : 0
  188. };
  189. return Number(this.count[button]) + 1;
  190. }
  191. getOnUp(button) {
  192. return this.down[button] === undefined ? undefined : Number(this.down[button]) + 1;
  193. }
  194. reset() {
  195. this.count = {};
  196. }
  197. constructor(){
  198. _define_property(this, "down", {});
  199. _define_property(this, "count", {});
  200. }
  201. }());
  202. }
  203. }
  204. exports.Mouse = Mouse;