setSelectionPerMouse.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. 'use strict';
  2. var UI = require('../../document/UI.js');
  3. require('../../utils/dataTransfer/Clipboard.js');
  4. var selection = require('../../utils/focus/selection.js');
  5. var resolveCaretPosition = require('./resolveCaretPosition.js');
  6. function setSelectionPerMouseDown({ document, target, clickCount, node, offset }) {
  7. if (selection.hasNoSelection(target)) {
  8. return;
  9. }
  10. const targetHasOwnSelection = selection.hasOwnSelection(target);
  11. // On non-input elements the text selection per multiple click
  12. // can extend beyond the target boundaries.
  13. // The exact mechanism what is considered in the same line is unclear.
  14. // Looks it might be every inline element.
  15. // TODO: Check what might be considered part of the same line of text.
  16. const text = String(targetHasOwnSelection ? UI.getUIValue(target) : target.textContent);
  17. const [start, end] = node ? // which elements might be considered in the same line of text.
  18. // TODO: support expanding initial range on multiple clicks if node is given
  19. [
  20. offset,
  21. offset
  22. ] : getTextRange(text, offset, clickCount);
  23. // TODO: implement modifying selection per shift/ctrl+mouse
  24. if (targetHasOwnSelection) {
  25. UI.setUISelection(target, {
  26. anchorOffset: start !== null && start !== undefined ? start : text.length,
  27. focusOffset: end !== null && end !== undefined ? end : text.length
  28. });
  29. return {
  30. node: target,
  31. start: start !== null && start !== undefined ? start : 0,
  32. end: end !== null && end !== undefined ? end : text.length
  33. };
  34. } else {
  35. const { node: startNode, offset: startOffset } = resolveCaretPosition.resolveCaretPosition({
  36. target,
  37. node,
  38. offset: start
  39. });
  40. const { node: endNode, offset: endOffset } = resolveCaretPosition.resolveCaretPosition({
  41. target,
  42. node,
  43. offset: end
  44. });
  45. const range = target.ownerDocument.createRange();
  46. try {
  47. range.setStart(startNode, startOffset);
  48. range.setEnd(endNode, endOffset);
  49. } catch (e) {
  50. throw new Error('The given offset is out of bounds.');
  51. }
  52. const selection = document.getSelection();
  53. selection === null || selection === undefined ? undefined : selection.removeAllRanges();
  54. selection === null || selection === undefined ? undefined : selection.addRange(range.cloneRange());
  55. return range;
  56. }
  57. }
  58. function getTextRange(text, pos, clickCount) {
  59. if (clickCount % 3 === 1 || text.length === 0) {
  60. return [
  61. pos,
  62. pos
  63. ];
  64. }
  65. const textPos = pos !== null && pos !== undefined ? pos : text.length;
  66. if (clickCount % 3 === 2) {
  67. return [
  68. textPos - text.substr(0, pos).match(/(\w+|\s+|\W)?$/)[0].length,
  69. pos === undefined ? pos : pos + text.substr(pos).match(/^(\w+|\s+|\W)?/)[0].length
  70. ];
  71. }
  72. // triple click
  73. return [
  74. textPos - text.substr(0, pos).match(/[^\r\n]*$/)[0].length,
  75. pos === undefined ? pos : pos + text.substr(pos).match(/^[^\r\n]*/)[0].length
  76. ];
  77. }
  78. exports.setSelectionPerMouseDown = setSelectionPerMouseDown;