@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
1,065 lines (867 loc) • 33.5 kB
JavaScript
import './kendo.core.js';
import './kendo.progressbar.js';
import './kendo.icons.js';
import './kendo.licensing.js';
import '@progress/kendo-licensing';
import './kendo.html.icon.js';
import './kendo.html.base.js';
import '@progress/kendo-svg-icons';
const __meta__ = {
id: "stepper",
name: "Stepper",
category: "web",
description: "The Stepper widget displays navigation steps.",
depends: [ "core", "progressbar", "icons" ]
};
(function($, undefined$1) {
var kendo = window.kendo,
Widget = kendo.ui.Widget,
keys = kendo.keys,
extend = $.extend,
encode = kendo.htmlEncode,
STEPPER = ".kendoStepper",
CLICK = "click",
ACTIVATE = "activate",
SELECT = "select",
KEYDOWN = "keydown",
FOCUSOUT = "focusout",
DOT = ".",
SPACE = " ",
VERTICAL = "vertical",
TABINDEX = "tabindex",
ARIA_CURRENT = "aria-current",
ARIA_DISABLED = "aria-disabled",
ARIA_INVALID = "aria-invalid",
ARIA_HIDDEN = "aria-hidden";
var stepStyles = {
step: "k-step",
firstStep: "k-step-first",
lastStep: "k-step-last",
doneStep: "k-step-done",
successStep: "k-step-success",
errorStep: "k-step-error",
currentStep: "k-step-current",
focusStep: "k-focus",
disabledStep: "k-disabled",
stepLink: "k-step-link",
stepIndicator: "k-step-indicator"};
var stepperStyles = {
widget: "k-stepper",
stepperLinear: "k-stepper-linear",
stepList: "k-step-list",
stepListHorizontal: "k-step-list-horizontal",
stepListVertical: "k-step-list-vertical"
};
var Step = kendo.Class.extend({
init: function(options) {
this.options = extend({}, this.options, options);
this._render();
},
options: {
label: "",
icon: "",
successIcon: "",
iconTemplate: null,
enabled: true,
error: false,
selected: false,
isFirstStep: false,
isLastStep: false,
indicatorVisible: true,
labelVisible: true,
index: 0,
previous: false,
selectable: true
},
_indicatorTemplate: ({ successIcon, index, icon, previous, error }) => {
let indicatorContent;
if (successIcon && previous && !error) {
indicatorContent = kendo.ui.icon({ icon: encode(successIcon), iconClass: "k-step-indicator-icon" });
} else if (icon) {
indicatorContent = kendo.ui.icon({ icon: encode(icon), iconClass: "k-step-indicator-icon" });
} else if (previous && !error) {
indicatorContent = kendo.ui.icon({ icon: "check", iconClass: "k-step-indicator-icon" });
} else {
indicatorContent = `<span class="k-step-indicator-text">${encode(index + 1)}</span>`;
}
return '<span class="k-step-indicator" aria-hidden="true">' + indicatorContent + '</span>';
},
_labelTemplate: ({ label, indicatorVisible, previous, error }) =>
'<span class="k-step-label">' +
'<span class="k-step-text">' +
encode(label) +
'</span>' +
' ' +
((error || (!indicatorVisible && !error && previous)) ?
kendo.ui.icon($('<span aria-hidden="true"></span>'), {
icon: error ? "warning-circle" : "check-circle"
})
: '') +
'</span>',
deselect: function() {
this.options.selected = false;
this._link();
this._stepClasses();
},
enable: function(value) {
if (this.options.enabled !== value) {
this.options.enabled = value;
this.options.selectable = value;
this._link();
this._stepClasses();
}
},
select: function() {
this.options.selected = true;
this._link();
this._stepClasses();
},
getEnabled: function() {
return this.options.enabled;
},
getIndex: function() {
return this.options.index;
},
setPrevious: function(previous) {
this.options.previous = previous;
this._link();
this._stepClasses();
},
getSelectable: function() {
return this.options.selectable;
},
getSelected: function() {
return this.options.selected;
},
setValid: function(valid) {
if (this.options.error === valid) {
this.options.error = !valid;
this._link();
this._stepClasses();
}
},
_indicator: function() {
var options = this.options,
stepIndicator;
if (!!options.iconTemplate) {
stepIndicator = $("<span>").addClass(stepStyles.stepIndicator).attr(ARIA_HIDDEN, "true");
stepIndicator.append(kendo.template(options.iconTemplate)(options));
} else {
stepIndicator = kendo.template(this._indicatorTemplate)(options);
}
this.element.find(DOT + stepStyles.stepLink).append(stepIndicator);
},
_label: function() {
var stepLabel = kendo.template(this._labelTemplate)(this.options);
this.element.find(DOT + stepStyles.stepLink).append(stepLabel);
},
_link: function() {
var options = this.options;
this.element.find(DOT + stepStyles.stepLink).empty();
this._linkAttributes();
if (options.indicatorVisible) {
this._indicator();
}
if (options.labelVisible) {
this._label();
}
},
_linkAttributes: function() {
var options = this.options,
link = this.element.find(DOT + stepStyles.stepLink);
link.removeAttr(ARIA_DISABLED + SPACE + ARIA_INVALID + SPACE + ARIA_CURRENT + SPACE + TABINDEX);
if (!options.selected) {
link.attr(TABINDEX, "-1");
} else {
link.attr(ARIA_CURRENT, "step");
}
if (!options.enabled || !options.selectable) {
link.attr(ARIA_DISABLED, "true");
}
if (options.error) {
link.attr(ARIA_INVALID, "true");
}
},
_render: function() {
var stepLink = $("<a href='#'>").addClass(stepStyles.stepLink).attr("title", this.options.label);
this.element = $("<li>").append(stepLink);
this._link();
this._stepClasses();
},
_stepClasses: function() {
var options = this.options,
stepClasses = stepStyles.step;
if (options.isFirstStep) {
stepClasses += (SPACE + stepStyles.firstStep);
}
if (options.isLastStep) {
stepClasses += (SPACE + stepStyles.lastStep);
}
if (!options.enabled) {
stepClasses += (SPACE + stepStyles.disabledStep);
}
if (options.error) {
stepClasses += (SPACE + stepStyles.errorStep);
}
if (options.previous) {
stepClasses += (SPACE + stepStyles.doneStep);
if (!options.error) {
stepClasses += (SPACE + stepStyles.successStep);
}
} else if (options.selected) {
stepClasses += (SPACE + stepStyles.currentStep);
stepClasses += (SPACE + stepStyles.focusStep);
}
this.element.removeClass().addClass(stepClasses);
}
});
var Stepper = Widget.extend({
init: function(element, options) {
var that = this;
options = options || {};
Widget.fn.init.call(that, element, options);
that._indicatorAndLabel();
that._wrapper();
if (options.steps && options.steps.length) {
that._processSteps(options.steps);
that._progressBar();
}
that._attachEvents();
that._resizeHandler = kendo.onResize(function() {
that.resize();
});
},
options: {
orientation: "horizontal",
linear: true,
indicator: true,
label: true,
selectOnFocus: false,
steps: null,
name: "Stepper"
},
events: [ ACTIVATE, SELECT, "kendoKeydown" ],
destroy: function() {
var that = this;
if (that.progressBar) {
Widget.fn.destroy.call(that.progressBar);
}
Widget.fn.destroy.call(that);
kendo.unbindResize(that._resizeHandler);
that.wrapper.off(STEPPER);
},
setOptions: function(options) {
var that = this;
Widget.fn.setOptions.call(that, options);
if (that.progressBar) {
Widget.fn.destroy.call(that.progressBar);
}
that._indicatorAndLabel();
that._addStepList();
if (that.options.steps && that.options.steps.length) {
that._processSteps(that.options.steps);
that._progressBar();
}
},
enable: function(value) {
var steps = this.steps(),
stepsOptions = this.options.steps;
var enableStep = function(step, idx) {
step.enable(value);
stepsOptions[idx] = step.options;
};
if (value) {
this.wrapper.removeAttr(ARIA_DISABLED);
} else {
this.wrapper.attr(ARIA_DISABLED, "true");
}
this.progressBar.enable(value);
steps.forEach(enableStep);
},
insertAt: function(index, stepOptions) {
var steps = this.options.steps,
selectedStep;
var findSelectedStep = function(step) {
if (step.selected) {
selectedStep = step;
}
};
if (!stepOptions || isNaN(index)) {
return;
}
if (index < 0) {
index = steps.length + index;
}
if (index < 0) {
return;
}
if (!steps) {
steps = [];
}
if (steps.length === 0 || index >= steps.length) {
index = steps.length;
}
steps.forEach(findSelectedStep);
if (stepOptions.selected === true) {
selectedStep.selected = false;
}
steps.splice(index, 0, stepOptions);
this._createSteps();
this._renderSteps();
this._resetProgressBar();
this._calculateDimensions();
},
next: function() {
if (!this._steps || this._steps.length <= 1) {
return;
}
var selectedStep = this.selectedStep;
var selectedIndex = selectedStep.getIndex();
if (selectedIndex + 1 === this._steps.length) {
return;
} else {
this._select(selectedIndex + 1);
}
},
previous: function() {
if (!this._steps || this._steps.length <= 1) {
return;
}
var selectedStep = this.selectedStep;
var selectedIndex = selectedStep.getIndex();
if (selectedIndex === 0) {
return;
} else {
this._select(selectedIndex - 1);
}
},
removeAt: function(index) {
var steps = this.options.steps,
removedStep, newSelected, newSelectedIndex;
if (isNaN(index) || !steps || steps.length < 2 || index >= steps.length) {
return;
}
if (index < 0) {
index = steps.length + index;
}
if (index < 0) {
return;
}
removedStep = steps.splice(index, 1)[0];
if (removedStep.selected === true && steps.length > 0) {
if (index > 0) {
newSelectedIndex = index - 1;
} else {
newSelectedIndex = 0;
}
newSelected = steps[newSelectedIndex];
if (typeof newSelected === "string") {
newSelected = {
label: newSelected
};
steps[newSelectedIndex] = newSelected;
}
newSelected.selected = true;
newSelected.previous = false;
}
this._createSteps();
this._renderSteps();
this._resetProgressBar();
this._calculateDimensions();
},
resize: function() {
this._calculateDimensions();
},
select: function(stepIndex) {
var that = this;
if (stepIndex === undefined$1 || stepIndex === null || isNaN(stepIndex)) {
return that.selectedStep;
}
if (stepIndex >= that._steps.length || stepIndex < 0) {
return;
}
stepIndex = Number(stepIndex);
that._select(stepIndex);
},
steps: function(steps) {
if (steps === undefined$1) {
return this._steps;
}
this._processSteps(steps);
this._resetProgressBar();
this._calculateDimensions();
},
_processSteps: function(steps) {
var that = this,
selectedStep;
var findSelectedStep = function(step) {
if (step.selected) {
selectedStep = step;
}
};
steps.forEach(findSelectedStep);
if (!selectedStep) {
if (typeof steps[0] === "string") {
steps[0] = {
label: steps[0]
};
}
steps[0].selected = true;
}
that.options.steps = steps;
that._createSteps();
that._renderSteps();
},
_addStepList: function() {
var that = this;
that.wrapper.empty().append($("<ol />").addClass(stepperStyles.stepList));
that._stepList = that.wrapper.find(DOT + stepperStyles.stepList);
if (that.options.orientation === VERTICAL) {
that._stepList.addClass(stepperStyles.stepListVertical);
} else {
that._stepList.addClass(stepperStyles.stepListHorizontal);
}
},
_attachEvents: function() {
var that = this;
that.wrapper
.on(CLICK + STEPPER, DOT + stepStyles.step, that._selectClickHandler.bind(that))
.on(CLICK + STEPPER, that._wrapperClickHandler.bind(that))
.on(FOCUSOUT + STEPPER, that._focusout.bind(that))
.on(KEYDOWN + STEPPER, that, that._keydown.bind(that));
},
_calculateDimensions: function() {
if (!this._steps) {
return;
}
var orientation = this.options.orientation,
numberOfSteps = this._steps.length,
stepList = this._stepList,
steps = stepList.find(DOT + stepStyles.step),
stepWidth = stepList.width() / numberOfSteps,
stepHeight = stepList.height() / numberOfSteps,
progressElement = this.progressBar.element,
margin = "margin-left",
style = {};
if (orientation === VERTICAL) {
steps.css("max-height", 100 / numberOfSteps + "%");
progressElement.css({
"margin-top": -1 * (stepList.height() - 16),
"height": stepHeight * (numberOfSteps - 1)
});
} else {
steps.css("max-width", 100 / numberOfSteps + "%");
if (kendo.support.isRtl(this.wrapper)) {
margin = "margin-right";
}
style[margin] = stepWidth / 2;
style.width = stepWidth * (numberOfSteps - 1);
progressElement.css(style);
}
},
_createStep: function(stepOptions, idx, isLastStep) {
var that = this,
isFirstStep = idx === 0,
options = that.options,
indicatorVisible = options.indicator,
labelVisible = options.label;
stepOptions = extend({}, stepOptions, {
enabled: stepOptions.enabled === false ? false : true
});
stepOptions = extend({}, stepOptions, {
isFirstStep: isFirstStep,
isLastStep: isLastStep,
indicatorVisible: indicatorVisible,
labelVisible: labelVisible,
index: idx
});
return new Step(stepOptions);
},
_createSteps: function() {
var that = this,
stepsOptions = that.options.steps,
selected = false,
step, idx, isLastStep, stepOpt;
that._steps = [];
for (idx = 0; idx < stepsOptions.length; idx++) {
stepOpt = stepsOptions[idx];
if (typeof stepOpt === "string") {
stepOpt = {
label: stepOpt
};
}
if (stepOpt !== undefined$1) {
isLastStep = idx === stepsOptions.length - 1;
if (stepOpt.selected) {
selected = true;
} else {
stepOpt = that._selectablePreviousState(stepOpt, selected, idx);
}
step = that._createStep(stepOpt, idx, isLastStep);
that._steps.push(step);
if (step.getSelected()) {
that.selectedStep = step;
}
}
}
},
_indicatorAndLabel: function() {
if (!this.options.indicator && !this.options.label) {
this.options.indicator = true;
this.options.label = true;
}
},
_focusout: function(e) {
var that = this;
if (!that.wrapper.get(0).contains(e.relatedTarget)) {
setTimeout(function() {
that._leaveStepper();
});
}
},
_focusStep: function(newStep) {
var focusedStep = this.wrapper.find(DOT + stepStyles.focusStep),
allStepLinks = this.wrapper.find(DOT + stepStyles.stepLink);
if (newStep.length > 0) {
focusedStep.removeClass(stepStyles.focusStep);
allStepLinks.attr(TABINDEX, "-1");
newStep.find(DOT + stepStyles.stepLink).removeAttr(TABINDEX)[0].focus();
}
},
_focusNextStep: function() {
var focusedStep = $(document.activeElement).closest(DOT + stepStyles.step),
nextStep = focusedStep.next();
this._focusStep(nextStep);
},
_focusPreviousStep: function() {
var focusedStep = $(document.activeElement).closest(DOT + stepStyles.step),
previousStep = focusedStep.prev();
this._focusStep(previousStep);
},
_focusFirstStep: function() {
var wrapper = this.wrapper,
firstStep = wrapper.find(DOT + stepStyles.firstStep);
this._focusStep(firstStep);
},
_focusLastStep: function() {
var wrapper = this.wrapper,
lastStep = wrapper.find(DOT + stepStyles.lastStep);
this._focusStep(lastStep);
},
_keydown: function(e) {
var that = this,
keyCode = e.keyCode,
focusedStepElement = $(document.activeElement).closest(DOT + stepStyles.step),
focusedStepIndex = focusedStepElement.index(),
stepsCount = that.steps().length;
if (keyCode === keys.TAB) {
if (e.shiftKey && focusedStepIndex > 0) {
e.preventDefault();
that._tabKey(e, -1);
} else if (!e.shiftKey && focusedStepIndex < stepsCount - 1) {
e.preventDefault();
that._tabKey(e, 1);
}
} else if (keyCode > 34 && keyCode < 41) {
e.preventDefault();
that._navKeys(e);
} else if (keyCode === keys.ENTER || keyCode === keys.SPACEBAR) {
e.preventDefault();
that._selectHandler(e, $(document.activeElement).closest(DOT + stepStyles.step));
} else {
e.preventDefault();
}
},
_leaveStepper: function() {
var selectedStep = this.wrapper.find(DOT + stepStyles.currentStep),
allStepLinks = this.wrapper.find(DOT + stepStyles.stepLink);
allStepLinks.removeClass(stepStyles.focusStep).attr(TABINDEX, "-1");
selectedStep.addClass(stepStyles.focusStep);
selectedStep.find(DOT + stepStyles.stepLink).removeAttr(TABINDEX);
},
_navKeys: function(e) {
var selectOnFocus = this.options.selectOnFocus;
if (selectOnFocus) {
this._navKeysSelect(e);
} else {
this._navKeysFocus(e);
}
},
_navKeysFocus: function(e) {
var keyCode = e.keyCode,
rtl = kendo.support.isRtl(this.wrapper),
orientation = this.options.orientation;
switch (keyCode) {
case keys.DOWN:
if (rtl && orientation !== VERTICAL) {
this._focusPreviousStep();
} else {
this._focusNextStep();
}
break;
case keys.RIGHT:
if (rtl) {
this._focusPreviousStep();
} else {
this._focusNextStep();
}
break;
case keys.UP:
if (rtl && orientation !== VERTICAL) {
this._focusNextStep();
} else {
this._focusPreviousStep();
}
break;
case keys.LEFT:
if (rtl) {
this._focusNextStep();
} else {
this._focusPreviousStep();
}
break;
case keys.HOME:
this._focusFirstStep();
break;
case keys.END:
this._focusLastStep();
break;
}
},
_navKeysSelect: function(e) {
var keyCode = e.keyCode,
focusedStepIndex = $(document.activeElement).closest(DOT + stepStyles.step).index(),
rtl = kendo.support.isRtl(this.wrapper),
steps = this.steps(),
orientation = this.options.orientation,
targetStep;
switch (keyCode) {
case keys.DOWN:
if (rtl && orientation !== VERTICAL) {
targetStep = steps[focusedStepIndex - 1];
} else {
targetStep = steps[focusedStepIndex + 1];
}
break;
case keys.RIGHT:
if (rtl) {
targetStep = steps[focusedStepIndex - 1];
} else {
targetStep = steps[focusedStepIndex + 1];
}
break;
case keys.UP:
if (rtl && orientation !== VERTICAL) {
targetStep = steps[focusedStepIndex + 1];
} else {
targetStep = steps[focusedStepIndex - 1];
}
break;
case keys.LEFT:
if (rtl) {
targetStep = steps[focusedStepIndex + 1];
} else {
targetStep = steps[focusedStepIndex - 1];
}
break;
case keys.HOME:
targetStep = steps[0];
break;
case keys.END:
targetStep = steps[steps.length - 1];
break;
}
if (targetStep) {
this._focusStep(targetStep.element);
this._selectHandlerOnKey(e, targetStep.element);
}
},
_progressBar: function() {
var wrapper = this.wrapper,
progressBarOptions = this._progressOptions();
this.progressBar = $("<div>").kendoProgressBar(progressBarOptions).getKendoProgressBar();
// TODO: for 2021 R2 the following line must be removed!
this.progressBar.element.css("position", "absolute");
this._calculateDimensions();
wrapper.append(this.progressBar.element);
},
_progressOptions: function() {
var options = this.options,
orientation = options.orientation,
stepsOptions = options.steps,
numberOfSteps, progressBarOptions;
if (!stepsOptions || stepsOptions.length === 0) {
return;
} else {
numberOfSteps = stepsOptions.length;
}
progressBarOptions = {
max: numberOfSteps - 1,
value: this.select().getIndex(),
orientation: orientation,
showStatus: false
};
if (orientation === VERTICAL) {
progressBarOptions.reverse = true;
}
return progressBarOptions;
},
_resetProgressBar: function() {
var progressBar = this.progressBar,
newOptions;
if (!progressBar) {
return;
}
newOptions = this._progressOptions();
progressBar.setOptions(newOptions);
},
_renderSteps: function() {
var steps = this._steps,
stepsList = this._stepList,
step, idx;
stepsList.empty();
for (idx = 0; idx < steps.length; idx++) {
step = steps[idx];
stepsList.append(step.element);
}
},
_resetStep: function(i, index, forward) {
var step = this._steps[i];
if (i === index) {
step.options.previous = false;
step.options.selected = true;
} else if ((forward || i > index) && (!forward || i < index)) {
step.options.selected = false;
step.options.previous = forward;
}
if (this.options.linear && (i < index - 1 || i > index + 1)) {
step.options.selectable = false;
} else {
step.options.selectable = true;
}
step._link();
step._stepClasses();
this.options.steps[i] = step.options;
},
_select: function(index) {
var options = this.options,
linear = options.linear,
selectedStep = this.select(),
selectedIndex = selectedStep.getIndex(),
stepsOptions = options.steps,
targetStep = this._steps[index],
forward, i, min, max;
if (!targetStep || !targetStep.getEnabled()) {
return;
}
if (index > selectedIndex) {
forward = true;
if (linear) {
min = Math.max(selectedIndex - 1, 0);
max = Math.min(index + 1, stepsOptions.length - 1);
} else {
min = selectedIndex;
max = index;
}
} else {
forward = false;
if (linear) {
min = Math.max(index - 1, 0);
max = Math.min(selectedIndex + 1, stepsOptions.length - 1);
} else {
min = index;
max = selectedIndex;
}
}
for (i = min; i <= max; i ++) {
this._resetStep(i, index, forward);
}
this.selectedStep = targetStep;
this.progressBar.value(index);
},
_selectablePreviousState: function(stepOpt, selected, idx) {
var stepsOptions = this.options.steps,
linear = this.options.linear;
if (!selected) {
stepOpt.previous = true;
if (linear && !stepsOptions[idx + 1].selected) {
stepOpt.selectable = false;
} else {
stepOpt.selectable = true;
}
} else if (linear && !stepsOptions[idx - 1].selected) {
stepOpt.selectable = false;
} else {
stepOpt.selectable = true;
}
return stepOpt;
},
_selectClickHandler: function(e) {
var stepElement = $(e.target).closest(DOT + stepStyles.step);
e.preventDefault();
this._preventWrapperClick = true;
this._selectHandler(e, stepElement);
},
_selectHandler: function(e, stepElement) {
var that = this,
step = that._steps[stepElement.index()],
currentStep = this.select();
if (!step || step.getIndex() === currentStep.getIndex() || !step.getEnabled() || !step.getSelectable()) {
that._focusStep(currentStep.element);
return;
}
if (!that.trigger(SELECT, { sender: that, originalEvent: e, step: step })) {
that._select(step.getIndex());
stepElement.find(DOT + stepStyles.stepLink)[0].focus();
that.trigger(ACTIVATE, { sender: that, originalEvent: e, step: step });
}
},
_selectHandlerOnKey: function(e, stepElement) {
var that = this,
step = that._steps[stepElement.index()];
if (!step.getEnabled() || !step.getSelectable()) {
return;
}
if (!that.trigger(SELECT, { sender: that, originalEvent: e, step: step })) {
that._select(step.getIndex());
stepElement.find(DOT + stepStyles.stepLink)[0].focus();
that.trigger(ACTIVATE, { sender: that, originalEvent: e, step: step });
}
},
_tabKey: function(e, shift) {
var selectOnFocus = this.options.selectOnFocus,
focusedStepElement = $(document.activeElement).closest(DOT + stepStyles.step),
focusedStepIndex = focusedStepElement.index(),
targetStep = $(focusedStepElement.parent().find(DOT + stepStyles.step)[focusedStepIndex + shift]);
this._focusStep(targetStep);
if (selectOnFocus) {
this._selectHandlerOnKey(e, targetStep);
}
},
_wrapper: function() {
var that = this,
element = that.element;
that.wrapper = element;
that.wrapper.addClass(stepperStyles.widget);
if (that.options.linear) {
that.wrapper.addClass(stepperStyles.stepperLinear);
}
this._addStepList();
},
_wrapperClickHandler: function(e) {
var currentStep = this.select();
if (!this._preventWrapperClick) {
e.preventDefault();
this._focusStep(currentStep.element);
} else {
this._preventWrapperClick = false;
}
}
});
kendo.stepper = {
Step: Step
};
kendo.ui.plugin(Stepper);
})(window.kendo.jQuery);
var kendo$1 = kendo;
export { __meta__, kendo$1 as default };