Subversion-Projekte lars-tiefland.webanos.faltradxxs.de

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
24 lars 1
/*!
2
 * jQuery Steps v1.1.0 - 09/04/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, function()
514
        {
515
            wizard.triggerHandler("stepChanged", [index, oldIndex]);
516
        });
517
    }
518
    else
519
    {
520
        wizard.find(".steps li").eq(oldIndex).addClass("error");
521
    }
522
 
523
    return true;
524
}
525
 
526
function increaseCurrentIndexBy(state, increaseBy)
527
{
528
    return state.currentIndex + increaseBy;
529
}
530
 
531
/**
532
 * Initializes the component.
533
 *
534
 * @static
535
 * @private
536
 * @method initialize
537
 * @param options {Object} The component settings
538
 **/
539
function initialize(options)
540
{
541
    /*jshint -W040 */
542
    var opts = $.extend(true, {}, defaults, options);
543
 
544
    return this.each(function ()
545
    {
546
        var wizard = $(this);
547
        var state = {
548
            currentIndex: opts.startIndex,
549
            currentStep: null,
550
            stepCount: 0,
551
            transitionElement: null
552
        };
553
 
554
        // Create data container
555
        wizard.data("options", opts);
556
        wizard.data("state", state);
557
        wizard.data("steps", []);
558
 
559
        analyzeData(wizard, opts, state);
560
        render(wizard, opts, state);
561
        registerEvents(wizard, opts);
562
 
563
        // Trigger focus
564
        if (opts.autoFocus && _uniqueId === 0)
565
        {
566
            getStepAnchor(wizard, opts.startIndex).focus();
567
        }
568
 
569
        wizard.triggerHandler("init", [opts.startIndex]);
570
    });
571
}
572
 
573
/**
574
 * Inserts a new step to a specific position.
575
 *
576
 * @static
577
 * @private
578
 * @method insertStep
579
 * @param wizard {Object} The jQuery wizard object
580
 * @param options {Object} Settings of the current wizard
581
 * @param state {Object} The state container of the current wizard
582
 * @param index {Integer} The position (zero-based) to add
583
 * @param step {Object} The step object to add
584
 * @example
585
 *     $("#wizard").steps().insert(0, {
586
 *         title: "Title",
587
 *         content: "", // optional
588
 *         contentMode: "async", // optional
589
 *         contentUrl: "/Content/Step/1" // optional
590
 *     });
591
 * @chainable
592
 **/
593
function insertStep(wizard, options, state, index, step)
594
{
595
    if (index < 0 || index > state.stepCount)
596
    {
597
        throwError(_indexOutOfRangeErrorMessage);
598
    }
599
 
600
    // TODO: Validate step object
601
 
602
    // Change data
603
    step = $.extend({}, stepModel, step);
604
    insertStepToCache(wizard, index, step);
605
    if (state.currentIndex !== state.stepCount && state.currentIndex >= index)
606
    {
607
        state.currentIndex++;
608
        saveCurrentStateToCookie(wizard, options, state);
609
    }
610
    state.stepCount++;
611
 
612
    var contentContainer = wizard.find(".content"),
613
        header = $("<{0}>{1}</{0}>".format(options.headerTag, step.title)),
614
        body = $("<{0}></{0}>".format(options.bodyTag));
615
 
616
    if (step.contentMode == null || step.contentMode === contentMode.html)
617
    {
618
        body.html(step.content);
619
    }
620
 
621
    if (index === 0)
622
    {
623
        contentContainer.prepend(body).prepend(header);
624
    }
625
    else
626
    {
627
        getStepPanel(wizard, (index - 1)).after(body).after(header);
628
    }
629
 
630
    renderBody(wizard, state, body, index);
631
    renderTitle(wizard, options, state, header, index);
632
    refreshSteps(wizard, options, state, index);
633
    if (index === state.currentIndex)
634
    {
635
        refreshStepNavigation(wizard, options, state);
636
    }
637
    refreshPagination(wizard, options, state);
638
 
639
    return wizard;
640
}
641
 
642
/**
643
 * Inserts a step object to the cache at a specific position.
644
 *
645
 * @static
646
 * @private
647
 * @method insertStepToCache
648
 * @param wizard {Object} A jQuery wizard object
649
 * @param index {Integer} The position (zero-based) to add
650
 * @param step {Object} The step object to add
651
 **/
652
function insertStepToCache(wizard, index, step)
653
{
654
    getSteps(wizard).splice(index, 0, step);
655
}
656
 
657
/**
658
 * Handles the keyup DOM event for pagination.
659
 *
660
 * @static
661
 * @private
662
 * @event keyup
663
 * @param event {Object} An event object
664
 */
665
function keyUpHandler(event)
666
{
667
    var wizard = $(this),
668
        options = getOptions(wizard),
669
        state = getState(wizard);
670
 
671
    if (options.suppressPaginationOnFocus && wizard.find(":focus").is(":input"))
672
    {
673
        event.preventDefault();
674
        return false;
675
    }
676
 
677
    var keyCodes = { left: 37, right: 39 };
678
    if (event.keyCode === keyCodes.left)
679
    {
680
        event.preventDefault();
681
        goToPreviousStep(wizard, options, state);
682
    }
683
    else if (event.keyCode === keyCodes.right)
684
    {
685
        event.preventDefault();
686
        goToNextStep(wizard, options, state);
687
    }
688
}
689
 
690
/**
691
 * Loads and includes async content.
692
 *
693
 * @static
694
 * @private
695
 * @method loadAsyncContent
696
 * @param wizard {Object} A jQuery wizard object
697
 * @param options {Object} Settings of the current wizard
698
 * @param state {Object} The state container of the current wizard
699
 */
