Verified Commit 7a06caef authored by Sandro Lutz's avatar Sandro Lutz
Browse files

Update studydocuments filter

parent ffffb48d
......@@ -5844,9 +5844,9 @@
"dev": true
},
"fsevents": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz",
"integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==",
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz",
"integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==",
"dev": true,
"optional": true,
"requires": {
......@@ -5873,7 +5873,7 @@
"optional": true
},
"are-we-there-yet": {
"version": "1.1.4",
"version": "1.1.5",
"bundled": true,
"dev": true,
"optional": true,
......@@ -5899,7 +5899,7 @@
}
},
"chownr": {
"version": "1.0.1",
"version": "1.1.1",
"bundled": true,
"dev": true,
"optional": true
......@@ -5938,7 +5938,7 @@
}
},
"deep-extend": {
"version": "0.5.1",
"version": "0.6.0",
"bundled": true,
"dev": true,
"optional": true
......@@ -5987,7 +5987,7 @@
}
},
"glob": {
"version": "7.1.2",
"version": "7.1.3",
"bundled": true,
"dev": true,
"optional": true,
......@@ -6007,12 +6007,12 @@
"optional": true
},
"iconv-lite": {
"version": "0.4.21",
"version": "0.4.24",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safer-buffer": "^2.1.0"
"safer-buffer": ">= 2.1.2 < 3"
}
},
"ignore-walk": {
......@@ -6077,17 +6077,17 @@
"optional": true
},
"minipass": {
"version": "2.2.4",
"version": "2.3.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
}
},
"minizlib": {
"version": "1.1.0",
"version": "1.2.1",
"bundled": true,
"dev": true,
"optional": true,
......@@ -6111,7 +6111,7 @@
"optional": true
},
"needle": {
"version": "2.2.0",
"version": "2.2.4",
"bundled": true,
"dev": true,
"optional": true,
......@@ -6122,18 +6122,18 @@
}
},
"node-pre-gyp": {
"version": "0.10.0",
"version": "0.10.3",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"detect-libc": "^1.0.2",
"mkdirp": "^0.5.1",
"needle": "^2.2.0",
"needle": "^2.2.1",
"nopt": "^4.0.1",
"npm-packlist": "^1.1.6",
"npmlog": "^4.0.2",
"rc": "^1.1.7",
"rc": "^1.2.7",
"rimraf": "^2.6.1",
"semver": "^5.3.0",
"tar": "^4"
......@@ -6150,13 +6150,13 @@
}
},
"npm-bundled": {
"version": "1.0.3",
"version": "1.0.5",
"bundled": true,
"dev": true,
"optional": true
},
"npm-packlist": {
"version": "1.1.10",
"version": "1.2.0",
"bundled": true,
"dev": true,
"optional": true,
......@@ -6233,12 +6233,12 @@
"optional": true
},
"rc": {
"version": "1.2.7",
"version": "1.2.8",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"deep-extend": "^0.5.1",
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
"minimist": "^1.2.0",
"strip-json-comments": "~2.0.1"
......@@ -6268,16 +6268,16 @@
}
},
"rimraf": {
"version": "2.6.2",
"version": "2.6.3",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"glob": "^7.0.5"
"glob": "^7.1.3"
}
},
"safe-buffer": {
"version": "5.1.1",
"version": "5.1.2",
"bundled": true,
"dev": true,
"optional": true
......@@ -6295,7 +6295,7 @@
"optional": true
},
"semver": {
"version": "5.5.0",
"version": "5.6.0",
"bundled": true,
"dev": true,
"optional": true
......@@ -6348,17 +6348,17 @@
"optional": true
},
"tar": {
"version": "4.4.1",
"version": "4.4.8",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"chownr": "^1.0.1",
"chownr": "^1.1.1",
"fs-minipass": "^1.2.5",
"minipass": "^2.2.4",
"minizlib": "^1.1.0",
"minipass": "^2.3.4",
"minizlib": "^1.1.1",
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.1",
"safe-buffer": "^5.1.2",
"yallist": "^3.0.2"
}
},
......@@ -6369,12 +6369,12 @@
"optional": true
},
"wide-align": {
"version": "1.1.2",
"version": "1.1.3",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"string-width": "^1.0.2"
"string-width": "^1.0.2 || 2"
}
},
"wrappy": {
......@@ -6384,7 +6384,7 @@
"optional": true
},
"yallist": {
"version": "3.0.2",
"version": "3.0.3",
"bundled": true,
"dev": true,
"optional": true
......
......@@ -7,7 +7,7 @@ import debounce from 'amiv-web-ui-components/src/debounce';
import icons from 'amiv-web-ui-components/src/icons';
import Button from './Button';
import Checkbox from './Checkbox';
import Dropdown from './Dropdown';
import Select from './Select';
import TextField from './TextField';
import './FilterView.less';
......@@ -22,7 +22,7 @@ import './FilterView.less';
*
* `fields` example:
*
* ```json
* ```javascript
* [
* {
* type: 'text',
......@@ -52,8 +52,14 @@ import './FilterView.less';
* ],
* },
* {
* type: 'dropdown',
* type: 'select',
* key: 'key3',
* multiple: true,
* hint: 'hint message',
* // Called whenever the selection has changed.
* // This allows to add some additional logic to the
* // allowed selection when multiple is set to true.
* adjustSelection: (newValue, currentValue) => newValue,
* default: 'value2',
* values: [
* { label: 'Label 1', value: 'value1' },
......@@ -238,41 +244,43 @@ export default class FilterViewComponent {
]);
}
_createDropdown(field) {
_createSelect(field) {
const options = {};
this.values[field.key] = this.values[field.key] || field.default || '';
if (!this.values[field.key]) {
this.values[field.key] = field.default || '';
}
let values;
if (typeof field.values === 'function') {
options.data = field.values(this.values);
values = field.values(this.values);
} else {
options.data = field.values;
// eslint-disable-next-line prefer-destructuring
values = field.values;
}
if (field.disabled) {
if (typeof field.disabled === 'function') {
options.disabled = field.disabled();
if (field.disabled()) {
options.disabled = true;
}
} else {
options.disabled = field.disabled;
}
}
let invalidSelection = true;
options.data.forEach(item => {
if (item.value === this.values[field.key]) {
invalidSelection = false;
}
});
if (invalidSelection) {
this.values[field.key] = field.default || '';
}
options.selected = this.values[field.key];
options.onchange = event => {
this.values[field.key] = event.target.value;
options.name = field.key;
options.label = field.label;
options.value = this.values[field.key];
options.multiple = field.multiple || false;
options.hint = field.hint;
options.adjustSelection = field.adjustSelection ? field.adjustSelection : value => value;
options.options = values;
options.onChange = ({ value }) => {
this.values[field.key] = options.adjustSelection(value, this.values[field.key]);
this.notify();
};
return m(Dropdown, options);
return m(Select, options);
}
_createButton(field) {
......@@ -316,8 +324,8 @@ export default class FilterViewComponent {
views.push(this._createCheckboxGroup(field));
} else if (field.type === 'radio') {
views.push(this._createRadioGroup(field));
} else if (field.type === 'dropdown') {
views.push(this._createDropdown(field));
} else if (field.type === 'select') {
views.push(this._createSelect(field));
} else if (field.type === 'button') {
views.push(this._createButton(field));
} else if (field.type === 'hr') {
......
......@@ -2,7 +2,3 @@
width: 100%;
border: 1px solid #eee;
}
.pe-textfield__input,.pe-textfield__label {
box-sizing: border-box;
}
import m from 'mithril';
import { Menu, List, ListTile } from 'polythene-mithril';
import { vars as theme } from 'polythene-theme';
import './Select.less';
const arrowDropdownIcon =
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M7 10l5 5 5-5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>';
export default class SelectComponent {
/**
* Generic select component
*
* @param {object} attrs unless specified below, attrs will be
* passed into the <select/> input field.
* @param {string} attrs.name name of the form field.
* @param {string} attrs.label Text which is shown above the selected value.
* @param {function} attrs.onChange function ({ value, valid }) -
* this function is called every time that the value of the select changes
* (i.e. not the focus, as would happen with polythene inputs)
* @param {array} attrs.options Array containing the selectable items
* * as a list of strings (value and label will be the same)
* Example: `['item1', 'item2']`
* * as a list of objects (set label and value independently)
* Example: `[{ label: 'label1', value: 'value1' }, { label: 'label2', value: 'value2', disabled: true }]`
* @param {string} attrs.value Selected value
* @param {boolean} attrs.multiple Specifies if multiple values can be selected (Default: false)
* @param {boolean} attrs.required Specifies if this field is mandatory (Default: false)
* @param {string} attrs.requiredIndicator Indicator that this field is required (Default: "*")
* @param {boolean} attrs.disabled Disable/enable the select field (Default: false)
* @param {string} attrs.error Error message to be shown (Default: "Error")
* @param {string} attrs.hint Hint message to be shown (Default: "")
*
* Example:
* ```javascript
* m(SelectComponent, {
* options: [
* { label: 'Label 1', value: 'value1' },
* { label: 'Label 2', value: 'value2', disabled: true },
* ],
* required: true,
* value: 'value1',
* onChange: ({ value }) => {
* // some event handling
* },
* })
* ```
*/
constructor({
attrs: {
name,
multiple = false,
onChange = () => {},
value = multiple ? [] : null,
requiredIndicator = '*',
},
}) {
this.name = name;
this.value = value;
this.multiple = multiple;
this.requiredIndicator = requiredIndicator;
this.onChange = onChange;
this.focused = false;
this.isOpen = false;
this.valid = true;
}
validate() {
this.valid =
!this.required || (this.value !== null && (!this.multiple || this.value.length > 0));
}
view({
attrs: {
label = this.name,
options,
value,
hint,
error = 'Error',
required = false,
disabled = false,
},
}) {
this.required = required;
// update the selected value if set.
if (value !== undefined) {
this.value = value;
}
const focusedColorStyle = { color: `rgb(${theme.color_primary})` };
const focusedBorderColorStyle = { borderColor: `rgb(${theme.color_primary})` };
let textView = null;
if (!this.valid) {
textView = m('p.pe-select--error', error);
} else if (hint) {
textView = m('p', hint);
}
return m(
'div',
{
id: `${this.name}-select`,
className: [
'pe-select',
disabled ? 'pe-select--disabled' : null,
!this.valid ? 'pe-select--invalid' : null,
].join(' '),
},
[
m(
'label',
{
for: `${this.name}-input`,
className:
this.focused || (this.value !== null && this.value.length > 0) ? 'transformed' : null,
style: this.focused ? focusedColorStyle : null,
},
[label, required ? m('span', this.requiredIndicator) : undefined]
),
m(
'.pe-select--field',
{
id: `${this.name}-field`,
role: 'button',
tabIndex: disabled ? undefined : 0,
style: this.focused ? focusedBorderColorStyle : null,
onfocus: () => {
this.focused = !disabled;
},
onblur: () => {
this.focused = false;
},
onclick: () => {
if (!disabled) {
this.focused = true;
this.isOpen = true;
}
},
},
m('div', [
m('.pe-select--value', this._renderValue(options)),
m('input', {
type: 'hidden',
name: this.name,
id: `${this.name}-input`,
value: this.value,
}),
m.trust(arrowDropdownIcon),
])
),
textView,
this._renderMenu(options),
]
);
}
_renderValue(options) {
if (this.value === null || this.value.length === 0) return '';
if (this.multiple) {
const labels = [];
this.value.forEach(value => {
const label = this.constructor._resolveLabel(value, options);
labels.push(label);
});
return labels.join(', ');
}
return this.constructor._resolveLabel(this.value, options);
}
static _resolveLabel(value, options) {
let label;
options.some(option => {
// Get label for the given value (if labels are provided)
if (typeof option === 'object' && option !== null && value === option.value) {
// eslint-disable-next-line prefer-destructuring
label = option.label;
return true;
}
if (value === option) {
label = option;
return true;
}
return false;
});
return label;
}
_renderMenu(options) {
return m(Menu, {
className: 'pe-select--menu',
target: `#${this.name}-select`,
show: this.isOpen,
offsetV: 0,
didHide: () => {
this.isOpen = false;
},
content: m(
List,
options.map(option => {
const isObject = typeof option === 'object' && option !== null;
const label = isObject ? option.label : option;
let selected;
if (this.multiple) {
selected = this.value && this.value.indexOf(isObject ? option.value : option) !== -1;
} else {
selected = this.value === (isObject ? option.value : option);
}
return m(ListTile, {
title: label,
hoverable: true,
ink: true,
highlight: selected,
selected: !this.multiple ? selected : null,
events: {
onclick: () => {
const value = isObject ? option.value : option;
if (this.multiple) {
const i = this.value.indexOf(value);
if (i !== -1) {
this.value.splice(i, 1);
} else {
const newValue = [];
options.forEach(item => {
const isItemObject = typeof item === 'object' && item !== null;
const itemValue = isItemObject ? item.value : item;
if (this.value.indexOf(itemValue) !== -1 || value === itemValue) {
newValue.push(itemValue);
}
});
this.value = newValue;
}
} else {
this.value = value;
}
this.validate();
this.onChange({ value: this.value });
},
},
});
})
),
});
}
}
.pe-select {
min-width: 120px;
border: 0;
display: inline-flex;
padding: 0;
position: relative;
flex-direction: column;
vertical-align: top;
font-size: 1rem;
}
.pe-select label {
top: 0;
left: 0;
position: absolute;
transition: color 200ms cubic-bezier(0, 0, .2, 1) 0ms, transform 200ms cubic-bezier(0, 0, .2, 1) 0ms;
transform: translate(0, 24px) scale(1);
transform-origin: top left;
color: rgba(0, 0, 0, .54);
padding: 0;
line-height: 1;
&.transformed {
transform: translate(0, 1.5px) scale(.75);
}
span {
margin-left: 4px;
}
}
.pe-select p {
color: rgba(0, 0, 0, .54);
margin: 0;
font-size: .75rem;
text-align: left;
margin-top: 8px;
min-height: 1em;
line-height: 1em;