Skip to content

Commit

Permalink
Adapt restoreSelection to work for *all* activeElements
Browse files Browse the repository at this point in the history
  • Loading branch information
acusti committed Oct 13, 2016
1 parent 6b17090 commit acc235c
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 19 deletions.
70 changes: 53 additions & 17 deletions src/renderers/dom/client/ReactInputSelection.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,31 @@ function getFocusedElement() {
return focusedElem;
}

function getElementsWithSelections(acc, win) {
acc = acc || [];
win = win || window;
var doc;
try {
doc = win.document;
} catch (e) {
return acc;
}
var element = null;
if (win.getSelection) {
var selection = win.getSelection();
if (selection.anchorNode === selection.focusNode) {
element = selection.anchorNode;
}
} else if (doc.selection) {
var range = doc.selection.createRange();
element = range.parentElement();
}
if (ReactInputSelection.hasSelectionCapabilities(element)) {
acc = acc.concat(element);
}
return Array.prototype.reduce.call(win.frames, getElementsWithSelections, acc);
}

/**
* @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
Expand All @@ -53,13 +78,15 @@ var ReactInputSelection = {
},

getSelectionInformation: function() {
var focusedElem = getFocusedElement();
var focusedElement = getFocusedElement();
return {
focusedElem: focusedElem,
selectionRange:
ReactInputSelection.hasSelectionCapabilities(focusedElem) ?
ReactInputSelection.getSelection(focusedElem) :
null,
focusedElement: focusedElement,
activeElements: getElementsWithSelections().map(function(element) {
return {
element: element,
selectionRange: ReactInputSelection.getSelection(element),
};
}),
};
},

Expand All @@ -69,18 +96,27 @@ var ReactInputSelection = {
* nodes and place them back in, resulting in focus being lost.
*/
restoreSelection: function(priorSelectionInformation) {
var curFocusedElem = getFocusedElement();
var priorFocusedElem = priorSelectionInformation.focusedElem;
var priorSelectionRange = priorSelectionInformation.selectionRange;
if (curFocusedElem !== priorFocusedElem &&
isInDocument(priorFocusedElem)) {
if (ReactInputSelection.hasSelectionCapabilities(priorFocusedElem)) {
ReactInputSelection.setSelection(
priorFocusedElem,
priorSelectionRange
);
priorSelectionInformation.activeElements.forEach(function(activeElement) {
var element = activeElement.element;
if (!isInDocument(element) ||
getActiveElement(element.ownerDocument) === element) {
return;
}
focusNode(priorFocusedElem);
if (!ReactInputSelection.hasSelectionCapabilities(element)) {
return;
}
ReactInputSelection.setSelection(
element,
activeElement.selectionRange
);
focusNode(element);
});

var curFocusedElement = getFocusedElement();
var priorFocusedElement = priorSelectionInformation.focusedElement;
if (curFocusedElement !== priorFocusedElement &&
isInDocument(priorFocusedElement)) {
focusNode(priorFocusedElement);
}
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,9 @@ describe('ReactInputSelection', () => {
input.selectionStart = 1;
input.selectionEnd = 10;
var selectionInfo = ReactInputSelection.getSelectionInformation();
expect(selectionInfo.focusedElem).toBe(input);
expect(selectionInfo.selectionRange).toEqual({start: 1, end: 10});
expect(selectionInfo.focusedElement).toBe(input);
expect(selectionInfo.activeElements[0].element).toBe(input);
expect(selectionInfo.activeElements[0].selectionRange).toEqual({start: 1, end: 10});
expect(document.activeElement).toBe(input);
input.setSelectionRange(0, 0);
document.body.removeChild(input);
Expand Down

0 comments on commit acc235c

Please sign in to comment.