/** * jWizard: a jQuery UI Wizard Widget * * @author Dominic Barnes * @version <%= pkg.version %> */ (function ($, undefined) { /** * jWizard: a jQuery UI Wizard Widget * * @author Dominic Barnes * @version {{VERSION}} * * @required jQuery * @required jQuery UI Widget Factory * @required jQuery UI Button * @optional jQuery UI ProgressBar * @required jQuery UI Menu */ $.widget("db.jWizard", { $steps: null, // all steps $current: null, // current/active step widgetEventPrefix: "wizard", _create: function () { var o = this.options; if (this._super) { this._super(); } else { $.Widget.prototype._create.call(this); } if (o.disabled) this.disable(); this.element.addClass("ui-widget jw-widget"); this._buildSteps(); if (o.title) this._buildTitle(); if (o.menu) this._buildMenu(); this._buildButtons(); if (o.progress) this._buildProgress(); }, destroy: function () { var o = this.options; this.element.removeClass("ui-widget jw-widget jw-hasprogress"); if (o.progress) this._destroyProgress(); this._destroyButtons(); if (o.menu) this._destroyMenu(); if (o.title) this._destroyTitle(); this._destroySteps(); if (this._super) { this._super(); } else { $.Widget.prototype.destroy.call(this); } }, first: function () { return this.step(this.$steps.first()); }, last: function () { return this.step(this.$steps.last()); }, cancel: function () { // TODO: ui data this._trigger("cancel"); }, prev: function () { return this.step(this.$current.prev()); }, next: function () { return this.step(this.$current.next()); }, finish: function () { // TODO: ui data this._trigger("finish"); }, step: function ($step) { var wizard = this, dfd = $.Deferred(); if (typeof $step === "number") { $step = this.$steps.eq($step); } function goback() { wizard._enableButtons(); wizard._enter(wizard.$current).then(dfd.resolve, dfd.reject); } function proceed() { wizard._enableButtons(); dfd.resolve(); } this._disableButtons(); this._leave(this.$current).then(function () { wizard._enter($step).then(proceed, goback); }, goback); return dfd.promise(); }, _leave: function ($step) { var hide = $.Event("stephide"), dfd = $.Deferred(), effect = this.options.effects.steps.hide; function done() { $step.trigger("stephidden"); dfd.resolve(); } if ($step) { $step.trigger(hide); if (hide.isDefaultPrevented()) { dfd.reject(); } else { if (this._hide) { this._hide($step, effect, done); } else { $step.hide(effect, done); } } } else { dfd.resolve(); } return dfd.promise(); }, _enter: function ($step) { var wizard = this, show = $.Event("stepshow"), dfd = $.Deferred(), effect = this.options.effects.steps.show; function done() { wizard.$current = $step; wizard._updateTitle(); wizard._updateMenu(); wizard._updateButtons(); wizard._updateProgress(); $step.trigger("stepshown"); dfd.resolve(); } if ($step) { $step.trigger(show); if (show.isDefaultPrevented()) { dfd.reject(); } else { if (this._show) { this._show($step, effect, done); } else { $step.show(effect, done); } } } else { dfd.resolve(); } return dfd.promise(); }, // Generates .jw-header > .jw-title _buildTitle: function () { if (this.$title) return; this.$title = $('
'); this.$header = $('
') .append(this.$title) .prependTo(this.element); this._updateTitle(); }, // Update .jw-title _updateTitle: function () { var $title = this.$title; if ($title) { $title.text(this.$current.data("jwizard-title")); } }, // Destroy .jw-header _destroyTitle: function () { this.$header.remove(); this.$title = this.$header = null; }, /** * Initializes the step collection. * * Any direct children
(with a title or data-jwizard-title attr) * or
(with a ) are considered steps, and there should * be no other sibling elements. * * Lastly, a
is wrapped around all the steps to * isolate them from the rest of the widget. */ _buildSteps: function () { var $steps = this.$steps = this.element.children(); $steps.addClass("jw-step").each(function () { var $step = $(this), title; if ($step.is("fieldset")) { title = $step.find("legend").text(); } else { title = $step.attr("title"); } if (title) { $step.data("jwizard-title", title); } }); $steps.hide().wrapAll($("
", { "class": "jw-content ui-widget-content ui-helper-clearfix", html: '
' })); this.$current = this.$steps.first().show(); }, /** * Destroys the step wrappers and restores the steps to their original state */ _destroySteps: function () { this.$steps.show() .unwrap().unwrap() // Unwrap 2x: .jw-steps-wrap + .jw-content .removeData("jwizard-title") .removeClass("jw-step"); this.$steps = null; }, /** * Builds the menu based on the collection of steps * Assigns a class to the main
to indicate to CSS that there is a menu * Binds a click event to each of the that will change the step * accordingly when clicked */ _buildMenu: function () { var wizard = this; this.element.addClass("jw-hasmenu"); if (this.$menu) return; this.$menu = $("
    ", { "class": "jw-menu", html: $.map(this.$steps, function (step) { var title = $(step).data("jwizard-title"); return '
  1. ' + title + ''; }).join("") }).menu({ select: function (e, ui) { wizard.step(ui.item.index()); } }); this.$menuWrap = $('
    ') .append(this.$menu) .prependTo(this.element.children(".jw-content")); this._updateMenu(); }, _updateMenu: function () { if (!this.$menu) return; var index = this.$current.index(); this.$menu.children("li") .removeClass("ui-state-highlight ui-state-disabled") .eq(index).addClass("ui-state-highlight").end() .slice(index).addClass("ui-state-disabled"); }, /** * Removes the 'jw-hasmenu' class and pulls the menu out of the DOM entirely */ _destroyMenu: function () { this.element.removeClass("jw-hasmenu"); this.$menu.menu("destroy"); this.$menuWrap.remove(); this.$menu = this.$menuWrap = null; }, _buildProgress: function () { if (this.$progress) return; var options = $.extend({}, this.options.progress), location = options.location, $progress = $("
    ").appendTo(this.element.find(location)); delete options.location; options.max = this.$steps.length; this.element.addClass("jw-hasprogress"); this.$progress = $progress.progressbar(options).addClass("jw-progress"); this._updateProgress(); }, _updateProgress: function () { if (!this.$progress) return; var $current = this.$current, index = $current ? $current.index() : 0; this.$progress.progressbar("value", index); }, _destroyProgress: function () { this.element.removeClass("jw-hasprogress"); this.$progress.progressbar("destroy").remove(); this.$progress = null; }, /** * @private * @description This generates the