UI.js 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. const UIValue = Symbol('Displayed value in UI');
  2. const UISelection = Symbol('Displayed selection in UI');
  3. const InitialValue = Symbol('Initial value to compare on blur');
  4. function isUIValue(value) {
  5. return typeof value === 'object' && UIValue in value;
  6. }
  7. function isUISelectionStart(start) {
  8. return !!start && typeof start === 'object' && UISelection in start;
  9. }
  10. function setUIValue(element, value) {
  11. if (element[InitialValue] === undefined) {
  12. element[InitialValue] = element.value;
  13. }
  14. element[UIValue] = value;
  15. // eslint-disable-next-line no-new-wrappers
  16. element.value = Object.assign(new String(value), {
  17. [UIValue]: true
  18. });
  19. }
  20. function getUIValue(element) {
  21. return element[UIValue] === undefined ? element.value : String(element[UIValue]);
  22. }
  23. /** Flag the IDL value as clean. This does not change the value.*/ function setUIValueClean(element) {
  24. element[UIValue] = undefined;
  25. }
  26. function clearInitialValue(element) {
  27. element[InitialValue] = undefined;
  28. }
  29. function getInitialValue(element) {
  30. return element[InitialValue];
  31. }
  32. function setUISelectionRaw(element, selection) {
  33. element[UISelection] = selection;
  34. }
  35. function setUISelection(element, { focusOffset: focusOffsetParam, anchorOffset: anchorOffsetParam = focusOffsetParam }, mode = 'replace') {
  36. const valueLength = getUIValue(element).length;
  37. const sanitizeOffset = (o)=>Math.max(0, Math.min(valueLength, o));
  38. const anchorOffset = mode === 'replace' || element[UISelection] === undefined ? sanitizeOffset(anchorOffsetParam) : element[UISelection].anchorOffset;
  39. const focusOffset = sanitizeOffset(focusOffsetParam);
  40. const startOffset = Math.min(anchorOffset, focusOffset);
  41. const endOffset = Math.max(anchorOffset, focusOffset);
  42. element[UISelection] = {
  43. anchorOffset,
  44. focusOffset
  45. };
  46. if (element.selectionStart === startOffset && element.selectionEnd === endOffset) {
  47. return;
  48. }
  49. // eslint-disable-next-line no-new-wrappers
  50. const startObj = Object.assign(new Number(startOffset), {
  51. [UISelection]: true
  52. });
  53. try {
  54. element.setSelectionRange(startObj, endOffset);
  55. } catch {
  56. // DOMException for invalid state is expected when calling this
  57. // on an element without support for setSelectionRange
  58. }
  59. }
  60. function getUISelection(element) {
  61. var _element_selectionStart, _element_selectionEnd, _element_UISelection;
  62. const sel = (_element_UISelection = element[UISelection]) !== null && _element_UISelection !== undefined ? _element_UISelection : {
  63. anchorOffset: (_element_selectionStart = element.selectionStart) !== null && _element_selectionStart !== undefined ? _element_selectionStart : 0,
  64. focusOffset: (_element_selectionEnd = element.selectionEnd) !== null && _element_selectionEnd !== undefined ? _element_selectionEnd : 0
  65. };
  66. return {
  67. ...sel,
  68. startOffset: Math.min(sel.anchorOffset, sel.focusOffset),
  69. endOffset: Math.max(sel.anchorOffset, sel.focusOffset)
  70. };
  71. }
  72. function hasUISelection(element) {
  73. return !!element[UISelection];
  74. }
  75. /** Flag the IDL selection as clean. This does not change the selection. */ function setUISelectionClean(element) {
  76. element[UISelection] = undefined;
  77. }
  78. export { clearInitialValue, getInitialValue, getUISelection, getUIValue, hasUISelection, isUISelectionStart, isUIValue, setUISelection, setUISelectionClean, setUISelectionRaw, setUIValue, setUIValueClean };