700
function loadAsyncContent(wizard, options, state)
701
{
702
    if (state.stepCount > 0)
703
    {
704
        var currentIndex = state.currentIndex,
705
            currentStep = getStep(wizard, currentIndex);
706
 
707
        if (!options.enableContentCache || !currentStep.contentLoaded)
708
        {
709
            switch (getValidEnumValue(contentMode, currentStep.contentMode))
710
            {
711
                case contentMode.iframe:
712
                    wizard.find(".content > .body").eq(state.currentIndex).empty()
713
                        .html("<iframe src=\"" + currentStep.contentUrl + "\" frameborder=\"0\" scrolling=\"no\" />")
714
                        .data("loaded", "1");
715
                    break;
716
 
717
                case contentMode.async:
718
                    var currentStepContent = getStepPanel(wizard, currentIndex)._aria("busy", "true")
719
                        .empty().append(renderTemplate(options.loadingTemplate, { text: options.labels.loading }));
720
 
721
                    $.ajax({ url: currentStep.contentUrl, cache: false }).done(function (data)
722
                    {
723
                        currentStepContent.empty().html(data)._aria("busy", "false").data("loaded", "1");
724
                        wizard.triggerHandler("contentLoaded", [currentIndex]);
725
                    });
726
                    break;
727
            }
728
        }
729
    }
730
}
731
 
732
/**
733
 * Fires the action next or previous click event.
734
 *
735
 * @static
736
 * @private
737
 * @method paginationClick
738
 * @param wizard {Object} The jQuery wizard object
739
 * @param options {Object} Settings of the current wizard
740
 * @param state {Object} The state container of the current wizard
741
 * @param index {Integer} The position (zero-based) to route to
742
 * @return {Boolean} Indicates whether the event fired successfully or not
743
 **/
744
function paginationClick(wizard, options, state, index)
745
{
746
    var oldIndex = state.currentIndex;
747
 
748
    if (index >= 0 && index < state.stepCount && !(options.forceMoveForward && index < state.currentIndex))
749
    {
750
        var anchor = getStepAnchor(wizard, index),
751
            parent = anchor.parent(),
752
            isDisabled = parent.hasClass("disabled");
753
 
754
        // Enable the step to make the anchor clickable!
755
        parent._enableAria();
756
        anchor.click();
757
 
758
        // An error occured
759
        if (oldIndex === state.currentIndex && isDisabled)
760
        {
761
            // Disable the step again if current index has not changed; prevents click action.
762
            parent._enableAria(false);
763
            return false;
764
        }
765
 
766
        return true;
767
    }
768
 
769
    return false;
770
}
771
 
772
/**
773
 * Fires when a pagination click happens.
774
 *
775
 * @static
776
 * @private
777
 * @event click
778
 * @param event {Object} An event object
779
 */
780
function paginationClickHandler(event)
781
{
782
    event.preventDefault();
783
 
784
    var anchor = $(this),
785
        wizard = anchor.parent().parent().parent().parent(),
786
        options = getOptions(wizard),
787
        state = getState(wizard),
788
        href = anchor.attr("href");
789
 
790
    switch (href.substring(href.lastIndexOf("#") + 1))
791
    {
792
        case "cancel":
793
            cancel(wizard);
794
            break;
795
 
796
        case "finish":
797
            finishStep(wizard, state);
798
            break;
799
 
800
        case "next":
801
            goToNextStep(wizard, options, state);
802
            break;
803
 
804
        case "previous":
805
            goToPreviousStep(wizard, options, state);
806
            break;
807
    }
808
}
809
 
810
/**
811
 * Refreshs the visualization state for the entire pagination.
812
 *
813
 * @static
814
 * @private
815
 * @method refreshPagination
816
 * @param wizard {Object} A jQuery wizard object
817
 * @param options {Object} Settings of the current wizard
818
 * @param state {Object} The state container of the current wizard
819
 */
820
function refreshPagination(wizard, options, state)
821
{
822
    if (options.enablePagination)
823
    {
824
        var finish = wizard.find(".actions a[href$='#finish']").parent(),
825
            next = wizard.find(".actions a[href$='#next']").parent();
826
 
827
        if (!options.forceMoveForward)
828
        {
829
            var previous = wizard.find(".actions a[href$='#previous']").parent();
830
            previous._enableAria(state.currentIndex > 0);
831
        }
832
 
833
        if (options.enableFinishButton && options.showFinishButtonAlways)
834
        {
835
            finish._enableAria(state.stepCount > 0);
836
            next._enableAria(state.stepCount > 1 && state.stepCount > (state.currentIndex + 1));
837
        }
838
        else
839
        {
840
            finish._showAria(options.enableFinishButton && state.stepCount === (state.currentIndex + 1));
841
            next._showAria(state.stepCount === 0 || state.stepCount > (state.currentIndex + 1)).
842
                _enableAria(state.stepCount > (state.currentIndex + 1) || !options.enableFinishButton);
843
        }
844
    }
845
}
846
 
847
/**
848
 * Refreshs the visualization state for the step navigation (tabs).
849
 *
850
 * @static
851
 * @private
852
 * @method refreshStepNavigation
853
 * @param wizard {Object} A jQuery wizard object
854
 * @param options {Object} Settings of the current wizard
855
 * @param state {Object} The state container of the current wizard
856
 * @param [oldIndex] {Integer} The index of the prior step
857
 */
858
function refreshStepNavigation(wizard, options, state, oldIndex)
859
{
860
    var currentOrNewStepAnchor = getStepAnchor(wizard, state.currentIndex),
861
        currentInfo = $("<span class=\"current-info audible\">" + options.labels.current + " </span>"),
862
        stepTitles = wizard.find(".content > .title");
863
 
864
    if (oldIndex != null)
865
    {
866
        var oldStepAnchor = getStepAnchor(wizard, oldIndex);
867
        oldStepAnchor.parent().addClass("done").removeClass("error")._selectAria(false);
868
        stepTitles.eq(oldIndex).removeClass("current").next(".body").removeClass("current");
869
        currentInfo = oldStepAnchor.find(".current-info");
870
        currentOrNewStepAnchor.focus();
871
    }
872
 
873
    currentOrNewStepAnchor.prepend(currentInfo).parent()._selectAria().removeClass("done")._enableAria();
874
    stepTitles.eq(state.currentIndex).addClass("current").next(".body").addClass("current");
875
}
876
 
877
/**
878
 * Refreshes step buttons and their related titles beyond a certain position.
879
 *
880
 * @static
881
 * @private
882
 * @method refreshSteps
883
 * @param wizard {Object} A jQuery wizard object
884
 * @param options {Object} Settings of the current wizard
885
 * @param state {Object} The state container of the current wizard
886
 * @param index {Integer} The start point for refreshing ids
887
 */
