jquery-steps-rails 1.0.4.1

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