UNPKG

4.27 kBJavaScriptView Raw
1/**
2 * Copyright 2013-present, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 */
10
11'use strict';
12
13var ReactDOMSelection = require('./ReactDOMSelection');
14
15var containsNode = require('fbjs/lib/containsNode');
16var focusNode = require('fbjs/lib/focusNode');
17var getActiveElement = require('fbjs/lib/getActiveElement');
18
19function isInDocument(node) {
20 return containsNode(document.documentElement, node);
21}
22
23/**
24 * @ReactInputSelection: React input selection module. Based on Selection.js,
25 * but modified to be suitable for react and has a couple of bug fixes (doesn't
26 * assume buttons have range selections allowed).
27 * Input selection module for React.
28 */
29var ReactInputSelection = {
30 hasSelectionCapabilities: function (elem) {
31 var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase();
32 return nodeName && (nodeName === 'input' && elem.type === 'text' || nodeName === 'textarea' || elem.contentEditable === 'true');
33 },
34
35 getSelectionInformation: function () {
36 var focusedElem = getActiveElement();
37 return {
38 focusedElem: focusedElem,
39 selectionRange: ReactInputSelection.hasSelectionCapabilities(focusedElem) ? ReactInputSelection.getSelection(focusedElem) : null
40 };
41 },
42
43 /**
44 * @restoreSelection: If any selection information was potentially lost,
45 * restore it. This is useful when performing operations that could remove dom
46 * nodes and place them back in, resulting in focus being lost.
47 */
48 restoreSelection: function (priorSelectionInformation) {
49 var curFocusedElem = getActiveElement();
50 var priorFocusedElem = priorSelectionInformation.focusedElem;
51 var priorSelectionRange = priorSelectionInformation.selectionRange;
52 if (curFocusedElem !== priorFocusedElem && isInDocument(priorFocusedElem)) {
53 if (ReactInputSelection.hasSelectionCapabilities(priorFocusedElem)) {
54 ReactInputSelection.setSelection(priorFocusedElem, priorSelectionRange);
55 }
56 focusNode(priorFocusedElem);
57 }
58 },
59
60 /**
61 * @getSelection: Gets the selection bounds of a focused textarea, input or
62 * contentEditable node.
63 * -@input: Look up selection bounds of this input
64 * -@return {start: selectionStart, end: selectionEnd}
65 */
66 getSelection: function (input) {
67 var selection;
68
69 if ('selectionStart' in input) {
70 // Modern browser with input or textarea.
71 selection = {
72 start: input.selectionStart,
73 end: input.selectionEnd
74 };
75 } else if (document.selection && input.nodeName && input.nodeName.toLowerCase() === 'input') {
76 // IE8 input.
77 var range = document.selection.createRange();
78 // There can only be one selection per document in IE, so it must
79 // be in our element.
80 if (range.parentElement() === input) {
81 selection = {
82 start: -range.moveStart('character', -input.value.length),
83 end: -range.moveEnd('character', -input.value.length)
84 };
85 }
86 } else {
87 // Content editable or old IE textarea.
88 selection = ReactDOMSelection.getOffsets(input);
89 }
90
91 return selection || { start: 0, end: 0 };
92 },
93
94 /**
95 * @setSelection: Sets the selection bounds of a textarea or input and focuses
96 * the input.
97 * -@input Set selection bounds of this input or textarea
98 * -@offsets Object of same form that is returned from get*
99 */
100 setSelection: function (input, offsets) {
101 var start = offsets.start;
102 var end = offsets.end;
103 if (end === undefined) {
104 end = start;
105 }
106
107 if ('selectionStart' in input) {
108 input.selectionStart = start;
109 input.selectionEnd = Math.min(end, input.value.length);
110 } else if (document.selection && input.nodeName && input.nodeName.toLowerCase() === 'input') {
111 var range = input.createTextRange();
112 range.collapse(true);
113 range.moveStart('character', start);
114 range.moveEnd('character', end - start);
115 range.select();
116 } else {
117 ReactDOMSelection.setOffsets(input, offsets);
118 }
119 }
120};
121
122module.exports = ReactInputSelection;
\No newline at end of file