86 lines
3.4 KiB
JavaScript
86 lines
3.4 KiB
JavaScript
import { getUIValue, setUISelection } from '../../document/UI.js';
|
|
import '../../utils/click/isClickableInput.js';
|
|
import '../../utils/dataTransfer/Clipboard.js';
|
|
import '../../utils/edit/isEditable.js';
|
|
import '../../utils/edit/maxLength.js';
|
|
import { hasNoSelection, hasOwnSelection } from '../../utils/focus/selection.js';
|
|
import '../../utils/keyDef/readNextDescriptor.js';
|
|
import '../../utils/misc/level.js';
|
|
import '../../options.js';
|
|
import { resolveCaretPosition } from './resolveCaretPosition.js';
|
|
|
|
function setSelectionPerMouseDown({ document, target, clickCount, node, offset }) {
|
|
if (hasNoSelection(target)) {
|
|
return;
|
|
}
|
|
const targetHasOwnSelection = hasOwnSelection(target);
|
|
// On non-input elements the text selection per multiple click
|
|
// can extend beyond the target boundaries.
|
|
// The exact mechanism what is considered in the same line is unclear.
|
|
// Looks it might be every inline element.
|
|
// TODO: Check what might be considered part of the same line of text.
|
|
const text = String(targetHasOwnSelection ? getUIValue(target) : target.textContent);
|
|
const [start, end] = node ? // which elements might be considered in the same line of text.
|
|
// TODO: support expanding initial range on multiple clicks if node is given
|
|
[
|
|
offset,
|
|
offset
|
|
] : getTextRange(text, offset, clickCount);
|
|
// TODO: implement modifying selection per shift/ctrl+mouse
|
|
if (targetHasOwnSelection) {
|
|
setUISelection(target, {
|
|
anchorOffset: start !== null && start !== void 0 ? start : text.length,
|
|
focusOffset: end !== null && end !== void 0 ? end : text.length
|
|
});
|
|
return {
|
|
node: target,
|
|
start: start !== null && start !== void 0 ? start : 0,
|
|
end: end !== null && end !== void 0 ? end : text.length
|
|
};
|
|
} else {
|
|
const { node: startNode, offset: startOffset } = resolveCaretPosition({
|
|
target,
|
|
node,
|
|
offset: start
|
|
});
|
|
const { node: endNode, offset: endOffset } = resolveCaretPosition({
|
|
target,
|
|
node,
|
|
offset: end
|
|
});
|
|
const range = target.ownerDocument.createRange();
|
|
try {
|
|
range.setStart(startNode, startOffset);
|
|
range.setEnd(endNode, endOffset);
|
|
} catch (e) {
|
|
throw new Error('The given offset is out of bounds.');
|
|
}
|
|
const selection = document.getSelection();
|
|
selection === null || selection === void 0 ? void 0 : selection.removeAllRanges();
|
|
selection === null || selection === void 0 ? void 0 : selection.addRange(range.cloneRange());
|
|
return range;
|
|
}
|
|
}
|
|
function getTextRange(text, pos, clickCount) {
|
|
if (clickCount % 3 === 1 || text.length === 0) {
|
|
return [
|
|
pos,
|
|
pos
|
|
];
|
|
}
|
|
const textPos = pos !== null && pos !== void 0 ? pos : text.length;
|
|
if (clickCount % 3 === 2) {
|
|
return [
|
|
textPos - text.substr(0, pos).match(/(\w+|\s+|\W)?$/)[0].length,
|
|
pos === undefined ? pos : pos + text.substr(pos).match(/^(\w+|\s+|\W)?/)[0].length
|
|
];
|
|
}
|
|
// triple click
|
|
return [
|
|
textPos - text.substr(0, pos).match(/[^\r\n]*$/)[0].length,
|
|
pos === undefined ? pos : pos + text.substr(pos).match(/^[^\r\n]*/)[0].length
|
|
];
|
|
}
|
|
|
|
export { setSelectionPerMouseDown };
|