gitlab-org--gitlab-foss/app/assets/javascripts/droplab/drop_down.js

175 lines
4.1 KiB
JavaScript
Raw Normal View History

import { SELECTED_CLASS, IGNORE_CLASS } from './constants';
import utils from './utils';
2017-04-06 06:36:26 -04:00
class DropDown {
constructor(list, config = {}) {
this.currentIndex = 0;
this.hidden = true;
this.list = typeof list === 'string' ? document.querySelector(list) : list;
this.items = [];
this.eventWrapper = {};
this.hideOnClick = config.hideOnClick !== false;
2017-04-06 06:36:26 -04:00
if (config.addActiveClassToDropdownButton) {
this.dropdownToggle = this.list.parentNode.querySelector('.js-dropdown-toggle');
}
this.getItems();
this.initTemplateString();
this.addEvents();
2017-04-06 06:36:26 -04:00
this.initialState = list.innerHTML;
}
2017-04-06 06:36:26 -04:00
getItems() {
2017-04-06 06:36:26 -04:00
this.items = [].slice.call(this.list.querySelectorAll('li'));
return this.items;
}
2017-04-06 06:36:26 -04:00
initTemplateString() {
const items = this.items || this.getItems();
2017-04-06 06:36:26 -04:00
let templateString = '';
2017-04-06 06:36:26 -04:00
if (items.length > 0) templateString = items[items.length - 1].outerHTML;
this.templateString = templateString;
return this.templateString;
}
2017-04-06 06:36:26 -04:00
clickEvent(e) {
2017-04-06 19:56:46 -04:00
if (e.target.tagName === 'UL') return;
if (e.target.closest(`.${IGNORE_CLASS}`)) return;
2017-04-06 19:56:46 -04:00
const selected = e.target.closest('li');
2017-04-06 06:36:26 -04:00
if (!selected) return;
this.addSelectedClass(selected);
e.preventDefault();
if (this.hideOnClick) {
this.hide();
}
2017-04-06 06:36:26 -04:00
const listEvent = new CustomEvent('click.dl', {
2017-04-06 06:36:26 -04:00
detail: {
list: this,
selected,
2017-04-06 06:36:26 -04:00
data: e.target.dataset,
},
});
this.list.dispatchEvent(listEvent);
}
2017-04-06 06:36:26 -04:00
addSelectedClass(selected) {
2017-04-06 06:36:26 -04:00
this.removeSelectedClasses();
selected.classList.add(SELECTED_CLASS);
}
2017-04-06 06:36:26 -04:00
removeSelectedClasses() {
2017-04-06 06:36:26 -04:00
const items = this.items || this.getItems();
items.forEach((item) => item.classList.remove(SELECTED_CLASS));
}
2017-04-06 06:36:26 -04:00
addEvents() {
this.eventWrapper.clickEvent = this.clickEvent.bind(this);
this.eventWrapper.closeDropdown = this.closeDropdown.bind(this);
2017-04-06 06:36:26 -04:00
this.list.addEventListener('click', this.eventWrapper.clickEvent);
this.list.addEventListener('keyup', this.eventWrapper.closeDropdown);
}
closeDropdown(event) {
// `ESC` key closes the dropdown.
if (event.keyCode === 27) {
event.preventDefault();
return this.toggle();
}
return true;
}
2017-04-06 06:36:26 -04:00
setData(data) {
2017-04-06 06:36:26 -04:00
this.data = data;
this.render(data);
}
2017-04-06 06:36:26 -04:00
addData(data) {
2017-04-06 06:36:26 -04:00
this.data = (this.data || []).concat(data);
this.render(this.data);
}
2017-04-06 06:36:26 -04:00
render(data) {
2017-04-06 06:36:26 -04:00
const children = data ? data.map(this.renderChildren.bind(this)) : [];
if (this.list.querySelector('.filter-dropdown-loading')) {
return;
}
2017-04-06 06:36:26 -04:00
const renderableList = this.list.querySelector('ul[data-dynamic]') || this.list;
renderableList.innerHTML = children.join('');
2017-08-30 03:48:55 -04:00
const listEvent = new CustomEvent('render.dl', {
detail: {
list: this,
},
});
this.list.dispatchEvent(listEvent);
}
2017-04-06 06:36:26 -04:00
renderChildren(data) {
const html = utils.template(this.templateString, data);
const template = document.createElement('div');
2017-04-06 06:36:26 -04:00
template.innerHTML = html;
DropDown.setImagesSrc(template);
2017-04-06 06:36:26 -04:00
template.firstChild.style.display = data.droplab_hidden ? 'none' : 'block';
return template.firstChild.outerHTML;
}
2017-04-06 06:36:26 -04:00
show() {
2017-04-06 06:36:26 -04:00
if (!this.hidden) return;
this.list.style.display = 'block';
this.currentIndex = 0;
this.hidden = false;
if (this.dropdownToggle) this.dropdownToggle.classList.add('active');
}
2017-04-06 06:36:26 -04:00
hide() {
2017-04-06 06:36:26 -04:00
if (this.hidden) return;
this.list.style.display = 'none';
this.currentIndex = 0;
this.hidden = true;
if (this.dropdownToggle) this.dropdownToggle.classList.remove('active');
}
2017-04-06 06:36:26 -04:00
toggle() {
if (this.hidden) return this.show();
2017-04-06 06:36:26 -04:00
return this.hide();
}
destroy() {
2017-04-06 06:36:26 -04:00
this.hide();
this.list.removeEventListener('click', this.eventWrapper.clickEvent);
this.list.removeEventListener('keyup', this.eventWrapper.closeDropdown);
2017-04-06 06:36:26 -04:00
}
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');
});
}
}
2017-04-06 06:36:26 -04:00
export default DropDown;