@collectionspace/cspace-public-browser 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +71 -0
- package/README.md +38 -0
- package/dist/cspacePublicBrowser.js +4680 -0
- package/dist/cspacePublicBrowser.min.js +2 -0
- package/dist/cspacePublicBrowser.min.js.LICENSE.txt +56 -0
- package/images/check.svg +3 -0
- package/images/close.svg +3 -0
- package/images/collapse.svg +3 -0
- package/images/collapseActive.svg +3 -0
- package/images/expand.svg +3 -0
- package/images/expandActive.svg +3 -0
- package/images/filter.svg +4 -0
- package/images/hideLeft.svg +4 -0
- package/images/linkBack.svg +4 -0
- package/images/linkDown.svg +4 -0
- package/images/linkNext.svg +4 -0
- package/images/linkPrev.svg +4 -0
- package/images/openNew.svg +4 -0
- package/images/search.svg +4 -0
- package/images/select.svg +4 -0
- package/images/top.svg +1 -0
- package/lib/actions/detailActions.js +177 -0
- package/lib/actions/filterActions.js +16 -0
- package/lib/actions/mediaActions.js +63 -0
- package/lib/actions/prefsActions.js +84 -0
- package/lib/actions/searchActions.js +140 -0
- package/lib/actions/searchEntryFormActions.js +19 -0
- package/lib/components/App.js +24 -0
- package/lib/components/detail/DetailNavBar.js +98 -0
- package/lib/components/detail/DetailPanel.js +171 -0
- package/lib/components/detail/DetailPanelContainer.js +22 -0
- package/lib/components/detail/ExhibitionSection.js +54 -0
- package/lib/components/detail/FieldList.js +95 -0
- package/lib/components/detail/FieldValueList.js +30 -0
- package/lib/components/detail/ImageGallery.js +137 -0
- package/lib/components/detail/ImageGalleryContainer.js +19 -0
- package/lib/components/detail/InstitutionHoldingList.js +155 -0
- package/lib/components/detail/InstitutionHoldingListContainer.js +22 -0
- package/lib/components/detail/InstitutionIndex.js +53 -0
- package/lib/components/detail/InstitutionIndexContainer.js +15 -0
- package/lib/components/detail/InstitutionSection.js +44 -0
- package/lib/components/detail/InstitutionSectionContainer.js +15 -0
- package/lib/components/layout/Fixed.js +26 -0
- package/lib/components/layout/IconButton.js +41 -0
- package/lib/components/layout/Panel.js +56 -0
- package/lib/components/layout/PanelContainer.js +19 -0
- package/lib/components/layout/PanelTitle.js +38 -0
- package/lib/components/layout/ScrollTopButton.js +70 -0
- package/lib/components/layout/ToggleFilterPanelButton.js +42 -0
- package/lib/components/pages/DetailPage.js +93 -0
- package/lib/components/pages/DetailPageContainer.js +20 -0
- package/lib/components/pages/RootPage.js +41 -0
- package/lib/components/pages/SearchPage.js +130 -0
- package/lib/components/pages/SearchPageContainer.js +23 -0
- package/lib/components/search/entry/SearchEntryForm.js +74 -0
- package/lib/components/search/entry/SearchEntryFormContainer.js +20 -0
- package/lib/components/search/entry/SearchEntryPanel.js +30 -0
- package/lib/components/search/entry/SearchQueryInput.js +89 -0
- package/lib/components/search/entry/SearchSubmitButton.js +22 -0
- package/lib/components/search/entry/SortSelect.js +89 -0
- package/lib/components/search/entry/SortSelectContainer.js +15 -0
- package/lib/components/search/result/ClearSearchParamsLink.js +42 -0
- package/lib/components/search/result/Filter.js +186 -0
- package/lib/components/search/result/FilterContainer.js +22 -0
- package/lib/components/search/result/FilterGroup.js +72 -0
- package/lib/components/search/result/FilterList.js +48 -0
- package/lib/components/search/result/FilterPanel.js +115 -0
- package/lib/components/search/result/FilterPanelContainer.js +16 -0
- package/lib/components/search/result/FilterSearchInput.js +63 -0
- package/lib/components/search/result/RemoveSearchParamLink.js +66 -0
- package/lib/components/search/result/SearchError.js +29 -0
- package/lib/components/search/result/SearchLoadMore.js +36 -0
- package/lib/components/search/result/SearchParamList.js +41 -0
- package/lib/components/search/result/SearchPending.js +21 -0
- package/lib/components/search/result/SearchResultImage.js +227 -0
- package/lib/components/search/result/SearchResultList.js +119 -0
- package/lib/components/search/result/SearchResultPanel.js +139 -0
- package/lib/components/search/result/SearchResultPanelContainer.js +23 -0
- package/lib/components/search/result/SearchResultStats.js +39 -0
- package/lib/components/search/result/SearchResultTile.js +61 -0
- package/lib/config/anthro.js +123 -0
- package/lib/config/bonsai.js +50 -0
- package/lib/config/botgarden.js +10 -0
- package/lib/config/default.js +530 -0
- package/lib/config/fcart.js +36 -0
- package/lib/config/herbarium.js +10 -0
- package/lib/config/index.js +53 -0
- package/lib/config/lhmc.js +10 -0
- package/lib/config/materials.js +982 -0
- package/lib/config/publicart.js +10 -0
- package/lib/constants/actionCodes.js +46 -0
- package/lib/constants/ids.js +12 -0
- package/lib/helpers/bodyClassName.js +11 -0
- package/lib/helpers/esQueryHelpers.js +206 -0
- package/lib/helpers/formatHelpers.js +293 -0
- package/lib/helpers/searchDimensions.js +28 -0
- package/lib/helpers/urlHelpers.js +43 -0
- package/lib/index.js +53 -0
- package/lib/intl/index.js +16 -0
- package/lib/reducers/detailReducer.js +145 -0
- package/lib/reducers/filterReducer.js +22 -0
- package/lib/reducers/index.js +66 -0
- package/lib/reducers/mediaReducer.js +43 -0
- package/lib/reducers/prefsReducer.js +27 -0
- package/lib/reducers/searchEntryFormReducer.js +24 -0
- package/lib/reducers/searchReducer.js +88 -0
- package/package.json +118 -0
- package/src/actions/detailActions.js +231 -0
- package/src/actions/filterActions.js +10 -0
- package/src/actions/mediaActions.js +65 -0
- package/src/actions/prefsActions.js +95 -0
- package/src/actions/searchActions.js +188 -0
- package/src/actions/searchEntryFormActions.js +15 -0
- package/src/components/App.jsx +18 -0
- package/src/components/detail/DetailNavBar.jsx +132 -0
- package/src/components/detail/DetailPanel.jsx +215 -0
- package/src/components/detail/DetailPanelContainer.js +29 -0
- package/src/components/detail/ExhibitionSection.jsx +71 -0
- package/src/components/detail/FieldList.jsx +122 -0
- package/src/components/detail/FieldValueList.jsx +31 -0
- package/src/components/detail/ImageGallery.jsx +153 -0
- package/src/components/detail/ImageGalleryContainer.js +17 -0
- package/src/components/detail/InstitutionHoldingList.jsx +188 -0
- package/src/components/detail/InstitutionHoldingListContainer.js +29 -0
- package/src/components/detail/InstitutionIndex.jsx +57 -0
- package/src/components/detail/InstitutionIndexContainer.js +11 -0
- package/src/components/detail/InstitutionSection.jsx +48 -0
- package/src/components/detail/InstitutionSectionContainer.js +11 -0
- package/src/components/layout/Fixed.jsx +29 -0
- package/src/components/layout/IconButton.jsx +41 -0
- package/src/components/layout/Panel.jsx +60 -0
- package/src/components/layout/PanelContainer.js +20 -0
- package/src/components/layout/PanelTitle.jsx +43 -0
- package/src/components/layout/ScrollTopButton.jsx +76 -0
- package/src/components/layout/ToggleFilterPanelButton.jsx +43 -0
- package/src/components/pages/DetailPage.jsx +101 -0
- package/src/components/pages/DetailPageContainer.js +18 -0
- package/src/components/pages/RootPage.jsx +37 -0
- package/src/components/pages/SearchPage.jsx +160 -0
- package/src/components/pages/SearchPageContainer.js +21 -0
- package/src/components/search/entry/SearchEntryForm.jsx +82 -0
- package/src/components/search/entry/SearchEntryFormContainer.js +22 -0
- package/src/components/search/entry/SearchEntryPanel.jsx +28 -0
- package/src/components/search/entry/SearchQueryInput.jsx +95 -0
- package/src/components/search/entry/SearchSubmitButton.jsx +22 -0
- package/src/components/search/entry/SortSelect.jsx +104 -0
- package/src/components/search/entry/SortSelectContainer.js +12 -0
- package/src/components/search/result/ClearSearchParamsLink.jsx +43 -0
- package/src/components/search/result/Filter.jsx +226 -0
- package/src/components/search/result/FilterContainer.js +20 -0
- package/src/components/search/result/FilterGroup.jsx +83 -0
- package/src/components/search/result/FilterList.jsx +51 -0
- package/src/components/search/result/FilterPanel.jsx +143 -0
- package/src/components/search/result/FilterPanelContainer.js +16 -0
- package/src/components/search/result/FilterSearchInput.jsx +68 -0
- package/src/components/search/result/RemoveSearchParamLink.jsx +79 -0
- package/src/components/search/result/SearchError.jsx +30 -0
- package/src/components/search/result/SearchLoadMore.jsx +37 -0
- package/src/components/search/result/SearchParamList.jsx +47 -0
- package/src/components/search/result/SearchPending.jsx +19 -0
- package/src/components/search/result/SearchResultImage.jsx +275 -0
- package/src/components/search/result/SearchResultList.jsx +144 -0
- package/src/components/search/result/SearchResultPanel.jsx +169 -0
- package/src/components/search/result/SearchResultPanelContainer.js +31 -0
- package/src/components/search/result/SearchResultStats.jsx +38 -0
- package/src/components/search/result/SearchResultTile.jsx +70 -0
- package/src/config/anthro.js +153 -0
- package/src/config/bonsai.js +50 -0
- package/src/config/botgarden.js +3 -0
- package/src/config/default.js +604 -0
- package/src/config/fcart.js +38 -0
- package/src/config/herbarium.js +3 -0
- package/src/config/index.js +51 -0
- package/src/config/lhmc.js +3 -0
- package/src/config/materials.js +1173 -0
- package/src/config/publicart.js +3 -0
- package/src/constants/actionCodes.js +26 -0
- package/src/constants/ids.js +3 -0
- package/src/helpers/bodyClassName.js +5 -0
- package/src/helpers/esQueryHelpers.js +224 -0
- package/src/helpers/formatHelpers.jsx +361 -0
- package/src/helpers/searchDimensions.js +21 -0
- package/src/helpers/urlHelpers.js +49 -0
- package/src/index.jsx +59 -0
- package/src/intl/index.js +16 -0
- package/src/reducers/detailReducer.js +201 -0
- package/src/reducers/filterReducer.js +16 -0
- package/src/reducers/index.js +56 -0
- package/src/reducers/mediaReducer.js +44 -0
- package/src/reducers/prefsReducer.js +24 -0
- package/src/reducers/searchEntryFormReducer.js +19 -0
- package/src/reducers/searchReducer.js +118 -0
- package/styles/colors.css +7 -0
- package/styles/cspace/DetailNavBar.css +17 -0
- package/styles/cspace/DetailPage.css +3 -0
- package/styles/cspace/DetailPanel.css +69 -0
- package/styles/cspace/ExhibitionSection.css +9 -0
- package/styles/cspace/FieldList.css +15 -0
- package/styles/cspace/FieldListField.css +7 -0
- package/styles/cspace/FieldListGroup.css +27 -0
- package/styles/cspace/FieldValueList.css +19 -0
- package/styles/cspace/Filter.css +64 -0
- package/styles/cspace/FilterGroup.css +21 -0
- package/styles/cspace/FilterPanel.css +45 -0
- package/styles/cspace/FilterSearchInput.css +13 -0
- package/styles/cspace/Fixed.css +8 -0
- package/styles/cspace/IconButton.css +11 -0
- package/styles/cspace/ImageGallery.css +43 -0
- package/styles/cspace/InstitutionHoldingList.css +109 -0
- package/styles/cspace/InstitutionIndex.css +13 -0
- package/styles/cspace/InstitutionSection.css +4 -0
- package/styles/cspace/Link.css +39 -0
- package/styles/cspace/Panel.css +53 -0
- package/styles/cspace/PanelTitle.css +48 -0
- package/styles/cspace/RemoveSearchParamLink.css +15 -0
- package/styles/cspace/RootPage.css +60 -0
- package/styles/cspace/ScrollTopButton.css +32 -0
- package/styles/cspace/SearchEntryForm.css +4 -0
- package/styles/cspace/SearchEntryPanel.css +11 -0
- package/styles/cspace/SearchPage.css +2 -0
- package/styles/cspace/SearchParamLink.css +21 -0
- package/styles/cspace/SearchParamList.css +6 -0
- package/styles/cspace/SearchQueryInput.css +30 -0
- package/styles/cspace/SearchResultImage.css +29 -0
- package/styles/cspace/SearchResultList.css +10 -0
- package/styles/cspace/SearchResultPanel.css +31 -0
- package/styles/cspace/SearchResultStats.css +4 -0
- package/styles/cspace/SearchResultTile.css +67 -0
- package/styles/cspace/SearchStatus.css +12 -0
- package/styles/cspace/SearchSubmitButton.css +3 -0
- package/styles/cspace/SortSelect.css +19 -0
- package/styles/cspace/ToggleFilterPanelButton.css +44 -0
- package/styles/dimensions.css +9 -0
package/src/index.jsx
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/* global document, window */
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { render } from 'react-dom';
|
|
5
|
+
import { RawIntlProvider } from 'react-intl';
|
|
6
|
+
import { applyMiddleware, compose, createStore } from 'redux';
|
|
7
|
+
import { Provider as StoreProvider } from 'react-redux';
|
|
8
|
+
import thunk from 'redux-thunk';
|
|
9
|
+
import warning from 'warning';
|
|
10
|
+
import { loadPrefs } from './actions/prefsActions';
|
|
11
|
+
import config from './config';
|
|
12
|
+
import App from './components/App';
|
|
13
|
+
import { createIntl } from './intl';
|
|
14
|
+
import reducer from './reducers';
|
|
15
|
+
import * as formatters from './helpers/formatHelpers';
|
|
16
|
+
|
|
17
|
+
const cspacePublicBrowser = (...customConfigs) => {
|
|
18
|
+
config.merge(...customConfigs);
|
|
19
|
+
|
|
20
|
+
const container = config.get('container');
|
|
21
|
+
const mountNode = document.querySelector(container);
|
|
22
|
+
|
|
23
|
+
warning(
|
|
24
|
+
mountNode,
|
|
25
|
+
`No container element was found using the selector '${container}'. The CollectionSpace collection browser will not be rendered.`,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
if (!mountNode) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
33
|
+
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
|
34
|
+
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)));
|
|
35
|
+
|
|
36
|
+
store.dispatch(loadPrefs());
|
|
37
|
+
|
|
38
|
+
const locale = config.get('locale');
|
|
39
|
+
const messages = config.get('messages');
|
|
40
|
+
|
|
41
|
+
const intl = createIntl({
|
|
42
|
+
locale,
|
|
43
|
+
messages,
|
|
44
|
+
defaultLocale: 'en-US',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
render(
|
|
48
|
+
<RawIntlProvider value={intl}>
|
|
49
|
+
<StoreProvider store={store}>
|
|
50
|
+
<App />
|
|
51
|
+
</StoreProvider>
|
|
52
|
+
</RawIntlProvider>,
|
|
53
|
+
mountNode,
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
cspacePublicBrowser.formatters = formatters;
|
|
58
|
+
|
|
59
|
+
export default cspacePublicBrowser;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createIntl as baseCreateIntl,
|
|
3
|
+
createIntlCache,
|
|
4
|
+
} from 'react-intl';
|
|
5
|
+
|
|
6
|
+
const intlCache = createIntlCache();
|
|
7
|
+
|
|
8
|
+
let intl;
|
|
9
|
+
|
|
10
|
+
export const createIntl = (config) => {
|
|
11
|
+
intl = baseCreateIntl(config, intlCache);
|
|
12
|
+
|
|
13
|
+
return intl;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const getIntl = () => intl;
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import Immutable from 'immutable';
|
|
2
|
+
import get from 'lodash/get';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
CLEAR_DETAIL,
|
|
6
|
+
DETAIL_READ_FULFILLED,
|
|
7
|
+
DETAIL_READ_REJECTED,
|
|
8
|
+
DETAIL_READ_STARTED,
|
|
9
|
+
INST_SEARCH_FULFILLED,
|
|
10
|
+
INST_SEARCH_REJECTED,
|
|
11
|
+
INST_SEARCH_STARTED,
|
|
12
|
+
SET_DETAIL_PARAMS,
|
|
13
|
+
} from '../constants/actionCodes';
|
|
14
|
+
|
|
15
|
+
const findAdjacents = (csid, hits) => {
|
|
16
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
17
|
+
const csidIndex = hits ? hits.findIndex((hit) => hit._source['ecm:name'] === csid) : -1;
|
|
18
|
+
|
|
19
|
+
if (csidIndex < 0) {
|
|
20
|
+
return {
|
|
21
|
+
prev: undefined,
|
|
22
|
+
next: undefined,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
28
|
+
prev: (csidIndex > 0) ? hits[csidIndex - 1]._source : undefined,
|
|
29
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
30
|
+
next: (csidIndex < hits.length - 1) ? hits[csidIndex + 1]._source : undefined,
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const handleDetailReadStarted = (state, action) => {
|
|
35
|
+
const {
|
|
36
|
+
params: readParams,
|
|
37
|
+
} = action.meta;
|
|
38
|
+
|
|
39
|
+
const currentParams = state.get('params');
|
|
40
|
+
|
|
41
|
+
if (readParams !== currentParams) {
|
|
42
|
+
return state;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return state
|
|
46
|
+
.set('pending', true)
|
|
47
|
+
.delete('error');
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const handleDetailReadFulfilled = (state, action) => {
|
|
51
|
+
const {
|
|
52
|
+
params: readParams,
|
|
53
|
+
} = action.meta;
|
|
54
|
+
|
|
55
|
+
const currentParams = state.get('params');
|
|
56
|
+
|
|
57
|
+
if (readParams !== currentParams) {
|
|
58
|
+
return state;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const response = action.payload;
|
|
62
|
+
|
|
63
|
+
const data = get(response, ['responses', 0, 'hits', 'hits', 0, '_source']);
|
|
64
|
+
|
|
65
|
+
const adjacents = findAdjacents(
|
|
66
|
+
readParams.get('csid'),
|
|
67
|
+
get(response, ['responses', 1, 'hits', 'hits']),
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
return state
|
|
71
|
+
.set('adjacents', adjacents)
|
|
72
|
+
.delete('pending')
|
|
73
|
+
.set('data', data)
|
|
74
|
+
.delete('error');
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const handleDetailReadRejected = (state, action) => {
|
|
78
|
+
const {
|
|
79
|
+
params: readParams,
|
|
80
|
+
} = action.meta;
|
|
81
|
+
|
|
82
|
+
const currentParams = state.get('params');
|
|
83
|
+
|
|
84
|
+
if (readParams !== currentParams) {
|
|
85
|
+
return state;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return state
|
|
89
|
+
.delete('pending')
|
|
90
|
+
.set('error', action.payload);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const handleInstSearchStarted = (state, action) => {
|
|
94
|
+
const {
|
|
95
|
+
institutionId,
|
|
96
|
+
params: readParams,
|
|
97
|
+
} = action.meta;
|
|
98
|
+
|
|
99
|
+
const currentParams = state.get('params');
|
|
100
|
+
|
|
101
|
+
if (readParams !== currentParams) {
|
|
102
|
+
return state;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return state
|
|
106
|
+
.setIn(['inst', institutionId, 'pending'], true)
|
|
107
|
+
.deleteIn(['inst', institutionId, 'error']);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const handleInstSearchFulfilled = (state, action) => {
|
|
111
|
+
const {
|
|
112
|
+
institutionId,
|
|
113
|
+
params: readParams,
|
|
114
|
+
} = action.meta;
|
|
115
|
+
|
|
116
|
+
const currentParams = state.get('params');
|
|
117
|
+
|
|
118
|
+
if (readParams !== currentParams) {
|
|
119
|
+
return state;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const response = action.payload;
|
|
123
|
+
|
|
124
|
+
const hits = get(response, ['hits', 'hits']);
|
|
125
|
+
|
|
126
|
+
return state
|
|
127
|
+
.deleteIn(['inst', institutionId, 'pending'])
|
|
128
|
+
.setIn(['inst', institutionId, 'hits'], hits)
|
|
129
|
+
.deleteIn(['inst', institutionId, 'error']);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const handleInstSearchRejected = (state, action) => {
|
|
133
|
+
const {
|
|
134
|
+
institutionId,
|
|
135
|
+
params: readParams,
|
|
136
|
+
} = action.meta;
|
|
137
|
+
|
|
138
|
+
const currentParams = state.get('params');
|
|
139
|
+
|
|
140
|
+
if (readParams !== currentParams) {
|
|
141
|
+
return state;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return state
|
|
145
|
+
.deleteIn(['inst', institutionId, 'pending'])
|
|
146
|
+
.setIn(['inst', institutionId, 'error'], action.payload);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export default (state = Immutable.Map(), action) => {
|
|
150
|
+
switch (action.type) {
|
|
151
|
+
case CLEAR_DETAIL:
|
|
152
|
+
return state.clear();
|
|
153
|
+
case DETAIL_READ_STARTED:
|
|
154
|
+
return handleDetailReadStarted(state, action);
|
|
155
|
+
case DETAIL_READ_FULFILLED:
|
|
156
|
+
return handleDetailReadFulfilled(state, action);
|
|
157
|
+
case DETAIL_READ_REJECTED:
|
|
158
|
+
return handleDetailReadRejected(state, action);
|
|
159
|
+
case INST_SEARCH_STARTED:
|
|
160
|
+
return handleInstSearchStarted(state, action);
|
|
161
|
+
case INST_SEARCH_FULFILLED:
|
|
162
|
+
return handleInstSearchFulfilled(state, action);
|
|
163
|
+
case INST_SEARCH_REJECTED:
|
|
164
|
+
return handleInstSearchRejected(state, action);
|
|
165
|
+
case SET_DETAIL_PARAMS:
|
|
166
|
+
return state
|
|
167
|
+
.set('params', action.payload);
|
|
168
|
+
default:
|
|
169
|
+
return state;
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
export const getAdjacents = (state) => state.get('adjacents');
|
|
174
|
+
export const getError = (state) => state.get('error');
|
|
175
|
+
export const getParams = (state) => state.get('params');
|
|
176
|
+
export const getData = (state) => state.get('data');
|
|
177
|
+
export const isPending = (state) => !!state.get('pending');
|
|
178
|
+
|
|
179
|
+
export const getHoldingInstitutions = (state) => {
|
|
180
|
+
const inst = state.get('inst');
|
|
181
|
+
|
|
182
|
+
if (!inst) {
|
|
183
|
+
return Immutable.Set();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const institutionIds = inst.keySeq().filter((institutionId) => {
|
|
187
|
+
const hits = inst.getIn([institutionId, 'hits']);
|
|
188
|
+
|
|
189
|
+
return (hits && hits.length > 0);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
return Immutable.Set(institutionIds);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export const getInstitutionHits = (state, institutionId) => (
|
|
196
|
+
state.getIn(['inst', institutionId, 'hits'])
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
export const isInstSearchPending = (state, institutionId) => (
|
|
200
|
+
state.getIn(['inst', institutionId, 'pending'])
|
|
201
|
+
);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Immutable from 'immutable';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
SET_FILTER_SEARCH_VALUE,
|
|
5
|
+
} from '../constants/actionCodes';
|
|
6
|
+
|
|
7
|
+
export default (state = Immutable.Map(), action) => {
|
|
8
|
+
switch (action.type) {
|
|
9
|
+
case SET_FILTER_SEARCH_VALUE:
|
|
10
|
+
return state.setIn([action.meta.id, 'searchValue'], action.payload);
|
|
11
|
+
default:
|
|
12
|
+
return state;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const getSearchValue = (state, id) => state.getIn([id, 'searchValue']);
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { combineReducers } from 'redux';
|
|
2
|
+
import detail, * as fromDetail from './detailReducer';
|
|
3
|
+
import filter, * as fromFilter from './filterReducer';
|
|
4
|
+
import media, * as fromMedia from './mediaReducer';
|
|
5
|
+
import prefs, * as fromPrefs from './prefsReducer';
|
|
6
|
+
import search, * as fromSearch from './searchReducer';
|
|
7
|
+
import searchEntryForm, * as fromSearchEntryForm from './searchEntryFormReducer';
|
|
8
|
+
|
|
9
|
+
export default combineReducers({
|
|
10
|
+
detail,
|
|
11
|
+
filter,
|
|
12
|
+
media,
|
|
13
|
+
prefs,
|
|
14
|
+
search,
|
|
15
|
+
searchEntryForm,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const getDetailAdjacents = (state) => fromDetail.getAdjacents(state.detail);
|
|
19
|
+
export const getDetailError = (state) => fromDetail.getError(state.detail);
|
|
20
|
+
export const getDetailParams = (state) => fromDetail.getParams(state.detail);
|
|
21
|
+
export const getDetailData = (state) => fromDetail.getData(state.detail);
|
|
22
|
+
export const isDetailPending = (state) => fromDetail.isPending(state.detail);
|
|
23
|
+
|
|
24
|
+
export const getDetailHoldingInstitutions = (state) => (
|
|
25
|
+
fromDetail.getHoldingInstitutions(state.detail)
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export const getDetailInstitutionHits = (state, institutionId) => (
|
|
29
|
+
fromDetail.getInstitutionHits(state.detail, institutionId)
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
export const isDetailInstSearchPending = (state, institutionId) => (
|
|
33
|
+
fromDetail.isInstSearchPending(state.detail, institutionId)
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
export const getFilterSearchValue = (state, id) => fromFilter.getSearchValue(state.filter, id);
|
|
37
|
+
|
|
38
|
+
export const getMedia = (state, referenceValue, institutionId) => (
|
|
39
|
+
fromMedia.get(state.media, referenceValue, institutionId)
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
export const getPrefs = (state) => state.prefs;
|
|
43
|
+
export const isPanelExpanded = (state, id) => fromPrefs.isPanelExpanded(state.prefs, id);
|
|
44
|
+
|
|
45
|
+
export const getSearchError = (state) => fromSearch.getError(state.search);
|
|
46
|
+
export const getSearchOffset = (state) => fromSearch.getOffset(state.search);
|
|
47
|
+
export const getSearchNextOffset = (state) => fromSearch.getNextOffset(state.search);
|
|
48
|
+
export const getSearchPageSize = (state) => fromSearch.getPageSize(state.search);
|
|
49
|
+
export const getSearchParams = (state) => fromSearch.getParams(state.search);
|
|
50
|
+
export const getSearchResult = (state) => fromSearch.getResult(state.search);
|
|
51
|
+
export const isSearchPending = (state) => fromSearch.isPending(state.search);
|
|
52
|
+
export const searchHasMore = (state) => fromSearch.hasMore(state.search);
|
|
53
|
+
|
|
54
|
+
export const getSearchEntryFormParams = (state) => (
|
|
55
|
+
fromSearchEntryForm.getParams(state.searchEntryForm)
|
|
56
|
+
);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import Immutable from 'immutable';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
SET_MEDIA,
|
|
5
|
+
} from '../constants/actionCodes';
|
|
6
|
+
|
|
7
|
+
const setMedia = (state, action) => {
|
|
8
|
+
const {
|
|
9
|
+
csids,
|
|
10
|
+
altTexts,
|
|
11
|
+
title,
|
|
12
|
+
} = action.payload;
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
institutionId,
|
|
16
|
+
referenceValue,
|
|
17
|
+
} = action.meta;
|
|
18
|
+
|
|
19
|
+
return state.setIn(
|
|
20
|
+
[referenceValue, 'media', institutionId],
|
|
21
|
+
Immutable.fromJS({
|
|
22
|
+
csids,
|
|
23
|
+
altTexts,
|
|
24
|
+
title,
|
|
25
|
+
}),
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default (state = Immutable.Map(), action) => {
|
|
30
|
+
switch (action.type) {
|
|
31
|
+
case SET_MEDIA:
|
|
32
|
+
return setMedia(state, action);
|
|
33
|
+
default:
|
|
34
|
+
return state;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const get = (state, referenceValue, institutionId) => {
|
|
39
|
+
if (typeof institutionId === 'undefined') {
|
|
40
|
+
return state.getIn([referenceValue, 'media']);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return state.getIn([referenceValue, 'media', institutionId]);
|
|
44
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import Immutable from 'immutable';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
PREFS_LOADED,
|
|
5
|
+
EXPAND_PANEL,
|
|
6
|
+
TOGGLE_PANEL,
|
|
7
|
+
} from '../constants/actionCodes';
|
|
8
|
+
|
|
9
|
+
const setPanelExpanded = (state, id, expanded) => state.setIn(['panels', id, 'expand'], expanded);
|
|
10
|
+
|
|
11
|
+
export const isPanelExpanded = (state, id) => state.getIn(['panels', id, 'expand']);
|
|
12
|
+
|
|
13
|
+
export default (state = Immutable.Map(), action) => {
|
|
14
|
+
switch (action.type) {
|
|
15
|
+
case PREFS_LOADED:
|
|
16
|
+
return (action.payload ? Immutable.fromJS(action.payload) : Immutable.Map());
|
|
17
|
+
case EXPAND_PANEL:
|
|
18
|
+
return setPanelExpanded(state, action.meta.id, action.payload);
|
|
19
|
+
case TOGGLE_PANEL:
|
|
20
|
+
return setPanelExpanded(state, action.meta.id, !isPanelExpanded(state, action.meta.id));
|
|
21
|
+
default:
|
|
22
|
+
return state;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Immutable from 'immutable';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
SET_SEARCH_ENTRY_FORM_PARAM,
|
|
5
|
+
SET_SEARCH_PARAMS,
|
|
6
|
+
} from '../constants/actionCodes';
|
|
7
|
+
|
|
8
|
+
export default (state = Immutable.Map(), action) => {
|
|
9
|
+
switch (action.type) {
|
|
10
|
+
case SET_SEARCH_PARAMS:
|
|
11
|
+
return state.set('params', action.payload);
|
|
12
|
+
case SET_SEARCH_ENTRY_FORM_PARAM:
|
|
13
|
+
return state.setIn(['params', action.meta.id], action.payload);
|
|
14
|
+
default:
|
|
15
|
+
return state;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const getParams = (state) => state.get('params');
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import Immutable from 'immutable';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
SEARCH_STARTED,
|
|
5
|
+
SEARCH_FULFILLED,
|
|
6
|
+
SEARCH_REJECTED,
|
|
7
|
+
SET_SEARCH_PAGE_SIZE,
|
|
8
|
+
SET_SEARCH_PARAMS,
|
|
9
|
+
} from '../constants/actionCodes';
|
|
10
|
+
|
|
11
|
+
const handleSearchFulfilled = (state, action) => {
|
|
12
|
+
const {
|
|
13
|
+
offset,
|
|
14
|
+
pageSize,
|
|
15
|
+
params: searchParams,
|
|
16
|
+
} = action.meta;
|
|
17
|
+
|
|
18
|
+
const currentParams = state.get('params');
|
|
19
|
+
|
|
20
|
+
if (searchParams !== currentParams) {
|
|
21
|
+
return state;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const {
|
|
25
|
+
responses,
|
|
26
|
+
} = action.payload;
|
|
27
|
+
|
|
28
|
+
const [
|
|
29
|
+
resultResponse,
|
|
30
|
+
...filterResponses
|
|
31
|
+
] = responses;
|
|
32
|
+
|
|
33
|
+
const {
|
|
34
|
+
aggregations,
|
|
35
|
+
hits,
|
|
36
|
+
} = resultResponse;
|
|
37
|
+
|
|
38
|
+
const currentResult = state.get('result') || Immutable.Map();
|
|
39
|
+
const currentHits = currentResult.get('hits') || Immutable.List();
|
|
40
|
+
|
|
41
|
+
const nextHits = currentHits.setSize(offset).concat(Immutable.fromJS(hits.hits));
|
|
42
|
+
|
|
43
|
+
let nextResult = currentResult
|
|
44
|
+
.set('params', searchParams)
|
|
45
|
+
.set('total', hits.total)
|
|
46
|
+
.set('hits', nextHits);
|
|
47
|
+
|
|
48
|
+
if (offset === 0) {
|
|
49
|
+
let nextAggregations = Immutable.fromJS(aggregations);
|
|
50
|
+
|
|
51
|
+
filterResponses.forEach((filterResponse) => {
|
|
52
|
+
nextAggregations = nextAggregations.merge(Immutable.fromJS(filterResponse.aggregations));
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
nextResult = nextResult.set('aggregations', nextAggregations);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return state
|
|
59
|
+
.set('offset', offset)
|
|
60
|
+
.set('nextOffset', offset + pageSize)
|
|
61
|
+
.delete('pending')
|
|
62
|
+
.set('result', nextResult)
|
|
63
|
+
.delete('error');
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default (state = Immutable.Map(), action) => {
|
|
67
|
+
switch (action.type) {
|
|
68
|
+
case SEARCH_STARTED:
|
|
69
|
+
return state
|
|
70
|
+
.set('pending', true)
|
|
71
|
+
.delete('error');
|
|
72
|
+
case SEARCH_FULFILLED:
|
|
73
|
+
return handleSearchFulfilled(state, action);
|
|
74
|
+
case SEARCH_REJECTED:
|
|
75
|
+
return state
|
|
76
|
+
.delete('pending')
|
|
77
|
+
.set('error', action.payload);
|
|
78
|
+
case SET_SEARCH_PAGE_SIZE:
|
|
79
|
+
return state.set('pageSize', action.payload);
|
|
80
|
+
case SET_SEARCH_PARAMS:
|
|
81
|
+
return state
|
|
82
|
+
.delete('error')
|
|
83
|
+
.delete('nextOffset')
|
|
84
|
+
.set('params', action.payload)
|
|
85
|
+
.delete('pending');
|
|
86
|
+
default:
|
|
87
|
+
return state;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const getError = (state) => state.get('error');
|
|
92
|
+
export const getOffset = (state) => state.get('offset') || 0;
|
|
93
|
+
export const getNextOffset = (state) => state.get('nextOffset') || 0;
|
|
94
|
+
export const getPageSize = (state) => state.get('pageSize');
|
|
95
|
+
export const getParams = (state) => state.get('params');
|
|
96
|
+
export const getResult = (state) => state.get('result');
|
|
97
|
+
|
|
98
|
+
export const hasMore = (state) => {
|
|
99
|
+
const result = getResult(state);
|
|
100
|
+
|
|
101
|
+
if (!result) {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const currentParams = getParams(state);
|
|
106
|
+
const resultParams = result.get('params');
|
|
107
|
+
|
|
108
|
+
if (currentParams !== resultParams) {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const total = result.get('total');
|
|
113
|
+
const nextOffset = getNextOffset(state);
|
|
114
|
+
|
|
115
|
+
return (nextOffset < total);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export const isPending = (state) => !!state.get('pending');
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
@value buttonBgColor: #3D77C2;
|
|
2
|
+
@value buttonBgHoverColor: rgba(51, 122, 183, .2);
|
|
3
|
+
@value highlightColor: rgb(51, 122, 183);
|
|
4
|
+
@value inputBgColor: white;
|
|
5
|
+
@value inputBorderColor: #8C8C8C;
|
|
6
|
+
@value noteColor: inherit;
|
|
7
|
+
@value panelBorderColor: rgba(160, 160, 160, .3);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
.common {
|
|
2
|
+
display: flex;
|
|
3
|
+
margin-bottom: 10px;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.common > div:first-of-type {
|
|
7
|
+
flex: 1 1 auto;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.common > div > span + span {
|
|
11
|
+
margin-left: 8px;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.common > div > span + span::before {
|
|
15
|
+
margin-right: 8px;
|
|
16
|
+
content: '|';
|
|
17
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
@value highlightColor from '../colors.css';
|
|
2
|
+
|
|
3
|
+
.common {
|
|
4
|
+
display: grid;
|
|
5
|
+
grid-template-columns: auto 400px;
|
|
6
|
+
grid-template-rows: auto auto minmax(0, auto) minmax(0, auto) 1fr;
|
|
7
|
+
grid-column-gap: 16px;
|
|
8
|
+
grid-template-areas:
|
|
9
|
+
"header header"
|
|
10
|
+
"desc desc"
|
|
11
|
+
"fields1 gallery"
|
|
12
|
+
"fields1 fields2"
|
|
13
|
+
"inst inst";
|
|
14
|
+
margin-left: auto;
|
|
15
|
+
margin-right: auto;
|
|
16
|
+
max-width: 840px;
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
padding-bottom: 64px;
|
|
19
|
+
font-size: 1rem;
|
|
20
|
+
line-height: normal;
|
|
21
|
+
grid-auto-flow: row dense;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.common > header {
|
|
25
|
+
grid-area: header;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.common > p {
|
|
29
|
+
grid-area: desc;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.common :global(.cspace-ImageGallery--common) {
|
|
33
|
+
grid-area: gallery;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.common h1,
|
|
37
|
+
.common h2 {
|
|
38
|
+
margin: 0;
|
|
39
|
+
padding: 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.common h1 {
|
|
43
|
+
font-size: 2rem;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.common h2 {
|
|
47
|
+
font-size: 1.5rem;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.common button:hover {
|
|
51
|
+
background-color: inherit;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@media only screen
|
|
55
|
+
and (max-width: 719px) {
|
|
56
|
+
.common {
|
|
57
|
+
max-width: 100%;
|
|
58
|
+
display: block;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@media only screen
|
|
63
|
+
and (min-width: 720px)
|
|
64
|
+
and (max-width: 839px) {
|
|
65
|
+
.common {
|
|
66
|
+
max-width: 100%;
|
|
67
|
+
grid-template-columns: auto 360px;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
@value highlightColor, panelBorderColor from '../colors.css';
|
|
2
|
+
|
|
3
|
+
.common h3 {
|
|
4
|
+
margin: 0 0 6px 0;
|
|
5
|
+
font-family: inherit;
|
|
6
|
+
font-size: inherit;
|
|
7
|
+
font-weight: 600;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@media only screen
|
|
11
|
+
and (max-width: 719px) {
|
|
12
|
+
.common {
|
|
13
|
+
margin-top: 16px;
|
|
14
|
+
}
|
|
15
|
+
}
|