summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/droplab/drop_down.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/droplab/drop_down.js')
-rw-r--r--app/assets/javascripts/droplab/drop_down.js138
1 files changed, 138 insertions, 0 deletions
diff --git a/app/assets/javascripts/droplab/drop_down.js b/app/assets/javascripts/droplab/drop_down.js
new file mode 100644
index 00000000000..70cd337fb8a
--- /dev/null
+++ b/app/assets/javascripts/droplab/drop_down.js
@@ -0,0 +1,138 @@
+import utils from './utils';
+import { SELECTED_CLASS, IGNORE_CLASS } from './constants';
+
+class DropDown {
+ constructor(list) {
+ this.currentIndex = 0;
+ this.hidden = true;
+ this.list = typeof list === 'string' ? document.querySelector(list) : list;
+ this.items = [];
+
+ this.eventWrapper = {};
+
+ this.getItems();
+ this.initTemplateString();
+ this.addEvents();
+
+ this.initialState = list.innerHTML;
+ }
+
+ getItems() {
+ this.items = [].slice.call(this.list.querySelectorAll('li'));
+ return this.items;
+ }
+
+ initTemplateString() {
+ const items = this.items || this.getItems();
+
+ let templateString = '';
+ if (items.length > 0) templateString = items[items.length - 1].outerHTML;
+ this.templateString = templateString;
+
+ return this.templateString;
+ }
+
+ clickEvent(e) {
+ if (e.target.tagName === 'UL') return;
+ if (e.target.classList.contains(IGNORE_CLASS)) return;
+
+ const selected = utils.closest(e.target, 'LI');
+ if (!selected) return;
+
+ this.addSelectedClass(selected);
+
+ e.preventDefault();
+ this.hide();
+
+ const listEvent = new CustomEvent('click.dl', {
+ detail: {
+ list: this,
+ selected,
+ data: e.target.dataset,
+ },
+ });
+ this.list.dispatchEvent(listEvent);
+ }
+
+ addSelectedClass(selected) {
+ this.removeSelectedClasses();
+ selected.classList.add(SELECTED_CLASS);
+ }
+
+ removeSelectedClasses() {
+ const items = this.items || this.getItems();
+
+ items.forEach(item => item.classList.remove(SELECTED_CLASS));
+ }
+
+ addEvents() {
+ this.eventWrapper.clickEvent = this.clickEvent.bind(this);
+ this.list.addEventListener('click', this.eventWrapper.clickEvent);
+ }
+
+ setData(data) {
+ this.data = data;
+ this.render(data);
+ }
+
+ addData(data) {
+ this.data = (this.data || []).concat(data);
+ this.render(this.data);
+ }
+
+ render(data) {
+ const children = data ? data.map(this.renderChildren.bind(this)) : [];
+ const renderableList = this.list.querySelector('ul[data-dynamic]') || this.list;
+
+ renderableList.innerHTML = children.join('');
+ }
+
+ renderChildren(data) {
+ const html = utils.template(this.templateString, data);
+ const template = document.createElement('div');
+
+ template.innerHTML = html;
+ DropDown.setImagesSrc(template);
+ template.firstChild.style.display = data.droplab_hidden ? 'none' : 'block';
+
+ return template.firstChild.outerHTML;
+ }
+
+ show() {
+ if (!this.hidden) return;
+ this.list.style.display = 'block';
+ this.currentIndex = 0;
+ this.hidden = false;
+ }
+
+ hide() {
+ if (this.hidden) return;
+ this.list.style.display = 'none';
+ this.currentIndex = 0;
+ this.hidden = true;
+ }
+
+ toggle() {
+ if (this.hidden) return this.show();
+
+ return this.hide();
+ }
+
+ destroy() {
+ this.hide();
+ this.list.removeEventListener('click', this.eventWrapper.clickEvent);
+ }
+
+ static setImagesSrc(template) {
+ const images = [...template.querySelectorAll('img[data-src]')];
+
+ images.forEach((image) => {
+ const img = image;
+
+ img.src = img.getAttribute('data-src');
+ img.removeAttribute('data-src');
+ });
+ }
+}
+
+export default DropDown;