Something went wrong on our end
-
Hermann authored
problem: When searching, the result list was not updated properly and clicking on a result was not registered if the user did not scroll through the list before (and therefore update) this fix now makes debouncing searchupdates cleaner also fixes a problem with the cancel button in the searchfield, which can apparently only handle iconbuttons
Hermann authoredproblem: When searching, the result list was not updated properly and clicking on a result was not registered if the user did not scroll through the list before (and therefore update) this fix now makes debouncing searchupdates cleaner also fixes a problem with the cancel button in the searchfield, which can apparently only handle iconbuttons
selectList.js 5.33 KiB
import m from 'mithril';
import Stream from 'mithril/stream';
import {
List, ListTile, Search, IconButton, Button, Toolbar,
ToolbarTitle,
} from 'polythene-mithril';
import infinite from 'mithril-infinite';
import { icons, BackButton, ClearButton, SearchIcon } from './elements';
class SearchField {
oninit() {
this.value = Stream('');
this.setInputState = Stream();
// const clear = () => setInputState()({ value: '', focus: false});
this.clear = () => this.value('');
this.leave = () => this.value('');
}
view({ state, attrs }) {
// incoming value and focus added for result list example:
const value = attrs.value !== undefined ? attrs.value : state.value();
return m(Search, Object.assign(
{},
{
textfield: {
label: 'type here',
onChange: (newState) => {
state.value(newState.value);
state.setInputState(newState.setInputState);
// onChange callback added for result list example:
if (attrs.onChange) attrs.onChange(newState, state.setInputState);
},
value,
defaultValue: attrs.defaultValue,
},
buttons: {
focus: {
before: m(BackButton, { leave: state.leave }),
},
focus_dirty: {
before: m(BackButton, { leave: state.leave }),
after: m(ClearButton, { clear: state.clear }),
},
dirty: {
before: m(BackButton, { leave: state.leave }),
after: m(ClearButton, { clear: state.clear }),
},
},
},
attrs,
));
}
}
export default class SelectList {
constructor({ attrs: { listTileAttrs, onSelect = false } }) {
this.showList = false;
this.searchValue = '';
this.listTileAttrs = listTileAttrs;
this.onSelect = onSelect;
// initialize the Selection
this.selected = null;
}
onupdate({ attrs: { selection = null } }) {
// make it possible to change the selection from outside, e.g. to set the field to an
// existing group moderator
if (selection) this.selected = selection;
}
item() {
return (data) => {
const attrs = {
compactFront: true,
hoverable: true,
className: 'themed-list-tile',
events: {
onclick: () => {
if (this.onSelect) { this.onSelect(data); }
this.selected = data;
this.showList = false;
},
},
};
// Overwrite default attrs
Object.assign(attrs, this.listTileAttrs(data));
return m(ListTile, attrs);
};
}
view({
attrs: {
controller,
onSubmit = false,
onCancel = false,
selectedText,
},
}) {
return m('div', [
m(Toolbar, { compact: true, style: { background: 'rgb(78, 242, 167)' } }, this.selected ? [
m(IconButton, {
icon: { svg: m.trust(icons.clear) },
ink: false,
events: {
onclick: () => {
if (this.onSelect) { this.onSelect(null); }
this.selected = null;
},
},
}),
m(ToolbarTitle, { text: selectedText(this.selected) }),
onSubmit ? m(Button, {
label: 'Submit',
className: 'blue-button',
events: {
onclick: () => {
onSubmit(this.selected);
this.selected = null;
controller.setSearch('');
controller.refresh();
},
},
}) : '',
] : [
m(SearchField, Object.assign({}, {
style: { background: 'rgb(78, 242, 167)' },
onChange: ({ value, focus }) => {
// onChange is called either if the value or focus fo the SearchField
// changes.
// At value change we want to update the search
// at focus changt we hie the list of results. As focus change also
// happens while clicking on an item in the list of results, the list
// is hidden after a short Timeout that has to be sufficiently long
// to register the onclick of the listitem. Can be a problem for different
// OS and browsers.
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.searchValue) {
// 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.searchValue = value;
controller.debouncedSearch(value);
}
},
})),
onCancel ? m(Button, {
label: 'cancel',
className: 'blue-button',
events: { onclick: onCancel },
}) : '',
]),
(this.showList && !this.selected) ? m(List, {
style: { height: '400px', 'background-color': 'white' },
tiles: m(infinite, controller.infiniteScrollParams(this.item())),
}) : '',
]);
}
}