888
function refreshSteps(wizard, options, state, index)
889
{
890
    var uniqueId = getUniqueId(wizard);
891
 
892
    for (var i = index; i < state.stepCount; i++)
893
    {
894
        var uniqueStepId = uniqueId + _tabSuffix + i,
895
            uniqueBodyId = uniqueId + _tabpanelSuffix + i,
896
            uniqueHeaderId = uniqueId + _titleSuffix + i,
897
            title = wizard.find(".title").eq(i)._id(uniqueHeaderId);
898
 
899
        wizard.find(".steps a").eq(i)._id(uniqueStepId)
900
            ._aria("controls", uniqueBodyId).attr("href", "#" + uniqueHeaderId)
901
            .html(renderTemplate(options.titleTemplate, { index: i + 1, title: title.html() }));
902
        wizard.find(".body").eq(i)._id(uniqueBodyId)
903
            ._aria("labelledby", uniqueHeaderId);
904
    }
905
}
906
 
907
function registerEvents(wizard, options)
908
{
909
    var eventNamespace = getEventNamespace(wizard);
910
 
911
    wizard.bind("canceled" + eventNamespace, options.onCanceled);
912
    wizard.bind("contentLoaded" + eventNamespace, options.onContentLoaded);
913
    wizard.bind("finishing" + eventNamespace, options.onFinishing);
914
    wizard.bind("finished" + eventNamespace, options.onFinished);
915
    wizard.bind("init" + eventNamespace, options.onInit);
916
    wizard.bind("stepChanging" + eventNamespace, options.onStepChanging);
917
    wizard.bind("stepChanged" + eventNamespace, options.onStepChanged);
918
 
919
    if (options.enableKeyNavigation)
920
    {
921
        wizard.bind("keyup" + eventNamespace, keyUpHandler);
922
    }
923
 
924
    wizard.find(".actions a").bind("click" + eventNamespace, paginationClickHandler);
925
}
926
 
927
/**
928
 * Removes a specific step by an given index.
929
 *
930
 * @static
931
 * @private
932
 * @method removeStep
933
 * @param wizard {Object} A jQuery wizard object
934
 * @param options {Object} Settings of the current wizard
935
 * @param state {Object} The state container of the current wizard
936
 * @param index {Integer} The position (zero-based) of the step to remove
937
 * @return Indecates whether the item is removed.
938
 **/
939
function removeStep(wizard, options, state, index)
940
{
941
    // Index out of range and try deleting current item will return false.
942
    if (index < 0 || index >= state.stepCount || state.currentIndex === index)
943
    {
944
        return false;
945
    }
946
 
947
    // Change data
948
    removeStepFromCache(wizard, index);
949
    if (state.currentIndex > index)
950
    {
951
        state.currentIndex--;
952
        saveCurrentStateToCookie(wizard, options, state);
953
    }
954
    state.stepCount--;
955
 
956
    getStepTitle(wizard, index).remove();
957
    getStepPanel(wizard, index).remove();
958
    getStepAnchor(wizard, index).parent().remove();
959
 
960
    // Set the "first" class to the new first step button
961
    if (index === 0)
962
    {
963
        wizard.find(".steps li").first().addClass("first");
964
    }
965
 
966
    // Set the "last" class to the new last step button
967
    if (index === state.stepCount)
968
    {
969
        wizard.find(".steps li").eq(index).addClass("last");
970
    }
971
 
972
    refreshSteps(wizard, options, state, index);
973
    refreshPagination(wizard, options, state);
974
 
975
    return true;
976
}
977
 
978
function removeStepFromCache(wizard, index)
979
{
980
    getSteps(wizard).splice(index, 1);
981
}
982
 
983
/**
984
 * Transforms the base html structure to a more sensible html structure.
985
 *
986
 * @static
987
 * @private
988
 * @method render
989
 * @param wizard {Object} A jQuery wizard object
990
 * @param options {Object} Settings of the current wizard
991
 * @param state {Object} The state container of the current wizard
992
 **/
993
function render(wizard, options, state)
994
{
995
    // Create a content wrapper and copy HTML from the intial wizard structure
996
    var wrapperTemplate = "<{0} class=\"{1}\">{2}</{0}>",
997
        orientation = getValidEnumValue(stepsOrientation, options.stepsOrientation),
998
        verticalCssClass = (orientation === stepsOrientation.vertical) ? " vertical" : "",
999
        contentWrapper = $(wrapperTemplate.format(options.contentContainerTag, "content " + options.clearFixCssClass, wizard.html())),
1000
        stepsWrapper = $(wrapperTemplate.format(options.stepsContainerTag, "steps " + options.clearFixCssClass, "<ul role=\"tablist\"></ul>")),
1001
        stepTitles = contentWrapper.children(options.headerTag),
1002
        stepContents = contentWrapper.children(options.bodyTag);
1003
 
1004
    // Transform the wizard wrapper and remove the inner HTML
1005
    wizard.attr("role", "application").empty().append(stepsWrapper).append(contentWrapper)
1006
        .addClass(options.cssClass + " " + options.clearFixCssClass + verticalCssClass);
1007
 
1008
    // Add WIA-ARIA support
1009
    stepContents.each(function (index)
1010
    {
1011
        renderBody(wizard, state, $(this), index);
1012
    });
1013
 
1014
    stepTitles.each(function (index)
1015
    {
1016
        renderTitle(wizard, options, state, $(this), index);
1017
    });
1018
 
1019
    refreshStepNavigation(wizard, options, state);
1020
    renderPagination(wizard, options, state);
1021
}
1022
 
1023
/**
1024
 * Transforms the body to a proper tabpanel.
1025
 *
1026
 * @static
1027
 * @private
1028
 * @method renderBody
1029
 * @param wizard {Object} A jQuery wizard object
1030
 * @param body {Object} A jQuery body object
1031
 * @param index {Integer} The position of the body
1032
 */
