UNPKG

@testing-library/user-event

Version:
164 lines (159 loc) 6.46 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var index = require('../../event/index.js'); require('../click/isClickableInput.js'); require('../dataTransfer/Clipboard.js'); require('./isEditable.js'); require('@testing-library/dom'); var isElementType = require('../misc/isElementType.js'); var selection = require('../focus/selection.js'); require('@testing-library/dom/dist/helpers.js'); var cursor = require('../focus/cursor.js'); require('../keyDef/readNextDescriptor.js'); require('../misc/level.js'); require('../../options.js'); var value = require('../../document/value.js'); var buildTimeValue = require('./buildTimeValue.js'); var isValidDateOrTimeValue = require('./isValidDateOrTimeValue.js'); var maxLength = require('./maxLength.js'); function isDateOrTime(element) { return isElementType.isElementType(element, 'input') && [ 'date', 'time' ].includes(element.type); } function input(config, element, data, inputType = 'insertText') { const inputRange = selection.getInputRange(element); /* istanbul ignore if */ if (!inputRange) { return; } // There is no `beforeinput` event on `date` and `time` input if (!isDateOrTime(element)) { const unprevented = index.dispatchUIEvent(config, element, 'beforeinput', { inputType, data }); if (!unprevented) { return; } } if ('startContainer' in inputRange) { editContenteditable(config, element, inputRange, data, inputType); } else { editInputElement(config, element, inputRange, data, inputType); } } function editContenteditable(config, element, inputRange, data, inputType) { let del = false; if (!inputRange.collapsed) { del = true; inputRange.deleteContents(); } else if ([ 'deleteContentBackward', 'deleteContentForward' ].includes(inputType)) { const nextPosition = cursor.getNextCursorPosition(inputRange.startContainer, inputRange.startOffset, inputType === 'deleteContentBackward' ? -1 : 1, inputType); if (nextPosition) { del = true; const delRange = inputRange.cloneRange(); if (delRange.comparePoint(nextPosition.node, nextPosition.offset) < 0) { delRange.setStart(nextPosition.node, nextPosition.offset); } else { delRange.setEnd(nextPosition.node, nextPosition.offset); } delRange.deleteContents(); } } if (data) { if (inputRange.endContainer.nodeType === 3) { const offset = inputRange.endOffset; inputRange.endContainer.insertData(offset, data); inputRange.setStart(inputRange.endContainer, offset + data.length); inputRange.setEnd(inputRange.endContainer, offset + data.length); } else { const text = element.ownerDocument.createTextNode(data); inputRange.insertNode(text); inputRange.setStart(text, data.length); inputRange.setEnd(text, data.length); } } if (del || data) { index.dispatchUIEvent(config, element, 'input', { inputType }); } } function editInputElement(config, element, inputRange, data, inputType) { let dataToInsert = data; const spaceUntilMaxLength = maxLength.getSpaceUntilMaxLength(element); if (spaceUntilMaxLength !== undefined && data.length > 0) { if (spaceUntilMaxLength > 0) { dataToInsert = data.substring(0, spaceUntilMaxLength); } else { return; } } const { newValue , newOffset , oldValue } = calculateNewValue(dataToInsert, element, inputRange, inputType); if (newValue === oldValue && newOffset === inputRange.startOffset && newOffset === inputRange.endOffset) { return; } if (isElementType.isElementType(element, 'input', { type: 'number' }) && !isValidNumberInput(newValue)) { return; } value.setUIValue(element, newValue); selection.setSelection({ focusNode: element, anchorOffset: newOffset, focusOffset: newOffset }); if (isDateOrTime(element)) { if (isValidDateOrTimeValue.isValidDateOrTimeValue(element, newValue)) { commitInput(config, element, newOffset, {}); index.dispatchUIEvent(config, element, 'change'); value.clearInitialValue(element); } } else { commitInput(config, element, newOffset, { data, inputType }); } } function calculateNewValue(inputData, node, { startOffset , endOffset }, inputType) { const value$1 = value.getUIValue(node); const prologEnd = Math.max(0, startOffset === endOffset && inputType === 'deleteContentBackward' ? startOffset - 1 : startOffset); const prolog = value$1.substring(0, prologEnd); const epilogStart = Math.min(value$1.length, startOffset === endOffset && inputType === 'deleteContentForward' ? startOffset + 1 : endOffset); const epilog = value$1.substring(epilogStart, value$1.length); let newValue = `${prolog}${inputData}${epilog}`; let newOffset = prologEnd + inputData.length; if (isElementType.isElementType(node, 'input', { type: 'time' })) { const builtValue = buildTimeValue.buildTimeValue(newValue); if (builtValue !== '' && isValidDateOrTimeValue.isValidDateOrTimeValue(node, builtValue)) { newValue = builtValue; newOffset = builtValue.length; } } return { oldValue: value$1, newValue, newOffset }; } function commitInput(config, element, newOffset, inputInit) { index.dispatchUIEvent(config, element, 'input', inputInit); value.commitValueAfterInput(element, newOffset); } function isValidNumberInput(value) { var ref, ref1; // the browser allows some invalid input but not others // it allows up to two '-' at any place before any 'e' or one directly following 'e' // it allows one '.' at any place before e const valueParts = value.split('e', 2); return !(/[^\d.\-e]/.test(value) || Number((ref = value.match(/-/g)) === null || ref === void 0 ? void 0 : ref.length) > 2 || Number((ref1 = value.match(/\./g)) === null || ref1 === void 0 ? void 0 : ref1.length) > 1 || valueParts[1] && !/^-?\d*$/.test(valueParts[1])); } exports.input = input;