Skip to content
Snippets Groups Projects
Commit 1454ec67 authored by Sandro Lutz's avatar Sandro Lutz Committed by Sandro Lutz
Browse files

Add autocomplete field

parent 7d223c4f
No related branches found
No related tags found
1 merge request!30Studydocs autocomplete
......@@ -27,6 +27,25 @@ export function load(query = {}) {
});
}
export function getInputSuggestions(field, input) {
const query = {};
query[field] = { $regex: `^(?i).*${input}.*` };
// TODO: debug Error 502 Bad Gateway returned by API
// const projection = {};
// projection[field] = 1;
const queryEncoded = m.buildQueryString({
where: JSON.stringify(query),
// projection: JSON.stringify(projection),
});
return m.request({
method: 'GET',
url: `${apiUrl}/studydocuments?${queryEncoded}`,
headers: {
Authorization: `Token ${getToken()}`,
},
});
}
export function reload() {
return load(querySaved);
}
......
......@@ -4,7 +4,7 @@ import * as events from '../models/events';
import { log } from '../models/log';
import { isLoggedIn } from '../models/auth';
import inputGroup from './form/inputGroup';
import submitButton from './form/submitButton';
import button from './form/button';
import JSONSchemaForm from './form/jsonSchemaForm';
class EventSignupForm extends JSONSchemaForm {
......@@ -34,7 +34,7 @@ class EventSignupForm extends JSONSchemaForm {
if (!events.currentSignupHasLoaded()) return m('span', 'Loading...');
if (typeof events.getCurrentSignup() === 'undefined') {
const elements = this.renderFormElements();
elements.push(m(submitButton, {
elements.push(m(button, {
active: super.isValid(),
args: {
onclick: () => this.submit(),
......@@ -68,7 +68,7 @@ class EventSignupForm extends JSONSchemaForm {
getErrors: () => this.emailErrors,
value: this.email,
}));
elements.push(m(submitButton, {
elements.push(m(button, {
active: this.emailValid && super.isValid(),
args: {
onclick: () => this.submit(),
......
import m from 'mithril';
export default class SubmitButton {
export default class Button {
static view(vnode) {
const { args } = vnode.attrs;
let { args } = vnode.attrs;
if (args === undefined) {
args = {};
}
if (args.type === undefined) {
args.type = 'button';
}
if (!vnode.attrs.active) {
args.disabled = 'disabled';
}
return m('button[type=button]', args, vnode.attrs.text);
return m('button', args, vnode.attrs.title);
}
}
import m from 'mithril';
import { log } from '../../models/log';
export default class InputGroup {
constructor(vnode) {
......@@ -37,18 +36,16 @@ export default class InputGroup {
errorField,
]);
}
args.list = `${args.id}-datalist`;
log(args);
if (args.getSuggestions) {
log('test');
args.list = `${vnode.attrs.name}-datalist`;
if (typeof args.getSuggestions === 'function') {
args.oninput_original = args.oninput;
args.oninput = (e) => {
log(`get suggestions for '${e.target.value}'`);
args.getSuggestions(e.target.value, (result) => {
log('callback called!');
this.suggestions = result;
});
if (args.oninput_original) {
if (typeof args.getSuggestions === 'function') {
args.getSuggestions(e.target.value, (result) => {
this.suggestions = result;
});
}
if (typeof args.oninput_original === 'function') {
args.oninput_original(e);
}
};
......
......@@ -5,7 +5,6 @@ import { isNullOrUndefined } from 'util';
import { log } from '../../models/log';
import inputGroup from './inputGroup';
import selectGroup from './selectGroup';
import mediaGroup from './mediaGroup';
export default class JSONSchemaForm {
constructor() {
......@@ -111,14 +110,6 @@ export default class JSONSchemaForm {
multipleSelect: true,
},
}));
} else if (item.type === 'media') {
return m(mediaGroup, this.bind({
name: key,
title: item.description,
args: {
multiple: 'multiple',
},
}));
}
log('Unknown array property type');
return m('');
......
import m from 'mithril';
export default class MediaGroup {
constructor(vnode) {
this.suggestions = [];
// Link the error-getting function from the binding
this.getErrors = () => [];
if (vnode.attrs.getErrors) {
this.getErrors = vnode.attrs.getErrors;
}
}
view(vnode) {
// set display-settings accoridng to error-state
let errorField = null;
let groupClasses = vnode.attrs.classes ? vnode.attrs.classes : '';
const errors = this.getErrors();
if (errors.length > 0) {
errorField = m('span', `Error: ${errors.join(', ')}`);
groupClasses += ' has-error';
}
let { args } = vnode.attrs;
if (args === undefined) {
args = {};
}
args.value = vnode.attrs.value;
args.onchange = vnode.attrs.onchange;
args.oninput = vnode.attrs.oninput;
args.type = 'file';
return m('div', { class: groupClasses }, [
m(`label[for=${vnode.attrs.name}]`, vnode.attrs.title),
m(`input[name=${vnode.attrs.name}][id=${vnode.attrs.name}]`, args),
errorField,
]);
}
}
......@@ -8,16 +8,24 @@ export default class SelectGroup {
}
view(vnode) {
switch (vnode.attrs.args.type) {
let { args } = vnode.attrs;
if (args === undefined) {
args = {};
}
args.value = vnode.attrs.value;
args.onchange = vnode.attrs.onchange;
args.oninput = vnode.attrs.oninput;
switch (vnode.attrs.type) {
case 'buttons': {
if (vnode.attrs.args.multipleSelect) {
if (args.multipleSelect) {
return m('div', { class: vnode.attrs.classes }, [
m(`label[for=${vnode.attrs.name}]`, vnode.attrs.title),
m('div', vnode.attrs.args.options.map(option =>
m('div', vnode.attrs.options.map(option =>
m(inputGroup, {
name: vnode.attrs.name,
title: option,
value: option,
title: option.text,
value: option.value,
onchange: (e) => {
if (e.target.checked) {
this.value.push(e.target.value);
......@@ -51,12 +59,13 @@ export default class SelectGroup {
}
case 'select':
default: {
if (vnode.attrs.args.multipleSelect) {
if (args.multipleSelect) {
return m('div', { class: vnode.attrs.classes }, [
m(`label[for=${vnode.attrs.name}]`, vnode.attrs.title),
m(
`select[name=${vnode.attrs.name}][id=${vnode.attrs.name}]`,
{
args,
onchange: (e) => {
const value = [];
let opt;
......@@ -79,9 +88,8 @@ export default class SelectGroup {
}
vnode.attrs.oninput({ target: { name: e.target.name, value } });
},
multiple: true,
},
vnode.attrs.options.map(option => m('option', option)),
vnode.attrs.options.map(option => m('option', { value: option.value }, option.text)),
),
]);
}
......@@ -89,13 +97,8 @@ export default class SelectGroup {
m(`label[for=${vnode.attrs.name}]`, vnode.attrs.title),
m(
`select[name=${vnode.attrs.name}][id=${vnode.attrs.name}]`,
{
value: vnode.attrs.value,
onchange: vnode.attrs.onchange,
oninput: vnode.attrs.oninput,
multiple: false,
},
vnode.attrs.args.options.map(option => m('option', option)),
args,
vnode.attrs.options.map(option => m('option', { value: option.value }, option.text)),
),
]);
}
......
import m from 'mithril';
// import Ajv from 'ajv';
import * as studydocs from '../models/studydocs';
// import { apiUrl } from '../models/config';
import { isLoggedIn } from '../models/auth';
import { log } from '../models/log';
import { Error401 } from './errors';
// TODO: add validate
import inputGroup from './form/inputGroup';
import selectGroup from './form/selectGroup';
import button from './form/button';
export default class studydocNew {
oninit() {
// this.ajv = new Ajv({
// missingRefs: 'ignore',
// errorDataPath: 'property',
// allErrors: true,
// });
// // load schema
// m.request(`${apiUrl}/docs/api-docs`).then((schema) => {
// const objectSchema = schema.definitions.Studydocument;
// this.ajv.addSchema(objectSchema, 'schema');
// this.validate = this.ajv.getSchema('schema');
// });
this.doc = { type: 'exams' };
this.isValid = false;
}
this.doc = { semester: '1', department: 'itet', type: 'exams' };
static _getInputSuggestions(field, input, callback) {
if (input.length > 2) {
studydocs.getInputSuggestions(field, input).then((result) => {
const suggestions = new Set();
result._items.forEach((item) => {
suggestions.add(item[field]);
});
callback(Array.from(suggestions));
});
}
}
submit() {
if (this.isValid) {
studydocs.addNew(this.doc);
m.route.set('/studydocuments');
}
}
view() {
if (!isLoggedIn()) return m(Error401);
return m('div', [
m('form', {
onsubmit: (e) => {
e.preventDefault();
log(this.doc);
studydocs.addNew(this.doc);
m.route.set('/studydocuments');
return m('form', [
m(inputGroup, {
name: 'title',
title: 'Title',
oninput: (e) => {
this.doc.title = e.target.value;
},
getSuggestions: (input, callback) =>
studydocNew._getInputSuggestions('title', input, callback),
}),
m(inputGroup, {
name: 'professor',
title: 'Professor',
oninput: (e) => {
this.doc.professor = e.target.value;
},
getSuggestions: (input, callback) =>
studydocNew._getInputSuggestions('professor', input, callback),
}),
m(inputGroup, {
name: 'author',
title: 'Author',
oninput: (e) => {
this.doc.author = e.target.value;
},
getSuggestions: (input, callback) =>
studydocNew._getInputSuggestions('author', input, callback),
}),
m(selectGroup, {
name: 'semester',
title: 'Semester',
type: 'select',
onchange: (e) => {
this.doc.semester = e.target.value;
},
options: [
{ value: '1', text: '1' },
{ value: '2', text: '2' },
{ value: '3', text: '3' },
{ value: '4', text: '4' },
{ value: '5+', text: '5+' },
],
}),
m(selectGroup, {
name: 'department',
title: 'Department',
type: 'select',
onchange: (e) => {
this.doc.department = e.target.value;
},
options: [
{ value: 'itet', text: 'itet' },
{ value: 'mavt', text: 'mavt' },
],
}),
m(inputGroup, {
name: 'lecture',
title: 'Lecture',
oninput: (e) => {
this.doc.lecture = e.target.value;
},
getSuggestions: (input, callback) =>
studydocNew._getInputSuggestions('lecture', input, callback),
}),
m(inputGroup, {
name: 'course_year',
title: 'Course Year',
type: 'number',
args: {
placeholder: (new Date()).getFullYear(),
},
oninput: (e) => {
this.doc.course_year = e.target.value;
},
}),
m(selectGroup, {
name: 'type',
title: 'Type',
type: 'select',
onchange: (e) => {
this.doc.type = e.target.value;
},
options: [
{ value: 'exams', text: 'Exam' },
{ value: 'cheat sheets', text: 'Cheat sheet' },
{ value: 'lecture documents', text: 'Lecture Document' },
{ value: 'exercises', text: 'Exercise' },
],
}),
m(inputGroup, {
name: 'files',
title: 'Files',
args: {
type: 'file',
multiple: 1,
},
}, [
m('input[name=title]', {
placeholder: 'title',
onchange: (e) => {
this.doc.title = e.target.value;
// this.validate(this.doc);
},
}),
m('input[name=professor]', {
placeholder: 'professor',
onchange: (e) => {
this.doc.professor = e.target.value;
// this.validate(this.doc);
},
}),
m('input[name=author]', {
placeholder: 'author',
onchange: (e) => {
this.doc.author = e.target.value;
// this.validate(this.doc);
},
}),
m('select[name=semester]', {
onchange: (e) => {
this.doc.semester = e.target.value;
// this.validate(this.doc);
},
}, [
m('option', { value: '1' }, '1'),
m('option', { value: '2' }, '2'),
m('option', { value: '3' }, '3'),
m('option', { value: '4' }, '4'),
m('option', { value: '5+' }, '5+'),
]),
m('select[name=department]', {
onchange: (e) => {
this.doc.department = e.target.value;
// this.validate(this.doc);
},
}, [
m('option', { value: 'itet' }, 'itet'),
m('option', { value: 'mavt' }, 'mavt'),
]),
m('input[name=lecture]', {
placeholder: 'lecture',
onchange: (e) => {
this.doc.lecture = e.target.value;
// this.validate(this.doc);
},
}),
m('input[name=course_year]', {
type: 'number',
placeholder: 2018,
onchange: (e) => {
this.doc.course_year = e.target.value;
// this.validate(this.doc);
},
}),
m('select[name=type]', {
onchange: (e) => {
this.doc.type = e.target.value;
// this.validate(this.doc);
},
}, [
m('option', { value: 'exams' }, 'exams'),
m('option', { value: 'cheat sheets' }, 'cheat sheets'),
m('option', { value: 'lecture documents' }, 'lecture documents'),
m('option', { value: 'exercises' }, 'exercises'),
]),
m('button.button[type=submit]', 'Submit'),
]),
m('input[type=file][multiple]', {
onchange: (e) => {
this.doc.files = e.target.files;
if (this.doc.files.length > 0) {
this.isValid = true;
}
},
}),
m(button, {
name: 'submit',
title: 'Submit',
active: this.isValid,
args: {
onclick: () => this.submit(),
},
}),
]);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment