Skip to content

Commit 09f1812

Browse files
authored
Merge pull request #201 from 4dn-dcic/spc_child_window_navigation
Child Popup Window Updates
2 parents c7eb6df + 33071ec commit 09f1812

File tree

12 files changed

+178
-45
lines changed

12 files changed

+178
-45
lines changed

es/components/browse/SearchView.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import _inherits from "@babel/runtime/helpers/inherits";
55
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
66
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
77
import _defineProperty from "@babel/runtime/helpers/defineProperty";
8-
var _excluded = ["href", "context", "showClearFiltersButton", "schemas", "currentAction", "facets", "navigate", "columns", "columnExtensionMap", "placeholderReplacementFxn", "windowWidth"];
8+
var _excluded = ["href", "context", "showClearFiltersButton", "schemas", "currentAction", "facets", "navigate", "columns", "columnExtensionMap", "placeholderReplacementFxn", "keepSelectionInStorage", "windowWidth"];
99

1010
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
1111

@@ -79,6 +79,7 @@ export var SearchView = /*#__PURE__*/function (_React$PureComponent) {
7979
_this$props$columnExt = _this$props.columnExtensionMap,
8080
columnExtensionMap = _this$props$columnExt === void 0 ? basicColumnExtensionMap : _this$props$columnExt,
8181
placeholderReplacementFxn = _this$props.placeholderReplacementFxn,
82+
keepSelectionInStorage = _this$props.keepSelectionInStorage,
8283
windowWidth = _this$props.windowWidth,
8384
passProps = _objectWithoutProperties(_this$props, _excluded);
8485

@@ -117,7 +118,8 @@ export var SearchView = /*#__PURE__*/function (_React$PureComponent) {
117118
// though if desired.
118119
React.createElement(SelectedItemsController, {
119120
columnExtensionMap: columnExtensionMap,
120-
currentAction: currentAction
121+
currentAction: currentAction,
122+
keepSelectionInStorage: keepSelectionInStorage
121123
}, controllersAndView);
122124
}
123125

@@ -150,8 +152,9 @@ _defineProperty(SearchView, "propTypes", {
150152
'showClearFiltersButton': PropTypes.bool,
151153
'isOwnPage': PropTypes.bool,
152154
'schemas': PropTypes.object,
153-
'placeholderReplacementFxn': PropTypes.func // Passed down to AboveSearchTablePanel StaticSection
154-
155+
'placeholderReplacementFxn': PropTypes.func,
156+
// Passed down to AboveSearchTablePanel StaticSection
157+
'keepSelectionInStorage': PropTypes.bool
155158
});
156159

157160
_defineProperty(SearchView, "defaultProps", {
@@ -163,5 +166,6 @@ _defineProperty(SearchView, "defaultProps", {
163166
'currentAction': null,
164167
'columnExtensionMap': basicColumnExtensionMap,
165168
'separateSingleTermFacets': true,
166-
'isOwnPage': true
169+
'isOwnPage': true,
170+
'keepSelectionInStorage': false
167171
});

es/components/browse/components/SelectedItemsController.js

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@ function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflec
2626
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
2727

2828
import React, { useMemo, useCallback } from 'react';
29+
import PropTypes from 'prop-types';
2930
import _ from 'underscore';
3031
import { Alerts } from './../../ui/Alerts';
3132
import { itemUtil } from './../../util/object';
32-
import { isSelectAction } from './../../util/misc';
33+
import { isSelectAction, storeExists } from './../../util/misc';
3334
import * as logger from '../../util/logger';
3435
import { DisplayTitleColumnWrapper, DisplayTitleColumnDefault } from './../../browse/components/table-commons/basicColumnExtensionMap';
3536
import { getSchemaTypeFromSearchContext, getTitleForType } from './../../util/schema-transforms';
@@ -87,15 +88,29 @@ export var SelectedItemsController = /*#__PURE__*/function (_React$PureComponent
8788
};
8889
return _this;
8990
}
90-
/**
91-
* This function add/or removes the selected item into an Map in state,
92-
* if `props.currentAction` is set to "multiselect" or "selection".
93-
*/
94-
9591

9692
_createClass(SelectedItemsController, [{
93+
key: "componentDidMount",
94+
value: function componentDidMount() {
95+
var keepSelectionInStorage = this.props.keepSelectionInStorage;
96+
this.setState(function () {
97+
if (keepSelectionInStorage === true && storeExists() && localStorage.getItem("selected_items") !== null) {
98+
var foundItems = JSON.parse(localStorage.getItem("selected_items"));
99+
return {
100+
selectedItems: new Map(foundItems)
101+
};
102+
}
103+
});
104+
}
105+
/**
106+
* This function add/or removes the selected item into an Map in state,
107+
* if `props.currentAction` is set to "multiselect" or "selection".
108+
*/
109+
110+
}, {
97111
key: "handleSelectItem",
98112
value: function handleSelectItem(result, isMultiSelect) {
113+
var keepSelectionInStorage = this.props.keepSelectionInStorage;
99114
this.setState(function (_ref) {
100115
var prevItems = _ref.selectedItems;
101116
var nextItems = new Map(prevItems);
@@ -125,6 +140,10 @@ export var SelectedItemsController = /*#__PURE__*/function (_React$PureComponent
125140
}
126141
}
127142

143+
if (keepSelectionInStorage && storeExists()) {
144+
localStorage.setItem("selected_items", JSON.stringify(Array.from(nextItems.entries())));
145+
}
146+
128147
return {
129148
selectedItems: nextItems
130149
};
@@ -333,6 +352,40 @@ export var SelectStickyFooter = /*#__PURE__*/React.memo(function (props) {
333352
className: "icon icon-fw fas icon-times"
334353
}), "\xA0 Cancel"))));
335354
});
355+
export var BackNavigationStickyFooter = /*#__PURE__*/React.memo(function (props) {
356+
var text = props.text,
357+
tooltip = props.tooltip,
358+
navigateToInitialPage = props.navigateToInitialPage;
359+
var onBackButtonClick = useCallback(function () {
360+
if (window.history.length === 0) {
361+
return;
362+
}
363+
364+
history.go(navigateToInitialPage === true ? -(window.history.length - 1) : -1);
365+
});
366+
return /*#__PURE__*/React.createElement(StickyFooter, null, /*#__PURE__*/React.createElement("div", {
367+
className: "row selection-controls-footer pull-right"
368+
}, /*#__PURE__*/React.createElement("div", {
369+
className: "col-12 col-md-auto"
370+
}, /*#__PURE__*/React.createElement("button", {
371+
type: "button",
372+
className: "btn btn-outline-warning ml-1",
373+
onClick: onBackButtonClick,
374+
"data-tip": tooltip || ''
375+
}, /*#__PURE__*/React.createElement("i", {
376+
className: "icon icon-fw fas icon-arrow-left"
377+
}), "\xA0 ", text || ''))));
378+
});
379+
BackNavigationStickyFooter.propTypes = {
380+
'text': PropTypes.string,
381+
'tooltip': PropTypes.string,
382+
'navigateToInitialPage': PropTypes.bool
383+
};
384+
BackNavigationStickyFooter.defaultProps = {
385+
'text': 'Return to Selection List',
386+
'tooltip': 'Go to selection page',
387+
'navigateToInitialPage': true
388+
};
336389
/**
337390
* General purpose sticky footer component
338391
* TODO: Component can be moved to a separate file.

es/components/forms/components/LinkToSelector.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import _ from 'underscore';
1616
import url from 'url';
1717
import { patchedConsoleInstance as console } from './../../util/patched-console';
1818
import { itemUtil } from './../../util/object';
19+
import { storeExists } from '../../util/misc';
1920
/**
2021
* Global variable which holds reference to child window, if any.
2122
* Is re-used if one is open to prevent additional windows being created.
@@ -63,7 +64,11 @@ export var LinkToSelector = /*#__PURE__*/function (_React$PureComponent) {
6364
value: function componentDidMount() {
6465
this.manageChildWindow({
6566
'isSelecting': false
66-
}, this.props);
67+
}, this.props); //clear storage
68+
69+
if (storeExists()) {
70+
localStorage.removeItem("selected_items");
71+
}
6772
}
6873
}, {
6974
key: "componentDidUpdate",
@@ -238,6 +243,12 @@ export var LinkToSelector = /*#__PURE__*/function (_React$PureComponent) {
238243

239244
if (!this || !this.windowObjectReference) {
240245
console.warn('Child window no longer available to unbind event handlers. Fine if closed.');
246+
return;
247+
} //clear storage
248+
249+
250+
if (storeExists()) {
251+
localStorage.removeItem("selected_items");
241252
}
242253
}
243254
}, {

es/components/util/json-web-token.js

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,11 @@
11
import _ from 'underscore';
22
import memoize from 'memoize-one';
3-
import { isServerSide } from './misc';
3+
import { isServerSide, storeExists } from './misc';
44
import { patchedConsoleInstance as console } from './patched-console';
55
import { getNestedProperty } from './object';
66
/** Used for serverside */
77

88
var dummyStorage = {};
9-
/**
10-
* Check to see if localStorage is supported by the browser or environment.
11-
*
12-
* @private
13-
* @returns {boolean} True if supported.
14-
*/
15-
16-
function storeExists() {
17-
if (typeof Storage === 'undefined' || typeof localStorage === 'undefined' || !localStorage) return false;
18-
return true;
19-
}
209
/**
2110
* Checks to see if a JWT token is in proper
2211
* format. Does not validate it.
@@ -25,7 +14,6 @@ function storeExists() {
2514
* @returns {boolean} True if looks well-formated.
2615
*/
2716

28-
2917
export function maybeValid(jwtToken) {
3018
return typeof jwtToken === 'string' && jwtToken.length > 0 && jwtToken !== "null" && jwtToken !== "expired" ? true : false;
3119
}

es/components/util/misc.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ export function isServerSide() {
2222

2323
return false;
2424
}
25+
/**
26+
* Check to see if localStorage is supported by the browser or environment.
27+
*
28+
* @private
29+
* @returns {boolean} True if supported.
30+
*/
31+
32+
export function storeExists() {
33+
if (typeof Storage === 'undefined' || typeof localStorage === 'undefined' || !localStorage) return false;
34+
return true;
35+
}
2536
/**
2637
* `url.parse`, but globally memoized for performance.
2738
* **ONLY** pass in the _current_ `props.href` here.

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@hms-dbmi-bgm/shared-portal-components",
3-
"version": "0.1.57",
3+
"version": "0.1.58",
44
"description": "Shared components used for DBMI/BGM portal(s).",
55
"repository": {
66
"type": "git",

src/components/browse/SearchView.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ export class SearchView extends React.PureComponent {
3939
'showClearFiltersButton' : PropTypes.bool,
4040
'isOwnPage' : PropTypes.bool,
4141
'schemas' : PropTypes.object,
42-
'placeholderReplacementFxn' : PropTypes.func // Passed down to AboveSearchTablePanel StaticSection
42+
'placeholderReplacementFxn' : PropTypes.func, // Passed down to AboveSearchTablePanel StaticSection
43+
'keepSelectionInStorage': PropTypes.bool,
4344
};
4445

4546
/**
@@ -57,7 +58,8 @@ export class SearchView extends React.PureComponent {
5758
'currentAction' : null,
5859
'columnExtensionMap' : basicColumnExtensionMap,
5960
'separateSingleTermFacets' : true,
60-
'isOwnPage' : true
61+
'isOwnPage' : true,
62+
'keepSelectionInStorage': false,
6163
};
6264

6365
componentDidMount(){
@@ -80,6 +82,7 @@ export class SearchView extends React.PureComponent {
8082
columns = null,
8183
columnExtensionMap = basicColumnExtensionMap,
8284
placeholderReplacementFxn,
85+
keepSelectionInStorage,
8386
//isOwnPage = true,
8487
windowWidth,
8588
...passProps
@@ -121,7 +124,7 @@ export class SearchView extends React.PureComponent {
121124
// SelectedItemsController must be above ColumnCombiner because it adjusts
122125
// columnExtensionMap, rather than columnDefinitions. This can be easily changed
123126
// though if desired.
124-
<SelectedItemsController {...{ columnExtensionMap, currentAction }}>
127+
<SelectedItemsController {...{ columnExtensionMap, currentAction, keepSelectionInStorage }}>
125128
{ controllersAndView }
126129
</SelectedItemsController>
127130
);

src/components/browse/components/SelectedItemsController.js

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import React, { useMemo, useCallback } from 'react';
2+
import PropTypes from 'prop-types';
23
import _ from 'underscore';
34
import { Alerts } from './../../ui/Alerts';
45
import { itemUtil } from './../../util/object';
5-
import { isSelectAction } from './../../util/misc';
6+
import { isSelectAction, storeExists } from './../../util/misc';
67
import * as logger from '../../util/logger';
78
import { DisplayTitleColumnWrapper, DisplayTitleColumnDefault } from './../../browse/components/table-commons/basicColumnExtensionMap';
89
import { getSchemaTypeFromSearchContext, getTitleForType } from './../../util/schema-transforms';
@@ -52,11 +53,24 @@ export class SelectedItemsController extends React.PureComponent {
5253
this.state = { "selectedItems": new Map() };
5354
}
5455

56+
componentDidMount() {
57+
const { keepSelectionInStorage } = this.props;
58+
59+
this.setState(function () {
60+
if (keepSelectionInStorage === true && storeExists() && localStorage.getItem("selected_items") !== null) {
61+
const foundItems = JSON.parse(localStorage.getItem("selected_items"));
62+
return { selectedItems: new Map(foundItems) };
63+
}
64+
});
65+
}
66+
5567
/**
5668
* This function add/or removes the selected item into an Map in state,
5769
* if `props.currentAction` is set to "multiselect" or "selection".
5870
*/
5971
handleSelectItem(result, isMultiSelect) {
72+
const { keepSelectionInStorage } = this.props;
73+
6074
this.setState(function({ selectedItems: prevItems }){
6175
const nextItems = new Map(prevItems);
6276

@@ -84,6 +98,10 @@ export class SelectedItemsController extends React.PureComponent {
8498
}
8599
}
86100

101+
if (keepSelectionInStorage && storeExists()){
102+
localStorage.setItem("selected_items", JSON.stringify(Array.from(nextItems.entries())));
103+
}
104+
87105
return { selectedItems: nextItems };
88106
});
89107
}
@@ -237,6 +255,41 @@ export const SelectStickyFooter = React.memo(function SelectStickyFooter(props){
237255
);
238256
});
239257

