UNPKG

core-resource-app-test

Version:

App that contains assets and scripts for the core apps

496 lines (453 loc) 19.4 kB
import React from 'react'; import { findDOMNode } from 'react-dom'; // Material UI import Paper from 'material-ui/Paper/Paper'; import RaisedButton from 'material-ui/RaisedButton/RaisedButton'; // D2 import { config } from 'd2/lib/d2'; // D2-UI import TranslateMixin from '../i18n/Translate.mixin.js'; import CircularProgress from '../circular-progress/CircularProgress'; // TODO: TOAST! // TODO: Undo support (in TOAST?) config.i18n.strings.add('selected'); config.i18n.strings.add('assign_all'); config.i18n.strings.add('remove_all'); config.i18n.strings.add('hidden_by_filters'); export default React.createClass({ displayName: 'GroupEditor.component', propTypes: { // itemStore: d2-ui store containing all available items, either as a D2 ModelCollection, // or an array on the following format: [{value: 1, text: '1'}, {value: 2, text: '2'}, ...] itemStore: React.PropTypes.object.isRequired, // assignedItemStore: d2-ui store containing all items assigned to the current group, either // as a D2 ModelCollectionProperty or an array of ID's that match values in the itemStore assignedItemStore: React.PropTypes.object.isRequired, // filterText: A string that will be used to filter items in both columns filterText: React.PropTypes.string, // Note: Callbacks should return a promise that will resolve when the operation succeeds // and is rejected when it fails. The component will be in a loading state until the promise // resolves or is rejected. // assign items callback, called with an array of values to be assigned to the group onAssignItems: React.PropTypes.func.isRequired, // remove items callback, called with an array of values to be removed from the group onRemoveItems: React.PropTypes.func.isRequired, // The height of the component, defaults to 500px height: React.PropTypes.number }, contextTypes: { d2: React.PropTypes.object }, mixins: [TranslateMixin], componentDidMount: function componentDidMount() { var _this = this; this.disposables = []; this.disposables.push(this.props.itemStore.subscribe(function (state) { return _this.setState({ loading: !state }); })); this.disposables.push(this.props.assignedItemStore.subscribe(function () { return _this.forceUpdate(); })); }, componentWillReceiveProps: function componentWillReceiveProps(props) { if (props.hasOwnProperty('filterText') && this.leftSelect && this.rightSelect) { this.setState({ selectedLeft: [].filter.call(this.leftSelect.selectedOptions, function (item) { return item.text.toLowerCase().indexOf(('' + props.filterText).trim().toLowerCase()) !== -1; }).length, selectedRight: [].filter.call(this.rightSelect.selectedOptions, function (item) { return item.text.toLowerCase().indexOf(('' + props.filterText).trim().toLowerCase()) !== -1; }).length }); } }, componentWillUnmount: function componentWillUnmount() { this.disposables.forEach(function (disposable) { disposable.unsubscribe(); }); }, getDefaultProps: function getDefaultProps() { return { height: 500, filterText: '' }; }, getInitialState: function getInitialState() { return { // Number of items selected in the left/right columns selectedLeft: 0, selectedRight: 0, // Loading loading: true }; }, // // Data handling utility functions // getItemStoreIsCollection: function getItemStoreIsCollection() { return this.props.itemStore.state !== undefined && typeof this.props.itemStore.state.values === 'function' && typeof this.props.itemStore.state.has === 'function'; }, getItemStoreIsArray: function getItemStoreIsArray() { return this.props.itemStore.state !== undefined && this.props.itemStore.state.constructor.name === 'Array'; }, getAssignedItemStoreIsCollection: function getAssignedItemStoreIsCollection() { return this.props.assignedItemStore.state !== undefined && typeof this.props.assignedItemStore.state.values === 'function' && typeof this.props.assignedItemStore.state.has === 'function'; }, getAssignedItemStoreIsArray: function getAssignedItemStoreIsArray() { return this.props.assignedItemStore.state !== undefined && this.props.assignedItemStore.state.constructor.name === 'Array'; }, getAllItems: function getAllItems() { return this.getItemStoreIsCollection() ? Array.from(this.props.itemStore.state.values()).map(function (item) { return { value: item.id, text: item.name }; }) : this.props.itemStore.state || []; }, getItemCount: function getItemCount() { return this.getItemStoreIsCollection() && this.props.itemStore.state.size || this.getItemStoreIsArray() && this.props.itemStore.state.length || 0; }, getIsValueAssigned: function getIsValueAssigned(value) { return this.getAssignedItemStoreIsCollection() ? this.props.assignedItemStore.state.has(value) : this.props.assignedItemStore.state && this.props.assignedItemStore.state.indexOf(value) !== -1; }, getAssignedItems: function getAssignedItems() { var _this2 = this; return this.getAllItems().filter(function (item) { return _this2.getIsValueAssigned(item.value); }); }, getAvailableItems: function getAvailableItems() { var _this3 = this; return this.getAllItems().filter(function (item) { return !_this3.getIsValueAssigned(item.value); }); }, getAllItemsFiltered: function getAllItemsFiltered() { return this.filterItems(this.getAllItems()); }, getAssignedItemsFiltered: function getAssignedItemsFiltered() { return this.filterItems(this.getAssignedItems()); }, getAvailableItemsFiltered: function getAvailableItemsFiltered() { return this.filterItems(this.getAvailableItems()); }, getAssignedItemsCount: function getAssignedItemsCount() { return this.getAssignedItems().length; }, getAvailableItemsCount: function getAvailableItemsCount() { return this.getAvailableItems().length; }, getAssignedItemsFilterCount: function getAssignedItemsFilterCount() { return this.getFilterText().length === 0 ? 0 : this.getAssignedItems().length - this.getAssignedItemsFiltered().length; }, getAvailableItemsFilterCount: function getAvailableItemsFilterCount() { return this.getFilterText().length === 0 ? 0 : this.getAvailableItems().length - this.getAvailableItemsFiltered().length; }, getAssignedItemsUnfilteredCount: function getAssignedItemsUnfilteredCount() { return this.getFilterText().length === 0 ? this.getAssignedItemsCount() : this.getAssignedItemsCount() - this.getAssignedItemsFilterCount(); }, getAvailableItemsUnfilteredCount: function getAvailableItemsUnfilteredCount() { return this.getFilterText().length === 0 ? this.getAvailableItemsCount() : this.getAvailableItemsCount() - this.getAvailableItemsFilterCount(); }, getFilterText: function getFilterText() { return this.props.filterText ? this.props.filterText.trim().toLowerCase() : ''; }, getAvailableSelectedCount: function getAvailableSelectedCount() { return Math.max(this.state.selectedLeft, 0); }, getAssignedSelectedCount: function getAssignedSelectedCount() { return Math.max(this.state.selectedRight, 0); }, getSelectedCount: function getSelectedCount() { return Math.max(this.getAvailableSelectedCount(), this.getAssignedSelectedCount()); }, byAssignedItemsOrder: function byAssignedItemsOrder(left, right) { var assignedItemStore = this.props.assignedItemStore.state; // Don't order anything if the assignedItemStore is not an array // TODO: Support sorting for a ModelCollectionProperty if (!Array.isArray(assignedItemStore)) { return 0; } return assignedItemStore.indexOf(left.value) > assignedItemStore.indexOf(right.value) ? 1 : -1; }, // // Rendering // render: function render() { var _this4 = this; var filterHeight = this.getFilterText().length > 0 ? 15 : 0; var styles = { container: { display: 'flex', marginTop: 16, marginBottom: 32, height: this.props.height + 'px' }, left: { flex: '1 0 120px' }, middle: { flex: '0 0 120px', alignSelf: 'center', textAlign: 'center' }, right: { flex: '1 0 120px' }, paper: { width: '100%', height: '100%' }, select: { width: '100%', minHeight: '50px', height: this.props.height - filterHeight + 'px', border: 'none', fontFamily: 'Roboto', fontSize: 13, outline: 'none' }, options: { padding: '.25rem .5rem' }, buttons: { minWidth: '100px', maxWidth: '100px', marginTop: '8px' }, selected: { fontSize: 13, minHeight: '15px', marginTop: '45px', padding: '0 8px' }, status: { marginTop: '8px', minHeight: '60px' }, hidden: { fontSize: 13, color: '#404040', fontStyle: 'italic', textAlign: 'center', width: '100%', background: '#d0d0d0', maxHeight: '15px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }; var onChangeLeft = function onChangeLeft(e) { _this4.clearSelection(false, true); _this4.setState({ selectedLeft: e.target.selectedOptions.length }); }; var onChangeRight = function onChangeRight(e) { _this4.clearSelection(true, false); _this4.setState({ selectedRight: e.target.selectedOptions.length }); }; var hiddenLabel = function hiddenLabel(itemCount) { return _this4.getItemCount() > 0 && _this4.getFilterText().length > 0 ? itemCount + ' ' + _this4.getTranslation('hidden_by_filters') : ''; }; var selectedLabel = function selectedLabel() { return _this4.getSelectedCount() > 0 ? _this4.getSelectedCount() + ' ' + _this4.getTranslation('selected') : ''; }; return React.createElement( 'div', { style: styles.container }, React.createElement( 'div', { style: styles.left }, React.createElement( Paper, { style: styles.paper }, React.createElement( 'div', { style: styles.hidden }, hiddenLabel(this.getAvailableItemsFilterCount()) ), React.createElement( 'select', { multiple: true, style: styles.select, onChange: onChangeLeft, ref: function ref(r) { _this4.leftSelect = findDOMNode(r); } }, this.getAvailableItemsFiltered().map(function (item) { return React.createElement( 'option', { key: item.value, value: item.value, onDoubleClick: _this4._assignItems, style: styles.options }, item.text ); }) ) ), React.createElement(RaisedButton, { label: this.getTranslation('assign_all') + ' ' + (this.getAvailableItemsUnfilteredCount() === 0 ? '' : this.getAvailableItemsUnfilteredCount()) + ' \u2192', disabled: this.state.loading || this.getAvailableItemsUnfilteredCount() === 0, onClick: this._assignAll, style: { marginTop: '1rem' }, secondary: true }) ), React.createElement( 'div', { style: styles.middle }, React.createElement( 'div', { style: styles.selected }, selectedLabel() ), React.createElement(RaisedButton, { label: '\u2192', secondary: true, onClick: this._assignItems, style: styles.buttons, disabled: this.state.loading || this.state.selectedLeft === 0 }), React.createElement(RaisedButton, { label: '\u2190', secondary: true, onClick: this._removeItems, style: styles.buttons, disabled: this.state.loading || this.state.selectedRight === 0 }), React.createElement( 'div', { style: styles.status }, this.state.loading ? React.createElement(CircularProgress, { small: true, style: { width: 60, height: 60 } }) : undefined ) ), React.createElement( 'div', { style: styles.right }, React.createElement( Paper, { style: styles.paper }, React.createElement( 'div', { style: styles.hidden }, hiddenLabel(this.getAssignedItemsFilterCount()) ), React.createElement( 'select', { multiple: true, style: styles.select, onChange: onChangeRight, ref: function ref(r) { _this4.rightSelect = findDOMNode(r); } }, this.getAssignedItemsFiltered().sort(this.byAssignedItemsOrder).map(function (item) { return React.createElement( 'option', { key: item.value, value: item.value, onDoubleClick: _this4._removeItems, style: styles.options }, item.text ); }) ) ), React.createElement(RaisedButton, { label: '\u2190 ' + this.getTranslation('remove_all') + ' ' + (this.getAssignedItemsUnfilteredCount() > 0 ? this.getAssignedItemsUnfilteredCount() : ''), style: { float: 'right', marginTop: '1rem' }, disabled: this.state.loading || this.getAssignedItemsUnfilteredCount() === 0, onClick: this._removeAll, secondary: true }) ) ); }, clearSelection: function clearSelection() { var left = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; var right = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; if (left) { this.leftSelect.selectedIndex = -1; } if (right) { this.rightSelect.selectedIndex = -1; } this.setState(function (state) { return { selectedLeft: left ? 0 : state.selectedLeft, selectedRight: right ? 0 : state.selectedRight }; }); }, filterItems: function filterItems(items) { var _this5 = this; return items.filter(function (item) { return _this5.getFilterText().length === 0 || item.text.trim().toLowerCase().indexOf(_this5.getFilterText()) !== -1; }); }, getSelectedItems: function getSelectedItems() { return [].map.call(this.rightSelect.selectedOptions, function (item) { return item.value; }); }, // // Event handlers // _assignItems: function _assignItems() { var _this6 = this; this.setState({ loading: true }); this.props.onAssignItems([].map.call(this.leftSelect.selectedOptions, function (item) { return item.value; })).then(function () { _this6.clearSelection(); _this6.setState({ loading: false }); }).catch(function () { _this6.setState({ loading: false }); }); }, _removeItems: function _removeItems() { var _this7 = this; this.setState({ loading: true }); this.props.onRemoveItems([].map.call(this.rightSelect.selectedOptions, function (item) { return item.value; })).then(function () { _this7.clearSelection(); _this7.setState({ loading: false }); }).catch(function () { _this7.setState({ loading: false }); }); }, _assignAll: function _assignAll() { var _this8 = this; this.setState({ loading: true }); this.props.onAssignItems([].map.call(this.leftSelect.options, function (item) { return item.value; })).then(function () { _this8.clearSelection(); _this8.setState({ loading: false }); }).catch(function () { _this8.setState({ loading: false }); }); }, _removeAll: function _removeAll() { var _this9 = this; this.setState({ loading: true }); this.props.onRemoveItems([].map.call(this.rightSelect.options, function (item) { return item.value; })).then(function () { _this9.clearSelection(); _this9.setState({ loading: false }); }).catch(function () { _this9.setState({ loading: false }); }); } });