views/mdc/assets/js/mdl-stepper.js
/*
This file was copied from the MDL Stepper Polyfill at https://ahlechandre.github.io/mdl-stepper/component/
The stepper looks and behaves failry well but we wanted some specific behavior changes so pulled in a copy here.
*/
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports) {
'use strict';
/**
* MDL Stepper - A library that implements to the Material Design Lite (MDL) a polyfill for stepper
* component specified by Material Design.
* @version v1.1.6
* @author Alexandre Thebaldi <ahlechandre@gmail.com>.
* @link https://github.com/ahlechandre/mdl-stepper
*/
(function () {
'use strict';
/**
* Class constructor for Stepper MDL component.
* Implements MDL component design pattern defined at:
* https://github.com/jasonmayes/mdl-component-design-pattern
*
* @constructor
* @param {HTMLElement} element The element that will be upgraded.
*/
function MaterialStepper(element) {
this.element_ = element;
// initialize instance.
this.init();
}
window.MaterialStepper = MaterialStepper;
/**
* Store properties of stepper.
* @private
*/
MaterialStepper.prototype.Stepper_ = {};
/**
* Get properties of stepper.
* @return {Object}
* @private
*/
MaterialStepper.prototype.getStepper_ = function () {
return {
isLinear: this.element_.classList.contains(this.CssClasses_.STEPPER_LINEAR),
hasFeedback: this.element_.classList.contains(this.CssClasses_.STEPPER_FEEDBACK)
};
};
/**
* Store strings for steps states.
* @enum {string}
* @private
*/
MaterialStepper.prototype.StepState_ = {
COMPLETED: 'completed',
ERROR: 'error',
NORMAL: 'normal'
};
/**
* Store strings for dataset attributes defined by this component that are used for
* JavaScript custom events.
*
* @enum {string}
* @private
*/
MaterialStepper.prototype.DatasetAttributes_ = {
CONTINUE: 'stepper-next',
CANCEL: 'stepper-cancel',
SKIP: 'stepper-skip',
BACK: 'stepper-back'
};
/**
* Issue: https://github.com/ahlechandre/mdl-stepper/issues/14
* Returns a custom event object
* @param {string} evtName The name/type of custom event to create.
* @param {bool} bubble If event is bubbleable.
* @param {bool} cancel If event is cancelable.
* @returns {Event}
*/
MaterialStepper.prototype.defineCustomEvent = function (evtName, bubble, cancel) {
var ev;
if ('CustomEvent' in window && typeof window.CustomEvent === 'function') {
ev = new Event(evtName, {
bubbles: bubble,
cancelable: cancel
});
} else {
ev = document.createEvent('Events');
ev.initEvent(evtName, bubble, cancel);
}
return ev;
};
/**
* Store the custom events applieds to the steps and stepper.
*
* @private
*/
MaterialStepper.prototype.CustomEvents_ = {
onstepnext: MaterialStepper.prototype.defineCustomEvent('onstepnext', true, true),
onstepcancel: MaterialStepper.prototype.defineCustomEvent('onstepcancel', true, true),
onstepskip: MaterialStepper.prototype.defineCustomEvent('onstepskip', true, true),
onstepback: MaterialStepper.prototype.defineCustomEvent('onstepback', true, true),
onstepcomplete: MaterialStepper.prototype.defineCustomEvent('onstepcomplete', true, true),
onsteperror: MaterialStepper.prototype.defineCustomEvent('onsteperror', true, true),
onsteppercomplete: MaterialStepper.prototype.defineCustomEvent('onsteppercomplete', true, true)
};
/**
* Store strings for class names defined by this component that are used in
* JavaScript. This allows us to simply change it in one place should we
* decide to modify at a later date.
*
* @enum {string}
* @private
*/
MaterialStepper.prototype.CssClasses_ = {
BUTTON_JS: 'mdl-js-button',
STEPPER_LINEAR: 'mdl-stepper--linear',
STEPPER_FEEDBACK: 'mdl-stepper--feedback',
STEP_COMPLETED: 'mdl-step--completed',
STEP_ERROR: 'mdl-step--error',
STEP_TRANSIENT: 'mdl-step--transient',
STEP_OPTIONAL: 'mdl-step--optional',
STEP_EDITABLE: 'mdl-step--editable',
IS_ACTIVE: 'is-active',
TRANSIENT: 'mdl-step__transient',
TRANSIENT_OVERLAY: 'mdl-step__transient-overlay',
TRANSIENT_LOADER: 'mdl-step__transient-loader',
SPINNER: 'mdl-spinner',
SPINNER_JS: 'mdl-js-spinner',
SPINNER_IS_ACTIVE: 'is-active',
STEPPER: 'mdl-stepper',
STEP: 'mdl-step',
STEP_LABEL: 'mdl-step__label',
STEP_LABEL_INDICATOR: 'mdl-step__label-indicator',
STEP_LABEL_INDICATOR_CONTENT: 'mdl-step__label-indicator-content',
STEP_TITLE: 'mdl-step__title',
STEP_TITLE_TEXT: 'mdl-step__title-text',
STEP_TITLE_MESSAGE: 'mdl-step__title-message',
STEP_CONTENT: 'mdl-step__content',
STEP_ACTIONS: 'mdl-step__actions',
V_STEP_ACTIONS: 'v-step__actions',
V_STEP_CONTENT: 'v-step__content',
};
/**
* Store collection of steps and important data about them
* @private
*/
MaterialStepper.prototype.Steps_ = {};
/**
* Returns the label indicator for referred to the passed step.
* @param {MaterialStepper.Steps_.collection.<step>} step The step that will get
* the label indicator.
* @return {HTMLElement}
* @private
*/
MaterialStepper.prototype.getIndicatorElement_ = function (step) {
/** @type {HTMLElement} */
var indicatorElement;
/** @type {HTMLElement} */
var indicatorContent;
indicatorElement = document.createElement('span');
indicatorContent = this.getIndicatorContentNormal_(step.labelndicatorText);
indicatorElement.classList.add(this.CssClasses_.STEP_LABEL_INDICATOR);
indicatorElement.appendChild(indicatorContent);
return indicatorElement;
};
/**
* Create a new element that's represent "normal" label indicator.
* @param {string} text The text content of indicator (e.g. 1, 2..N).
* @return {HTMLElement}
* @private
*/
MaterialStepper.prototype.getIndicatorContentNormal_ = function (text) {
/** @type {HTMLElement} */
var normal;
normal = document.createElement('span');
normal.classList.add(this.CssClasses_.STEP_LABEL_INDICATOR_CONTENT);
normal.textContent = text;
return normal;
};
/**
* Create a new element that's represent "completed" label indicator.
* @param {boolean} isEditable Flag to check if step is of editable type.
* @return {HTMLElement}
* @private
*/
MaterialStepper.prototype.getIndicatorContentCompleted_ = function (isEditable) {
// Creates a new material icon to represent the completed step.
/** @type {HTMLElement} */
var completed;
completed = document.createElement('i');
completed.classList.add('material-icons', this.CssClasses_.STEP_LABEL_INDICATOR_CONTENT);
// If step is editable the icon used will be "edit",
// else the icon will be "check".
completed.textContent = isEditable ? 'edit' : 'check';
return completed;
};
/**
* Create a new element that's represent "error" label indicator.
* @return {HTMLElement}
* @private
*/
MaterialStepper.prototype.getIndicatorContentError_ = function () {
/** @type {HTMLElement} */
var error;
error = document.createElement('span');
error.classList.add(this.CssClasses_.STEP_LABEL_INDICATOR_CONTENT);
error.textContent = '!';
return error;
};
/**
* Defines a new step model.
* @param {HTMLElement} step The step element.
* @param {number} id The unique number for each step.
* @return {Object}
* @private
*/
MaterialStepper.prototype.getStepModel_ = function (step, id) {
/** @type {Object} */
var model;
/** @type {string} */
var selectorActionsBack;
/** @type {string} */
var selectorActionsCancel;
/** @type {string} */
var selectorActionsNext;
/** @type {string} */
var selectorActionsSkip;
selectorActionsBack = '[data-' + this.DatasetAttributes_.BACK + ']';
selectorActionsCancel = '[data-' + this.DatasetAttributes_.CANCEL + ']';
selectorActionsNext = '[data-' + this.DatasetAttributes_.CONTINUE + ']';
selectorActionsSkip = '[data-' + this.DatasetAttributes_.SKIP + ']';
model = {};
model.container = step;
model.id = id;
model.label = step.querySelector('.' + this.CssClasses_.STEP_LABEL);
model.labelndicatorText = id;
model.labelTitle = step.querySelector('.' + this.CssClasses_.STEP_TITLE);
model.labelTitleText = step.querySelector('.' + this.CssClasses_.STEP_TITLE_TEXT).textContent;
model.labelTitleMessage = step.querySelector('.' + this.CssClasses_.STEP_TITLE_MESSAGE);
model.labelTitleMessageText = model.labelTitleMessage ? model.labelTitleMessage.textContent : '';
// model.content = step.querySelector('.' + this.CssClasses_.STEP_CONTENT);
// model.actions = step.querySelector('.' + this.CssClasses_.STEP_ACTIONS);
// I made this mod as the step contents are no longer children of the steps themselves
model.content = document.querySelector('.' + this.CssClasses_.V_STEP_CONTENT + '-' + step.id);
model.actions = document.querySelector('.' + this.CssClasses_.V_STEP_ACTIONS + '-' + step.id);
model.actionsBack = model.actions.querySelector(selectorActionsBack) || null;
model.actionsCancel = model.actions.querySelector(selectorActionsCancel) || null;
model.actionsNext = model.actions.querySelector(selectorActionsNext) || null;
model.actionsSkip = model.actions.querySelector(selectorActionsSkip) || null;
model.labelIndicator = model.label.querySelector('.' + this.CssClasses_.STEP_LABEL_INDICATOR);
if (!model.labelIndicator) {
// Creates a new indicator for the label if not exists
model.labelIndicator = this.getIndicatorElement_(model);
model.label.appendChild(model.labelIndicator);
}
if (step.classList.contains(this.CssClasses_.STEP_COMPLETED)) {
model.state = this.StepState_.COMPLETED;
} else if (step.classList.contains(this.CssClasses_.STEP_ERROR)) {
model.state = this.StepState_.ERROR;
} else {
model.state = this.StepState_.NORMAL;
}
model.isActive = step.classList.contains(this.CssClasses_.IS_ACTIVE);
model.isOptional = step.classList.contains(this.CssClasses_.STEP_OPTIONAL);
model.isEditable = step.classList.contains(this.CssClasses_.STEP_EDITABLE);
return model;
};
/**
* Get the active step element.
* @return {HTMLElement}
*/
MaterialStepper.prototype.getActive = function () {
return this.Steps_.collection[this.Steps_.active - 1].container;
};
/**
* Get the active step id.
* @return {number}
*/
MaterialStepper.prototype.getActiveId = function () {
return this.Steps_.collection[this.Steps_.active - 1].id;
};
/**
* Load the model of all steps and store inside a collection.
* @return {Object}
* @private
*/
MaterialStepper.prototype.getSteps_ = function () {
/** @type {array} */
var collection;
/** @type {number} */
var total;
/** @type {number} */
var completed;
/** @type {number} */
var optional;
/** @type {number} */
var active;
/** @type {HTMLElement} */
var stepElements;
/** @type {number} */
var i;
collection = [];
total = 0;
completed = 0;
optional = 0;
active = 0;
stepElements = this.element_.querySelectorAll('.' + this.CssClasses_.STEP);
for (i = 0; i < stepElements.length; i++) {
collection[i] = this.getStepModel_(stepElements[i], i + 1);
if (collection[i].isOptional) {
optional += 1;
}
if (collection[i].isActive) {
active = collection[i].id;
}
// Prevents the step label to scrolling out of user view on Google Chrome.
// More details here: <https://github.com/ahlechandre/mdl-stepper/issues/11 />.
stepElements[i].addEventListener('scroll', function (event) {
event.target.scrollTop = 0;
});
}
total = collection.length;
return {
collection: collection,
total: total,
completed: completed,
optional: optional,
active: active
};
};
/**
* Defines a specific step as "active".
* @param {MaterialStepper.Steps_.collection<step>} step A model of step.
* @return {boolean}
* @private
*/
MaterialStepper.prototype.setStepActive_ = function (step) {
/** @type {function} */
var stepsDeactivator;
// The transient effect blocks the stepper to move
if (this.hasTransient()) return false;
stepsDeactivator = function stepsDeactivator(step) {
step.container.classList.remove(this.CssClasses_.IS_ACTIVE);
step.content.classList.remove(this.CssClasses_.IS_ACTIVE);
if (step.isActive) {
step.isActive = false;
}
};
this.Steps_.collection.forEach(stepsDeactivator.bind(this));
// remove if step was in transient (feedback) effect
step.container.classList.remove(this.CssClasses_.STEP_TRANSIENT);
step.container.classList.add(this.CssClasses_.IS_ACTIVE);
step.content.classList.add(this.CssClasses_.IS_ACTIVE);
step.isActive = true;
this.Steps_.active = step.id;
return true;
};
/**
* Defines as "active" the first step or a specific id.
* @param {number | undefined} id Unique number of a step.
* @return {boolean}
* @private
*/
MaterialStepper.prototype.setActive_ = function (id) {
/** @type {HTMLElement | null} */
var active;
/** MaterialStepper.Steps_.collection<step> */
var first;
/** @type {number} */
var i;
/** @type {boolean} */
var moved;
/** MaterialStepper.Steps_.collection<step> */
var step;
// Return false if specified id is less or equal 0 and bigger than the last step
if (!isNaN(id) && (id > this.Steps_.total || id <= 0)) return false;
moved = false;
if (id) {
for (i = 0; i < this.Steps_.total; i++) {
step = this.Steps_.collection[i];
if (step.id === id) {
moved = this.setStepActive_(step);
break;
}
}
} else {
active = this.element_.querySelector('.' + this.CssClasses_.IS_ACTIVE);
if (!active) {
// Set the first step as "active" if none id was specified and
// no "active" step was found at the DOM.
first = this.Steps_.collection[0];
moved = this.setStepActive_(first);
}
}
if (this.Stepper_.isLinear) {
// We know that all steps previous the "active" are "completed"
// case the stepper is linear
this.updateLinearStates_();
}
return moved;
};
/**
* Change the state of a step
* @param {MaterialStepper.Steps_.collection<step>} step The step to be updated.
* @param {string} state The step state ("completed", "error" or "normal").
* @return {boolean}
* @private
*/
MaterialStepper.prototype.updateStepState_ = function (step, state) {
/** @type {string} */
var stateClass;
/** @type {HTMLElement} */
var indicatorContent;
/** @type {HTMLElement} */
var currentIndicatorContent;
/** @type {boolean} */
var stepperCompleted;
/** @type {boolean} */
var hasRequired;
/** @type {MaterialStepper.Steps_.collection<stepItem>} */
var stepItem;
/** @type {number} */
var item;
/** @type {string} */
var selectorIndicator;
selectorIndicator = '.' + this.CssClasses_.STEP_LABEL_INDICATOR_CONTENT;
// Can't update the state for the same.
if (step.state === state) return false;
// Case the current step state to change is "completed",
// we can decrement the total number of completed.
if (step.state === this.StepState_.COMPLETED) {
this.Steps_.completed -= 1;
}
currentIndicatorContent = step.labelIndicator.querySelector(selectorIndicator);
switch (state) {
case this.StepState_.COMPLETED:
{
// Case changing the current step state to "completed",
// we can increment the total number of completed.
this.Steps_.completed += 1;
step.container.classList.remove(this.CssClasses_.STEP_ERROR);
indicatorContent = this.getIndicatorContentCompleted_(step.isEditable);
stateClass = this.CssClasses_.STEP_COMPLETED;
break;
}
case this.StepState_.ERROR:
{
step.container.classList.remove(this.CssClasses_.STEP_COMPLETED);
indicatorContent = this.getIndicatorContentError_();
stateClass = this.CssClasses_.STEP_ERROR;
break;
}
case this.StepState_.NORMAL:
{
step.container.classList.remove(this.CssClasses_.STEP_COMPLETED);
step.container.classList.remove(this.CssClasses_.STEP_ERROR);
indicatorContent = this.getIndicatorContentNormal_(step.labelndicatorText);
break;
}
default:
{
break;
}
}
// "normal" is the default state and don't have specific css class.
if (stateClass) {
step.container.classList.add(stateClass);
}
step.labelIndicator.replaceChild(indicatorContent, currentIndicatorContent);
step.state = state;
// Case the total number of completed steps
// are equal the total number of steps less the optionals
// or total number of completed steps are equal the total number of steps,
// we can consider that the stepper are successfully complete and
// dispatch the custom event.
stepperCompleted = false;
if (this.Steps_.completed === this.Steps_.total) {
stepperCompleted = true;
} else if (this.Steps_.completed === this.Steps_.total - this.Steps_.optional) {
for (item in this.Steps_.collection) {
// eslint guard-for-in.
if (this.Steps_.collection.hasOwnProperty(item)) {
stepItem = this.Steps_.collection[item];
hasRequired = !stepItem.isOptional && stepItem.state !== this.StepState_.COMPLETED;
if (hasRequired) break;
}
}
stepperCompleted = !hasRequired;
}
if (stepperCompleted) {
this.dispatchEventOnStepperComplete_();
}
return true;
};
/**
* Change to "completed" the state of all steps previous the "active"
* except the optionals.
* @return {undefined}
* @private
*/
MaterialStepper.prototype.updateLinearStates_ = function () {
/** @type {number} */
var i;
for (i = 0; i < this.Steps_.total; i++) {
if (this.Steps_.collection[i].isActive) {
break;
} else {
if (this.Steps_.collection[i].isOptional) continue;
this.updateStepState_(this.Steps_.collection[i], this.StepState_.COMPLETED);
}
}
};
/**
* Move "active" to the previous step. This operation can returns false
* if it does not regress the step.
* @return {boolean}
*/
MaterialStepper.prototype.back = function () {
/** @type {boolean} */
var moved;
/** @type {function} */
var moveStep;
/** @type {string} */
var model;
/** @type {MaterialStepper.Steps_.collection<step>} */
var step;
/** @type {MaterialStepper.Steps_.collection<step>} */
var previous;
moved = false;
moveStep = function moveStep(step) {
/** @type {boolean} */
var stepActivated;
stepActivated = this.setActive_(step.id);
if (stepActivated) {
if (stepActivated && this.Stepper_.hasFeedback) {
// Remove the (feedback) transient effect before move.
this.removeTransientEffect_(step);
}
}
return stepActivated;
};
for (model in this.Steps_.collection) {
// Rule eslint guard-for-in.
if (this.Steps_.collection.hasOwnProperty(model)) {
step = this.Steps_.collection[model];
if (step.isActive) {
previous = this.Steps_.collection[step.id - 2];
if (!previous) return false;
if (this.Stepper_.isLinear) {
if (previous.isEditable) {
moved = moveStep.bind(this)(previous);
}
} else {
moved = moveStep.bind(this)(previous);
}
break;
}
}
}
return moved;
};
/**
* Move "active" to the next if the current step is optional. This operation can returns false
* if it does not advances the step.
* @return {boolean}
*/
MaterialStepper.prototype.skip = function () {
/** @type {boolean} */
var moved;
/** @type {string} */
var model;
/** @type {MaterialStepper.Steps_.collection<step>} */
var step;
moved = false;
for (model in this.Steps_.collection) {
// Rule eslint guard-for-in.
if (this.Steps_.collection.hasOwnProperty(model)) {
step = this.Steps_.collection[model];
if (step.isActive) {
if (step.isOptional) {
moved = this.setActive_(step.id + 1);
if (moved && this.Stepper_.hasFeedback) {
// Remove the (feedback) transient effect before move
this.removeTransientEffect_(step);
}
}
break;
}
}
}
return moved;
};
/**
* Move "active" to specified step id.
* This operation is similar to the MaterialStepper.setActive_(<number>).
* @param {number} id Unique number for step.
* @return {boolean}
*/
MaterialStepper.prototype.goto = function (id) {
return this.setActive_(id);
};
/**
* Defines the current state of step to "error" and display
* an alert message instead of default title message.
* @param {string} message The text content to show with error state.
* @return {undefined}
*/
MaterialStepper.prototype.error = function (message) {
/** @type {string} */
var model;
/** @type {MaterialStepper.Steps_.collection<step>} */
var step;
for (model in this.Steps_.collection) {
// Rule eslint guard-for-in.
if (this.Steps_.collection.hasOwnProperty(model)) {
step = this.Steps_.collection[model];
if (step.isActive) {
if (this.Stepper_.hasFeedback) {
// Remove the (feedback) transient effect before move.
this.removeTransientEffect_(step);
}
this.updateStepState_(step, this.StepState_.ERROR);
if (message) {
this.updateTitleMessage_(step, message);
}
// Now dispatch on step the custom event "onsteperror".
this.dispatchEventOnStepError_(step);
break;
}
}
}
};
/**
* Defines current step state to "completed" and move active to the next.
* This operation can returns false if it does not advance the step.
* @return {boolean}
*/
MaterialStepper.prototype.next = function () {
/** @type {boolean} */
var moved;
/** @type {MaterialStepper.Steps_.collection<step>} */
var step;
/** @type {number} */
var activate;
/** @type {string} */
var model;
/** @type {string} */
var item;
/** @type {MaterialStepper.Steps_.collection<stepItem>} */
var stepItem;
moved = false;
for (model in this.Steps_.collection) {
// Rule eslint guard-for-in.
if (this.Steps_.collection.hasOwnProperty(model)) {
step = this.Steps_.collection[model];
if (step.isActive) {
activate = step.id + 1;
if (this.Stepper_.hasFeedback) {
// Remove the (feedback) transient effect before move
this.removeTransientEffect_(step);
}
if (step.state === this.StepState_.ERROR) {
// Case the current state of step is "error", update the error message
// to the original title message or just remove it.
if (step.labelTitleMessageText) {
this.updateTitleMessage_(step, step.labelTitleMessageText);
} else {
this.removeTitleMessage_(step);
}
}
if (step.isEditable && this.Stepper_.isLinear) {
// In linear steppers if the current step is editable the stepper needs to find
// the next step without "completed" state
for (item in this.Steps_.collection) {
// Rule eslint guard-for-in.
if (this.Steps_.collection.hasOwnProperty(item)) {
stepItem = this.Steps_.collection[item];
if (stepItem.id > step.id && stepItem.state !== this.StepState_.COMPLETED) {
activate = stepItem.id;
break;
}
}
}
}
moved = this.setActive_(activate);
// Update "manually" the state of current step to "completed" because
// MaterialStepper.setActive_(<number>) can't change the state of non-linears steppers
// and can't change the state of optional or last step in linears steppers.
if (this.Stepper_.isLinear) {
if (step.isOptional || step.id === this.Steps_.total) {
this.updateStepState_(step, this.StepState_.COMPLETED);
}
} else {
this.updateStepState_(step, this.StepState_.COMPLETED);
}
// Now dispatch on step the custom event "onstepcomplete"
this.dispatchEventOnStepComplete_(step);
break;
}
}
}
return moved;
};
/**
* Update the title message or creates a new if it not exists.
* @param {MaterialStepper.Steps_.collection<step>} step The step of label to be updated.
* @param {string} text The text content to update.
* @return {undefined}
*/
MaterialStepper.prototype.updateTitleMessage_ = function (step, text) {
/** @type {HTMLElement | null} */
var titleMessage;
titleMessage = step.container.querySelector('.' + this.CssClasses_.STEP_TITLE_MESSAGE);
if (!titleMessage) {
titleMessage = document.createElement('span');
titleMessage.classList.add(this.CssClasses_.STEP_TITLE_MESSAGE);
step.labelTitle.appendChild(titleMessage);
}
titleMessage.textContent = text;
};
/**
* Remove the title message if it exists.
* @param {MaterialStepper.Steps_.collection<step>} step The step to remove title message.
* @return {undefined}
*/
MaterialStepper.prototype.removeTitleMessage_ = function (step) {
/** @type {HTMLElement | null} */
var titleMessage;
titleMessage = step.container.querySelector('.' + this.CssClasses_.STEP_TITLE_MESSAGE);
if (titleMessage) {
titleMessage.parentNode.removeChild(titleMessage);
}
};
/**
* Remove (feedback) transient effect and applied to the step.
* @param {MaterialStepper.Steps_.collection<step>} step The step to remove effect.
* @return {boolean}
*/
MaterialStepper.prototype.removeTransientEffect_ = function (step) {
/** @type {HTMLElement | null} */
var transient;
transient = step.content.querySelector('.' + this.CssClasses_.TRANSIENT);
if (!transient) return false;
step.container.classList.remove(this.CssClasses_.STEP_TRANSIENT);
step.content.removeChild(transient);
return true;
};
/**
* Create (feedback) transient effect and apply to the current step.
* @param {MaterialStepper.Steps_.collection<step>} step The step to add effect.
* @return {boolean}
*/
MaterialStepper.prototype.addTransientEffect_ = function (step) {
/** @type {HTMLElement} */
var transient;
/** @type {HTMLElement} */
var overlay;
/** @type {HTMLElement} */
var loader;
/** @type {HTMLElement} */
var spinner;
if (step.content.querySelector('.' + this.CssClasses_.TRANSIENT)) return false;
transient = document.createElement('div');
overlay = document.createElement('div');
loader = document.createElement('div');
spinner = document.createElement('div');
transient.classList.add(this.CssClasses_.TRANSIENT);
overlay.classList.add(this.CssClasses_.TRANSIENT_OVERLAY);
loader.classList.add(this.CssClasses_.TRANSIENT_LOADER);
spinner.classList.add(this.CssClasses_.SPINNER);
spinner.classList.add(this.CssClasses_.SPINNER_JS);
spinner.classList.add(this.CssClasses_.SPINNER_IS_ACTIVE);
loader.appendChild(spinner);
transient.appendChild(overlay);
transient.appendChild(loader);
step.container.classList.add(this.CssClasses_.STEP_TRANSIENT);
step.content.appendChild(transient);
// Assume componentHandler is available in the global scope.
componentHandler.upgradeDom();
return true;
};
/**
* Add event listener to linear, non-linear steppers and dispatch the custom events.
* @return {undefined}
*/
MaterialStepper.prototype.setCustomEvents_ = function () {
/** @type {function} */
var linearLabels;
/** @type {function} */
var nonLinearLabels;
/** @type {function} */
var dispatchCustomEvents;
linearLabels = function linearLabels(step) {
// We know that editable steps can be activated by click on label case it's completed
if (step.isEditable) {
step.label.addEventListener('click', function (event) {
event.preventDefault();
if (step.state === this.StepState_.COMPLETED) {
this.setStepActive_(step);
}
}.bind(this));
}
};
nonLinearLabels = function nonLinearLabels(step) {
step.label.addEventListener('click', function (event) {
event.preventDefault();
this.setStepActive_(step);
}.bind(this));
};
dispatchCustomEvents = function dispatchCustomEvents(step) {
this.dispatchEventOnStepNext_(step);
this.dispatchEventOnStepCancel_(step);
this.dispatchEventOnStepSkip_(step);
this.dispatchEventOnStepBack_(step);
};
if (this.Stepper_.isLinear) {
this.Steps_.collection.forEach(linearLabels.bind(this));
} else {
this.Steps_.collection.forEach(nonLinearLabels.bind(this));
}
this.Steps_.collection.forEach(dispatchCustomEvents.bind(this));
};
/**
* Dispatch "onstepcomplete" event on step when method stepper.next() is invoked to the
* current and return true. Or just when the active step change your state to "completed".
* @param {MaterialStepper.Steps_.collection<step>} step The step to dispatch event.
* @return {undefined}
*/
MaterialStepper.prototype.dispatchEventOnStepComplete_ = function (step) {
step.container.dispatchEvent(this.CustomEvents_.onstepcomplete);
};
/**
* Dispatch "onsteperror" event on step when method stepper.error('Your alert message')
* is invoked to the current step and return true. Or just when the active step
* change your state to "error".
* @param {MaterialStepper.Steps_.collection<step>} step The step to dispatch event.
* @return {undefined}
*/
MaterialStepper.prototype.dispatchEventOnStepError_ = function (step) {
step.container.dispatchEvent(this.CustomEvents_.onsteperror);
};
/**
* Dispatch "onsteppercomplete" event on stepper when all steps are completed.
* If there is optionals steps, they will be ignored.
* @return {undefined}
*/
MaterialStepper.prototype.dispatchEventOnStepperComplete_ = function () {
this.element_.dispatchEvent(this.CustomEvents_.onsteppercomplete);
};
/**
* Dispatch "onstepnext" event on step when the step action button/link with
* [data-stepper-next] attribute is clicked.
* @param {MaterialStepper.Steps_.collection<step>} step The step to dispatch event.
* @return {boolean}
*/
MaterialStepper.prototype.dispatchEventOnStepNext_ = function (step) {
if (!step.actionsNext) return false;
step.actionsNext.addEventListener('click', function () {
if (this.Stepper_.hasFeedback) {
this.addTransientEffect_(step);
}
step.container.dispatchEvent(this.CustomEvents_.onstepnext);
}.bind(this));
return true;
};
/**
* Dispatch "onstepcancel" event on step when the step action button/link with
* [data-stepper-cancel] attribute is clicked.
* @param {MaterialStepper.Steps_.collection<step>} step The step to dispatch event.
* @return {boolean}
*/
MaterialStepper.prototype.dispatchEventOnStepCancel_ = function (step) {
if (!step.actionsCancel) return false;
step.actionsCancel.addEventListener('click', function (event) {
event.preventDefault();
step.container.dispatchEvent(this.CustomEvents_.onstepcancel);
}.bind(this));
return true;
};
/**
* Dispatch "onstepskip" event on step when the step action button/link with
* [data-stepper-skip] attribute is clicked.
* @param {MaterialStepper.Steps_.collection<step>} step The step to dispatch event.
* @return {boolean}
*/
MaterialStepper.prototype.dispatchEventOnStepSkip_ = function (step) {
if (!step.actionsSkip) return false;
step.actionsSkip.addEventListener('click', function (event) {
event.preventDefault();
step.container.dispatchEvent(this.CustomEvents_.onstepskip);
}.bind(this));
return true;
};
/**
* Dispatch "onstepback" event on step when the step action button/link with
* [data-stepper-back] attribute is clicked.
* @param {MaterialStepper.Steps_.collection<step>} step The step to dispatch event.
* @return {boolean}
*/
MaterialStepper.prototype.dispatchEventOnStepBack_ = function (step) {
if (!step.actionsBack) return false;
step.actionsBack.addEventListener('click', function (event) {
event.preventDefault();
step.container.dispatchEvent(this.CustomEvents_.onstepback);
}.bind(this));
return true;
};
/**
* Check if has some active transient effect on steps.
* @return {boolean}
*/
MaterialStepper.prototype.hasTransient = function () {
/** @type {string} */
var cssClasseStep;
/** @type {string} */
var cssClasseStepContent;
/** @type {string} */
var cssClasseTransient;
/** @type {string} */
var selectorTransient;
/** @type {HTMLElement | null} */
var transient;
cssClasseStep = '.' + this.CssClasses_.STEP;
cssClasseStepContent = '.' + this.CssClasses_.STEP_CONTENT;
cssClasseTransient = '.' + this.CssClasses_.TRANSIENT;
selectorTransient = cssClasseStep + ' > ' + cssClasseStepContent + ' > ' + cssClasseTransient;
transient = this.element_.querySelector(selectorTransient);
return transient !== null;
};
/**
* Initialize the instance.
* @return {undefined}
* @public
*/
MaterialStepper.prototype.init = function () {
// Check if stepper element exists.
if (this.element_) {
this.Stepper_ = this.getStepper_();
this.Steps_ = this.getSteps_();
this.setActive_();
this.setCustomEvents_();
}
};
// The component registers itself. It can assume componentHandler is available
// in the global scope.
componentHandler.register({
constructor: MaterialStepper,
classAsString: 'MaterialStepper',
cssClass: 'mdl-stepper',
widget: true
});
})();
/***/ }
/******/ ]);