/** * Gets an element's bounding rect in pixels relative to the viewport. * * @param {DOMElement} elem * @return {object} */ function getElementRect(elem) { const docElem = document.documentElement; // FF 2, Safari 3 and Opera 9.5- do not support getBoundingClientRect(). // IE9- will throw if the element is not in the document. if (!('getBoundingClientRect' in elem) || !containsNode(docElem, elem)) { return { left: 0, right: 0, top: 0, bottom: 0 }; } // Subtracts clientTop/Left because IE8- added a 2px border to the // <html> element (see http://fburl.com/1493213). IE 7 in // Quicksmode does not report clientLeft/clientTop so there // will be an unaccounted offset of 2px when in quirksmode const rect = elem.getBoundingClientRect(); return { left: Math.round(rect.left) - docElem.clientLeft, right: Math.round(rect.right) - docElem.clientLeft, top: Math.round(rect.top) - docElem.clientTop, bottom: Math.round(rect.bottom) - docElem.clientTop }; }
/** * A node is "valid" if it is contained by a currently mounted container. * * This means that the node does not have to be contained by a document in * order to be considered valid. * * @param {?DOMElement} node The candidate DOM node. * @param {string} id The expected ID of the node. * @return {boolean} Whether the node is contained by a mounted container. */ function isValid(node, id) { if (node) { invariant( internalGetID(node) === id, 'ReactMount: Unexpected modification of `%s`', ATTR_NAME ); var container = ReactMount.findReactContainerForID(id); if (container && containsNode(container, node)) { return true; } } return false; }
/** * Extend selection towards focus point. */ function addFocusToSelection( selection: Object, node: Node, offset: number ): void { if (selection.extend && containsNode(getActiveElement(), node)) { // If `extend` is called while another element has focus, an error is // thrown. We therefore disable `extend` if the active element is somewhere // other than the node we are selecting. This should only occur in Firefox, // since it is the only browser to support multiple selections. // See https://bugzilla.mozilla.org/show_bug.cgi?id=921444. selection.extend(node, offset); } else { // IE doesn't support extend. This will mean no backward selection. // Extract the existing selection range and add focus to it. // Additionally, clone the selection range. IE11 throws an // InvalidStateError when attempting to access selection properties // after the range is detached. var range = selection.getRangeAt(0); range.setEnd(node, offset); selection.addRange(range.cloneRange()); } }
/** * In modern non-IE browsers, we can support both forward and backward * selections. * * Note: IE10+ supports the Selection object, but it does not support * the `extend` method, which means that even in modern IE, it's not possible * to programatically create a backward selection. Thus, for all IE * versions, we use the old IE API to create our selections. */ function setDraftEditorSelection( selectionState: SelectionState, node: Node, blockKey: string, nodeStart: number, nodeEnd: number ): void { // It's possible that the editor has been removed from the DOM but // our selection code doesn't know it yet. Forcing selection in // this case may lead to errors, so just bail now. if (!containsNode(document.documentElement, node)) { return; } var selection = global.getSelection(); var anchorKey = selectionState.getAnchorKey(); var anchorOffset = selectionState.getAnchorOffset(); var focusKey = selectionState.getFocusKey(); var focusOffset = selectionState.getFocusOffset(); var isBackward = selectionState.getIsBackward(); // IE doesn't support backward selection. Swap key/offset pairs. if (!selection.extend && isBackward) { var tempKey = anchorKey; var tempOffset = anchorOffset; anchorKey = focusKey; anchorOffset = focusOffset; focusKey = tempKey; focusOffset = tempOffset; isBackward = false; } var hasAnchor = ( anchorKey === blockKey && nodeStart <= anchorOffset && nodeEnd >= anchorOffset ); var hasFocus = ( focusKey === blockKey && nodeStart <= focusOffset && nodeEnd >= focusOffset ); // If the selection is entirely bound within this node, set the selection // and be done. if (hasAnchor && hasFocus) { selection.removeAllRanges(); addPointToSelection(selection, node, anchorOffset - nodeStart); addFocusToSelection(selection, node, focusOffset - nodeStart); return; } if (!isBackward) { // If the anchor is within this node, set the range start. if (hasAnchor) { selection.removeAllRanges(); addPointToSelection(selection, node, anchorOffset - nodeStart); } // If the focus is within this node, we can assume that we have // already set the appropriate start range on the selection, and // can simply extend the selection. if (hasFocus) { addFocusToSelection(selection, node, focusOffset - nodeStart); } } else { // If this node has the focus, set the selection range to be a // collapsed range beginning here. Later, when we encounter the anchor, // we'll use this information to extend the selection. if (hasFocus) { selection.removeAllRanges(); addPointToSelection(selection, node, focusOffset - nodeStart); } // If this node has the anchor, we may assume that the correct // focus information is already stored on the selection object. // We keep track of it, reset the selection range, and extend it // back to the focus point. if (hasAnchor) { var storedFocusNode = selection.focusNode; var storedFocusOffset = selection.focusOffset; selection.removeAllRanges(); addPointToSelection(selection, node, anchorOffset - nodeStart); addFocusToSelection(selection, storedFocusNode, storedFocusOffset); } } }
function isInDocument(node) { return containsNode(document.documentElement, node); }
function isInDocument(e){return containsNode(document.documentElement,e)}var ReactDOMSelection=require("ReactDOMSelection"),containsNode=require("containsNode"),focusNode=require("focusNode"),getActiveElement=require("getActiveElement"),ReactInputSelection={hasSelectionCapabilities:function(e){return e&&("INPUT"===e.nodeName&&"text"===e.type||"TEXTAREA"===e.nodeName||"true"===e.contentEditable)},getSelectionInformation:function(){var e=getActiveElement();return{focusedElem:e,selectionRange:ReactInputSelection.hasSelectionCapabilities(e)?ReactInputSelection.getSelection(e):null}},restoreSelection:function(e){var t=getActiveElement(),n=e.focusedElem,c=e.selectionRange;t!==n&&isInDocument(n)&&(ReactInputSelection.hasSelectionCapabilities(n)&&ReactInputSelection.setSelection(n,c),focusNode(n))},getSelection:function(e){var t;if("selectionStart"in e)t={start:e.selectionStart,end:e.selectionEnd};else if(document.selection&&"INPUT"===e.nodeName){var n=document.selection.createRange();n.parentElement()===e&&(t={start:-n.moveStart("character",-e.value.length),end:-n.moveEnd("character",-e.value.length)})}else t=ReactDOMSelection.getOffsets(e);return t||{start:0,end:0}},setSelection:function(e,t){var n=t.start,c=t.end;if("undefined"==typeof c&&(c=n),"selectionStart"in e)e.selectionStart=n,e.selectionEnd=Math.min(c,e.value.length);else if(document.selection&&"INPUT"===e.nodeName){var o=e.createTextRange();o.collapse(!0),o.moveStart("character",n),o.moveEnd("character",c-n),o.select()}else ReactDOMSelection.setOffsets(e,t)}};module.exports=ReactInputSelection;
contains: function(outerNode, innerNode) { outerNode = ge(outerNode); innerNode = ge(innerNode); return containsNode(outerNode, innerNode); },
/** * Extend selection towards focus point. */ function addFocusToSelection( selection: Object, node: Node, offset: number, selectionState: SelectionState, ): void { const activeElement = getActiveElement(); if (selection.extend && containsNode(activeElement, node)) { // If `extend` is called while another element has focus, an error is // thrown. We therefore disable `extend` if the active element is somewhere // other than the node we are selecting. This should only occur in Firefox, // since it is the only browser to support multiple selections. // See https://bugzilla.mozilla.org/show_bug.cgi?id=921444. // logging to catch bug that is being reported in t16250795 if (offset > getNodeLength(node)) { // the call to 'selection.extend' is about to throw DraftJsDebugLogging.logSelectionStateFailure({ anonymizedDom: getAnonymizedEditorDOM(node), extraParams: JSON.stringify({offset: offset}), selectionState: JSON.stringify(selectionState.toJS()), }); } // logging to catch bug that is being reported in t18110632 const nodeWasFocus = node === selection.focusNode; try { selection.extend(node, offset); } catch (e) { DraftJsDebugLogging.logSelectionStateFailure({ anonymizedDom: getAnonymizedEditorDOM(node, function(n) { const labels = []; if (n === activeElement) { labels.push('active element'); } if (n === selection.anchorNode) { labels.push('selection anchor node'); } if (n === selection.focusNode) { labels.push('selection focus node'); } return labels; }), extraParams: JSON.stringify( { activeElementName: activeElement ? activeElement.nodeName : null, nodeIsFocus: node === selection.focusNode, nodeWasFocus: nodeWasFocus, selectionRangeCount: selection.rangeCount, selectionAnchorNodeName: selection.anchorNode ? selection.anchorNode.nodeName : null, selectionAnchorOffset: selection.anchorOffset, selectionFocusNodeName: selection.focusNode ? selection.focusNode.nodeName : null, selectionFocusOffset: selection.focusOffset, message: e ? '' + e : null, offset: offset, }, null, 2, ), selectionState: JSON.stringify(selectionState.toJS(), null, 2), }); // allow the error to be thrown - // better than continuing in a broken state throw e; } } else { // IE doesn't support extend. This will mean no backward selection. // Extract the existing selection range and add focus to it. // Additionally, clone the selection range. IE11 throws an // InvalidStateError when attempting to access selection properties // after the range is detached. const range = selection.getRangeAt(0); range.setEnd(node, offset); selection.addRange(range.cloneRange()); } }