diff --git a/js/src/listitem.js b/js/src/listitem.js new file mode 100644 index 0000000..19dc3b2 --- /dev/null +++ b/js/src/listitem.js @@ -0,0 +1,34 @@ +/* + * μlogger + * + * Copyright(C) 2019 Bartek Fabiszewski (www.fabiszewski.net) + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +/** + * @interface + * @member {string} listId + * @member {string} listValue + */ +export default class uListItem { + /** + * @param {string|number} id + * @param {string|number} value + */ + constructor(id, value) { + this.listValue = String(id); + this.listText = String(value); + } +} diff --git a/js/src/select.js b/js/src/select.js new file mode 100644 index 0000000..7d5bac0 --- /dev/null +++ b/js/src/select.js @@ -0,0 +1,124 @@ +/* + * μlogger + * + * Copyright(C) 2019 Bartek Fabiszewski (www.fabiszewski.net) + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +export default class uSelect { + + /** + * @param {HTMLSelectElement} element Select element + * @param {string=} head Optional header text + */ + constructor(element, head) { + this.element = element; + this.hasAllOption = false; + this.allText = ''; + if (head && head.length) { + this.head = head; + } else { + this.hasHead = false; + this.headText = ''; + } + } + + /** + * @param {string} value + */ + set selected(value) { + if (this.hasValue(value)) { + this.element.value = value; + } + } + + /** + * @param {string} text + */ + set head(text) { + if (text.length) { + this.hasHead = true; + this.headText = text; + this.addHead(); + } + } + + /** + * @param {string=} text Optional text + */ + showAllOption(text) { + if (text) { + this.allText = text; + } + this.hasAllOption = true; + const index = this.hasHead ? 1 : 0; + this.element.add(new Option(this.allText, 'all'), index); + } + + hideAllOption() { + this.hasAllOption = false; + this.remove('all'); + } + + addHead() { + const head = new Option(this.headText, '0', true, true); + head.disabled = true; + this.element.options.add(head, 0); + } + + /** + * @param {string} value + * @return {boolean} + */ + hasValue(value) { + return (typeof this.getOption(value) !== 'undefined'); + } + + /** + * @param {string} value + */ + getOption(value) { + return [ ...this.element.options ].find((o) => o.value === value); + } + + /** + * @param {string} value + */ + remove(value) { + /** @type HTMLOptionElement */ + const option = this.getOption(value); + if (option) { + this.element.remove(option.index); + } + } + + /** + * @param {uListItem[]} options + * @param {string=} selected + */ + setOptions(options, selected) { + selected = selected || ''; + this.element.options.length = 0; + if (this.hasHead) { + this.addHead(); + } + if (this.hasAllOption) { + this.element.add(new Option(this.allText, 'all', false, selected === 'all')); + } + for (const option of options) { + this.element.add(new Option(option.listText, option.listValue, false, selected === option.listValue)); + } + } +} diff --git a/js/src/user.js b/js/src/user.js index a8e7f66..d4b2609 100644 --- a/js/src/user.js +++ b/js/src/user.js @@ -18,6 +18,7 @@ */ import uAjax from './ajax.js'; +import uListItem from './listitem.js'; /** * @class uUser @@ -25,12 +26,13 @@ import uAjax from './ajax.js'; * @property {string} login * @property {string} [password] */ -export default class uUser { +export default class uUser extends uListItem { /** * @param {number} id * @param {string} login */ constructor(id, login) { + super(id, login); this.id = id; this.login = login; } diff --git a/js/test/select.test.js b/js/test/select.test.js new file mode 100644 index 0000000..3123d43 --- /dev/null +++ b/js/test/select.test.js @@ -0,0 +1,254 @@ +/* + * μlogger + * + * Copyright(C) 2019 Bartek Fabiszewski (www.fabiszewski.net) + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +import uListItem from '../src/listitem.js'; +import uSelect from '../src/select.js'; + +describe('Select tests', () => { + + const head = 'test header'; + const allText = 'all text'; + let element; + let options; + + class TestItem extends uListItem { + constructor(id, name) { + super(id, name); + this.id = id; + // noinspection JSUnusedGlobalSymbols + this.name = name; + } + } + + beforeEach(() => { + options = [ + new TestItem(1, 'test1'), + new TestItem(5, 'test5') + ]; + element = document.createElement('select'); + }); + + it('should construct class instance with default values', () => { + // when + const select = new uSelect(element); + // then + expect(select.element).toBe(element); + expect(select.element.options.length).toBe(0); + expect(select.element.value).toBe(''); + expect(select.hasAllOption).toBe(false); + expect(select.allText).toBe(''); + expect(select.hasHead).toBe(false); + expect(select.headText).toBe(''); + }); + + it('should construct class instance with header', () => { + // when + const select = new uSelect(element, head); + // then + expect(select.element).toBe(element); + expect(select.element.options.length).toBe(1); + expect(select.element.options[0].disabled).toBe(true); + expect(select.element.options[0].defaultSelected).toBe(true); + expect(select.element.options[0].selected).toBe(true); + expect(select.element.options[0].text).toBe(head); + expect(select.element.options[0].value).toBe('0'); + }); + + it('should construct class instance and set options', () => { + // when + const select = new uSelect(element); + select.setOptions(options); + // then + expect(select.element).toBe(element); + expect(select.element.options.length).toBe(options.length); + expect(select.element.options[0].disabled).toBe(false); + expect(select.element.options[0].defaultSelected).toBe(false); + expect(select.element.options[0].selected).toBe(true); + expect(select.element.options[0].text).toBe(options[0].listText); + expect(select.element.options[0].value).toBe(options[0].listValue); + expect(select.element.options[1].disabled).toBe(false); + expect(select.element.options[1].defaultSelected).toBe(false); + expect(select.element.options[1].selected).toBe(false); + expect(select.element.options[1].text).toBe(options[1].listText); + expect(select.element.options[1].value).toBe(options[1].listValue); + }); + + it('should construct class instance and set options and default value', () => { + // when + const select = new uSelect(element); + select.setOptions(options, options[1].listValue); + // then + expect(select.element).toBe(element); + expect(select.element.options.length).toBe(options.length); + expect(select.element.options[0].disabled).toBe(false); + expect(select.element.options[0].defaultSelected).toBe(false); + expect(select.element.options[0].selected).toBe(false); + expect(select.element.options[0].text).toBe(options[0].listText); + expect(select.element.options[0].value).toBe(options[0].listValue); + expect(select.element.options[1].disabled).toBe(false); + expect(select.element.options[1].defaultSelected).toBe(false); + expect(select.element.options[1].selected).toBe(true); + expect(select.element.options[1].text).toBe(options[1].listText); + expect(select.element.options[1].value).toBe(options[1].listValue); + }); + + it('should construct class instance with options and head', () => { + // when + const select = new uSelect(element, head); + select.setOptions(options); + // then + expect(select.element).toBe(element); + expect(select.element.options.length).toBe(options.length + 1); + expect(select.element.options[0].disabled).toBe(true); + expect(select.element.options[0].defaultSelected).toBe(true); + expect(select.element.options[0].selected).toBe(true); + expect(select.element.options[0].text).toBe(head); + expect(select.element.options[0].value).toBe('0'); + expect(select.element.options[1].disabled).toBe(false); + expect(select.element.options[1].defaultSelected).toBe(false); + expect(select.element.options[1].selected).toBe(false); + expect(select.element.options[1].text).toBe(options[0].listText); + expect(select.element.options[1].value).toBe(options[0].listValue); + expect(select.element.options[2].disabled).toBe(false); + expect(select.element.options[2].defaultSelected).toBe(false); + expect(select.element.options[2].selected).toBe(false); + expect(select.element.options[2].text).toBe(options[1].listText); + expect(select.element.options[2].value).toBe(options[1].listValue); + }); + + it('should construct class instance with options, default value and head', () => { + // when + const select = new uSelect(element, head); + select.setOptions(options, options[1].listValue); + // then + expect(select.element).toBe(element); + expect(select.element.options.length).toBe(options.length + 1); + expect(select.element.options[0].disabled).toBe(true); + expect(select.element.options[0].defaultSelected).toBe(true); + expect(select.element.options[0].selected).toBe(false); + expect(select.element.options[0].text).toBe(head); + expect(select.element.options[0].value).toBe('0'); + expect(select.element.options[1].disabled).toBe(false); + expect(select.element.options[1].defaultSelected).toBe(false); + expect(select.element.options[1].selected).toBe(false); + expect(select.element.options[1].text).toBe(options[0].listText); + expect(select.element.options[1].value).toBe(options[0].listValue); + expect(select.element.options[2].disabled).toBe(false); + expect(select.element.options[2].defaultSelected).toBe(false); + expect(select.element.options[2].selected).toBe(true); + expect(select.element.options[2].text).toBe(options[1].listText); + expect(select.element.options[2].value).toBe(options[1].listValue); + }); + + it('should set selected option', () => { + // given + const select = new uSelect(element); + select.setOptions(options, options[1].listValue); + + expect(select.element.options[1].selected).toBe(true); + // when + select.selected = options[0].listValue; + // then + expect(select.element.options[1].selected).toBe(false); + expect(select.element.options[0].selected).toBe(true); + }); + + it('should set "all" option and render when setting options', () => { + // given + const select = new uSelect(element); + select.showAllOption(allText); + + expect(select.element.options.length).toBe(1); + // when + select.setOptions(options, options[1].listValue); + // then + expect(select.element.options.length).toBe(3); + expect(select.element.options[0].value).toBe('all'); + expect(select.element.options[0].text).toBe(allText); + expect(select.element.options[2].selected).toBe(true); + }); + + it('should add/remove "all" option', () => { + // given + const select = new uSelect(element); + select.setOptions(options, options[1].listValue); + + expect(select.element.options.length).toBe(2); + expect(select.element.options[1].selected).toBe(true); + // when + select.showAllOption(allText); + // then + expect(select.element.options.length).toBe(3); + expect(select.element.options[0].value).toBe('all'); + expect(select.element.options[0].text).toBe(allText); + expect(select.element.options[2].selected).toBe(true); + // when + select.hideAllOption(); + // then + expect(select.element.options.length).toBe(2); + expect(select.element.options[0].value).toBe(options[0].listValue); + expect(select.element.options[0].text).toBe(options[0].listText); + expect(select.element.options[1].value).toBe(options[1].listValue); + expect(select.element.options[1].text).toBe(options[1].listText); + expect(select.element.options[1].selected).toBe(true); + }); + + it('should set "all" option and render when setting options with header', () => { + // given + const select = new uSelect(element, head); + select.showAllOption(allText); + + expect(select.element.options.length).toBe(2); + // when + select.setOptions(options, options[1].listValue); + // then + expect(select.element.options.length).toBe(4); + expect(select.element.options[0].value).toBe('0'); + expect(select.element.options[0].text).toBe(head); + expect(select.element.options[1].value).toBe('all'); + expect(select.element.options[1].text).toBe(allText); + expect(select.element.options[3].selected).toBe(true); + }); + + it('should add/remove "all" option with head set', () => { + // given + const select = new uSelect(element, head); + select.setOptions(options, options[1].listValue); + + expect(select.element.options.length).toBe(3); + expect(select.element.options[2].selected).toBe(true); + // when + select.showAllOption(allText); + // then + expect(select.element.options.length).toBe(4); + expect(select.element.options[1].value).toBe('all'); + expect(select.element.options[1].text).toBe(allText); + expect(select.element.options[3].selected).toBe(true); + // when + select.hideAllOption(); + // then + expect(select.element.options.length).toBe(3); + expect(select.element.options[1].value).toBe(options[0].listValue); + expect(select.element.options[1].text).toBe(options[0].listText); + expect(select.element.options[2].value).toBe(options[1].listValue); + expect(select.element.options[2].text).toBe(options[1].listText); + expect(select.element.options[2].selected).toBe(true); + }); + +}); diff --git a/js/test/user.test.js b/js/test/user.test.js index a0bbdf3..b91cda6 100644 --- a/js/test/user.test.js +++ b/js/test/user.test.js @@ -46,7 +46,7 @@ describe('User tests', () => { spyOnProperty(XMLHttpRequest.prototype, 'status').and.returnValue(200); }); - it('should make successful request and user array', (done) => { + it('should make successful request and return user array', (done) => { // when spyOnProperty(XMLHttpRequest.prototype, 'responseText').and.returnValue(JSON.stringify(validResponse)); // then