1033
function renderBody(wizard, state, body, index)
1034
{
1035
    var uniqueId = getUniqueId(wizard),
1036
        uniqueBodyId = uniqueId + _tabpanelSuffix + index,
1037
        uniqueHeaderId = uniqueId + _titleSuffix + index;
1038
 
1039
    body._id(uniqueBodyId).attr("role", "tabpanel")._aria("labelledby", uniqueHeaderId)
1040
        .addClass("body")._showAria(state.currentIndex === index);
1041
}
1042
 
1043
/**
1044
 * Renders a pagination if enabled.
1045
 *
1046
 * @static
1047
 * @private
1048
 * @method renderPagination
1049
 * @param wizard {Object} A jQuery wizard object
1050
 * @param options {Object} Settings of the current wizard
1051
 * @param state {Object} The state container of the current wizard
1052
 */
1053
function renderPagination(wizard, options, state)
1054
{
1055
    if (options.enablePagination)
1056
    {
1057
        var pagination = "<{0} class=\"actions {1}\"><ul role=\"menu\" aria-label=\"{2}\">{3}</ul></{0}>",
1058
            buttonTemplate = "<li><a href=\"#{0}\" role=\"menuitem\">{1}</a></li>",
1059
            buttons = "";
1060
 
1061
        if (!options.forceMoveForward)
1062
        {
1063
            buttons += buttonTemplate.format("previous", options.labels.previous);
1064
        }
1065
 
1066
        buttons += buttonTemplate.format("next", options.labels.next);
1067
 
1068
        if (options.enableFinishButton)
1069
        {
1070
            buttons += buttonTemplate.format("finish", options.labels.finish);
1071
        }
1072
 
1073
        if (options.enableCancelButton)
1074
        {
1075
            buttons += buttonTemplate.format("cancel", options.labels.cancel);
1076
        }
1077
 
1078
        wizard.append(pagination.format(options.actionContainerTag, options.clearFixCssClass,
1079
            options.labels.pagination, buttons));
1080
 
1081
        refreshPagination(wizard, options, state);
1082
        loadAsyncContent(wizard, options, state);
1083
    }
1084
}
1085
 
1086
/**
1087
 * Renders a template and replaces all placeholder.
1088
 *
1089
 * @static
1090
 * @private
1091
 * @method renderTemplate
1092
 * @param template {String} A template
1093
 * @param substitutes {Object} A list of substitute
1094
 * @return {String} The rendered template
1095
 */