258+
export const BackNavigationStickyFooter = React.memo(function BackNavigationStickyFooter(props) {
259+
const { text, tooltip, navigateToInitialPage } = props;
260+
261+
const onBackButtonClick = useCallback(function () {
262+
if (window.history.length === 0) {
263+
return;
264+
}
265+
history.go(navigateToInitialPage === true ? -(window.history.length - 1) : -1);
266+
});
267+
268+
return (
269+
<StickyFooter>
270+
<div className="row selection-controls-footer pull-right">
271+
<div className="col-12 col-md-auto">
272+
<button type="button" className="btn btn-outline-warning ml-1" onClick={onBackButtonClick} data-tip={tooltip || ''}>
273+
<i className="icon icon-fw fas icon-arrow-left"></i>&nbsp; {text || ''}
274+
</button>
275+
</div>
276+
</div>
277+
</StickyFooter>
278+
);
279+
});
280+
281+
BackNavigationStickyFooter.propTypes = {
282+
'text': PropTypes.string,
283+
'tooltip': PropTypes.string,
284+
'navigateToInitialPage': PropTypes.bool
285+
};
286+
287+
BackNavigationStickyFooter.defaultProps = {
288+
'text': 'Return to Selection List',
289+
'tooltip': 'Go to selection page',
290+
'navigateToInitialPage': true
291+
};
292+
240293
/**
241294
* General purpose sticky footer component
242295
* TODO: Component can be moved to a separate file.

0 commit comments

Comments
 (0)