You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
4.1 KiB
133 lines
4.1 KiB
/** |
|
* Copyright 2013-2015, Facebook, Inc. |
|
* All rights reserved. |
|
* |
|
* This source code is licensed under the BSD-style license found in the |
|
* LICENSE file in the root directory of this source tree. An additional grant |
|
* of patent rights can be found in the PATENTS file in the same directory. |
|
* |
|
* @providesModule ReactInputSelection |
|
*/ |
|
|
|
'use strict'; |
|
|
|
var ReactDOMSelection = require("./ReactDOMSelection"); |
|
|
|
var containsNode = require("./containsNode"); |
|
var focusNode = require("./focusNode"); |
|
var getActiveElement = require("./getActiveElement"); |
|
|
|
function isInDocument(node) { |
|
return containsNode(document.documentElement, node); |
|
} |
|
|
|
/** |
|
* @ReactInputSelection: React input selection module. Based on Selection.js, |
|
* but modified to be suitable for react and has a couple of bug fixes (doesn't |
|
* assume buttons have range selections allowed). |
|
* Input selection module for React. |
|
*/ |
|
var ReactInputSelection = { |
|
|
|
hasSelectionCapabilities: function(elem) { |
|
return elem && ( |
|
((elem.nodeName === 'INPUT' && elem.type === 'text') || |
|
elem.nodeName === 'TEXTAREA' || elem.contentEditable === 'true') |
|
); |
|
}, |
|
|
|
getSelectionInformation: function() { |
|
var focusedElem = getActiveElement(); |
|
return { |
|
focusedElem: focusedElem, |
|
selectionRange: |
|
ReactInputSelection.hasSelectionCapabilities(focusedElem) ? |
|
ReactInputSelection.getSelection(focusedElem) : |
|
null |
|
}; |
|
}, |
|
|
|
/** |
|
* @restoreSelection: If any selection information was potentially lost, |
|
* restore it. This is useful when performing operations that could remove dom |
|
* nodes and place them back in, resulting in focus being lost. |
|
*/ |
|
restoreSelection: function(priorSelectionInformation) { |
|
var curFocusedElem = getActiveElement(); |
|
var priorFocusedElem = priorSelectionInformation.focusedElem; |
|
var priorSelectionRange = priorSelectionInformation.selectionRange; |
|
if (curFocusedElem !== priorFocusedElem && |
|
isInDocument(priorFocusedElem)) { |
|
if (ReactInputSelection.hasSelectionCapabilities(priorFocusedElem)) { |
|
ReactInputSelection.setSelection( |
|
priorFocusedElem, |
|
priorSelectionRange |
|
); |
|
} |
|
focusNode(priorFocusedElem); |
|
} |
|
}, |
|
|
|
/** |
|
* @getSelection: Gets the selection bounds of a focused textarea, input or |
|
* contentEditable node. |
|
* -@input: Look up selection bounds of this input |
|
* -@return {start: selectionStart, end: selectionEnd} |
|
*/ |
|
getSelection: function(input) { |
|
var selection; |
|
|
|
if ('selectionStart' in input) { |
|
// Modern browser with input or textarea. |
|
selection = { |
|
start: input.selectionStart, |
|
end: input.selectionEnd |
|
}; |
|
} else if (document.selection && input.nodeName === 'INPUT') { |
|
// IE8 input. |
|
var range = document.selection.createRange(); |
|
// There can only be one selection per document in IE, so it must |
|
// be in our element. |
|
if (range.parentElement() === input) { |
|
selection = { |
|
start: -range.moveStart('character', -input.value.length), |
|
end: -range.moveEnd('character', -input.value.length) |
|
}; |
|
} |
|
} else { |
|
// Content editable or old IE textarea. |
|
selection = ReactDOMSelection.getOffsets(input); |
|
} |
|
|
|
return selection || {start: 0, end: 0}; |
|
}, |
|
|
|
/** |
|
* @setSelection: Sets the selection bounds of a textarea or input and focuses |
|
* the input. |
|
* -@input Set selection bounds of this input or textarea |
|
* -@offsets Object of same form that is returned from get* |
|
*/ |
|
setSelection: function(input, offsets) { |
|
var start = offsets.start; |
|
var end = offsets.end; |
|
if (typeof end === 'undefined') { |
|
end = start; |
|
} |
|
|
|
if ('selectionStart' in input) { |
|
input.selectionStart = start; |
|
input.selectionEnd = Math.min(end, input.value.length); |
|
} else if (document.selection && input.nodeName === 'INPUT') { |
|
var range = input.createTextRange(); |
|
range.collapse(true); |
|
range.moveStart('character', start); |
|
range.moveEnd('character', end - start); |
|
range.select(); |
|
} else { |
|
ReactDOMSelection.setOffsets(input, offsets); |
|
} |
|
} |
|
}; |
|
|
|
module.exports = ReactInputSelection;
|
|
|