1096
function renderTemplate(template, substitutes)
1097
{
1098
    var matches = template.match(/#([a-z]*)#/gi);
1099
 
1100
    for (var i = 0; i < matches.length; i++)
1101
    {
1102
        var match = matches[i],
1103
            key = match.substring(1, match.length - 1);
1104
 
1105
        if (substitutes[key] === undefined)
1106
        {
1107
            throwError("The key '{0}' does not exist in the substitute collection!", key);
1108
        }
1109
 
1110
        template = template.replace(match, substitutes[key]);
1111
    }
1112
 
1113
    return template;
1114
}
1115
 
1116
/**
1117
 * Transforms the title to a step item button.
1118
 *
1119
 * @static
1120
 * @private
1121
 * @method renderTitle
1122
 * @param wizard {Object} A jQuery wizard object
1123
 * @param options {Object} Settings of the current wizard
1124
 * @param state {Object} The state container of the current wizard
1125
 * @param header {Object} A jQuery header object
1126
 * @param index {Integer} The position of the header
1127
 */
1128
function renderTitle(wizard, options, state, header, index)
1129
{
1130
    var uniqueId = getUniqueId(wizard),
1131
        uniqueStepId = uniqueId + _tabSuffix + index,
1132
        uniqueBodyId = uniqueId + _tabpanelSuffix + index,
1133
        uniqueHeaderId = uniqueId + _titleSuffix + index,
1134
        stepCollection = wizard.find(".steps > ul"),
1135
        title = renderTemplate(options.titleTemplate, {
1136
            index: index + 1,
1137
            title: header.html()
1138
        }),
1139
        stepItem = $("<li role=\"tab\"><a id=\"" + uniqueStepId + "\" href=\"#" + uniqueHeaderId +
1140
            "\" aria-controls=\"" + uniqueBodyId + "\">" + title + "</a></li>");
1141
 
1142
    stepItem._enableAria(options.enableAllSteps || state.currentIndex > index);
1143
 
1144
    if (state.currentIndex > index)
1145
    {
1146
        stepItem.addClass("done");
1147
    }
1148
 
1149
    header._id(uniqueHeaderId).attr("tabindex", "-1").addClass("title");
1150
 
1151
    if (index === 0)
1152
    {
1153
        stepCollection.prepend(stepItem);
1154
    }
1155
    else
1156
    {
1157
        stepCollection.find("li").eq(index - 1).after(stepItem);
1158
    }
1159
 
1160
    // Set the "first" class to the new first step button
1161
    if (index === 0)
1162
    {
1163
        stepCollection.find("li").removeClass("first").eq(index).addClass("first");
1164
    }
1165
 
1166
    // Set the "last" class to the new last step button
1167
    if (index === (state.stepCount - 1))
1168
    {
1169
        stepCollection.find("li").removeClass("last").eq(index).addClass("last");
1170
    }
1171
 
1172
    // Register click event
1173
    stepItem.children("a").bind("click" + getEventNamespace(wizard), stepClickHandler);
1174
}
1175
 
1176
/**
1177
 * Saves the current state to a cookie.
1178
 *
1179
 * @static
1180
 * @private
1181
 * @method saveCurrentStateToCookie
1182
 * @param wizard {Object} A jQuery wizard object
1183
 * @param options {Object} Settings of the current wizard
1184
 * @param state {Object} The state container of the current wizard
1185
 */
1186
function saveCurrentStateToCookie(wizard, options, state)
1187
{
1188
    if (options.saveState && $.cookie)
1189
    {
1190
        $.cookie(_cookiePrefix + getUniqueId(wizard), state.currentIndex);
1191
    }
1192
}
1193
 
1194
function startTransitionEffect(wizard, options, state, index, oldIndex, doneCallback)
1195
{
1196
    var stepContents = wizard.find(".content > .body"),
1197
        effect = getValidEnumValue(transitionEffect, options.transitionEffect),
1198
        effectSpeed = options.transitionEffectSpeed,
1199
        newStep = stepContents.eq(index),
1200
        currentStep = stepContents.eq(oldIndex);
1201
 
1202
    switch (effect)
1203
    {
1204
        case transitionEffect.fade:
1205
        case transitionEffect.slide:
1206
            var hide = (effect === transitionEffect.fade) ? "fadeOut" : "slideUp",
1207
                show = (effect === transitionEffect.fade) ? "fadeIn" : "slideDown";
1208
 
1209
            state.transitionElement = newStep;
1210
            currentStep[hide](effectSpeed, function ()
1211
            {
1212
                var wizard = $(this)._showAria(false).parent().parent(),
1213
                    state = getState(wizard);
1214
 
1215
                if (state.transitionElement)
1216
                {
1217
                    state.transitionElement[show](effectSpeed, function ()
1218
                    {
1219
                        $(this)._showAria();
1220
                    }).promise().done(doneCallback);
1221
                    state.transitionElement = null;
1222
                }
1223
            });
1224
            break;
1225
 
1226
        case transitionEffect.slideLeft:
1227
            var outerWidth = currentStep.outerWidth(true),
1228
                posFadeOut = (index > oldIndex) ? -(outerWidth) : outerWidth,
1229
                posFadeIn = (index > oldIndex) ? outerWidth : -(outerWidth);
1230
 
1231
            $.when(currentStep.animate({ left: posFadeOut }, effectSpeed,
1232
                    function () { $(this)._showAria(false); }),
1233
                newStep.css("left", posFadeIn + "px")._showAria()
1234
                    .animate({ left: 0 }, effectSpeed)).done(doneCallback);
1235
            break;
1236
 
1237
        default:
1238
            $.when(currentStep._showAria(false), newStep._showAria())
1239
                .done(doneCallback);
1240
            break;
1241
    }
1242
}
1243
 
1244
/**
1245
 * Fires when a step click happens.
1246
 *
1247
 * @static
1248
 * @private
1249
 * @event click
1250
 * @param event {Object} An event object
1251
 */
1252
function stepClickHandler(event)
1253
{
1254
    event.preventDefault();
1255
 
1256
    var anchor = $(this),
1257
        wizard = anchor.parent().parent().parent().parent(),
1258
        options = getOptions(wizard),
1259
        state = getState(wizard),
1260
        oldIndex = state.currentIndex;
1261
 
1262
    if (anchor.parent().is(":not(.disabled):not(.current)"))
1263
    {
1264
        var href = anchor.attr("href"),
1265
            position = parseInt(href.substring(href.lastIndexOf("-") + 1), 0);
1266
 
1267
        goToStep(wizard, options, state, position);
1268
    }
1269
 
1270
    // If nothing has changed
1271
    if (oldIndex === state.currentIndex)
1272
    {
1273
        getStepAnchor(wizard, oldIndex).focus();
1274
        return false;
1275
    }
1276
}
1277
 
1278
function throwError(message)
1279
{
1280
    if (arguments.length > 1)
1281
    {
1282
        message = message.format(Array.prototype.slice.call(arguments, 1));
1283
    }
1284
 
1285
    throw new Error(message);
1286
}
1287
 
1288
/**
1289
 * Checks an argument for null or undefined and throws an error if one check applies.
1290
 *
1291
 * @static
1292
 * @private
1293
 * @method validateArgument
1294
 * @param argumentName {String} The name of the given argument
1295
 * @param argumentValue {Object} The argument itself
1296
 */
1297
function validateArgument(argumentName, argumentValue)
1298
{
1299
    if (argumentValue == null)
1300
    {
1301
        throwError("The argument '{0}' is null or undefined.", argumentName);
1302
    }
1303
}
1304
 
1305
/**
1306
 * Represents a jQuery wizard plugin.
1307
 *
1308
 * @class steps
1309
 * @constructor
1310
 * @param [method={}] The name of the method as `String` or an JSON object for initialization
1311
 * @param [params=]* {Array} Additional arguments for a method call
1312
 * @chainable
1313
 **/
1314
$.fn.steps = function (method)
1315
{
1316
    if ($.fn.steps[method])
1317
    {
1318
        return $.fn.steps[method].apply(this, Array.prototype.slice.call(arguments, 1));
1319
    }
1320
    else if (typeof method === "object" || !method)
1321
    {
1322
        return initialize.apply(this, arguments);
1323
    }
1324
    else
1325
    {
1326
        $.error("Method " + method + " does not exist on jQuery.steps");
1327
    }
1328
};
1329
 
1330
/**
1331
 * Adds a new step.
1332
 *
1333
 * @method add
1334
 * @param step {Object} The step object to add
1335
 * @chainable
1336
 **/
1337
$.fn.steps.add = function (step)
1338
{
1339
    var state = getState(this);
1340
    return insertStep(this, getOptions(this), state, state.stepCount, step);
1341
};
1342
 
1343
/**
1344
 * Removes the control functionality completely and transforms the current state to the initial HTML structure.
1345
 *
1346
 * @method destroy
1347
 * @chainable
1348
 **/
1349
$.fn.steps.destroy = function ()
1350
{
1351
    return destroy(this, getOptions(this));
1352
};
1353
 
1354
/**
1355
 * Triggers the onFinishing and onFinished event.
1356
 *
1357
 * @method finish
1358
 **/
1359
$.fn.steps.finish = function ()
1360
{
1361
    finishStep(this, getState(this));
1362
};
1363
 
1364
/**
1365
 * Gets the current step index.
1366
 *
1367
 * @method getCurrentIndex
1368
 * @return {Integer} The actual step index (zero-based)
1369
 * @for steps
1370
 **/
1371
$.fn.steps.getCurrentIndex = function ()
1372
{
1373
    return getState(this).currentIndex;
1374
};
1375
 
1376
/**
1377
 * Gets the current step object.
1378
 *
1379
 * @method getCurrentStep
1380
 * @return {Object} The actual step object
1381
 **/
1382
$.fn.steps.getCurrentStep = function ()
1383
{
1384
    return getStep(this, getState(this).currentIndex);
1385
};
1386
 
1387
/**
1388
 * Gets a specific step object by index.
1389
 *
1390
 * @method getStep
1391
 * @param index {Integer} An integer that belongs to the position of a step
1392
 * @return {Object} A specific step object
1393
 **/
1394
$.fn.steps.getStep = function (index)
1395
{
1396
    return getStep(this, index);
1397
};
1398
 
1399
/**
1400
 * Inserts a new step to a specific position.
1401
 *
1402
 * @method insert
1403
 * @param index {Integer} The position (zero-based) to add
1404
 * @param step {Object} The step object to add
1405
 * @example
1406
 *     $("#wizard").steps().insert(0, {
1407
 *         title: "Title",
1408
 *         content: "", // optional
1409
 *         contentMode: "async", // optional
1410
 *         contentUrl: "/Content/Step/1" // optional
1411
 *     });
1412
 * @chainable
1413
 **/
1414
$.fn.steps.insert = function (index, step)
1415
{
1416
    return insertStep(this, getOptions(this), getState(this), index, step);
1417
};
1418
 
1419
/**
1420
 * Routes to the next step.
1421
 *
1422
 * @method next
1423
 * @return {Boolean} Indicates whether the action executed
1424
 **/
1425
$.fn.steps.next = function ()
1426
{
1427
    return goToNextStep(this, getOptions(this), getState(this));
1428
};
1429
 
1430
/**
1431
 * Routes to the previous step.
1432
 *
1433
 * @method previous
1434
 * @return {Boolean} Indicates whether the action executed
1435
 **/
1436
$.fn.steps.previous = function ()
1437
{
1438
    return goToPreviousStep(this, getOptions(this), getState(this));
1439
};
1440
 
1441
/**
1442
 * Removes a specific step by an given index.
1443
 *
1444
 * @method remove
1445
 * @param index {Integer} The position (zero-based) of the step to remove
1446
 * @return Indecates whether the item is removed.
1447
 **/
1448
$.fn.steps.remove = function (index)
1449
{
1450
    return removeStep(this, getOptions(this), getState(this), index);
1451
};
1452
 
1453
/**
1454
 * Sets a specific step object by index.
1455
 *
1456
 * @method setStep
1457
 * @param index {Integer} An integer that belongs to the position of a step
1458
 * @param step {Object} The step object to change
1459
 **/
1460
$.fn.steps.setStep = function (index, step)
1461
{
1462
    throw new Error("Not yet implemented!");
1463
};
1464
 
1465
/**
1466
 * Skips an certain amount of steps.
1467
 *
1468
 * @method skip
1469
 * @param count {Integer} The amount of steps that should be skipped
1470
 * @return {Boolean} Indicates whether the action executed
1471
 **/
1472
$.fn.steps.skip = function (count)
1473
{
1474
    throw new Error("Not yet implemented!");
1475
};
1476
 
1477
/**
1478
 * An enum represents the different content types of a step and their loading mechanisms.
1479
 *
1480
 * @class contentMode
1481
 * @for steps
1482
 **/
1483
var contentMode = $.fn.steps.contentMode = {
1484
    /**
1485
     * HTML embedded content
1486
     *
1487
     * @readOnly
1488
     * @property html
1489
     * @type Integer
1490
     * @for contentMode
1491
     **/
1492
    html: 0,
1493
 
1494
    /**
1495
     * IFrame embedded content
1496
     *
1497
     * @readOnly
1498
     * @property iframe
1499
     * @type Integer
1500
     * @for contentMode
1501
     **/
1502
    iframe: 1,
1503
 
1504
    /**
1505
     * Async embedded content
1506
     *
1507
     * @readOnly
1508
     * @property async
1509
     * @type Integer
1510
     * @for contentMode
1511
     **/
1512
    async: 2
1513
};
1514
 
1515
/**
1516
 * An enum represents the orientation of the steps navigation.
1517
 *
1518
 * @class stepsOrientation
1519
 * @for steps
1520
 **/
1521
var stepsOrientation = $.fn.steps.stepsOrientation = {
1522
    /**
1523
     * Horizontal orientation
1524
     *
1525
     * @readOnly
1526
     * @property horizontal
1527
     * @type Integer
1528
     * @for stepsOrientation
1529
     **/
1530
    horizontal: 0,
1531
 
1532
    /**
1533
     * Vertical orientation
1534
     *
1535
     * @readOnly
1536
     * @property vertical
1537
     * @type Integer
1538
     * @for stepsOrientation
1539
     **/
1540
    vertical: 1
1541
};
1542
 
1543
/**
1544
 * An enum that represents the various transition animations.
1545
 *
1546
 * @class transitionEffect
1547
 * @for steps
1548
 **/
1549
var transitionEffect = $.fn.steps.transitionEffect = {
1550
    /**
1551
     * No transition animation
1552
     *
1553
     * @readOnly
1554
     * @property none
1555
     * @type Integer
1556
     * @for transitionEffect
1557
     **/
1558
    none: 0,
1559
 
1560
    /**
1561
     * Fade in transition
1562
     *
1563
     * @readOnly
1564
     * @property fade
1565
     * @type Integer
1566
     * @for transitionEffect
1567
     **/
1568
    fade: 1,
1569
 
1570
    /**
1571
     * Slide up transition
1572
     *
1573
     * @readOnly
1574
     * @property slide
1575
     * @type Integer
1576
     * @for transitionEffect
1577
     **/
1578
    slide: 2,
1579
 
1580
    /**
1581
     * Slide left transition
1582
     *
1583
     * @readOnly
1584
     * @property slideLeft
1585
     * @type Integer
1586
     * @for transitionEffect
1587
     **/
1588
    slideLeft: 3
1589
};
1590
 
1591
var stepModel = $.fn.steps.stepModel = {
1592
    title: "",
1593
    content: "",
1594
    contentUrl: "",
1595
    contentMode: contentMode.html,
1596
    contentLoaded: false
1597
};
1598
 
1599
/**
1600
 * An object that represents the default settings.
1601
 * There are two possibities to override the sub-properties.
1602
 * Either by doing it generally (global) or on initialization.
1603
 *
1604
 * @static
1605
 * @class defaults
1606
 * @for steps
1607
 * @example
1608
 *   // Global approach
1609
 *   $.steps.defaults.headerTag = "h3";
1610
 * @example
1611
 *   // Initialization approach
1612
 *   $("#wizard").steps({ headerTag: "h3" });
1613
 **/
1614
var defaults = $.fn.steps.defaults = {
1615
    /**
1616
     * The header tag is used to find the step button text within the declared wizard area.
1617
     *
1618
     * @property headerTag
1619
     * @type String
1620
     * @default "h1"
1621
     * @for defaults
1622
     **/
1623
    headerTag: "h1",
1624
 
1625
    /**
1626
     * The body tag is used to find the step content within the declared wizard area.
1627
     *
1628
     * @property bodyTag
1629
     * @type String
1630
     * @default "div"
1631
     * @for defaults
1632
     **/
1633
    bodyTag: "div",
1634
 
1635
    /**
1636
     * The content container tag which will be used to wrap all step contents.
1637
     *
1638
     * @property contentContainerTag
1639
     * @type String
1640
     * @default "div"
1641
     * @for defaults
1642
     **/
1643
    contentContainerTag: "div",
1644
 
1645
    /**
1646
     * The action container tag which will be used to wrap the pagination navigation.
1647
     *
1648
     * @property actionContainerTag
1649
     * @type String
1650
     * @default "div"
1651
     * @for defaults
1652
     **/
1653
    actionContainerTag: "div",
1654
 
1655
    /**
1656
     * The steps container tag which will be used to wrap the steps navigation.
1657
     *
1658
     * @property stepsContainerTag
1659
     * @type String
1660
     * @default "div"
1661
     * @for defaults
1662
     **/
1663
    stepsContainerTag: "div",
1664
 
1665
    /**
1666
     * The css class which will be added to the outer component wrapper.
1667
     *
1668
     * @property cssClass
1669
     * @type String
1670
     * @default "wizard"
1671
     * @for defaults
1672
     * @example
1673
     *     <div class="wizard">
1674
     *         ...
1675
     *     </div>
1676
     **/
1677
    cssClass: "wizard",
1678
 
1679
    /**
1680
     * The css class which will be used for floating scenarios.
1681
     *
1682
     * @property clearFixCssClass
1683
     * @type String
1684
     * @default "clearfix"
1685
     * @for defaults
1686
     **/
1687
    clearFixCssClass: "clearfix",
1688
 
1689
    /**
1690
     * Determines whether the steps are vertically or horizontally oriented.
1691
     *
1692
     * @property stepsOrientation
1693
     * @type stepsOrientation
1694
     * @default horizontal
1695
     * @for defaults
1696
     * @since 1.0.0
1697
     **/
1698
    stepsOrientation: stepsOrientation.horizontal,
1699
 
1700
    /*
1701
     * Tempplates
1702
     */
1703
 
1704
    /**
1705
     * The title template which will be used to create a step button.
1706
     *
1707
     * @property titleTemplate
1708
     * @type String
1709
     * @default "<span class=\"number\">#index#.</span> #title#"
1710
     * @for defaults
1711
     **/
1712
    titleTemplate: "<span class=\"number\">#index#.</span> #title#",
1713
 
1714
    /**
1715
     * The loading template which will be used to create the loading animation.
1716
     *
1717
     * @property loadingTemplate
1718
     * @type String
1719
     * @default "<span class=\"spinner\"></span> #text#"
1720
     * @for defaults
1721
     **/
1722
    loadingTemplate: "<span class=\"spinner\"></span> #text#",
1723
 
1724
    /*
1725
     * Behaviour
1726
     */
1727
 
1728
    /**
1729
     * Sets the focus to the first wizard instance in order to enable the key navigation from the begining if `true`.
1730
     *
1731
     * @property autoFocus
1732
     * @type Boolean
1733
     * @default false
1734
     * @for defaults
1735
     * @since 0.9.4
1736
     **/
1737
    autoFocus: false,
1738
 
1739
    /**
1740
     * Enables all steps from the begining if `true` (all steps are clickable).
1741
     *
1742
     * @property enableAllSteps
1743
     * @type Boolean
1744
     * @default false
1745
     * @for defaults
1746
     **/
1747
    enableAllSteps: false,
1748
 
1749
    /**
1750
     * Enables keyboard navigation if `true` (arrow left and arrow right).
1751
     *
1752
     * @property enableKeyNavigation
1753
     * @type Boolean
1754
     * @default true
1755
     * @for defaults
1756
     **/
1757
    enableKeyNavigation: true,
1758
 
1759
    /**
1760
     * Enables pagination if `true`.
1761
     *
1762
     * @property enablePagination
1763
     * @type Boolean
1764
     * @default true
1765
     * @for defaults
1766
     **/
1767
    enablePagination: true,
1768
 
1769
    /**
1770
     * Suppresses pagination if a form field is focused.
1771
     *
1772
     * @property suppressPaginationOnFocus
1773
     * @type Boolean
1774
     * @default true
1775
     * @for defaults
1776
     **/
1777
    suppressPaginationOnFocus: true,
1778
 
1779
    /**
1780
     * Enables cache for async loaded or iframe embedded content.
1781
     *
1782
     * @property enableContentCache
1783
     * @type Boolean
1784
     * @default true
1785
     * @for defaults
1786
     **/
1787
    enableContentCache: true,
1788
 
1789
    /**
1790
     * Shows the cancel button if enabled.
1791
     *
1792
     * @property enableCancelButton
1793
     * @type Boolean
1794
     * @default false
1795
     * @for defaults
1796
     **/
1797
    enableCancelButton: false,
1798
 
1799
    /**
1800
     * Shows the finish button if enabled.
1801
     *
1802
     * @property enableFinishButton
1803
     * @type Boolean
1804
     * @default true
1805
     * @for defaults
1806
     **/
1807
    enableFinishButton: true,
1808
 
1809
    /**
1810
     * Not yet implemented.
1811
     *
1812
     * @property preloadContent
1813
     * @type Boolean
1814
     * @default false
1815
     * @for defaults
1816
     **/
1817
    preloadContent: false,
1818
 
1819
    /**
1820
     * Shows the finish button always (on each step; right beside the next button) if `true`.
1821
     * Otherwise the next button will be replaced by the finish button if the last step becomes active.
1822
     *
1823
     * @property showFinishButtonAlways
1824
     * @type Boolean
1825
     * @default false
1826
     * @for defaults
1827
     **/
1828
    showFinishButtonAlways: false,
1829
 
1830
    /**
1831
     * Prevents jumping to a previous step.
1832
     *
1833
     * @property forceMoveForward
1834
     * @type Boolean
1835
     * @default false
1836
     * @for defaults
1837
     **/
1838
    forceMoveForward: false,
1839
 
1840
    /**
1841
     * Saves the current state (step position) to a cookie.
1842
     * By coming next time the last active step becomes activated.
1843
     *
1844
     * @property saveState
1845
     * @type Boolean
1846
     * @default false
1847
     * @for defaults
1848
     **/
1849
    saveState: false,
1850
 
1851
    /**
1852
     * The position to start on (zero-based).
1853
     *
1854
     * @property startIndex
1855
     * @type Integer
1856
     * @default 0
1857
     * @for defaults
1858
     **/
1859
    startIndex: 0,
1860
 
1861
    /*
1862
     * Animation Effect Configuration
1863
     */
1864
 
1865
    /**
1866
     * The animation effect which will be used for step transitions.
1867
     *
1868
     * @property transitionEffect
1869
     * @type transitionEffect
1870
     * @default none
1871
     * @for defaults
1872
     **/
1873
    transitionEffect: transitionEffect.none,
1874
 
1875
    /**
1876
     * Animation speed for step transitions (in milliseconds).
1877
     *
1878
     * @property transitionEffectSpeed
1879
     * @type Integer
1880
     * @default 200
1881
     * @for defaults
1882
     **/
1883
    transitionEffectSpeed: 200,
1884
 
1885
    /*
1886
     * Events
1887
     */
1888
 
1889
    /**
1890
     * Fires before the step changes and can be used to prevent step changing by returning `false`.
1891
     * Very useful for form validation.
1892
     *
1893
     * @property onStepChanging
1894
     * @type Event
1895
     * @default function (event, currentIndex, newIndex) { return true; }
1896
     * @for defaults
1897
     **/
1898
    onStepChanging: function (event, currentIndex, newIndex) { return true; },
1899
 
1900
    /**
1901
     * Fires after the step has change.
1902
     *
1903
     * @property onStepChanged
1904
     * @type Event
1905
     * @default function (event, currentIndex, priorIndex) { }
1906
     * @for defaults
1907
     **/
1908
    onStepChanged: function (event, currentIndex, priorIndex) { },
1909
 
1910
    /**
1911
     * Fires after cancelation.
1912
     *
1913
     * @property onCanceled
1914
     * @type Event
1915
     * @default function (event) { }
1916
     * @for defaults
1917
     **/
1918
    onCanceled: function (event) { },
1919
 
1920
    /**
1921
     * Fires before finishing and can be used to prevent completion by returning `false`.
1922
     * Very useful for form validation.
1923
     *
1924
     * @property onFinishing
1925
     * @type Event
1926
     * @default function (event, currentIndex) { return true; }
1927
     * @for defaults
1928
     **/
1929
    onFinishing: function (event, currentIndex) { return true; },
1930
 
1931
    /**
1932
     * Fires after completion.
1933
     *
1934
     * @property onFinished
1935
     * @type Event
1936
     * @default function (event, currentIndex) { }
1937
     * @for defaults
1938
     **/
1939
    onFinished: function (event, currentIndex) { },
1940
 
1941
    /**
1942
     * Fires after async content is loaded.
1943
     *
1944
     * @property onContentLoaded
1945
     * @type Event
1946
     * @default function (event, index) { }
1947
     * @for defaults
1948
     **/
1949
    onContentLoaded: function (event, currentIndex) { },
1950
 
1951
    /**
1952
     * Fires when the wizard is initialized.
1953
     *
1954
     * @property onInit
1955
     * @type Event
1956
     * @default function (event) { }
1957
     * @for defaults
1958
     **/
1959
    onInit: function (event, currentIndex) { },
1960
 
1961
    /**
1962
     * Contains all labels.
1963
     *
1964
     * @property labels
1965
     * @type Object
1966
     * @for defaults
1967
     **/
1968
    labels: {
1969
        /**
1970
         * Label for the cancel button.
1971
         *
1972
         * @property cancel
1973
         * @type String
1974
         * @default "Cancel"
1975
         * @for defaults
1976
         **/
1977
        cancel: "Cancel",
1978
 
1979
        /**
1980
         * This label is important for accessability reasons.
1981
         * Indicates which step is activated.
1982
         *
1983
         * @property current
1984
         * @type String
1985
         * @default "current step:"
1986
         * @for defaults
1987
         **/
1988
        current: "current step:",
1989
 
1990
        /**
1991
         * This label is important for accessability reasons and describes the kind of navigation.
1992
         *
1993
         * @property pagination
1994
         * @type String
1995
         * @default "Pagination"
1996
         * @for defaults
1997
         * @since 0.9.7
1998
         **/
1999
        pagination: "Pagination",
2000
 
2001
        /**
2002
         * Label for the finish button.
2003
         *
2004
         * @property finish
2005
         * @type String
2006
         * @default "Finish"
2007
         * @for defaults
2008
         **/
2009
        finish: "Finish",
2010
 
2011
        /**
2012
         * Label for the next button.
2013
         *
2014
         * @property next
2015
         * @type String
2016
         * @default "Next"
2017
         * @for defaults
2018
         **/
2019
        next: "Next",
2020
 
2021
        /**
2022
         * Label for the previous button.
2023
         *
2024
         * @property previous
2025
         * @type String
2026
         * @default "Previous"
2027
         * @for defaults
2028
         **/
2029
        previous: "Previous",
2030
 
2031
        /**
2032
         * Label for the loading animation.
2033
         *
2034
         * @property loading
2035
         * @type String
2036
         * @default "Loading ..."
2037
         * @for defaults
2038
         **/
2039
        loading: "Loading ..."
2040
    }
2041
};
2042
})(jQuery);