diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2018-07-31 18:11:19 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2018-07-31 18:31:13 +0200 |
| commit | d16bc5cc876e4d8b057525338ea5b01c3629f6c4 (patch) | |
| tree | b92b899df56af49eccf2384eff23bbe9975e262e | |
| parent | aca43fd96c1d1937d2304d9602b84b24fe339b9b (diff) | |
| download | mullvadvpn-d16bc5cc876e4d8b057525338ea5b01c3629f6c4.tar.xz mullvadvpn-d16bc5cc876e4d8b057525338ea5b01c3629f6c4.zip | |
Auto scroll to selected location
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | app/components/CustomScrollbars.js | 25 | ||||
| -rw-r--r-- | app/components/SelectLocation.js | 18 |
3 files changed, 37 insertions, 7 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index aed8b5b68f..286890f11b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ Line wrap the file at 100 chars. Th - Create a new UI log file for every UI execution session, and preserve the log from the previous session. - Account token can be copied to the clipboard by clicking on it in the account settings screen. +- Automatically scroll to selected country/city in locations view. ### Changed - Format the expiry date and time using the system locale. diff --git a/app/components/CustomScrollbars.js b/app/components/CustomScrollbars.js index 6539a91185..be74bfddb5 100644 --- a/app/components/CustomScrollbars.js +++ b/app/components/CustomScrollbars.js @@ -56,7 +56,6 @@ export default class CustomScrollbars extends React.Component<Props, State> { } const scrollTop = this._computeScrollTop(scrollable, child, scrollPosition); - this.scrollTo(0, scrollTop); } } @@ -147,16 +146,34 @@ export default class CustomScrollbars extends React.Component<Props, State> { } } + // Computes the position of child element within scrollable container + _computeOffsetTop(scrollable: HTMLElement, child: HTMLElement) { + let offsetTop = 0; + let node = child; + + while (node && scrollable.contains(node)) { + offsetTop += node.offsetTop; + + // Flow bug in offsetParent definition: + // https://github.com/facebook/flow/issues/4407 + node = ((node.offsetParent: any): HTMLElement); + } + + return offsetTop; + } + _computeScrollTop(scrollable: HTMLElement, child: HTMLElement, scrollPosition: ScrollPosition) { + const offsetTop = this._computeOffsetTop(scrollable, child); + switch (scrollPosition) { case 'top': - return child.offsetTop; + return offsetTop; case 'bottom': - return child.offsetTop - (scrollable.offsetHeight - child.clientHeight); + return offsetTop - (scrollable.offsetHeight - child.clientHeight); case 'middle': - return child.offsetTop - (scrollable.offsetHeight - child.clientHeight) * 0.5; + return offsetTop - (scrollable.offsetHeight - child.clientHeight) * 0.5; default: throw new Error(`Unknown enum type for ScrollPosition: ${scrollPosition}`); diff --git a/app/components/SelectLocation.js b/app/components/SelectLocation.js index 6257f89aef..afa765dba6 100644 --- a/app/components/SelectLocation.js +++ b/app/components/SelectLocation.js @@ -1,5 +1,6 @@ // @flow import * as React from 'react'; +import ReactDOM from 'react-dom'; import { View } from 'reactxp'; import { Layout, Container } from './Layout'; import CustomScrollbars from './CustomScrollbars'; @@ -59,8 +60,12 @@ export default class SelectLocation extends React.Component<SelectLocationProps, const scrollView = this._scrollView; if (scrollView && cell) { - //TODO: fix this when repairing the auto-scroll in customscrollbars. - //scrollView.scrollToElement(cell, 'middle'); + // eslint-disable-next-line react/no-find-dom-node + const cellDOMNode = ReactDOM.findDOMNode(cell); + + if (cellDOMNode instanceof HTMLElement) { + scrollView.scrollToElement(cellDOMNode, 'middle'); + } } } @@ -150,6 +155,12 @@ export default class SelectLocation extends React.Component<SelectLocationProps, _renderCountry(relayCountry: RelayLocationRedux) { const isSelected = this._isSelected({ country: relayCountry.code }); + const onRef = isSelected + ? (element) => { + this._selectedCell = element; + } + : undefined; + // either expanded by user or when the city selected within the country const isExpanded = this.state.expanded.includes(relayCountry.code); @@ -172,7 +183,8 @@ export default class SelectLocation extends React.Component<SelectLocationProps, style={isSelected ? styles.cell_selected : styles.cell} onPress={handleSelect} disabled={!relayCountry.hasActiveRelays} - testName="country"> + testName="country" + ref={onRef}> {this._relayStatusIndicator(relayCountry.hasActiveRelays, isSelected)} <Cell.Label>{relayCountry.name}</Cell.Label> |
