bulma-extensions
Version:
Set of extensions for Bulma.io CSS Framework
260 lines (214 loc) • 7.01 kB
JavaScript
import EventEmitter from './events';
import defaultOptions from './defaultOptions';
const onStepsPrevious = Symbol('onStepsPrevious');
const onStepsNext = Symbol('onStepsNext');
export default class bulmaSteps extends EventEmitter {
constructor(selector, options = {}) {
super();
this.element = typeof selector === 'string'
? document.querySelector(selector)
: selector;
// An invalid selector or non-DOM node has been provided.
if (!this.element) {
throw new Error('An invalid selector or non-DOM node has been provided.');
}
this._clickEvents = ['click'];
/// Set default options and merge with instance defined
this.options = {
...defaultOptions,
...options
};
this[onStepsPrevious] = this[onStepsPrevious].bind(this);
this[onStepsNext] = this[onStepsNext].bind(this);
this.init();
}
/**
* Initiate all DOM element containing carousel class
* @method
* @return {Array} Array of all Carousel instances
*/
static attach(selector = '.steps', options = {}) {
let instances = new Array();
const elements = document.querySelectorAll(selector);
[].forEach.call(elements, element => {
setTimeout(() => {
instances.push(new bulmaSteps(element, options));
}, 100);
});
return instances;
}
/**
* Initiate plugin
* @method init
* @return {void}
*/
init() {
this._id = 'bulmaSteps' + (new Date()).getTime() + Math.floor(Math.random() * Math.floor(9999));
this.steps = this.element.querySelectorAll(this.options.selector);
this.contents = this.element.querySelectorAll(this.options.selector_content);
this.previous_btn = this.element.querySelector(this.options.previous_selector);
this.next_btn = this.element.querySelector(this.options.next_selector);
[].forEach.call(this.steps, (step, index) => {
step.setAttribute('data-step-id', index);
});
if (this.steps && this.steps.length) {
this.activate_step(0);
this.updateActions(this.steps[0]);
}
this._bindEvents();
this.emit('bulmasteps:ready', this.element.value);
}
/**
* Bind all events
* @method _bindEvents
* @return {void}
*/
_bindEvents() {
if (this.previous_btn != null) {
this._clickEvents.forEach(event => {
this.previous_btn.addEventListener(event, this[onStepsPrevious], false);
});
}
if (this.next_btn != null) {
this._clickEvents.forEach(event => {
this.next_btn.addEventListener(event, this[onStepsNext], false);
});
}
if (this.options.stepClickable) {
[].forEach.call(this.steps, (step, index) => {
this._clickEvents.forEach(event => {
while(index > this.current_id) {
this[onStepsNext](event);
}
while(index < this.current_id) {
this[onStepsPrevious](event);
}
});
})
}
}
[onStepsPrevious](e) {
e.preventDefault();
if (!e.target.getAttribute('disabled')) {
this.previous_step();
}
}
[onStepsNext](e) {
e.preventDefault();
if (!e.target.getAttribute('disabled')) {
this.next_step();
}
}
get_current_step_id() {
for (var i = 0; i < this.steps.length; i++) {
var step = this.steps[i];
if (step.classList.contains(this.options.active_class)) {
return parseInt(step.getAttribute('data-step-id'));
}
}
return null;
}
updateActions(step) {
var stepId = parseInt(step.getAttribute('data-step-id'));
if (stepId == 0) {
if (this.previous_btn != null) {
this.previous_btn.setAttribute('disabled', 'disabled');
}
if (this.next_btn != null) {
this.next_btn.removeAttribute('disabled', 'disabled');
}
} else if (stepId == (this.steps.length - 1)) {
if (this.previous_btn != null) {
this.previous_btn.removeAttribute('disabled', 'disabled');
}
if (this.next_btn != null) {
this.next_btn.setAttribute('disabled', 'disabled');
}
} else {
if (this.previous_btn != null) {
this.previous_btn.removeAttribute('disabled', 'disabled');
}
if (this.next_btn != null) {
this.next_btn.removeAttribute('disabled', 'disabled');
}
}
}
async next_step() {
var current_id = this.get_current_step_id();
if (current_id == null) {
return;
}
var next_id = current_id + 1,
errors = [];
if (typeof this.options.beforeNext != 'undefined' && this.options.beforeNext != null && this.options.beforeNext) {
errors = await this.options.beforeNext(current_id);
}
this.emit('bulmasteps:before:next', current_id);
if (typeof errors == 'undefined') {
errors = [];
}
if (errors.length > 0) {
this.emit('bulmasteps:errors', errors);
for (var i = 0; i < errors.length; i++) {
if (typeof this.options.onError != 'undefined' && this.options.onError != null && this.options.onError) {
this.options.onError(errors[i]);
}
}
return;
}
if (next_id >= this.steps.length - 1) {
if (typeof this.options.onFinish != 'undefined' && this.options.onFinish != null && this.options.onFinish) {
this.options.onFinish(current_id);
}
this.emit('bulmasteps:finish', current_id);
}
if (next_id < this.steps.length) {
this.complete_step(current_id);
this.activate_step(next_id);
}
}
previous_step() {
var current_id = this.get_current_step_id();
if (current_id == null) {
return;
}
this.uncomplete_step(current_id - 1);
this.activate_step(current_id - 1);
}
/**
* Activate a single step,
* will deactivate all other steps.
*/
activate_step(step_id) {
this.updateActions(this.steps[step_id]);
for (var i = 0; i < this.steps.length; i++) {
var _step = this.steps[i];
if (_step == this.steps[step_id]) {
continue;
}
this.deactivate_step(i);
}
this.steps[step_id].classList.add(this.options.active_class);
if (typeof this.contents[step_id] !== 'undefined') {
this.contents[step_id].classList.add(this.options.active_class);
}
if (typeof this.options.onShow != 'undefined' && this.options.onShow != null && this.options.onShow) {
this.options.onShow(step_id);
}
this.emit('bulmasteps:step:show', step_id);
}
complete_step(step_id) {
this.steps[step_id].classList.add(this.options.completed_class);
this.emit('bulmasteps:step:completed', step_id);
}
uncomplete_step(step_id) {
this.steps[step_id].classList.remove(this.options.completed_class);
this.emit('bulmasteps:step:uncompleted', step_id);
}
deactivate_step(step_id) {
this.steps[step_id].classList.remove(this.options.active_class);
if (typeof this.contents[step_id] !== 'undefined') {
this.contents[step_id].classList.remove(this.options.active_class);
}
}
}