To receive notifications about scheduled maintenance, please subscribe to the mailing-list gitlab-operations@sympa.ethz.ch. You can subscribe to the mailing-list at https://sympa.ethz.ch

Verified Commit 284d6f35 authored by Sandro Lutz's avatar Sandro Lutz
Browse files

Move SelectTextField to components

parent baad51b4
import m from 'mithril';
import { List } from 'polythene-mithril-list';
import { ListTile } from 'polythene-mithril-list-tile';
import { Card } from 'polythene-mithril-card';
import debounce from 'amiv-web-ui-components/src/debounce';
import Button from './Button';
import TextField from './TextField';
import { i18n } from '../models/language';
import './SelectTextField.less';
export default class SelectTextField {
constructor({ attrs: { options, onChange = () => {} } }) {
this.addNew = false;
this.value = '';
this.selected = null;
this.options = options;
this.filteredOptions = options;
this.onChange = onChange;
this.valid = true;
this.showList = false;
this.debouncedSearch = debounce(search => {
this.value = search;
if (search) {
const regex = RegExp(`.*(${search}).*`, 'gi');
this.filteredOptions = this.options.filter(item => regex.test(item));
} else {
this.filteredOptions = this.options;
}
this.notify();
}, 100);
}
validate() {
this.valid = this.value === '' || this.addNew || this.selected;
}
notify() {
this.validate();
let value = '';
if (this.selected) {
value = this.selected;
} else if (this.addNew) {
// eslint-disable-next-line prefer-destructuring
value = this.value;
}
this.onChange({ value, isValid: this.valid });
m.redraw();
}
onupdate({ dom, attrs: { options } }) {
if (this.options.length !== options.length) {
this.options = options;
this.debouncedSearch(this.value);
}
// Turn off browser's autofill functionality
dom.querySelector('input').setAttribute('autocomplete', 'off');
}
view({ attrs: { name, label, help, ...attrs } }) {
return m('div.pe-select-textfield', [
m('div.textfield', [
m(TextField, {
...attrs,
name,
label,
help,
error: help,
floatingLabel: true,
value: this.selected || this.value,
valid: this.valid,
readonly: this.selected !== null,
onChange: ({ focus, value }) => {
if (focus) {
this.showList = true;
} else if (!focus) {
// don't close the list immidiately, as 'out of focus' could
// also mean that the user is clicking on a list item
setTimeout(() => {
this.showList = false;
m.redraw();
}, 500);
}
if (value !== this.value) {
// if we always update the search value, this would also happen
// immidiately in the moment where we click on the listitem.
// Then, the list get's updated before the click is registered.
// So, we make sure this state change is due to value change and
// not due to focus change.
this.value = value;
if (this.addNew) {
this.notify();
} else {
this.debouncedSearch(value);
}
}
},
}),
this.selected
? m(Button, {
className: 'flat-button',
label: i18n('button.clear'),
events: {
onclick: () => {
this.value = '';
this.selected = null;
this.debouncedSearch('');
},
},
})
: this.addNew &&
m(Button, {
className: 'flat-button',
label: i18n('studydocs.createNewEntryLabel'),
disabled: true,
}),
]),
this.showList && !this.addNew && !this.selected
? m(Card, {
className: 'suggestions',
content: m(
'div',
m(List, {
style: { maxHeight: '400px', 'background-color': 'white' },
tiles: [
...this.filteredOptions.map(option =>
m(ListTile, {
title: option,
hoverable: true,
compactFront: true,
events: {
onclick: () => {
this.selected = option;
this.showList = false;
this.notify();
},
},
})
),
m(ListTile, {
title: i18n('studydocs.createNewEntry'),
hoverable: true,
compactFront: true,
events: {
onclick: () => {
this.addNew = true;
this.showList = false;
this.notify();
},
},
}),
],
})
),
})
: '',
]);
}
}
.pe-select-textfield {
height: 96px;
overflow-y: visible;
.textfield {
display: flex;
align-content: space-between;
align-items: flex-start;
.pe-button {
position: relative;
top: 2em;
margin-left: .5em;
}
}
.suggestions {
position: relative;
top: -24px;
z-index: 10000;
.pe-list {
overflow-y: auto;
}
}
}
\ No newline at end of file
......@@ -72,30 +72,3 @@
}
}
}
.studydocs-upload-textfield {
height: 96px;
overflow-y: visible;
.textfield {
display: grid;
grid-template-columns: 1fr auto;
grid-gap: 1em;
align-items: end;
.pe-checkbox-control,.pe-button {
position: relative;
bottom: 26px;
}
}
.suggestions {
position: relative;
top: -24px;
z-index: 10000;
.pe-list {
overflow-y: auto;
}
}
}
import m from 'mithril';
import marked from 'marked';
import animateScrollTo from 'animated-scroll-to';
import { List } from 'polythene-mithril-list';
import { ListTile } from 'polythene-mithril-list-tile';
import { Card } from 'polythene-mithril-card';
import { Icon } from 'polythene-mithril-icon';
import debounce from 'amiv-web-ui-components/src/debounce';
import Spinner from 'amiv-web-ui-components/src/spinner';
import StudydocsController from '../../models/studydocs';
import Select from '../../components/Select';
import Button from '../../components/Button';
import TextField from '../../components/TextField';
import SelectTextField from '../../components/SelectTextField';
import FileInput from '../../components/FileInput';
import { i18n, currentLanguage } from '../../models/language';
import { Infobox } from '../errors';
......@@ -41,158 +38,6 @@ const departments = [
'gess',
];
class SelectTextField {
constructor({ attrs: { options, onChange = () => {} } }) {
this.addNew = false;
this.value = '';
this.selected = null;
this.options = options;
this.filteredOptions = options;
this.onChange = onChange;
this.valid = true;
this.showList = false;
this.debouncedSearch = debounce(search => {
this.value = search;
if (search) {
const regex = RegExp(`.*(${search}).*`, 'gi');
this.filteredOptions = this.options.filter(item => regex.test(item));
} else {
this.filteredOptions = this.options;
}
this.notify();
}, 100);
}
validate() {
this.valid = this.value === '' || this.addNew || this.selected;
}
notify() {
this.validate();
let value = '';
if (this.selected) {
value = this.selected;
} else if (this.addNew) {
// eslint-disable-next-line prefer-destructuring
value = this.value;
}
this.onChange({ value, isValid: this.valid });
m.redraw();
}
onupdate({ dom, attrs: { options } }) {
if (this.options.length !== options.length) {
this.options = options;
this.debouncedSearch(this.value);
}
// Turn of browser's autofill functionality
dom.querySelector('input').setAttribute('autocomplete', 'off');
}
// view({ attrs: { name, label, help = i18n('studydocs.selectTextHelp'), ...attrs } }) {
view({ attrs: { name, label, help, ...attrs } }) {
return m('div.studydocs-upload-textfield', [
m('div.textfield', [
m(TextField, {
...attrs,
name,
label,
help,
error: help,
floatingLabel: true,
value: this.selected || this.value,
valid: this.valid,
readonly: this.selected !== null,
onChange: ({ focus, value }) => {
if (focus) {
this.showList = true;
} else if (!focus) {
// don't close the list immidiately, as 'out of focus' could
// also mean that the user is clicking on a list item
setTimeout(() => {
this.showList = false;
m.redraw();
}, 500);
}
if (value !== this.value) {
// if we always update the search value, this would also happen
// immidiately in the moment where we click on the listitem.
// Then, the list get's updated before the click is registered.
// So, we make sure this state change is due to value change and
// not due to focus change.
this.value = value;
if (this.addNew) {
this.notify();
} else {
this.debouncedSearch(value);
}
}
},
}),
this.selected
? m(Button, {
className: 'flat-button',
label: i18n('button.clear'),
events: {
onclick: () => {
this.value = '';
this.selected = null;
this.debouncedSearch('');
},
},
})
: this.addNew &&
m(Button, {
className: 'flat-button',
label: i18n('studydocs.createNewEntryLabel'),
disabled: true,
}),
]),
this.showList && !this.addNew && !this.selected
? m(Card, {
className: 'suggestions',
content: m(
'div',
m(List, {
style: { maxHeight: '400px', 'background-color': 'white' },
tiles: [
...this.filteredOptions.map(option =>
m(ListTile, {
title: option,
hoverable: true,
compactFront: true,
events: {
onclick: () => {
this.selected = option;
this.showList = false;
this.notify();
},
},
})
),
m(ListTile, {
title: i18n('studydocs.createNewEntry'),
hoverable: true,
compactFront: true,
events: {
onclick: () => {
this.addNew = true;
this.showList = false;
this.notify();
},
},
}),
],
})
),
})
: '',
]);
}
}
export default class StudydocNew {
oninit() {
this.invalid = new Set([]);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment