steps-rails 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2015 @@
1
+ /*!
2
+ * jQuery Steps v1.0.7 - 05/07/2014
3
+ * Copyright (c) 2014 Rafael Staib (http://www.jquery-steps.com)
4
+ * Licensed under MIT http://www.opensource.org/licenses/MIT
5
+ */
6
+ ;(function ($, undefined)
7
+ {
8
+ $.fn.extend({
9
+ _aria: function (name, value)
10
+ {
11
+ return this.attr("aria-" + name, value);
12
+ },
13
+
14
+ _removeAria: function (name)
15
+ {
16
+ return this.removeAttr("aria-" + name);
17
+ },
18
+
19
+ _enableAria: function (enable)
20
+ {
21
+ return (enable == null || enable) ?
22
+ this.removeClass("disabled")._aria("disabled", "false") :
23
+ this.addClass("disabled")._aria("disabled", "true");
24
+ },
25
+
26
+ _showAria: function (show)
27
+ {
28
+ return (show == null || show) ?
29
+ this.show()._aria("hidden", "false") :
30
+ this.hide()._aria("hidden", "true");
31
+ },
32
+
33
+ _selectAria: function (select)
34
+ {
35
+ return (select == null || select) ?
36
+ this.addClass("current")._aria("selected", "true") :
37
+ this.removeClass("current")._aria("selected", "false");
38
+ },
39
+
40
+ _id: function (id)
41
+ {
42
+ return (id) ? this.attr("id", id) : this.attr("id");
43
+ }
44
+ });
45
+
46
+ if (!String.prototype.format)
47
+ {
48
+ String.prototype.format = function()
49
+ {
50
+ var args = (arguments.length === 1 && $.isArray(arguments[0])) ? arguments[0] : arguments;
51
+ var formattedString = this;
52
+ for (var i = 0; i < args.length; i++)
53
+ {
54
+ var pattern = new RegExp("\\{" + i + "\\}", "gm");
55
+ formattedString = formattedString.replace(pattern, args[i]);
56
+ }
57
+ return formattedString;
58
+ };
59
+ }
60
+
61
+ /**
62
+ * A global unique id count.
63
+ *
64
+ * @static
65
+ * @private
66
+ * @property _uniqueId
67
+ * @type Integer
68
+ **/
69
+ var _uniqueId = 0;
70
+
71
+ /**
72
+ * The plugin prefix for cookies.
73
+ *
74
+ * @final
75
+ * @private
76
+ * @property _cookiePrefix
77
+ * @type String
78
+ **/
79
+ var _cookiePrefix = "jQu3ry_5teps_St@te_";
80
+
81
+ /**
82
+ * Suffix for the unique tab id.
83
+ *
84
+ * @final
85
+ * @private
86
+ * @property _tabSuffix
87
+ * @type String
88
+ * @since 0.9.7
89
+ **/
90
+ var _tabSuffix = "-t-";
91
+
92
+ /**
93
+ * Suffix for the unique tabpanel id.
94
+ *
95
+ * @final
96
+ * @private
97
+ * @property _tabpanelSuffix
98
+ * @type String
99
+ * @since 0.9.7
100
+ **/
101
+ var _tabpanelSuffix = "-p-";
102
+
103
+ /**
104
+ * Suffix for the unique title id.
105
+ *
106
+ * @final
107
+ * @private
108
+ * @property _titleSuffix
109
+ * @type String
110
+ * @since 0.9.7
111
+ **/
112
+ var _titleSuffix = "-h-";
113
+
114
+ /**
115
+ * An error message for an "index out of range" error.
116
+ *
117
+ * @final
118
+ * @private
119
+ * @property _indexOutOfRangeErrorMessage
120
+ * @type String
121
+ **/
122
+ var _indexOutOfRangeErrorMessage = "Index out of range.";
123
+
124
+ /**
125
+ * An error message for an "missing corresponding element" error.
126
+ *
127
+ * @final
128
+ * @private
129
+ * @property _missingCorrespondingElementErrorMessage
130
+ * @type String
131
+ **/
132
+ var _missingCorrespondingElementErrorMessage = "One or more corresponding step {0} are missing.";
133
+
134
+ /**
135
+ * Adds a step to the cache.
136
+ *
137
+ * @static
138
+ * @private
139
+ * @method addStepToCache
140
+ * @param wizard {Object} A jQuery wizard object
141
+ * @param step {Object} The step object to add
142
+ **/
143
+ function addStepToCache(wizard, step)
144
+ {
145
+ getSteps(wizard).push(step);
146
+ }
147
+
148
+ function analyzeData(wizard, options, state)
149
+ {
150
+ var stepTitles = wizard.children(options.headerTag),
151
+ stepContents = wizard.children(options.bodyTag);
152
+
153
+ // Validate content
154
+ if (stepTitles.length > stepContents.length)
155
+ {
156
+ throwError(_missingCorrespondingElementErrorMessage, "contents");
157
+ }
158
+ else if (stepTitles.length < stepContents.length)
159
+ {
160
+ throwError(_missingCorrespondingElementErrorMessage, "titles");
161
+ }
162
+
163
+ var startIndex = options.startIndex;
164
+
165
+ state.stepCount = stepTitles.length;
166
+
167
+ // Tries to load the saved state (step position)
168
+ if (options.saveState && $.cookie)
169
+ {
170
+ var savedState = $.cookie(_cookiePrefix + getUniqueId(wizard));
171
+ // Sets the saved position to the start index if not undefined or out of range
172
+ var savedIndex = parseInt(savedState, 0);
173
+ if (!isNaN(savedIndex) && savedIndex < state.stepCount)
174
+ {
175
+ startIndex = savedIndex;
176
+ }
177
+ }
178
+
179
+ state.currentIndex = startIndex;
180
+
181
+ stepTitles.each(function (index)
182
+ {
183
+ var item = $(this), // item == header
184
+ content = stepContents.eq(index),
185
+ modeData = content.data("mode"),
186
+ mode = (modeData == null) ? contentMode.html : getValidEnumValue(contentMode,
187
+ (/^\s*$/.test(modeData) || isNaN(modeData)) ? modeData : parseInt(modeData, 0)),
188
+ contentUrl = (mode === contentMode.html || content.data("url") === undefined) ?
189
+ "" : content.data("url"),
190
+ contentLoaded = (mode !== contentMode.html && content.data("loaded") === "1"),
191
+ step = $.extend({}, stepModel, {
192
+ title: item.html(),
193
+ content: (mode === contentMode.html) ? content.html() : "",
194
+ contentUrl: contentUrl,
195
+ contentMode: mode,
196
+ contentLoaded: contentLoaded
197
+ });
198
+
199
+ addStepToCache(wizard, step);
200
+ });
201
+ }
202
+
203
+ /**
204
+ * Triggers the onCanceled event.
205
+ *
206
+ * @static
207
+ * @private
208
+ * @method cancel
209
+ * @param wizard {Object} The jQuery wizard object
210
+ **/
211
+ function cancel(wizard)
212
+ {
213
+ wizard.triggerHandler("canceled");
214
+ }
215
+
216
+ function decreaseCurrentIndexBy(state, decreaseBy)
217
+ {
218
+ return state.currentIndex - decreaseBy;
219
+ }
220
+
221
+ /**
222
+ * Removes the control functionality completely and transforms the current state to the initial HTML structure.
223
+ *
224
+ * @static
225
+ * @private
226
+ * @method destroy
227
+ * @param wizard {Object} A jQuery wizard object
228
+ **/
229
+ function destroy(wizard, options)
230
+ {
231
+ var eventNamespace = getEventNamespace(wizard);
232
+
233
+ // Remove virtual data objects from the wizard
234
+ wizard.unbind(eventNamespace).removeData("uid").removeData("options")
235
+ .removeData("state").removeData("steps").removeData("eventNamespace")
236
+ .find(".actions a").unbind(eventNamespace);
237
+
238
+ // Remove attributes and CSS classes from the wizard
239
+ wizard.removeClass(options.clearFixCssClass + " vertical");
240
+
241
+ var contents = wizard.find(".content > *");
242
+
243
+ // Remove virtual data objects from panels and their titles
244
+ contents.removeData("loaded").removeData("mode").removeData("url");
245
+
246
+ // Remove attributes, CSS classes and reset inline styles on all panels and their titles
247
+ contents.removeAttr("id").removeAttr("role").removeAttr("tabindex")
248
+ .removeAttr("class").removeAttr("style")._removeAria("labelledby")
249
+ ._removeAria("hidden");
250
+
251
+ // Empty panels if the mode is set to 'async' or 'iframe'
252
+ wizard.find(".content > [data-mode='async'],.content > [data-mode='iframe']").empty();
253
+
254
+ var wizardSubstitute = $("<{0} class=\"{1}\"></{0}>".format(wizard.get(0).tagName, wizard.attr("class")));
255
+
256
+ var wizardId = wizard._id();
257
+ if (wizardId != null && wizardId !== "")
258
+ {
259
+ wizardSubstitute._id(wizardId);
260
+ }
261
+
262
+ wizardSubstitute.html(wizard.find(".content").html());
263
+ wizard.after(wizardSubstitute);
264
+ wizard.remove();
265
+
266
+ return wizardSubstitute;
267
+ }
268
+
269
+ /**
270
+ * Triggers the onFinishing and onFinished event.
271
+ *
272
+ * @static
273
+ * @private
274
+ * @method finishStep
275
+ * @param wizard {Object} The jQuery wizard object
276
+ * @param state {Object} The state container of the current wizard
277
+ **/
278
+ function finishStep(wizard, state)
279
+ {
280
+ var currentStep = wizard.find(".steps li").eq(state.currentIndex);
281
+
282
+ if (wizard.triggerHandler("finishing", [state.currentIndex]))
283
+ {
284
+ currentStep.addClass("done").removeClass("error");
285
+ wizard.triggerHandler("finished", [state.currentIndex]);
286
+ }
287
+ else
288
+ {
289
+ currentStep.addClass("error");
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Gets or creates if not exist an unique event namespace for the given wizard instance.
295
+ *
296
+ * @static
297
+ * @private
298
+ * @method getEventNamespace
299
+ * @param wizard {Object} A jQuery wizard object
300
+ * @return {String} Returns the unique event namespace for the given wizard
301
+ */
302
+ function getEventNamespace(wizard)
303
+ {
304
+ var eventNamespace = wizard.data("eventNamespace");
305
+
306
+ if (eventNamespace == null)
307
+ {
308
+ eventNamespace = "." + getUniqueId(wizard);
309
+ wizard.data("eventNamespace", eventNamespace);
310
+ }
311
+
312
+ return eventNamespace;
313
+ }
314
+
315
+ function getStepAnchor(wizard, index)
316
+ {
317
+ var uniqueId = getUniqueId(wizard);
318
+
319
+ return wizard.find("#" + uniqueId + _tabSuffix + index);
320
+ }
321
+
322
+ function getStepPanel(wizard, index)
323
+ {
324
+ var uniqueId = getUniqueId(wizard);
325
+
326
+ return wizard.find("#" + uniqueId + _tabpanelSuffix + index);
327
+ }
328
+
329
+ function getStepTitle(wizard, index)
330
+ {
331
+ var uniqueId = getUniqueId(wizard);
332
+
333
+ return wizard.find("#" + uniqueId + _titleSuffix + index);
334
+ }
335
+
336
+ function getOptions(wizard)
337
+ {
338
+ return wizard.data("options");
339
+ }
340
+
341
+ function getState(wizard)
342
+ {
343
+ return wizard.data("state");
344
+ }
345
+
346
+ function getSteps(wizard)
347
+ {
348
+ return wizard.data("steps");
349
+ }
350
+
351
+ /**
352
+ * Gets a specific step object by index.
353
+ *
354
+ * @static
355
+ * @private
356
+ * @method getStep
357
+ * @param index {Integer} An integer that belongs to the position of a step
358
+ * @return {Object} A specific step object
359
+ **/
360
+ function getStep(wizard, index)
361
+ {
362
+ var steps = getSteps(wizard);
363
+
364
+ if (index < 0 || index >= steps.length)
365
+ {
366
+ throwError(_indexOutOfRangeErrorMessage);
367
+ }
368
+
369
+ return steps[index];
370
+ }
371
+
372
+ /**
373
+ * Gets or creates if not exist an unique id from the given wizard instance.
374
+ *
375
+ * @static
376
+ * @private
377
+ * @method getUniqueId
378
+ * @param wizard {Object} A jQuery wizard object
379
+ * @return {String} Returns the unique id for the given wizard
380
+ */
381
+ function getUniqueId(wizard)
382
+ {
383
+ var uniqueId = wizard.data("uid");
384
+
385
+ if (uniqueId == null)
386
+ {
387
+ uniqueId = wizard._id();
388
+ if (uniqueId == null)
389
+ {
390
+ uniqueId = "steps-uid-".concat(_uniqueId);
391
+ wizard._id(uniqueId);
392
+ }
393
+
394
+ _uniqueId++;
395
+ wizard.data("uid", uniqueId);
396
+ }
397
+
398
+ return uniqueId;
399
+ }
400
+
401
+ /**
402
+ * Gets a valid enum value by checking a specific enum key or value.
403
+ *
404
+ * @static
405
+ * @private
406
+ * @method getValidEnumValue
407
+ * @param enumType {Object} Type of enum
408
+ * @param keyOrValue {Object} Key as `String` or value as `Integer` to check for
409
+ */
410
+ function getValidEnumValue(enumType, keyOrValue)
411
+ {
412
+ validateArgument("enumType", enumType);
413
+ validateArgument("keyOrValue", keyOrValue);
414
+
415
+ // Is key
416
+ if (typeof keyOrValue === "string")
417
+ {
418
+ var value = enumType[keyOrValue];
419
+ if (value === undefined)
420
+ {
421
+ throwError("The enum key '{0}' does not exist.", keyOrValue);
422
+ }
423
+
424
+ return value;
425
+ }
426
+ // Is value
427
+ else if (typeof keyOrValue === "number")
428
+ {
429
+ for (var key in enumType)
430
+ {
431
+ if (enumType[key] === keyOrValue)
432
+ {
433
+ return keyOrValue;
434
+ }
435
+ }
436
+
437
+ throwError("Invalid enum value '{0}'.", keyOrValue);
438
+ }
439
+ // Type is not supported
440
+ else
441
+ {
442
+ throwError("Invalid key or value type.");
443
+ }
444
+ }
445
+
446
+ /**
447
+ * Routes to the next step.
448
+ *
449
+ * @static
450
+ * @private
451
+ * @method goToNextStep
452
+ * @param wizard {Object} The jQuery wizard object
453
+ * @param options {Object} Settings of the current wizard
454
+ * @param state {Object} The state container of the current wizard
455
+ * @return {Boolean} Indicates whether the action executed
456
+ **/
457
+ function goToNextStep(wizard, options, state)
458
+ {
459
+ return paginationClick(wizard, options, state, increaseCurrentIndexBy(state, 1));
460
+ }
461
+
462
+ /**
463
+ * Routes to the previous step.
464
+ *
465
+ * @static
466
+ * @private
467
+ * @method goToPreviousStep
468
+ * @param wizard {Object} The jQuery wizard object
469
+ * @param options {Object} Settings of the current wizard
470
+ * @param state {Object} The state container of the current wizard
471
+ * @return {Boolean} Indicates whether the action executed
472
+ **/
473
+ function goToPreviousStep(wizard, options, state)
474
+ {
475
+ return paginationClick(wizard, options, state, decreaseCurrentIndexBy(state, 1));
476
+ }
477
+
478
+ /**
479
+ * Routes to a specific step by a given index.
480
+ *
481
+ * @static
482
+ * @private
483
+ * @method goToStep
484
+ * @param wizard {Object} The jQuery wizard object
485
+ * @param options {Object} Settings of the current wizard
486
+ * @param state {Object} The state container of the current wizard
487
+ * @param index {Integer} The position (zero-based) to route to
488
+ * @return {Boolean} Indicates whether the action succeeded or failed
489
+ **/
490
+ function goToStep(wizard, options, state, index)
491
+ {
492
+ if (index < 0 || index >= state.stepCount)
493
+ {
494
+ throwError(_indexOutOfRangeErrorMessage);
495
+ }
496
+
497
+ if (options.forceMoveForward && index < state.currentIndex)
498
+ {
499
+ return;
500
+ }
501
+
502
+ var oldIndex = state.currentIndex;
503
+ if (wizard.triggerHandler("stepChanging", [state.currentIndex, index]))
504
+ {
505
+ // Save new state
506
+ state.currentIndex = index;
507
+ saveCurrentStateToCookie(wizard, options, state);
508
+
509
+ // Change visualisation
510
+ refreshStepNavigation(wizard, options, state, oldIndex);
511
+ refreshPagination(wizard, options, state);
512
+ loadAsyncContent(wizard, options, state);
513
+ startTransitionEffect(wizard, options, state, index, oldIndex);
514
+
515
+ wizard.triggerHandler("stepChanged", [index, oldIndex]);
516
+ }
517
+ else
518
+ {
519
+ wizard.find(".steps li").eq(oldIndex).addClass("error");
520
+ }
521
+
522
+ return true;
523
+ }
524
+
525
+ function increaseCurrentIndexBy(state, increaseBy)
526
+ {
527
+ return state.currentIndex + increaseBy;
528
+ }
529
+
530
+ /**
531
+ * Initializes the component.
532
+ *
533
+ * @static
534
+ * @private
535
+ * @method initialize
536
+ * @param options {Object} The component settings
537
+ **/
538
+ function initialize(options)
539
+ {
540
+ /*jshint -W040 */
541
+ var opts = $.extend(true, {}, defaults, options);
542
+
543
+ return this.each(function ()
544
+ {
545
+ var wizard = $(this);
546
+ var state = {
547
+ currentIndex: opts.startIndex,
548
+ currentStep: null,
549
+ stepCount: 0,
550
+ transitionElement: null
551
+ };
552
+
553
+ // Create data container
554
+ wizard.data("options", opts);
555
+ wizard.data("state", state);
556
+ wizard.data("steps", []);
557
+
558
+ analyzeData(wizard, opts, state);
559
+ render(wizard, opts, state);
560
+ registerEvents(wizard, opts);
561
+
562
+ // Trigger focus
563
+ if (opts.autoFocus && _uniqueId === 0)
564
+ {
565
+ getStepAnchor(wizard, opts.startIndex).focus();
566
+ }
567
+ });
568
+ }
569
+
570
+ /**
571
+ * Inserts a new step to a specific position.
572
+ *
573
+ * @static
574
+ * @private
575
+ * @method insertStep
576
+ * @param wizard {Object} The jQuery wizard object
577
+ * @param options {Object} Settings of the current wizard
578
+ * @param state {Object} The state container of the current wizard
579
+ * @param index {Integer} The position (zero-based) to add
580
+ * @param step {Object} The step object to add
581
+ * @example
582
+ * $("#wizard").steps().insert(0, {
583
+ * title: "Title",
584
+ * content: "", // optional
585
+ * contentMode: "async", // optional
586
+ * contentUrl: "/Content/Step/1" // optional
587
+ * });
588
+ * @chainable
589
+ **/
590
+ function insertStep(wizard, options, state, index, step)
591
+ {
592
+ if (index < 0 || index > state.stepCount)
593
+ {
594
+ throwError(_indexOutOfRangeErrorMessage);
595
+ }
596
+
597
+ // TODO: Validate step object
598
+
599
+ // Change data
600
+ step = $.extend({}, stepModel, step);
601
+ insertStepToCache(wizard, index, step);
602
+ if (state.currentIndex !== state.stepCount && state.currentIndex >= index)
603
+ {
604
+ state.currentIndex++;
605
+ saveCurrentStateToCookie(wizard, options, state);
606
+ }
607
+ state.stepCount++;
608
+
609
+ var contentContainer = wizard.find(".content"),
610
+ header = $("<{0}>{1}</{0}>".format(options.headerTag, step.title)),
611
+ body = $("<{0}></{0}>".format(options.bodyTag));
612
+
613
+ if (step.contentMode == null || step.contentMode === contentMode.html)
614
+ {
615
+ body.html(step.content);
616
+ }
617
+
618
+ if (index === 0)
619
+ {
620
+ contentContainer.prepend(body).prepend(header);
621
+ }
622
+ else
623
+ {
624
+ getStepPanel(wizard, (index - 1)).after(body).after(header);
625
+ }
626
+
627
+ renderBody(wizard, state, body, index);
628
+ renderTitle(wizard, options, state, header, index);
629
+ refreshSteps(wizard, options, state, index);
630
+ if (index === state.currentIndex)
631
+ {
632
+ refreshStepNavigation(wizard, options, state);
633
+ }
634
+ refreshPagination(wizard, options, state);
635
+
636
+ return wizard;
637
+ }
638
+
639
+ /**
640
+ * Inserts a step object to the cache at a specific position.
641
+ *
642
+ * @static
643
+ * @private
644
+ * @method insertStepToCache
645
+ * @param wizard {Object} A jQuery wizard object
646
+ * @param index {Integer} The position (zero-based) to add
647
+ * @param step {Object} The step object to add
648
+ **/
649
+ function insertStepToCache(wizard, index, step)
650
+ {
651
+ getSteps(wizard).splice(index, 0, step);
652
+ }
653
+
654
+ /**
655
+ * Handles the keyup DOM event for pagination.
656
+ *
657
+ * @static
658
+ * @private
659
+ * @event keyup
660
+ * @param event {Object} An event object
661
+ */
662
+ function keyUpHandler(event)
663
+ {
664
+ var wizard = $(this),
665
+ options = getOptions(wizard),
666
+ state = getState(wizard);
667
+
668
+ if (options.suppressPaginationOnFocus && wizard.find(":focus").is(":input"))
669
+ {
670
+ event.preventDefault();
671
+ return false;
672
+ }
673
+
674
+ var keyCodes = { left: 37, right: 39 };
675
+ if (event.keyCode === keyCodes.left)
676
+ {
677
+ event.preventDefault();
678
+ goToPreviousStep(wizard, options, state);
679
+ }
680
+ else if (event.keyCode === keyCodes.right)
681
+ {
682
+ event.preventDefault();
683
+ goToNextStep(wizard, options, state);
684
+ }
685
+ }
686
+
687
+ /**
688
+ * Loads and includes async content.
689
+ *
690
+ * @static
691
+ * @private
692
+ * @method loadAsyncContent
693
+ * @param wizard {Object} A jQuery wizard object
694
+ * @param options {Object} Settings of the current wizard
695
+ * @param state {Object} The state container of the current wizard
696
+ */
697
+ function loadAsyncContent(wizard, options, state)
698
+ {
699
+ if (state.stepCount > 0)
700
+ {
701
+ var currentStep = getStep(wizard, state.currentIndex);
702
+
703
+ if (!options.enableContentCache || !currentStep.contentLoaded)
704
+ {
705
+ switch (getValidEnumValue(contentMode, currentStep.contentMode))
706
+ {
707
+ case contentMode.iframe:
708
+ wizard.find(".content > .body").eq(state.currentIndex).empty()
709
+ .html("<iframe src=\"" + currentStep.contentUrl + "\" frameborder=\"0\" scrolling=\"no\" />")
710
+ .data("loaded", "1");
711
+ break;
712
+
713
+ case contentMode.async:
714
+ var currentStepContent = getStepPanel(wizard, state.currentIndex)._aria("busy", "true")
715
+ .empty().append(renderTemplate(options.loadingTemplate, { text: options.labels.loading }));
716
+
717
+ $.ajax({ url: currentStep.contentUrl, cache: false }).done(function (data)
718
+ {
719
+ currentStepContent.empty().html(data)._aria("busy", "false").data("loaded", "1");
720
+ });
721
+ break;
722
+ }
723
+ }
724
+ }
725
+ }
726
+
727
+ /**
728
+ * Fires the action next or previous click event.
729
+ *
730
+ * @static
731
+ * @private
732
+ * @method paginationClick
733
+ * @param wizard {Object} The jQuery wizard object
734
+ * @param options {Object} Settings of the current wizard
735
+ * @param state {Object} The state container of the current wizard
736
+ * @param index {Integer} The position (zero-based) to route to
737
+ * @return {Boolean} Indicates whether the event fired successfully or not
738
+ **/
739
+ function paginationClick(wizard, options, state, index)
740
+ {
741
+ var oldIndex = state.currentIndex;
742
+
743
+ if (index >= 0 && index < state.stepCount && !(options.forceMoveForward && index < state.currentIndex))
744
+ {
745
+ var anchor = getStepAnchor(wizard, index),
746
+ parent = anchor.parent(),
747
+ isDisabled = parent.hasClass("disabled");
748
+
749
+ // Enable the step to make the anchor clickable!
750
+ parent._enableAria();
751
+ anchor.click();
752
+
753
+ // An error occured
754
+ if (oldIndex === state.currentIndex && isDisabled)
755
+ {
756
+ // Disable the step again if current index has not changed; prevents click action.
757
+ parent._enableAria(false);
758
+ return false;
759
+ }
760
+
761
+ return true;
762
+ }
763
+
764
+ return false;
765
+ }
766
+
767
+ /**
768
+ * Fires when a pagination click happens.
769
+ *
770
+ * @static
771
+ * @private
772
+ * @event click
773
+ * @param event {Object} An event object
774
+ */
775
+ function paginationClickHandler(event)
776
+ {
777
+ event.preventDefault();
778
+
779
+ var anchor = $(this),
780
+ wizard = anchor.parent().parent().parent().parent(),
781
+ options = getOptions(wizard),
782
+ state = getState(wizard),
783
+ href = anchor.attr("href");
784
+
785
+ switch (href.substring(href.lastIndexOf("#") + 1))
786
+ {
787
+ case "cancel":
788
+ cancel(wizard);
789
+ break;
790
+
791
+ case "finish":
792
+ finishStep(wizard, state);
793
+ break;
794
+
795
+ case "next":
796
+ goToNextStep(wizard, options, state);
797
+ break;
798
+
799
+ case "previous":
800
+ goToPreviousStep(wizard, options, state);
801
+ break;
802
+ }
803
+ }
804
+
805
+ /**
806
+ * Refreshs the visualization state for the entire pagination.
807
+ *
808
+ * @static
809
+ * @private
810
+ * @method refreshPagination
811
+ * @param wizard {Object} A jQuery wizard object
812
+ * @param options {Object} Settings of the current wizard
813
+ * @param state {Object} The state container of the current wizard
814
+ */
815
+ function refreshPagination(wizard, options, state)
816
+ {
817
+ if (options.enablePagination)
818
+ {
819
+ var finish = wizard.find(".actions a[href$='#finish']").parent(),
820
+ next = wizard.find(".actions a[href$='#next']").parent();
821
+
822
+ if (!options.forceMoveForward)
823
+ {
824
+ var previous = wizard.find(".actions a[href$='#previous']").parent();
825
+ previous._enableAria(state.currentIndex > 0);
826
+ }
827
+
828
+ if (options.enableFinishButton && options.showFinishButtonAlways)
829
+ {
830
+ finish._enableAria(state.stepCount > 0);
831
+ next._enableAria(state.stepCount > 1 && state.stepCount > (state.currentIndex + 1));
832
+ }
833
+ else
834
+ {
835
+ finish._showAria(options.enableFinishButton && state.stepCount === (state.currentIndex + 1));
836
+ next._showAria(state.stepCount === 0 || state.stepCount > (state.currentIndex + 1)).
837
+ _enableAria(state.stepCount > (state.currentIndex + 1) || !options.enableFinishButton);
838
+ }
839
+ }
840
+ }
841
+
842
+ /**
843
+ * Refreshs the visualization state for the step navigation (tabs).
844
+ *
845
+ * @static
846
+ * @private
847
+ * @method refreshStepNavigation
848
+ * @param wizard {Object} A jQuery wizard object
849
+ * @param options {Object} Settings of the current wizard
850
+ * @param state {Object} The state container of the current wizard
851
+ * @param [oldIndex] {Integer} The index of the prior step
852
+ */
853
+ function refreshStepNavigation(wizard, options, state, oldIndex)
854
+ {
855
+ var currentOrNewStepAnchor = getStepAnchor(wizard, state.currentIndex),
856
+ currentInfo = $("<span class=\"current-info audible\">" + options.labels.current + " </span>"),
857
+ stepTitles = wizard.find(".content > .title");
858
+
859
+ if (oldIndex != null)
860
+ {
861
+ var oldStepAnchor = getStepAnchor(wizard, oldIndex);
862
+ oldStepAnchor.parent().addClass("done").removeClass("error")._selectAria(false);
863
+ stepTitles.eq(oldIndex).removeClass("current").next(".body").removeClass("current");
864
+ currentInfo = oldStepAnchor.find(".current-info");
865
+ currentOrNewStepAnchor.focus();
866
+ }
867
+
868
+ currentOrNewStepAnchor.prepend(currentInfo).parent()._selectAria().removeClass("done")._enableAria();
869
+ stepTitles.eq(state.currentIndex).addClass("current").next(".body").addClass("current");
870
+ }
871
+
872
+ /**
873
+ * Refreshes step buttons and their related titles beyond a certain position.
874
+ *
875
+ * @static
876
+ * @private
877
+ * @method refreshSteps
878
+ * @param wizard {Object} A jQuery wizard object
879
+ * @param options {Object} Settings of the current wizard
880
+ * @param state {Object} The state container of the current wizard
881
+ * @param index {Integer} The start point for refreshing ids
882
+ */
883
+ function refreshSteps(wizard, options, state, index)
884
+ {
885
+ var uniqueId = getUniqueId(wizard);
886
+
887
+ for (var i = index; i < state.stepCount; i++)
888
+ {
889
+ var uniqueStepId = uniqueId + _tabSuffix + i,
890
+ uniqueBodyId = uniqueId + _tabpanelSuffix + i,
891
+ uniqueHeaderId = uniqueId + _titleSuffix + i,
892
+ title = wizard.find(".title").eq(i)._id(uniqueHeaderId);
893
+
894
+ wizard.find(".steps a").eq(i)._id(uniqueStepId)
895
+ ._aria("controls", uniqueBodyId).attr("href", "#" + uniqueHeaderId)
896
+ .html(renderTemplate(options.titleTemplate, { index: i + 1, title: title.html() }));
897
+ wizard.find(".body").eq(i)._id(uniqueBodyId)
898
+ ._aria("labelledby", uniqueHeaderId);
899
+ }
900
+ }
901
+
902
+ function registerEvents(wizard, options)
903
+ {
904
+ var eventNamespace = getEventNamespace(wizard);
905
+
906
+ wizard.bind("canceled" + eventNamespace, options.onCanceled);
907
+ wizard.bind("finishing" + eventNamespace, options.onFinishing);
908
+ wizard.bind("finished" + eventNamespace, options.onFinished);
909
+ wizard.bind("stepChanging" + eventNamespace, options.onStepChanging);
910
+ wizard.bind("stepChanged" + eventNamespace, options.onStepChanged);
911
+
912
+ if (options.enableKeyNavigation)
913
+ {
914
+ wizard.bind("keyup" + eventNamespace, keyUpHandler);
915
+ }
916
+
917
+ wizard.find(".actions a").bind("click" + eventNamespace, paginationClickHandler);
918
+ }
919
+
920
+ /**
921
+ * Removes a specific step by an given index.
922
+ *
923
+ * @static
924
+ * @private
925
+ * @method removeStep
926
+ * @param wizard {Object} A jQuery wizard object
927
+ * @param options {Object} Settings of the current wizard
928
+ * @param state {Object} The state container of the current wizard
929
+ * @param index {Integer} The position (zero-based) of the step to remove
930
+ * @return Indecates whether the item is removed.
931
+ **/
932
+ function removeStep(wizard, options, state, index)
933
+ {
934
+ // Index out of range and try deleting current item will return false.
935
+ if (index < 0 || index >= state.stepCount || state.currentIndex === index)
936
+ {
937
+ return false;
938
+ }
939
+
940
+ // Change data
941
+ removeStepFromCache(wizard, index);
942
+ if (state.currentIndex > index)
943
+ {
944
+ state.currentIndex--;
945
+ saveCurrentStateToCookie(wizard, options, state);
946
+ }
947
+ state.stepCount--;
948
+
949
+ getStepTitle(wizard, index).remove();
950
+ getStepPanel(wizard, index).remove();
951
+ getStepAnchor(wizard, index).parent().remove();
952
+
953
+ // Set the "first" class to the new first step button
954
+ if (index === 0)
955
+ {
956
+ wizard.find(".steps li").first().addClass("first");
957
+ }
958
+
959
+ // Set the "last" class to the new last step button
960
+ if (index === state.stepCount)
961
+ {
962
+ wizard.find(".steps li").eq(index).addClass("last");
963
+ }
964
+
965
+ refreshSteps(wizard, options, state, index);
966
+ refreshPagination(wizard, options, state);
967
+
968
+ return true;
969
+ }
970
+
971
+ function removeStepFromCache(wizard, index)
972
+ {
973
+ getSteps(wizard).splice(index, 1);
974
+ }
975
+
976
+ /**
977
+ * Transforms the base html structure to a more sensible html structure.
978
+ *
979
+ * @static
980
+ * @private
981
+ * @method render
982
+ * @param wizard {Object} A jQuery wizard object
983
+ * @param options {Object} Settings of the current wizard
984
+ * @param state {Object} The state container of the current wizard
985
+ **/
986
+ function render(wizard, options, state)
987
+ {
988
+ // Create a content wrapper and copy HTML from the intial wizard structure
989
+ var wrapperTemplate = "<{0} class=\"{1}\">{2}</{0}>",
990
+ orientation = getValidEnumValue(stepsOrientation, options.stepsOrientation),
991
+ verticalCssClass = (orientation === stepsOrientation.vertical) ? " vertical" : "",
992
+ contentWrapper = $(wrapperTemplate.format(options.contentContainerTag, "content " + options.clearFixCssClass, wizard.html())),
993
+ stepsWrapper = $(wrapperTemplate.format(options.stepsContainerTag, "steps " + options.clearFixCssClass, "<ul role=\"tablist\"></ul>")),
994
+ stepTitles = contentWrapper.children(options.headerTag),
995
+ stepContents = contentWrapper.children(options.bodyTag);
996
+
997
+ // Transform the wizard wrapper and remove the inner HTML
998
+ wizard.attr("role", "application").empty().append(stepsWrapper).append(contentWrapper)
999
+ .addClass(options.cssClass + " " + options.clearFixCssClass + verticalCssClass);
1000
+
1001
+ // Add WIA-ARIA support
1002
+ stepContents.each(function (index)
1003
+ {
1004
+ renderBody(wizard, state, $(this), index);
1005
+ });
1006
+
1007
+ stepTitles.each(function (index)
1008
+ {
1009
+ renderTitle(wizard, options, state, $(this), index);
1010
+ });
1011
+
1012
+ refreshStepNavigation(wizard, options, state);
1013
+ renderPagination(wizard, options, state);
1014
+ }
1015
+
1016
+ /**
1017
+ * Transforms the body to a proper tabpanel.
1018
+ *
1019
+ * @static
1020
+ * @private
1021
+ * @method renderBody
1022
+ * @param wizard {Object} A jQuery wizard object
1023
+ * @param body {Object} A jQuery body object
1024
+ * @param index {Integer} The position of the body
1025
+ */
1026
+ function renderBody(wizard, state, body, index)
1027
+ {
1028
+ var uniqueId = getUniqueId(wizard),
1029
+ uniqueBodyId = uniqueId + _tabpanelSuffix + index,
1030
+ uniqueHeaderId = uniqueId + _titleSuffix + index;
1031
+
1032
+ body._id(uniqueBodyId).attr("role", "tabpanel")._aria("labelledby", uniqueHeaderId)
1033
+ .addClass("body")._showAria(state.currentIndex === index);
1034
+ }
1035
+
1036
+ /**
1037
+ * Renders a pagination if enabled.
1038
+ *
1039
+ * @static
1040
+ * @private
1041
+ * @method renderPagination
1042
+ * @param wizard {Object} A jQuery wizard object
1043
+ * @param options {Object} Settings of the current wizard
1044
+ * @param state {Object} The state container of the current wizard
1045
+ */
1046
+ function renderPagination(wizard, options, state)
1047
+ {
1048
+ if (options.enablePagination)
1049
+ {
1050
+ var pagination = "<{0} class=\"actions {1}\"><ul role=\"menu\" aria-label=\"{2}\">{3}</ul></{0}>",
1051
+ buttonTemplate = "<li><a href=\"#{0}\" role=\"menuitem\">{1}</a></li>",
1052
+ buttons = "";
1053
+
1054
+ if (!options.forceMoveForward)
1055
+ {
1056
+ buttons += buttonTemplate.format("previous", options.labels.previous);
1057
+ }
1058
+
1059
+ buttons += buttonTemplate.format("next", options.labels.next);
1060
+
1061
+ if (options.enableFinishButton)
1062
+ {
1063
+ buttons += buttonTemplate.format("finish", options.labels.finish);
1064
+ }
1065
+
1066
+ if (options.enableCancelButton)
1067
+ {
1068
+ buttons += buttonTemplate.format("cancel", options.labels.cancel);
1069
+ }
1070
+
1071
+ wizard.append(pagination.format(options.actionContainerTag, options.clearFixCssClass,
1072
+ options.labels.pagination, buttons));
1073
+
1074
+ refreshPagination(wizard, options, state);
1075
+ loadAsyncContent(wizard, options, state);
1076
+ }
1077
+ }
1078
+
1079
+ /**
1080
+ * Renders a template and replaces all placeholder.
1081
+ *
1082
+ * @static
1083
+ * @private
1084
+ * @method renderTemplate
1085
+ * @param template {String} A template
1086
+ * @param substitutes {Object} A list of substitute
1087
+ * @return {String} The rendered template
1088
+ */
1089
+ function renderTemplate(template, substitutes)
1090
+ {
1091
+ var matches = template.match(/#([a-z]*)#/gi);
1092
+
1093
+ for (var i = 0; i < matches.length; i++)
1094
+ {
1095
+ var match = matches[i],
1096
+ key = match.substring(1, match.length - 1);
1097
+
1098
+ if (substitutes[key] === undefined)
1099
+ {
1100
+ throwError("The key '{0}' does not exist in the substitute collection!", key);
1101
+ }
1102
+
1103
+ template = template.replace(match, substitutes[key]);
1104
+ }
1105
+
1106
+ return template;
1107
+ }
1108
+
1109
+ /**
1110
+ * Transforms the title to a step item button.
1111
+ *
1112
+ * @static
1113
+ * @private
1114
+ * @method renderTitle
1115
+ * @param wizard {Object} A jQuery wizard object
1116
+ * @param options {Object} Settings of the current wizard
1117
+ * @param state {Object} The state container of the current wizard
1118
+ * @param header {Object} A jQuery header object
1119
+ * @param index {Integer} The position of the header
1120
+ */
1121
+ function renderTitle(wizard, options, state, header, index)
1122
+ {
1123
+ var uniqueId = getUniqueId(wizard),
1124
+ uniqueStepId = uniqueId + _tabSuffix + index,
1125
+ uniqueBodyId = uniqueId + _tabpanelSuffix + index,
1126
+ uniqueHeaderId = uniqueId + _titleSuffix + index,
1127
+ stepCollection = wizard.find(".steps > ul"),
1128
+ title = renderTemplate(options.titleTemplate, {
1129
+ index: index + 1,
1130
+ title: header.html()
1131
+ }),
1132
+ stepItem = $("<li role=\"tab\"><a id=\"" + uniqueStepId + "\" href=\"#" + uniqueHeaderId +
1133
+ "\" aria-controls=\"" + uniqueBodyId + "\">" + title + "</a></li>");
1134
+
1135
+ stepItem._enableAria(options.enableAllSteps || state.currentIndex > index);
1136
+
1137
+ if (state.currentIndex > index)
1138
+ {
1139
+ stepItem.addClass("done");
1140
+ }
1141
+
1142
+ header._id(uniqueHeaderId).attr("tabindex", "-1").addClass("title");
1143
+
1144
+ if (index === 0)
1145
+ {
1146
+ stepCollection.prepend(stepItem);
1147
+ }
1148
+ else
1149
+ {
1150
+ stepCollection.find("li").eq(index - 1).after(stepItem);
1151
+ }
1152
+
1153
+ // Set the "first" class to the new first step button
1154
+ if (index === 0)
1155
+ {
1156
+ stepCollection.find("li").removeClass("first").eq(index).addClass("first");
1157
+ }
1158
+
1159
+ // Set the "last" class to the new last step button
1160
+ if (index === (state.stepCount - 1))
1161
+ {
1162
+ stepCollection.find("li").removeClass("last").eq(index).addClass("last");
1163
+ }
1164
+
1165
+ // Register click event
1166
+ stepItem.children("a").bind("click" + getEventNamespace(wizard), stepClickHandler);
1167
+ }
1168
+
1169
+ /**
1170
+ * Saves the current state to a cookie.
1171
+ *
1172
+ * @static
1173
+ * @private
1174
+ * @method saveCurrentStateToCookie
1175
+ * @param wizard {Object} A jQuery wizard object
1176
+ * @param options {Object} Settings of the current wizard
1177
+ * @param state {Object} The state container of the current wizard
1178
+ */
1179
+ function saveCurrentStateToCookie(wizard, options, state)
1180
+ {
1181
+ if (options.saveState && $.cookie)
1182
+ {
1183
+ $.cookie(_cookiePrefix + getUniqueId(wizard), state.currentIndex);
1184
+ }
1185
+ }
1186
+
1187
+ function startTransitionEffect(wizard, options, state, index, oldIndex)
1188
+ {
1189
+ var stepContents = wizard.find(".content > .body"),
1190
+ effect = getValidEnumValue(transitionEffect, options.transitionEffect),
1191
+ effectSpeed = options.transitionEffectSpeed,
1192
+ newStep = stepContents.eq(index),
1193
+ currentStep = stepContents.eq(oldIndex);
1194
+
1195
+ switch (effect)
1196
+ {
1197
+ case transitionEffect.fade:
1198
+ case transitionEffect.slide:
1199
+ var hide = (effect === transitionEffect.fade) ? "fadeOut" : "slideUp",
1200
+ show = (effect === transitionEffect.fade) ? "fadeIn" : "slideDown";
1201
+
1202
+ state.transitionElement = newStep;
1203
+ currentStep[hide](effectSpeed, function ()
1204
+ {
1205
+ var wizard = $(this)._showAria(false).parent().parent(),
1206
+ state = getState(wizard);
1207
+
1208
+ if (state.transitionElement)
1209
+ {
1210
+ state.transitionElement[show](effectSpeed, function ()
1211
+ {
1212
+ $(this)._showAria();
1213
+ });
1214
+ state.transitionElement = null;
1215
+ }
1216
+ }).promise();
1217
+ break;
1218
+
1219
+ case transitionEffect.slideLeft:
1220
+ var outerWidth = currentStep.outerWidth(true),
1221
+ posFadeOut = (index > oldIndex) ? -(outerWidth) : outerWidth,
1222
+ posFadeIn = (index > oldIndex) ? outerWidth : -(outerWidth);
1223
+
1224
+ currentStep.animate({ left: posFadeOut }, effectSpeed,
1225
+ function () { $(this)._showAria(false); }).promise();
1226
+ newStep.css("left", posFadeIn + "px")._showAria()
1227
+ .animate({ left: 0 }, effectSpeed).promise();
1228
+ break;
1229
+
1230
+ default:
1231
+ currentStep._showAria(false);
1232
+ newStep._showAria();
1233
+ break;
1234
+ }
1235
+ }
1236
+
1237
+ /**
1238
+ * Fires when a step click happens.
1239
+ *
1240
+ * @static
1241
+ * @private
1242
+ * @event click
1243
+ * @param event {Object} An event object
1244
+ */
1245
+ function stepClickHandler(event)
1246
+ {
1247
+ event.preventDefault();
1248
+
1249
+ var anchor = $(this),
1250
+ wizard = anchor.parent().parent().parent().parent(),
1251
+ options = getOptions(wizard),
1252
+ state = getState(wizard),
1253
+ oldIndex = state.currentIndex;
1254
+
1255
+ if (anchor.parent().is(":not(.disabled):not(.current)"))
1256
+ {
1257
+ var href = anchor.attr("href"),
1258
+ position = parseInt(href.substring(href.lastIndexOf("-") + 1), 0);
1259
+
1260
+ goToStep(wizard, options, state, position);
1261
+ }
1262
+
1263
+ // If nothing has changed
1264
+ if (oldIndex === state.currentIndex)
1265
+ {
1266
+ getStepAnchor(wizard, oldIndex).focus();
1267
+ return false;
1268
+ }
1269
+ }
1270
+
1271
+ function throwError(message)
1272
+ {
1273
+ if (arguments.length > 1)
1274
+ {
1275
+ message = message.format(Array.prototype.slice.call(arguments, 1));
1276
+ }
1277
+
1278
+ throw new Error(message);
1279
+ }
1280
+
1281
+ /**
1282
+ * Checks an argument for null or undefined and throws an error if one check applies.
1283
+ *
1284
+ * @static
1285
+ * @private
1286
+ * @method validateArgument
1287
+ * @param argumentName {String} The name of the given argument
1288
+ * @param argumentValue {Object} The argument itself
1289
+ */
1290
+ function validateArgument(argumentName, argumentValue)
1291
+ {
1292
+ if (argumentValue == null)
1293
+ {
1294
+ throwError("The argument '{0}' is null or undefined.", argumentName);
1295
+ }
1296
+ }
1297
+
1298
+ /**
1299
+ * Represents a jQuery wizard plugin.
1300
+ *
1301
+ * @class steps
1302
+ * @constructor
1303
+ * @param [method={}] The name of the method as `String` or an JSON object for initialization
1304
+ * @param [params=]* {Array} Additional arguments for a method call
1305
+ * @chainable
1306
+ **/
1307
+ $.fn.steps = function (method)
1308
+ {
1309
+ if ($.fn.steps[method])
1310
+ {
1311
+ return $.fn.steps[method].apply(this, Array.prototype.slice.call(arguments, 1));
1312
+ }
1313
+ else if (typeof method === "object" || !method)
1314
+ {
1315
+ return initialize.apply(this, arguments);
1316
+ }
1317
+ else
1318
+ {
1319
+ $.error("Method " + method + " does not exist on jQuery.steps");
1320
+ }
1321
+ };
1322
+
1323
+ /**
1324
+ * Adds a new step.
1325
+ *
1326
+ * @method add
1327
+ * @param step {Object} The step object to add
1328
+ * @chainable
1329
+ **/
1330
+ $.fn.steps.add = function (step)
1331
+ {
1332
+ var state = getState(this);
1333
+ return insertStep(this, getOptions(this), state, state.stepCount, step);
1334
+ };
1335
+
1336
+ /**
1337
+ * Removes the control functionality completely and transforms the current state to the initial HTML structure.
1338
+ *
1339
+ * @method destroy
1340
+ * @chainable
1341
+ **/
1342
+ $.fn.steps.destroy = function ()
1343
+ {
1344
+ return destroy(this, getOptions(this));
1345
+ };
1346
+
1347
+ /**
1348
+ * Triggers the onFinishing and onFinished event.
1349
+ *
1350
+ * @method finish
1351
+ **/
1352
+ $.fn.steps.finish = function ()
1353
+ {
1354
+ finishStep(this, getState(this));
1355
+ };
1356
+
1357
+ /**
1358
+ * Gets the current step index.
1359
+ *
1360
+ * @method getCurrentIndex
1361
+ * @return {Integer} The actual step index (zero-based)
1362
+ * @for steps
1363
+ **/
1364
+ $.fn.steps.getCurrentIndex = function ()
1365
+ {
1366
+ return getState(this).currentIndex;
1367
+ };
1368
+
1369
+ /**
1370
+ * Gets the current step object.
1371
+ *
1372
+ * @method getCurrentStep
1373
+ * @return {Object} The actual step object
1374
+ **/
1375
+ $.fn.steps.getCurrentStep = function ()
1376
+ {
1377
+ return getStep(this, getState(this).currentIndex);
1378
+ };
1379
+
1380
+ /**
1381
+ * Gets a specific step object by index.
1382
+ *
1383
+ * @method getStep
1384
+ * @param index {Integer} An integer that belongs to the position of a step
1385
+ * @return {Object} A specific step object
1386
+ **/
1387
+ $.fn.steps.getStep = function (index)
1388
+ {
1389
+ return getStep(this, index);
1390
+ };
1391
+
1392
+ /**
1393
+ * Inserts a new step to a specific position.
1394
+ *
1395
+ * @method insert
1396
+ * @param index {Integer} The position (zero-based) to add
1397
+ * @param step {Object} The step object to add
1398
+ * @example
1399
+ * $("#wizard").steps().insert(0, {
1400
+ * title: "Title",
1401
+ * content: "", // optional
1402
+ * contentMode: "async", // optional
1403
+ * contentUrl: "/Content/Step/1" // optional
1404
+ * });
1405
+ * @chainable
1406
+ **/
1407
+ $.fn.steps.insert = function (index, step)
1408
+ {
1409
+ return insertStep(this, getOptions(this), getState(this), index, step);
1410
+ };
1411
+
1412
+ /**
1413
+ * Routes to the next step.
1414
+ *
1415
+ * @method next
1416
+ * @return {Boolean} Indicates whether the action executed
1417
+ **/
1418
+ $.fn.steps.next = function ()
1419
+ {
1420
+ return goToNextStep(this, getOptions(this), getState(this));
1421
+ };
1422
+
1423
+ /**
1424
+ * Routes to the previous step.
1425
+ *
1426
+ * @method previous
1427
+ * @return {Boolean} Indicates whether the action executed
1428
+ **/
1429
+ $.fn.steps.previous = function ()
1430
+ {
1431
+ return goToPreviousStep(this, getOptions(this), getState(this));
1432
+ };
1433
+
1434
+ /**
1435
+ * Removes a specific step by an given index.
1436
+ *
1437
+ * @method remove
1438
+ * @param index {Integer} The position (zero-based) of the step to remove
1439
+ * @return Indecates whether the item is removed.
1440
+ **/
1441
+ $.fn.steps.remove = function (index)
1442
+ {
1443
+ return removeStep(this, getOptions(this), getState(this), index);
1444
+ };
1445
+
1446
+ /**
1447
+ * Sets a specific step object by index.
1448
+ *
1449
+ * @method setStep
1450
+ * @param index {Integer} An integer that belongs to the position of a step
1451
+ * @param step {Object} The step object to change
1452
+ **/
1453
+ $.fn.steps.setStep = function (index, step)
1454
+ {
1455
+ throw new Error("Not yet implemented!");
1456
+ };
1457
+
1458
+ /**
1459
+ * Skips an certain amount of steps.
1460
+ *
1461
+ * @method skip
1462
+ * @param count {Integer} The amount of steps that should be skipped
1463
+ * @return {Boolean} Indicates whether the action executed
1464
+ **/
1465
+ $.fn.steps.skip = function (count)
1466
+ {
1467
+ throw new Error("Not yet implemented!");
1468
+ };
1469
+
1470
+ /**
1471
+ * An enum represents the different content types of a step and their loading mechanisms.
1472
+ *
1473
+ * @class contentMode
1474
+ * @for steps
1475
+ **/
1476
+ var contentMode = $.fn.steps.contentMode = {
1477
+ /**
1478
+ * HTML embedded content
1479
+ *
1480
+ * @readOnly
1481
+ * @property html
1482
+ * @type Integer
1483
+ * @for contentMode
1484
+ **/
1485
+ html: 0,
1486
+
1487
+ /**
1488
+ * IFrame embedded content
1489
+ *
1490
+ * @readOnly
1491
+ * @property iframe
1492
+ * @type Integer
1493
+ * @for contentMode
1494
+ **/
1495
+ iframe: 1,
1496
+
1497
+ /**
1498
+ * Async embedded content
1499
+ *
1500
+ * @readOnly
1501
+ * @property async
1502
+ * @type Integer
1503
+ * @for contentMode
1504
+ **/
1505
+ async: 2
1506
+ };
1507
+
1508
+ /**
1509
+ * An enum represents the orientation of the steps navigation.
1510
+ *
1511
+ * @class stepsOrientation
1512
+ * @for steps
1513
+ **/
1514
+ var stepsOrientation = $.fn.steps.stepsOrientation = {
1515
+ /**
1516
+ * Horizontal orientation
1517
+ *
1518
+ * @readOnly
1519
+ * @property horizontal
1520
+ * @type Integer
1521
+ * @for stepsOrientation
1522
+ **/
1523
+ horizontal: 0,
1524
+
1525
+ /**
1526
+ * Vertical orientation
1527
+ *
1528
+ * @readOnly
1529
+ * @property vertical
1530
+ * @type Integer
1531
+ * @for stepsOrientation
1532
+ **/
1533
+ vertical: 1
1534
+ };
1535
+
1536
+ /**
1537
+ * An enum that represents the various transition animations.
1538
+ *
1539
+ * @class transitionEffect
1540
+ * @for steps
1541
+ **/
1542
+ var transitionEffect = $.fn.steps.transitionEffect = {
1543
+ /**
1544
+ * No transition animation
1545
+ *
1546
+ * @readOnly
1547
+ * @property none
1548
+ * @type Integer
1549
+ * @for transitionEffect
1550
+ **/
1551
+ none: 0,
1552
+
1553
+ /**
1554
+ * Fade in transition
1555
+ *
1556
+ * @readOnly
1557
+ * @property fade
1558
+ * @type Integer
1559
+ * @for transitionEffect
1560
+ **/
1561
+ fade: 1,
1562
+
1563
+ /**
1564
+ * Slide up transition
1565
+ *
1566
+ * @readOnly
1567
+ * @property slide
1568
+ * @type Integer
1569
+ * @for transitionEffect
1570
+ **/
1571
+ slide: 2,
1572
+
1573
+ /**
1574
+ * Slide left transition
1575
+ *
1576
+ * @readOnly
1577
+ * @property slideLeft
1578
+ * @type Integer
1579
+ * @for transitionEffect
1580
+ **/
1581
+ slideLeft: 3
1582
+ };
1583
+
1584
+ var stepModel = $.fn.steps.stepModel = {
1585
+ title: "",
1586
+ content: "",
1587
+ contentUrl: "",
1588
+ contentMode: contentMode.html,
1589
+ contentLoaded: false
1590
+ };
1591
+
1592
+ /**
1593
+ * An object that represents the default settings.
1594
+ * There are two possibities to override the sub-properties.
1595
+ * Either by doing it generally (global) or on initialization.
1596
+ *
1597
+ * @static
1598
+ * @class defaults
1599
+ * @for steps
1600
+ * @example
1601
+ * // Global approach
1602
+ * $.steps.defaults.headerTag = "h3";
1603
+ * @example
1604
+ * // Initialization approach
1605
+ * $("#wizard").steps({ headerTag: "h3" });
1606
+ **/
1607
+ var defaults = $.fn.steps.defaults = {
1608
+ /**
1609
+ * The header tag is used to find the step button text within the declared wizard area.
1610
+ *
1611
+ * @property headerTag
1612
+ * @type String
1613
+ * @default "h1"
1614
+ * @for defaults
1615
+ **/
1616
+ headerTag: "h1",
1617
+
1618
+ /**
1619
+ * The body tag is used to find the step content within the declared wizard area.
1620
+ *
1621
+ * @property bodyTag
1622
+ * @type String
1623
+ * @default "div"
1624
+ * @for defaults
1625
+ **/
1626
+ bodyTag: "div",
1627
+
1628
+ /**
1629
+ * The content container tag which will be used to wrap all step contents.
1630
+ *
1631
+ * @property contentContainerTag
1632
+ * @type String
1633
+ * @default "div"
1634
+ * @for defaults
1635
+ **/
1636
+ contentContainerTag: "div",
1637
+
1638
+ /**
1639
+ * The action container tag which will be used to wrap the pagination navigation.
1640
+ *
1641
+ * @property actionContainerTag
1642
+ * @type String
1643
+ * @default "div"
1644
+ * @for defaults
1645
+ **/
1646
+ actionContainerTag: "div",
1647
+
1648
+ /**
1649
+ * The steps container tag which will be used to wrap the steps navigation.
1650
+ *
1651
+ * @property stepsContainerTag
1652
+ * @type String
1653
+ * @default "div"
1654
+ * @for defaults
1655
+ **/
1656
+ stepsContainerTag: "div",
1657
+
1658
+ /**
1659
+ * The css class which will be added to the outer component wrapper.
1660
+ *
1661
+ * @property cssClass
1662
+ * @type String
1663
+ * @default "wizard"
1664
+ * @for defaults
1665
+ * @example
1666
+ * <div class="wizard">
1667
+ * ...
1668
+ * </div>
1669
+ **/
1670
+ cssClass: "wizard",
1671
+
1672
+ /**
1673
+ * The css class which will be used for floating scenarios.
1674
+ *
1675
+ * @property clearFixCssClass
1676
+ * @type String
1677
+ * @default "clearfix"
1678
+ * @for defaults
1679
+ **/
1680
+ clearFixCssClass: "clearfix",
1681
+
1682
+ /**
1683
+ * Determines whether the steps are vertically or horizontally oriented.
1684
+ *
1685
+ * @property stepsOrientation
1686
+ * @type stepsOrientation
1687
+ * @default horizontal
1688
+ * @for defaults
1689
+ * @since 1.0.0
1690
+ **/
1691
+ stepsOrientation: stepsOrientation.horizontal,
1692
+
1693
+ /*
1694
+ * Tempplates
1695
+ */
1696
+
1697
+ /**
1698
+ * The title template which will be used to create a step button.
1699
+ *
1700
+ * @property titleTemplate
1701
+ * @type String
1702
+ * @default "<span class=\"number\">#index#.</span> #title#"
1703
+ * @for defaults
1704
+ **/
1705
+ titleTemplate: "<span class=\"number\">#index#.</span> #title#",
1706
+
1707
+ /**
1708
+ * The loading template which will be used to create the loading animation.
1709
+ *
1710
+ * @property loadingTemplate
1711
+ * @type String
1712
+ * @default "<span class=\"spinner\"></span> #text#"
1713
+ * @for defaults
1714
+ **/
1715
+ loadingTemplate: "<span class=\"spinner\"></span> #text#",
1716
+
1717
+ /*
1718
+ * Behaviour
1719
+ */
1720
+
1721
+ /**
1722
+ * Sets the focus to the first wizard instance in order to enable the key navigation from the begining if `true`.
1723
+ *
1724
+ * @property autoFocus
1725
+ * @type Boolean
1726
+ * @default false
1727
+ * @for defaults
1728
+ * @since 0.9.4
1729
+ **/
1730
+ autoFocus: false,
1731
+
1732
+ /**
1733
+ * Enables all steps from the begining if `true` (all steps are clickable).
1734
+ *
1735
+ * @property enableAllSteps
1736
+ * @type Boolean
1737
+ * @default false
1738
+ * @for defaults
1739
+ **/
1740
+ enableAllSteps: false,
1741
+
1742
+ /**
1743
+ * Enables keyboard navigation if `true` (arrow left and arrow right).
1744
+ *
1745
+ * @property enableKeyNavigation
1746
+ * @type Boolean
1747
+ * @default true
1748
+ * @for defaults
1749
+ **/
1750
+ enableKeyNavigation: true,
1751
+
1752
+ /**
1753
+ * Enables pagination if `true`.
1754
+ *
1755
+ * @property enablePagination
1756
+ * @type Boolean
1757
+ * @default true
1758
+ * @for defaults
1759
+ **/
1760
+ enablePagination: true,
1761
+
1762
+ /**
1763
+ * Suppresses pagination if a form field is focused.
1764
+ *
1765
+ * @property suppressPaginationOnFocus
1766
+ * @type Boolean
1767
+ * @default true
1768
+ * @for defaults
1769
+ **/
1770
+ suppressPaginationOnFocus: true,
1771
+
1772
+ /**
1773
+ * Enables cache for async loaded or iframe embedded content.
1774
+ *
1775
+ * @property enableContentCache
1776
+ * @type Boolean
1777
+ * @default true
1778
+ * @for defaults
1779
+ **/
1780
+ enableContentCache: true,
1781
+
1782
+ /**
1783
+ * Shows the cancel button if enabled.
1784
+ *
1785
+ * @property enableCancelButton
1786
+ * @type Boolean
1787
+ * @default false
1788
+ * @for defaults
1789
+ **/
1790
+ enableCancelButton: false,
1791
+
1792
+ /**
1793
+ * Shows the finish button if enabled.
1794
+ *
1795
+ * @property enableFinishButton
1796
+ * @type Boolean
1797
+ * @default true
1798
+ * @for defaults
1799
+ **/
1800
+ enableFinishButton: true,
1801
+
1802
+ /**
1803
+ * Not yet implemented.
1804
+ *
1805
+ * @property preloadContent
1806
+ * @type Boolean
1807
+ * @default false
1808
+ * @for defaults
1809
+ **/
1810
+ preloadContent: false,
1811
+
1812
+ /**
1813
+ * Shows the finish button always (on each step; right beside the next button) if `true`.
1814
+ * Otherwise the next button will be replaced by the finish button if the last step becomes active.
1815
+ *
1816
+ * @property showFinishButtonAlways
1817
+ * @type Boolean
1818
+ * @default false
1819
+ * @for defaults
1820
+ **/
1821
+ showFinishButtonAlways: false,
1822
+
1823
+ /**
1824
+ * Prevents jumping to a previous step.
1825
+ *
1826
+ * @property forceMoveForward
1827
+ * @type Boolean
1828
+ * @default false
1829
+ * @for defaults
1830
+ **/
1831
+ forceMoveForward: false,
1832
+
1833
+ /**
1834
+ * Saves the current state (step position) to a cookie.
1835
+ * By coming next time the last active step becomes activated.
1836
+ *
1837
+ * @property saveState
1838
+ * @type Boolean
1839
+ * @default false
1840
+ * @for defaults
1841
+ **/
1842
+ saveState: false,
1843
+
1844
+ /**
1845
+ * The position to start on (zero-based).
1846
+ *
1847
+ * @property startIndex
1848
+ * @type Integer
1849
+ * @default 0
1850
+ * @for defaults
1851
+ **/
1852
+ startIndex: 0,
1853
+
1854
+ /*
1855
+ * Animation Effect Configuration
1856
+ */
1857
+
1858
+ /**
1859
+ * The animation effect which will be used for step transitions.
1860
+ *
1861
+ * @property transitionEffect
1862
+ * @type transitionEffect
1863
+ * @default none
1864
+ * @for defaults
1865
+ **/
1866
+ transitionEffect: transitionEffect.none,
1867
+
1868
+ /**
1869
+ * Animation speed for step transitions (in milliseconds).
1870
+ *
1871
+ * @property transitionEffectSpeed
1872
+ * @type Integer
1873
+ * @default 200
1874
+ * @for defaults
1875
+ **/
1876
+ transitionEffectSpeed: 200,
1877
+
1878
+ /*
1879
+ * Events
1880
+ */
1881
+
1882
+ /**
1883
+ * Fires before the step changes and can be used to prevent step changing by returning `false`.
1884
+ * Very useful for form validation.
1885
+ *
1886
+ * @property onStepChanging
1887
+ * @type Event
1888
+ * @default function (event, currentIndex, newIndex) { return true; }
1889
+ * @for defaults
1890
+ **/
1891
+ onStepChanging: function (event, currentIndex, newIndex) { return true; },
1892
+
1893
+ /**
1894
+ * Fires after the step has change.
1895
+ *
1896
+ * @property onStepChanged
1897
+ * @type Event
1898
+ * @default function (event, currentIndex, priorIndex) { }
1899
+ * @for defaults
1900
+ **/
1901
+ onStepChanged: function (event, currentIndex, priorIndex) { },
1902
+
1903
+ /**
1904
+ * Fires after cancelation.
1905
+ *
1906
+ * @property onCanceled
1907
+ * @type Event
1908
+ * @default function (event) { }
1909
+ * @for defaults
1910
+ **/
1911
+ onCanceled: function (event) { },
1912
+
1913
+ /**
1914
+ * Fires before finishing and can be used to prevent completion by returning `false`.
1915
+ * Very useful for form validation.
1916
+ *
1917
+ * @property onFinishing
1918
+ * @type Event
1919
+ * @default function (event, currentIndex) { return true; }
1920
+ * @for defaults
1921
+ **/
1922
+ onFinishing: function (event, currentIndex) { return true; },
1923
+
1924
+ /**
1925
+ * Fires after completion.
1926
+ *
1927
+ * @property onFinished
1928
+ * @type Event
1929
+ * @default function (event, currentIndex) { }
1930
+ * @for defaults
1931
+ **/
1932
+ onFinished: function (event, currentIndex) { },
1933
+
1934
+ /**
1935
+ * Contains all labels.
1936
+ *
1937
+ * @property labels
1938
+ * @type Object
1939
+ * @for defaults
1940
+ **/
1941
+ labels: {
1942
+ /**
1943
+ * Label for the cancel button.
1944
+ *
1945
+ * @property cancel
1946
+ * @type String
1947
+ * @default "Cancel"
1948
+ * @for defaults
1949
+ **/
1950
+ cancel: "Cancel",
1951
+
1952
+ /**
1953
+ * This label is important for accessability reasons.
1954
+ * Indicates which step is activated.
1955
+ *
1956
+ * @property current
1957
+ * @type String
1958
+ * @default "current step:"
1959
+ * @for defaults
1960
+ **/
1961
+ current: "current step:",
1962
+
1963
+ /**
1964
+ * This label is important for accessability reasons and describes the kind of navigation.
1965
+ *
1966
+ * @property pagination
1967
+ * @type String
1968
+ * @default "Pagination"
1969
+ * @for defaults
1970
+ * @since 0.9.7
1971
+ **/
1972
+ pagination: "Pagination",
1973
+
1974
+ /**
1975
+ * Label for the finish button.
1976
+ *
1977
+ * @property finish
1978
+ * @type String
1979
+ * @default "Finish"
1980
+ * @for defaults
1981
+ **/
1982
+ finish: "Finish",
1983
+
1984
+ /**
1985
+ * Label for the next button.
1986
+ *
1987
+ * @property next
1988
+ * @type String
1989
+ * @default "Next"
1990
+ * @for defaults
1991
+ **/
1992
+ next: "Next",
1993
+
1994
+ /**
1995
+ * Label for the previous button.
1996
+ *
1997
+ * @property previous
1998
+ * @type String
1999
+ * @default "Previous"
2000
+ * @for defaults
2001
+ **/
2002
+ previous: "Previous",
2003
+
2004
+ /**
2005
+ * Label for the loading animation.
2006
+ *
2007
+ * @property loading
2008
+ * @type String
2009
+ * @default "Loading ..."
2010
+ * @for defaults
2011
+ **/
2012
+ loading: "Loading ..."
2013
+ }
2014
+ };
2015
+ })(jQuery);