(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(['DP'], factory);
} else {
// Browser globals
root.DP = factory(root.DP);
}
}(this, function (DP) {
"use strict";
/**
* GPDP dropdown selector
* Constructor for building object
* @param element
* @param {Object=} options
* @param {Array.<Object>=} options.data
* @param {boolean} [options.valueReturnByFunction=true]
* @param {string} options.name
* @returns {DP}
* @constructor
*/
DP = function (element, options) {
var self = this;
// private data tank
self.store = {};
// private settings
self.settings = {};
// store container
self.container = element;
if (typeof options === 'undefined' || typeof options.data === 'undefined') {
// DOM already
// store all elements
self.unit = self.container.getElementsByClassName('dp-unit')[0];
self.span = self.container.getElementsByClassName('dp-span')[0];
self.menu = self.container.getElementsByClassName('dp-menu')[0];
} else {
// automatically getting return value of function types data
self.settings.valueReturnByFunction = options.valueReturnByFunction || true;
// create all elements from data of options
// store data
self.data = options.data;
// validate if data's type is Array
if (Array.isArray(self.data)) {
// empty current container (if any)
self.container.innerHTML = '';
self.container.classList.add('dp-container');
// create all elements
// unit
self.unit = document.createElement('div');
self.unit.classList.add('dp-unit');
self.container.appendChild(self.unit);
// span(label)
self.span = document.createElement('div');
self.span.classList.add('dp-span');
self.span.textContent = options.name;
self.unit.appendChild(self.span);
// menu(ul)
self.menu = document.createElement('ul');
self.menu.classList.add('dp-menu');
self.unit.appendChild(self.menu);
// insert menu list
var listElement;
self.data.map(function (element, index) {
listElement = document.createElement('li');
listElement.classList.add('dp-item');
listElement.textContent = element.label;
listElement.dataset.index = index;
self.menu.appendChild(listElement);
});
} else {
console.error('Unsupported data type');
}
}
/* bind click event */
document.addEventListener('click', function (event) {
if (self.menu.classList.contains('open') && !self.isDescendant(self.container, event.target)) {
self.menu.classList.remove('open');
}
});
// click on tag
self.span.addEventListener('click', function () {
self.menu.classList.toggle('open');
});
// click on menu
self.menu.addEventListener('click', function (event) {
if (event.target.classList.contains('dp-item')) {
var index = parseInt(event.target.dataset.index, 10);
if (index > -1) {
self.setValueIndex(index);
} else {
self.setValue(event.target.dataset.value);
}
self.close();
}
});
return this;
};
/**
* Attach an event
* @param event - event's name
* @param {eventCallback}func - callback function
*/
DP.prototype.listen = function (event, func) {
this._events = this._events || {};
this._events[event] = this._events[event] || [];
this._events[event].push(func);
};
/**
* callback function definition of events
* @callback eventCallback
* @param {*} value - current selected value
*/
/**
* Detach an event
* @param event - event's name
* @param func - callback function
*/
DP.prototype.unlisten = function (event, func) {
this._events = this._events || {};
if (event in this._events === false) return;
this._events[event].splice(this._events[event].indexOf(func), 1);
};
/**
* Trigger an event
* @private
* @param event - event's name
*/
DP.prototype.trigger = function (event) {
this._events = this._events || {};
if (event in this._events === false) return;
for (var i = 0; i < this._events[event].length; i++) {
this._events[event][i].apply(this, [this.getValue(), Array.prototype.slice.call(arguments, 1)]);
}
};
/**
* get current selected value
* @returns {*} - current value
*/
DP.prototype.getValue = function () {
var value;
var index;
index = parseInt(this.store.currentIndex, 10);
if (index > -1) {
value = this.data[index].value;
if (typeof value === 'function') {
value = value();
}
} else {
value = this.store.value;
}
return value;
};
/**
* set current selected value
* @param value
*/
DP.prototype.setValue = function (value) {
this.store.currentIndex = null;
this.store.value = value;
this.trigger('changeValue');
return true;
};
/**
* set current selected value(index mode)
* @private
* @param index
*/
DP.prototype.setValueIndex = function (index) {
this.store.value = null;
this.store.currentIndex = index;
this.trigger('changeValue');
};
/**
* open dropdown menu
*/
DP.prototype.open = function () {
this.menu.classList.add('open');
};
/**
* close dropdown menu
*/
DP.prototype.close = function () {
this.menu.classList.remove('open');
};
//region Function for checking descendant
/**
* Check descendant
* @private
* @param parent - parent element
* @param child - child element
* @returns {boolean} - if is descendant
*/
DP.prototype.isDescendant = function (parent, child) {
var node = child.parentNode;
while (node != null) {
if (node == parent) {
return true;
}
node = node.parentNode;
}
return false;
};
//endregion
return DP;
}));