31 |
32 | States are attached to steps via the state attribute, as defined by
33 | `options.stateAttribute`. States can refer to the name of a transition
34 | function, the index of a step or the name of the branch.
35 |
36 | ### Transitions
37 |
38 | $( "form" ).wizard({
39 | transitions: {
40 | gender: function( state, action ) {
41 | return state.step.find( "[name=gender]" ).val();
42 | }
43 | }
44 | });
45 |
46 | Transitions act as a bridge between one state and another. They can be used
47 | to allow custom logic to determine where to go next and should ultimately
48 | return a step index or branch name in the wizard.
49 |
50 | #### Arguments
51 |
52 | Transitions are called with the wizard object as the context and these
53 | arguments:
54 |
55 | * **state** _Object_
56 | The current state of the wizard.
57 |
58 | * **action** _Function_
59 | The action function should be used to pass the result back to the wizard
60 | in the case that your transition function is asynchronous.
61 |
62 | ## Options
63 |
64 | Options is a map of key/value pairs that can be passed into the plugin as the
65 | first argument upon initialization. The default values are shown below:
66 |
67 | options: {
68 | animations: {
69 | show: {
70 | options: {
71 | duration: 0
72 | },
73 | properties: {
74 | opacity: "show"
75 | }
76 | },
77 | hide: {
78 | options: {
79 | duration: 0
80 | },
81 | properties: {
82 | opacity: "hide"
83 | }
84 | }
85 | },
86 | backward: ".backward",
87 | branches: ".branch",
88 | disabled: false,
89 | enableSubmit: false,
90 | forward: ".forward",
91 | header: ":header:first",
92 | initialStep: 0,
93 | stateAttribute: "data-state",
94 | stepClasses: {
95 | current: "current",
96 | exclude: "exclude",
97 | stop: "stop",
98 | submit: "submit",
99 | unidirectional: "unidirectional"
100 | },
101 | steps: ".step",
102 | submit: ":submit",
103 | transitions: {},
104 | unidirectional: false,
105 |
106 | /* callbacks */
107 | afterBackward: null,
108 | afterDestroy: null,
109 | afterForward: null,
110 | afterSelect: null,
111 | beforeBackward: null,
112 | beforeDestroy: null,
113 | beforeForward: null,
114 | beforeSelect: null,
115 | create: null
116 | }
117 |
118 | By default the wizard will start on the first step, show and hide steps
119 | instantly, transition to the next step in the same branch as the current step
120 | if no state attribute is present and allow movement forwards and backwards.
121 |
122 | * **animations** _Object_
123 | Used to define custom transition animations on step changes. For more
124 | information, read up on jQuery's [.animate()](http://api.jquery.com/animate)
125 | function.
126 |
127 | * **show** _Object_
128 | The options and properties that will be used when showing a step.
129 |
130 | * **hide** _Object_
131 | The options and properties that will be used when hiding a step.
132 |
133 | * **backward** _String_
134 | A selector string used to indicate which elements to bind the `backward()`
135 | method to. The method will be triggered on click.
136 |
137 | * **branches** _String_
138 | A selector string used to indicate which elements are branches within the
139 | wizard.
140 |
141 | * **enableSubmit** _Boolean_
142 | Whether or not to enable the submit button on all steps.
143 |
144 | * **forward** _String_
145 | A selector string used to indicate which elements to bind the `forward()`
146 | method to. The method will be triggered on click.
147 |
148 | * **header** _String_
149 | A selector string used to locate the header of the wizard.
150 |
151 | * **initialStep** _String_, _Number_, _Array_
152 | Which step to display after the wizard initializes. Accepts a string
153 | representing a step or branch ID, a number representing a step index,
154 | a jQuery object or DOM element representing a step or branch, or an
155 | array of arguments to be passed to the `select()` method.
156 |
157 | * **stateAttribute** _String_
158 | The attribute, applied to steps, that contains the name of a state.
159 |
160 | * **stepClasses** _Object_
161 | A map of meaningful step classes. These classes will have an effect on step
162 | behavior such as enabling or disabling navigation or preventing the step
163 | from being included in overall progress.
164 |
165 | * **current** _String_
166 | The class to toggle on the currently selected step.
167 |
168 | * **exclude** _String_
169 | If this class is present on a step the step will not be included in the
170 | progress estimate. This is useful for steps that might contain
171 | explanitory or introductory text without any inputs.
172 |
173 | * **stop** _String_
174 | If this class is present on a step the forward button will be disabled.
175 |
176 | * **submit** _String_
177 | If this class is present on a step the submit button will be enabled.
178 |
179 | * **unidirectional** _String_
180 | If this class is present on a step the backward button will be
181 | disabled.
182 |
183 | * **steps** _String_
184 | A selector string used to indicate which elements are steps within the
185 | wizard.
186 |
187 | * **transitions** _Object_
188 | A map of keys representing states and their corresponding action methods.
189 |
190 | * **default** _Function_
191 | The default transition to use on steps that contain no state attribute.
192 |
193 | * **unidirectional** _Boolean_
194 | Whether or not this wizard should be unidirectional; that is allowing only
195 | forward movement.
196 |
197 | ## Events
198 |
199 | $( "form" )
200 | // Bind on initialization
201 | .wizard({
202 | eventHandler: function( event, state ) { ... }
203 | })
204 | // Bind at any other time
205 | .bind( "wizardeventhandler", function( event, state ) { ... });
206 |
207 | Event handlers may be passed in on intialization in the options object, or they
208 | can be bound to the wizard at any time using the format _wizardeventname_
209 | (note that it must be in all lowercase).
210 |
211 | * **afterBackward** or _wizardafterbackward_
212 | Triggered after the wizard has completed going backwards.
213 |
214 | * **afterDestroy** or _wizardafterdestroy_
215 | Triggered after the wizard has been destroyed.
216 |
217 | * **afterForward** or _wizardafterforward_
218 | Triggered after the wizard has completed going forwards.
219 |
220 | * **afterSelect** or _wizardafterselect_
221 | Triggered after the wizard has completed selecting a new step.
222 |
223 | * **beforeBackward** or _wizardbeforebackward_
224 | Triggered before the wizard attempts to move backwards. Returning false
225 | inside of this method will prevent the move.
226 |
227 | * **beforeDestroy** or _wizardbeforedestroy_
228 | Triggered before the wizard is destroyed. Returning false inside of this
229 | method will prevent the destruction of the wizard.
230 |
231 | * **beforeForward** or _wizardbeforeforward_
232 | Triggered before the wizard attempts to move forward. Returning false inside
233 | of this method will prevent the move.
234 |
235 | * **beforeSelect** or _wizardbeforeselect_
236 | Triggered before the wizard attempts to move in any direction. Returning
237 | false inside of this method will prevent the move.
238 |
239 | #### Arguments
240 |
241 | Events are called with the wizard element as the context and these arguments:
242 |
243 | * **event** _Object_
244 | The [jQuery.Event](http://api.jquery.com/category/events/event-object/)
245 | object.
246 |
247 | * **state** _Object_
248 | An object containing either the current state of the wizard (for _after_
249 | events) or the state the wizard will be updating to (for _before_ events).
250 | See the [state](readme.md#state) section for further information.
251 |
252 | * [ **update** ] _Function_
253 | This function is available on any of the **before** events to allow
254 | deferred cancellation of events if asynchronous processing is needed.
255 |
256 | ## Methods
257 |
258 | $( "form" ).wizard( "methodName" [, args ] );
259 |
260 | The wizard comes with plenty of public methods to help you navigate and get at
261 | any relevent information you may need.
262 |
263 | * **backward( [ event, howMany ] )** returns _jQuery_
264 | Step backward through the wizard.
265 |
266 | * **event** _Event_
267 | The [jQuery.Event](http://api.jquery.com/category/events/event-object/)
268 | object. Used when the function is called via a trigger or event handler.
269 |
270 | * **howMany** _Number_
271 | How many steps to take backwards. Should be a positive integer greater
272 | than zero.
273 |
274 | * **branch( [ branch ] )** returns _jQuery_
275 | Returns a branch from the wizard. If no arguments are provided, it will
276 | return the currently active branch.
277 |
278 | * **branch** _String_
279 | The ID of a branch in the wizard.
280 |
281 | * **branches( [ branch ] )** returns _jQuery_
282 | Returns several branches in the wizard. If no arguments are provided, it
283 | will return all of the branches in the wizard.
284 |
285 | * **branch** _String_
286 | The ID of a branch in the wizard. If provided, all of the branches
287 | within the given branch are returned.
288 |
289 | * **branchesActivated()** returns _jQuery_
290 | Returns all of the activated branches in the wizard. An activated branch
291 | is defined as any branch containing a step that has been visited.
292 |
293 | * **destroy()** returns _jQuery_
294 | Completely remove the wizard functionality from the element it was attached
295 | to. This basically reverts the element to the state it was before the
296 | wizard was applied to it.
297 |
298 | * **form()** returns _jQuery_
299 | Returns the form associated with the wizard.
300 |
301 | * **forward( [ event, howMany ] )** returns _jQuery_
302 | Step forward through the wizard.
303 |
304 | * **event** _Event_
305 | The [jQuery.Event](http://api.jquery.com/category/events/event-object/)
306 | object. Used when the function is called via a trigger or event handler.
307 |
308 | * **howMany** _Number_
309 | How many steps to take forwards. Should be a positive integer greater
310 | than zero.
311 |
312 | * **isValidStep( step )** returns _Boolean_
313 | Returns whether or not a step is valid, or contained within the wizard.
314 |
315 | * **step** _String_, _Number_, _jQuery_, _Element_
316 | The step to check for in the wizard. Can be an element ID, step index,
317 | jQuery object or DOM element.
318 |
319 | * **isValidStepIndex( stepIndex )** returns _Boolean_
320 | Returns whether or not a step index is valid, or contained within the
321 | wizard.
322 |
323 | * **stepIndex** _Number_
324 | An integer representing the index of a step in the wizard.
325 |
326 | * **select( [ event, ] step [, branch, relative, history ] )** returns _jQuery_
327 | Selects a step within the wizard.
328 |
329 | * **event** _Event_
330 | The [jQuery.Event](http://api.jquery.com/category/events/event-object/)
331 | object. Used when the function is called via a trigger or event handler.
332 |
333 | * **step** _String_, _Number_, _jQuery_, _Element_
334 | A step in the wizard. Can be an element ID, step index, jQuery object
335 | or DOM element.
336 |
337 | * **branch** _String_
338 | The ID of the branch that contains the step. Useful of searching for a
339 | step by step index relative to a branch. This parameter may be omitted
340 | even if further arguments are needed.
341 |
342 | * **relative** _Boolean_
343 | If true, the step argument becomes an integer representing the number
344 | of steps to move forwards or backwards relative to the current step.
345 | This parameter may be omitted even if further arguments are needed.
346 |
347 | * **history** _Boolean_, _Array_
348 | Whether or not to track the movements between the current step and the
349 | destination step. If set to false, the history will not be kept. This
350 | means that when hitting the back button on the selected step, the user
351 | will be taken directly back to the step they were on beforehand instead
352 | of visiting any steps in between. You can specify which steps will be
353 | included in the history yourself by passing an array of step indexes
354 | that will override whatever steps the plugin actually takes.
355 |
356 | * **state( [ step, branch, stepsTaken ] )** returns _Object_
357 | Returns an object containing the state of the wizard at a certain step, or
358 | null if the step could not be found. If no arguments are provided, returns
359 | the current state of the wizard. See the [state](readme.md#state) section
360 | for further information.
361 |
362 | * **step** _String_, _Number_, _jQuery_, _Element_
363 | A step in the wizard. Can be an element ID, step index, jQuery object
364 | or DOM element.
365 |
366 | * **branch** _String_
367 | The ID of the branch that contains the step. Useful of searching for a
368 | step by step index relative to a branch. This parameter may be omitted
369 | even if further arguments are needed.
370 |
371 | * **stepsTaken** _Array_
372 | An array of step indexes that represent the path taken to get to the
373 | given step from the current step. This should be provided if tracking
374 | history for the generation of an accurate state.
375 |
376 | * **step( [ step, branch ] )** returns _jQuery_
377 | Returns a step from the wizard. If no arguments are provided, it will
378 | return the currently selected step in the wizard.
379 |
380 | * **step** _String_, _Number_, _jQuery_, _Element_
381 | A step in the wizard. Can be an element ID, step index, jQuery object
382 | or DOM element.
383 |
384 | * **branch** _String_
385 | The ID of the branch that contains the step. Useful of searching for a
386 | step by step index relative to a branch. This parameter may be omitted
387 | even if further arguments are needed.
388 |
389 | * **stepCount()** returns _Number_
390 | Returns the number of steps in the wizard.
391 |
392 | * **stepIndex( [ step, branch, relative ] )** returns _Number_
393 | Returns the index of a step in the wizard, or -1 of the step could not be
394 | found. If no arguments are provided, it will return the index of the
395 | currently selected step in the wizard.
396 |
397 | * **branch** _String_
398 | The ID of the branch that contains the step. Useful of searching for a
399 | step by step index relative to a branch. This parameter may be omitted
400 | even if further arguments are needed.
401 |
402 | * **relative** _Boolean_
403 | If true, the index returned will be relative to its containing branch.
404 |
405 | * **steps( [ branch ] )** returns _jQuery_
406 | Returns steps within the wizard. If no arguments are provided, it will
407 | return all of the steps in the wizard.
408 |
409 | * **branch** _String_
410 | An ID of a branch within the wizard. If this parameter is given, all
411 | of the steps within the branch will be returned.
412 |
413 | * **stepsActivated()** returns _jQuery_
414 | Returns all of the activated steps in the wizard. An activated step is
415 | defined as one that the user has visited.
416 |
417 | * **submit()** returns _jQuery_
418 | Submits the form attached to the wizard.
419 |
420 | ## State
421 |
422 | {
423 | branch: [ form#defaultBranch.ui-wizard-form ],
424 | branchLabel: "defaultBranch",
425 | branchStepCount: 3,
426 | branchesActivated: [ "defaultBranch" ],
427 | isFirstStep: true,
428 | isFirstStepInBranch: true,
429 | isLastStep: false,
430 | isLastStepInBranch: false,
431 | isMovingForward: false,
432 | percentComplete: 0,
433 | step: [ div.step ],
434 | stepIndex: 0,
435 | stepIndexInBranch: 0,
436 | stepsActivated: [ 0 ],
437 | stepsComplete: 0,
438 | stepsPossible: 2,
439 | stepsRemaining: 2
440 | }
441 |
442 | The wizard keeps track of its current state using an object map of keys and
443 | values. This map can be accessed at any time via the `state()` method. It is
444 | also passed in as the second argument to event handlers. The keys and their
445 | values are outlined below.
446 |
447 | * **branch** _jQuery_
448 | The branch the wizard is currently on.
449 |
450 | * **branchLabel** _String_
451 | The label, or ID, of the currently active branch.
452 |
453 | * **branchStepCount** _Number_
454 | The total number of steps in the current branch.
455 |
456 | * **branchesActivated** _Array_
457 | An array containing all of the currently activated branch labels.
458 |
459 | * **isFirstStep** _Boolean_
460 | Whether or not the current step is the first step in the wizard.
461 |
462 | * **isFirstStepInBranch** _Boolean_
463 | Whether or not the current step is the first step in its containing branch.
464 |
465 | * **isLastStep** _Boolean_
466 | Whether or not the current step is the last step in the wizard.
467 |
468 | * **isLastStepInBranch** _Boolean_
469 | Whether or not the current step is the last step in its containing branch.
470 |
471 | * **isMovingForward** _Boolean_
472 | Whether or not the wizard is progressing forward, that is that the current
473 | step index is greater than the previous step index.
474 |
475 | * **percentComplete** _Number_
476 | A number representing the _estimated_ percent of completion of the wizard.
477 | This is a numerical value between 0 and 100.
478 |
479 | * **step** _jQuery_
480 | The step the wizard is currently on.
481 |
482 | * **stepIndex** _Number_
483 | The index of the currently active step.
484 |
485 | * **stepIndexInBranch** _Number_
486 | The index of the currently active step relative to its containing branch.
487 |
488 | * **stepsActivated** _Array_
489 | An array containing all of the currently activated step indexes.
490 |
491 | * **stepsComplete** _Number_
492 | The number of steps in the wizard that the user has completed. These steps
493 | will be contained in the _stepsActivated_ array, minus any steps the
494 | developer has decided to exclude.
495 |
496 | * **stepsPossible** _Number_
497 | The _estimated_ number of steps the user could possibly activate. This is
498 | calculated by counting all of the steps in every branch the user has
499 | activated, minus any steps the developer has decided to exclude.
500 |
501 | * **stepsRemaining** _Number_
502 | The _estimated_ difference between _stepsComplete_ and _stepsPossible_.
503 |
504 | ## Installation
505 |
506 | The easiest way to install is via [NPM](http://npmjs.org):
507 |
508 | npm install @kflorence/jquery-wizard
509 |
510 | Or [Bower](http://bower.io):
511 |
512 | bower install jquery-wizard
513 |
514 | You can also [download releases](https://github.com/kflorence/jquery-wizard/releases)
515 | directly from github. The latest uncompressed version is available here:
516 |
517 | * [jquery.wizard.js](https://raw.githubusercontent.com/kflorence/jquery-wizard/master/src/jquery.wizard.js)
518 |
519 | ## Requirements
520 |
521 | * **[jQuery](http://jquery.com/)**
522 | Versions 1.7.0 or higher.
523 |
524 | * **[jQuery UI](http://jqueryui.com/)**
525 | Core and Widget, versions 1.9.0 or higher.
526 |
527 | ## Compatibility
528 |
529 | Tested and verified to work on the following browsers:
530 |
531 | * **[Internet Explorer](http://windows.microsoft.com/en-US/internet-explorer/products/ie/home)**
532 | Versions 6.0 and higher.
533 |
534 | * **[Mozilla Firefox](http://www.mozilla.com/en-US/firefox/new/)**
535 | Versions 3.0 and higher.
536 |
537 | * **[Google Chrome](http://www.google.com/chrome/)**
538 | Versions 7.0 and higher.
539 |
540 | Found a bug? [Submit an issue](https://github.com/kflorence/jquery-wizard/issues).
541 | Tested in another browser? [Send me a message](https://github.com/inbox/new/kflorence) or
542 | fork this project and add the browser to this readme.
543 |
544 | ## Integration
545 |
546 | This plugin has been designed to integrate well with the following plugins:
547 |
548 | * **[jQuery Form](https://github.com/malsup/form)**
549 | AJAX form submission capabilities.
550 |
551 | * **[jQuery Validation](https://github.com/jzaefferer/jquery-validation)**
552 | Form input validation which can prevent step changing or submission.
553 |
554 | * **[jQuery Autosave](https://github.com/nervetattoo/jquery-autosave)**
555 | Automatic form submission based on user-defined criteria.
556 |
557 | * **[jQuery Masked Input](https://github.com/digitalBush/jquery.maskedinput)**
558 | Ensures properly formatted form input data.
559 |
560 | ## License
561 |
562 | Copyright (c) 2017 Kyle Florence
563 | Dual licensed under the MIT and GPLv2 licenses.
564 |
--------------------------------------------------------------------------------
/src/jquery.wizard.js:
--------------------------------------------------------------------------------
1 | /*
2 | jQuery.wizard v1.1.3
3 | https://github.com/kflorence/jquery-wizard/
4 | An asynchronous form wizard that supports branching.
5 |
6 | Requires:
7 | - jQuery 1.6.0+
8 | - jQuery UI widget 1.9.0+
9 |
10 | Copyright (c) 2017 Kyle Florence
11 | Dual licensed under the MIT and GPLv2 licenses.
12 | */
13 |
14 | (function( $, undefined ) {
15 |
16 | var count = 0,
17 | selector = {},
18 | className = {},
19 |
20 | // Reference to commonly used methods
21 | aps = Array.prototype.slice,
22 |
23 | // Used to normalize function arguments that can be either
24 | // an array of values or a single value
25 | arr = function( obj ) {
26 | return $.isArray( obj ) ? obj : [ obj ];
27 | },
28 |
29 | // Commonly used strings
30 | id = "id",
31 | form = "form",
32 | click = "click",
33 | submit = "submit",
34 | disabled = "disabled",
35 | namespace = "kf-wizard",
36 | wizard = "wizard",
37 |
38 | def = "default",
39 | num = "number",
40 | obj = "object",
41 | str = "string",
42 | bool = "boolean",
43 |
44 | // Events
45 | afterBackward = "afterBackward",
46 | afterDestroy = "afterDestroy",
47 | afterForward = "afterForward",
48 | afterSelect = "afterSelect",
49 | beforeBackward = "beforeBackward",
50 | beforeDestroy = "beforeDestroy",
51 | beforeForward = "beforeForward",
52 | beforeSelect = "beforeSelect",
53 | beforeSubmit = "beforeSubmit";
54 |
55 | // Generate selectors and class names for common wizard elements
56 | $.each( "branch form header step wrapper".split( " " ), function() {
57 | selector[ this ] = "." + ( className[ this ] = wizard + "-" + this );
58 | });
59 |
60 | $.widget( "kf." + wizard, {
61 | version: "1.1.3",
62 | options: {
63 | animations: {
64 | show: {
65 | options: {
66 | duration: 0
67 | },
68 | properties: {
69 | opacity: "show"
70 | }
71 | },
72 | hide: {
73 | options: {
74 | duration: 0
75 | },
76 | properties: {
77 | opacity: "hide"
78 | }
79 | }
80 | },
81 | backward: ".backward",
82 | branches: ".branch",
83 | disabled: false,
84 | enableSubmit: false,
85 | forward: ".forward",
86 | header: ":header:first",
87 | initialStep: 0,
88 | stateAttribute: "data-state",
89 | stepClasses: {
90 | current: "current",
91 | exclude: "exclude",
92 | stop: "stop",
93 | submit: "submit",
94 | unidirectional: "unidirectional"
95 | },
96 | steps: ".step",
97 | submit: ":submit",
98 | transitions: {},
99 | unidirectional: false,
100 |
101 | /* callbacks */
102 | afterBackward: null,
103 | afterDestroy: null,
104 | afterForward: null,
105 | afterSelect: null,
106 | beforeBackward: null,
107 | beforeDestroy: null,
108 | beforeForward: null,
109 | beforeSelect: null,
110 | create: null
111 | },
112 |
113 | _create: function() {
114 | var $form, $header,
115 | self = this,
116 | o = self.options,
117 | $element = self.element,
118 | $steps = $element.find( o.steps ),
119 | $stepsWrapper = $steps.eq( 0 ).parent();
120 |
121 | if ( $element[ 0 ].elements ) {
122 | $form = $element;
123 |
124 | // If element isn't form, look inside and outside element
125 | } else if ( !( $form = $element.find( form ) ).length ) {
126 | $form = $element.closest( form );
127 | }
128 |
129 | // If header isn't found in element, look in form scope
130 | if ( !( $header = $element.find( o.header ) ).length ) {
131 | $header = $form.find( o.header );
132 | }
133 |
134 | self.elements = {
135 | form: $form.addClass( className.form ),
136 | submit: $form.find( o.submit ),
137 | forward: $form.find( o.forward ),
138 | backward: $form.find( o.backward ),
139 | header: $header.addClass( className.header ),
140 | steps: $element.find( o.steps ).hide().addClass( className.step ),
141 | branches: $element.find( o.branches ).add( $stepsWrapper ).addClass( className.branch ),
142 | stepsWrapper: $stepsWrapper.addClass( className.wrapper ),
143 | wizard: $element.addClass( wizard )
144 | };
145 |
146 | if ( !$stepsWrapper.attr( id ) ) {
147 |
148 | // stepsWrapper must have an ID as it also functions as the default branch
149 | $stepsWrapper.attr( id, wizard + "-" + ( ++count ) );
150 | }
151 |
152 | self.elements.forward.on( "click." + namespace, function( event ) {
153 | event.preventDefault();
154 | self.forward( event );
155 | });
156 |
157 | self.elements.backward.on( "click." + namespace, function( event ) {
158 | event.preventDefault();
159 | self.backward( event );
160 | });
161 |
162 | self._currentState = {
163 | branchesActivated: [],
164 | stepsActivated: []
165 | };
166 |
167 | self._stepCount = self.elements.steps.length;
168 | self._lastStepIndex = self._stepCount - 1;
169 |
170 | // Cache branch labels for quick access later
171 | self._branchLabels = [];
172 | self.elements.steps.each(function( i ) {
173 | self._branchLabels[ i ] = $( this ).parent().attr( id );
174 | });
175 |
176 | // Called in the context of jQuery's .filter() method in _state()
177 | self._excludesFilter = function() {
178 | return !$( this ).hasClass( o.stepClasses.exclude );
179 | };
180 |
181 | // Add default transition function if one wasn't defined
182 | if ( !o.transitions[ def ] ) {
183 | o.transitions[ def ] = function( state ) {
184 | return self.stepIndex( state.step.nextAll( selector.step ) );
185 | };
186 | }
187 |
188 | // Select initial step
189 | self.select.apply( self, arr( o.initialStep ) );
190 | },
191 |
192 | _fastForward: function( toIndex, relative, callback ) {
193 | var i = 0,
194 | self = this,
195 | stepIndex = self._currentState.stepIndex,
196 | stepsTaken = [ stepIndex ];
197 |
198 | if ( $.isFunction( relative ) ) {
199 | callback = relative;
200 | relative = undefined;
201 | }
202 |
203 | (function next() {
204 | self._transition( self._state( stepIndex, stepsTaken ), function( step, branch ) {
205 | if ( ( stepIndex = self.stepIndex( step, branch ) ) === -1 ) {
206 | throw new Error( '[_fastForward]: Invalid step "' + step + '"' );
207 |
208 | } else if ( $.inArray( stepIndex, stepsTaken ) >= 0 ) {
209 | throw new Error( '[_fastForward]: Recursion detected on step "' + step + '"' );
210 |
211 | } else {
212 | stepsTaken.push( stepIndex );
213 |
214 | if ( stepIndex === self._lastStepIndex ||
215 | ( relative ? ++i : stepIndex ) === toIndex ) {
216 | callback.call( self, stepIndex, stepsTaken );
217 |
218 | } else {
219 | next();
220 | }
221 | }
222 | });
223 | })();
224 | },
225 |
226 | _find: function( needles, haystack, wrap ) {
227 | var element, i, l, needle, type,
228 | found = [],
229 | $haystack = haystack instanceof jQuery ? haystack : $( haystack );
230 |
231 | function matchElement( i, current ) {
232 | if ( current === needle ) {
233 | element = current;
234 |
235 | // Break from .each loop
236 | return false;
237 | }
238 | }
239 |
240 | if ( needles !== null && $haystack.length ) {
241 | needles = arr( needles );
242 |
243 | for ( i = 0, l = needles.length; i < l; i++ ) {
244 | element = null;
245 | needle = needles[ i ];
246 | type = typeof needle;
247 |
248 | if ( type === num ) {
249 | element = $haystack.get( needle );
250 |
251 | } else if ( type === str ) {
252 | element = document.getElementById( needle.replace( '#', '' ) );
253 |
254 | } else if ( type === obj ) {
255 | if ( needle instanceof jQuery && needle.length ) {
256 | needle = needle[ 0 ];
257 | }
258 |
259 | if ( needle.nodeType ) {
260 | $haystack.each( matchElement );
261 | }
262 | }
263 |
264 | if ( element ) {
265 | found.push( element );
266 | }
267 | }
268 | }
269 |
270 | // Returns a jQuery object by default. If the wrap argument is
271 | // false, it will return an array of elements instead.
272 | return wrap === false ? found : $( found );
273 | },
274 |
275 | _move: function( step, branch, relative, history, callback ) {
276 | var self = this,
277 | current = self._currentState;
278 |
279 | if ( typeof branch === bool ) {
280 | callback = history;
281 | history = relative;
282 | relative = branch;
283 | branch = undefined;
284 | }
285 |
286 | function move( stepIndex, stepsTaken ) {
287 | callback.call( self, stepIndex, $.isArray( history ) ?
288 | history : history !== false ? stepsTaken : undefined );
289 | }
290 |
291 | if ( relative === true ) {
292 | if ( step > 0 ) {
293 | self._fastForward( step, relative, move );
294 |
295 | } else {
296 | callback.call( self, current.stepsActivated[
297 | // Normalize to zero if negative
298 | Math.max( 0, step + ( current.stepsActivated.length - 1 ) ) ] );
299 | }
300 |
301 | // Don't attempt to move to invalid steps
302 | } else if ( ( step = self.stepIndex( step, branch ) ) !== -1 ) {
303 | if ( step > current.stepIndex ) {
304 | self._fastForward( step, move );
305 |
306 | } else {
307 | move.call( self, step );
308 | }
309 | }
310 | },
311 |
312 | _state: function( stepIndex, stepsTaken ) {
313 | if ( !this.isValidStepIndex( stepIndex ) ) {
314 | return null;
315 | }
316 |
317 | var o = this.options,
318 | state = $.extend( true, {}, this._currentState );
319 |
320 | // stepsTaken must be an array of at least one step
321 | stepsTaken = arr( stepsTaken || stepIndex );
322 |
323 | state.step = this.elements.steps.eq( stepIndex );
324 | state.branch = state.step.parent();
325 | state.branchStepCount = state.branch.children( selector.step ).length;
326 | state.isMovingForward = stepIndex > state.stepIndex;
327 | state.stepIndexInBranch = state.branch.children( selector.step ).index( state.step );
328 |
329 | var branchLabel, indexOfBranch, indexOfStep,
330 | i = 0,
331 | l = stepsTaken.length;
332 |
333 | for ( ; i < l; i++ ) {
334 | stepIndex = stepsTaken[ i ];
335 | branchLabel = this._branchLabels[ stepIndex ];
336 |
337 | // Going forward
338 | if ( !state.stepIndex || state.stepIndex < stepIndex ) {
339 |
340 | // No duplicate steps
341 | if ( $.inArray( stepIndex, state.stepsActivated ) < 0 ) {
342 | state.stepsActivated.push( stepIndex );
343 |
344 | // No duplicate branch labels
345 | if ( $.inArray( branchLabel, state.branchesActivated ) < 0 ) {
346 | state.branchesActivated.push( branchLabel );
347 | }
348 | }
349 |
350 | // Going backward
351 | } else if ( state.stepIndex > stepIndex ) {
352 | indexOfBranch = $.inArray( branchLabel, state.branchesActivated ) + 1;
353 | indexOfStep = $.inArray( stepIndex, state.stepsActivated ) + 1;
354 |
355 | // Don't remove initial branch
356 | if ( indexOfBranch > 0 ) {
357 | state.branchesActivated.splice( indexOfBranch,
358 | // IE requires this argument
359 | state.branchesActivated.length - 1 );
360 | }
361 |
362 | // Don't remove the initial step
363 | if ( indexOfStep > 0 ) {
364 | state.stepsActivated.splice( indexOfStep,
365 | // IE requires this argument
366 | state.stepsActivated.length - 1 );
367 | }
368 | }
369 |
370 | state.stepIndex = stepIndex;
371 | state.branchLabel = branchLabel;
372 | }
373 |
374 | // Steps completed: the number of steps we have visited
375 | state.stepsComplete = Math.max( 0, this._find(
376 | state.stepsActivated, this.elements.steps
377 | ).filter( this._excludesFilter ).length - 1 );
378 |
379 | // Steps possible: the number of steps in all of the branches we have visited
380 | state.stepsPossible = Math.max( 0, this._find(
381 | state.branchesActivated, this.elements.branches
382 | ).children( selector.step ).filter( this._excludesFilter ).length - 1 );
383 |
384 | $.extend( state, {
385 | branchLabel: this._branchLabels[ stepIndex ],
386 | isFirstStep: stepIndex === 0,
387 | isFirstStepInBranch: state.stepIndexInBranch === 0,
388 | isLastStep: stepIndex === this._lastStepIndex,
389 | isLastStepInBranch: state.stepIndexInBranch === state.branchStepCount - 1,
390 | percentComplete: ( 100 * state.stepsComplete / state.stepsPossible ),
391 | stepsRemaining: ( state.stepsPossible - state.stepsComplete )
392 | });
393 |
394 | return state;
395 | },
396 |
397 | _transition: function( state, action ) {
398 | var response,
399 | self = this,
400 | o = self.options,
401 | stateName = state.step.attr( o.stateAttribute ),
402 | transitionFunc = stateName ? o.transitions[ stateName ] : o.transitions[ def ];
403 |
404 | if ( $.isFunction( transitionFunc ) ) {
405 | response = transitionFunc.call( self, state, function() {
406 | return action.apply( self, aps.call( arguments ) );
407 | });
408 |
409 | } else {
410 | response = stateName;
411 | }
412 |
413 | // A response of 'undefined' or 'false' will halt immediate action
414 | // waiting instead for the transition function to handle the call
415 | if ( response !== undefined && response !== false ) {
416 |
417 | // Response could be array like [ step, branch ]
418 | action.apply( self, arr( response ) );
419 | }
420 | },
421 |
422 | _update: function( event, state, force ) {
423 | var self = this,
424 | current = self._currentState,
425 | data = [ state, function( response ) {
426 | self._update( event, state, response !== false );
427 | } ],
428 | o = self.options;
429 |
430 | if ( current.step ) {
431 | if (
432 | !state ||
433 | o.disabled ||
434 | state.stepIndex === current.stepIndex ||
435 | force !== true && (
436 | !this._trigger( beforeSelect, event, data ) ||
437 | ( state.isMovingForward && !this._trigger( beforeForward, event, data ) ) ||
438 | ( !state.isMovingForward && !this._trigger( beforeBackward, event, data ) )
439 | )
440 | ) {
441 | return;
442 | }
443 |
444 | current.step.removeClass( o.stepClasses.current )
445 | .animate( o.animations.hide.properties,
446 | // Fixes #3583 - http://bugs.jquery.com/ticket/3583
447 | $.extend( {}, o.animations.hide.options ) );
448 | }
449 |
450 | // Note that this does not affect the value of 'current'
451 | this._currentState = state;
452 |
453 | state.step.addClass( o.stepClasses.current )
454 | .animate( o.animations.show.properties,
455 | // Fixes #3583 - http://bugs.jquery.com/ticket/3583
456 | $.extend( {}, o.animations.show.options ) );
457 |
458 | if ( state.isFirstStep || o.unidirectional ||
459 | state.step.hasClass( o.stepClasses.unidirectional ) ) {
460 | this.elements.backward.attr( disabled, true );
461 |
462 | } else {
463 | this.elements.backward.removeAttr( disabled );
464 | }
465 |
466 | if ( ( state.isLastStepInBranch && !state.step.attr( o.stateAttribute ) ) ||
467 | state.step.hasClass( o.stepClasses.stop ) ) {
468 | this.elements.forward.attr( disabled, true );
469 |
470 | } else {
471 | this.elements.forward.removeAttr( disabled );
472 | }
473 |
474 | if ( o.enableSubmit || state.step.hasClass( o.stepClasses.submit ) ) {
475 | this.elements.submit.removeAttr( disabled );
476 |
477 | } else {
478 | this.elements.submit.attr( disabled, true );
479 | }
480 |
481 | if ( current.step ) {
482 | this._trigger( afterSelect, event, state );
483 | this._trigger( state.isMovingForward ? afterForward : afterBackward, event, state );
484 | }
485 | },
486 |
487 | backward: function( event, howMany ) {
488 | if ( typeof event === num ) {
489 | howMany = event;
490 | event = undefined;
491 |
492 | }
493 |
494 | if ( howMany === undefined ) {
495 | howMany = 1;
496 | }
497 |
498 | if ( this._currentState.isFirstStep || typeof howMany !== num ) {
499 | return;
500 | }
501 |
502 | this._move( -howMany, true, false, function( stepIndex, stepsTaken ) {
503 | this._update( event, this._state( stepIndex, stepsTaken ) );
504 | });
505 | },
506 |
507 | branch: function( branch ) {
508 | return arguments.length ?
509 | this._find( branch, this.elements.branches ) : this._currentState.branch;
510 | },
511 |
512 | branches: function( branch ) {
513 | return arguments.length ?
514 | this.branch( branch ).children( selector.branch ) : this.elements.branches;
515 | },
516 |
517 | branchesActivated: function() {
518 | return this._find( this._currentState.branchesActivated, this.elements.branches );
519 | },
520 |
521 | destroy: function( event, force ) {
522 | var self = this,
523 | $elements = self.elements,
524 | data = [ self.state(), function( response ) {
525 | return self.destroy( event, response !== false );
526 | } ];
527 |
528 | // args: force
529 | if ( typeof event === bool ) {
530 | force = event;
531 | event = undefined;
532 | }
533 |
534 | if ( force !== true && !self._trigger( beforeDestroy, event, data ) ) {
535 | return;
536 | }
537 |
538 | self.elements.backward.off( "." + namespace );
539 | self.elements.forward.off( "." + namespace );
540 |
541 | self.element.removeClass( wizard );
542 |
543 | $elements.form.removeClass( className.form );
544 | $elements.header.removeClass( className.header );
545 | $elements.steps.show().removeClass( className.step );
546 | $elements.stepsWrapper.removeClass( className.wrapper );
547 | $elements.branches.removeClass( className.branch );
548 |
549 | $.Widget.prototype.destroy.call( self );
550 |
551 | self._trigger( afterDestroy );
552 | },
553 |
554 | form: function() {
555 | return this.elements.form;
556 | },
557 |
558 | forward: function( event, howMany, history ) {
559 | if ( typeof event === num ) {
560 | history = howMany;
561 | howMany = event;
562 | event = undefined;
563 |
564 | }
565 |
566 | if ( howMany === undefined ) {
567 | howMany = 1;
568 | }
569 |
570 | if ( this._currentState.isLastStep || typeof howMany !== num ) {
571 | return;
572 | }
573 |
574 | this._move( howMany, true, history, function( stepIndex, stepsTaken ) {
575 | this._update( event, this._state( stepIndex, stepsTaken ) );
576 | });
577 | },
578 |
579 | isValidStep: function( step, branch ) {
580 | return this.isValidStepIndex( this.stepIndex( step, branch ) );
581 | },
582 |
583 | isValidStepIndex: function( stepIndex ) {
584 | return typeof stepIndex === num && stepIndex >= 0 && stepIndex <= this._lastStepIndex;
585 | },
586 |
587 | stepCount: function() {
588 | return this._stepCount;
589 | },
590 |
591 | select: function( event, step, branch, relative, history ) {
592 |
593 | // args: step, branch, relative, history
594 | if ( !( event instanceof $.Event ) ) {
595 | history = relative;
596 | relative = branch;
597 | branch = step;
598 | step = event;
599 | event = undefined;
600 | }
601 |
602 | if ( step === undefined ) {
603 | return;
604 | }
605 |
606 | // args: [ step, branch ], relative, history
607 | if ( $.isArray( step ) ) {
608 | history = relative;
609 | relative = branch;
610 | branch = step[ 1 ];
611 | step = step[ 0 ];
612 |
613 | // args: step, relative, history
614 | } else if ( typeof branch === bool ) {
615 | history = relative;
616 | relative = branch;
617 | branch = undefined;
618 |
619 | // args: step, history
620 | } else if ( $.isArray( branch ) ) {
621 | history = branch;
622 | branch = undefined;
623 | }
624 |
625 | this._move( step, branch, relative, history, function( stepIndex, stepsTaken ) {
626 | this._update( event, this._state( stepIndex, stepsTaken ) );
627 | });
628 | },
629 |
630 | state: function( step, branch, stepsTaken ) {
631 | if ( !arguments.length ) {
632 | return this._currentState;
633 | }
634 |
635 | // args: [ step, branch ], stepsTaken
636 | if ( $.isArray( step ) ) {
637 | stepsTaken = branch;
638 | branch = step[ 1 ];
639 | step = step[ 0 ];
640 |
641 | // args: step, stepsTaken
642 | } else if ( $.isArray( branch ) ) {
643 | stepsTaken = branch;
644 | branch = undefined;
645 | }
646 |
647 | return this._state( this.stepIndex( step, branch ), stepsTaken );
648 | },
649 |
650 | step: function( step, branch ) {
651 | if ( !arguments.length ) {
652 | return this._currentState.step;
653 | }
654 |
655 | // args: [ step, branch ]
656 | if ( $.isArray( step ) ) {
657 | branch = step[ 1 ];
658 | step = step[ 0 ];
659 | }
660 |
661 | var $step,
662 | type = typeof step;
663 |
664 | // Searching for a step by index
665 | if ( type === num ) {
666 | $step = this._find( step,
667 | // Search within branch, if defined, otherwise search all steps
668 | branch !== undefined ? this.steps( branch ) : this.elements.steps );
669 |
670 | // Searching for a step or branch by string ID, DOM element or jQuery object
671 | } else {
672 | $step = this._find( step, this.elements.steps.add( this.elements.branches ) );
673 |
674 | if ( $step && $step.hasClass( className.branch ) ) {
675 |
676 | // If a branch is found, the arguments are essentially flip-flopped
677 | $step = this._find( branch || 0, this.steps( $step ) );
678 | }
679 | }
680 |
681 | return $step;
682 | },
683 |
684 | stepIndex: function( step, branch, relative ) {
685 | if ( !arguments.length ) {
686 | return this._currentState.stepIndex;
687 | }
688 |
689 | var $step;
690 |
691 | // args: [ step, branch ], relative
692 | if ( $.isArray( step ) ) {
693 | relative = branch;
694 | branch = step[ 1 ];
695 | step = step[ 0 ];
696 |
697 | // args: step, relative
698 | } else if ( typeof branch === bool ) {
699 | relative = branch;
700 | branch = undefined;
701 | }
702 |
703 | return ( $step = this.step( step, branch ) ) ?
704 | // The returned index can be relative to a branch, or to all steps
705 | ( relative ? $step.siblings( selector.step ).andSelf() : this.elements.steps ).index( $step )
706 | : -1;
707 | },
708 |
709 | steps: function( branch ) {
710 | return arguments.length ?
711 | this.branch( branch ).children( selector.step ) : this.elements.steps;
712 | },
713 |
714 | stepsActivated: function() {
715 | return this._find( this._currentState.stepsActivated, this.elements.steps );
716 | },
717 |
718 | submit: function() {
719 | this.elements.form.submit();
720 | }
721 | });
722 |
723 | })( jQuery );
724 |
--------------------------------------------------------------------------------
/tests/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
jQuery.wizard Unit Tests
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
Heading
34 |
35 |
60 |
61 |
62 |
63 |
78 |
79 |
80 |
84 |
85 |
86 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/tests/qunit/qunit.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * QUnit 1.14.0
3 | * http://qunitjs.com/
4 | *
5 | * Copyright 2013 jQuery Foundation and other contributors
6 | * Released under the MIT license
7 | * http://jquery.org/license
8 | *
9 | * Date: 2014-01-31T16:40Z
10 | */
11 |
12 | /** Font Family and Sizes */
13 |
14 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
15 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
16 | }
17 |
18 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
19 | #qunit-tests { font-size: smaller; }
20 |
21 |
22 | /** Resets */
23 |
24 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
25 | margin: 0;
26 | padding: 0;
27 | }
28 |
29 |
30 | /** Header */
31 |
32 | #qunit-header {
33 | padding: 0.5em 0 0.5em 1em;
34 |
35 | color: #8699A4;
36 | background-color: #0D3349;
37 |
38 | font-size: 1.5em;
39 | line-height: 1em;
40 | font-weight: 400;
41 |
42 | border-radius: 5px 5px 0 0;
43 | }
44 |
45 | #qunit-header a {
46 | text-decoration: none;
47 | color: #C2CCD1;
48 | }
49 |
50 | #qunit-header a:hover,
51 | #qunit-header a:focus {
52 | color: #FFF;
53 | }
54 |
55 | #qunit-testrunner-toolbar label {
56 | display: inline-block;
57 | padding: 0 0.5em 0 0.1em;
58 | }
59 |
60 | #qunit-banner {
61 | height: 5px;
62 | }
63 |
64 | #qunit-testrunner-toolbar {
65 | padding: 0.5em 0 0.5em 2em;
66 | color: #5E740B;
67 | background-color: #EEE;
68 | overflow: hidden;
69 | }
70 |
71 | #qunit-userAgent {
72 | padding: 0.5em 0 0.5em 2.5em;
73 | background-color: #2B81AF;
74 | color: #FFF;
75 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
76 | }
77 |
78 | #qunit-modulefilter-container {
79 | float: right;
80 | }
81 |
82 | /** Tests: Pass/Fail */
83 |
84 | #qunit-tests {
85 | list-style-position: inside;
86 | }
87 |
88 | #qunit-tests li {
89 | padding: 0.4em 0.5em 0.4em 2.5em;
90 | border-bottom: 1px solid #FFF;
91 | list-style-position: inside;
92 | }
93 |
94 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
95 | display: none;
96 | }
97 |
98 | #qunit-tests li strong {
99 | cursor: pointer;
100 | }
101 |
102 | #qunit-tests li a {
103 | padding: 0.5em;
104 | color: #C2CCD1;
105 | text-decoration: none;
106 | }
107 | #qunit-tests li a:hover,
108 | #qunit-tests li a:focus {
109 | color: #000;
110 | }
111 |
112 | #qunit-tests li .runtime {
113 | float: right;
114 | font-size: smaller;
115 | }
116 |
117 | .qunit-assert-list {
118 | margin-top: 0.5em;
119 | padding: 0.5em;
120 |
121 | background-color: #FFF;
122 |
123 | border-radius: 5px;
124 | }
125 |
126 | .qunit-collapsed {
127 | display: none;
128 | }
129 |
130 | #qunit-tests table {
131 | border-collapse: collapse;
132 | margin-top: 0.2em;
133 | }
134 |
135 | #qunit-tests th {
136 | text-align: right;
137 | vertical-align: top;
138 | padding: 0 0.5em 0 0;
139 | }
140 |
141 | #qunit-tests td {
142 | vertical-align: top;
143 | }
144 |
145 | #qunit-tests pre {
146 | margin: 0;
147 | white-space: pre-wrap;
148 | word-wrap: break-word;
149 | }
150 |
151 | #qunit-tests del {
152 | background-color: #E0F2BE;
153 | color: #374E0C;
154 | text-decoration: none;
155 | }
156 |
157 | #qunit-tests ins {
158 | background-color: #FFCACA;
159 | color: #500;
160 | text-decoration: none;
161 | }
162 |
163 | /*** Test Counts */
164 |
165 | #qunit-tests b.counts { color: #000; }
166 | #qunit-tests b.passed { color: #5E740B; }
167 | #qunit-tests b.failed { color: #710909; }
168 |
169 | #qunit-tests li li {
170 | padding: 5px;
171 | background-color: #FFF;
172 | border-bottom: none;
173 | list-style-position: inside;
174 | }
175 |
176 | /*** Passing Styles */
177 |
178 | #qunit-tests li li.pass {
179 | color: #3C510C;
180 | background-color: #FFF;
181 | border-left: 10px solid #C6E746;
182 | }
183 |
184 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
185 | #qunit-tests .pass .test-name { color: #366097; }
186 |
187 | #qunit-tests .pass .test-actual,
188 | #qunit-tests .pass .test-expected { color: #999; }
189 |
190 | #qunit-banner.qunit-pass { background-color: #C6E746; }
191 |
192 | /*** Failing Styles */
193 |
194 | #qunit-tests li li.fail {
195 | color: #710909;
196 | background-color: #FFF;
197 | border-left: 10px solid #EE5757;
198 | white-space: pre;
199 | }
200 |
201 | #qunit-tests > li:last-child {
202 | border-radius: 0 0 5px 5px;
203 | }
204 |
205 | #qunit-tests .fail { color: #000; background-color: #EE5757; }
206 | #qunit-tests .fail .test-name,
207 | #qunit-tests .fail .module-name { color: #000; }
208 |
209 | #qunit-tests .fail .test-actual { color: #EE5757; }
210 | #qunit-tests .fail .test-expected { color: #008000; }
211 |
212 | #qunit-banner.qunit-fail { background-color: #EE5757; }
213 |
214 |
215 | /** Result */
216 |
217 | #qunit-testresult {
218 | padding: 0.5em 0.5em 0.5em 2.5em;
219 |
220 | color: #2B81AF;
221 | background-color: #D2E0E6;
222 |
223 | border-bottom: 1px solid #FFF;
224 | }
225 | #qunit-testresult .module-name {
226 | font-weight: 700;
227 | }
228 |
229 | /** Fixture */
230 |
231 | #qunit-fixture {
232 | position: absolute;
233 | top: -10000px;
234 | left: -10000px;
235 | width: 1000px;
236 | height: 1000px;
237 | }
--------------------------------------------------------------------------------
/tests/unit/testsuite.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var namespace = "kf";
3 |
4 | function testWidgetDefaults( widget, defaults ) {
5 | var pluginDefaults = $[ namespace ][ widget ].prototype.options;
6 |
7 | // ensure that all defaults have the correct value
8 | test( "defined defaults", function() {
9 | $.each( defaults, function( key, val ) {
10 | if ( $.isFunction( val ) ) {
11 | ok( $.isFunction( pluginDefaults[ key ] ), key );
12 | return;
13 | }
14 | deepEqual( pluginDefaults[ key ], val, key );
15 | });
16 | });
17 |
18 | // ensure that all defaults were tested
19 | test( "tested defaults", function() {
20 | deepEqual(pluginDefaults, defaults);
21 | });
22 | }
23 |
24 | var privateMethods = [
25 | "_createWidget",
26 | "destroy",
27 | "option",
28 | "_trigger"
29 | ];
30 |
31 | function testWidgetOverrides( widget ) {
32 | if ( $.uiBackCompat === false ) {
33 | test( "$.widget overrides", function() {
34 | $.each( privateMethods, function( i, method ) {
35 | strictEqual( $[ namespace ][ widget ].prototype[ method ],
36 | $.Widget.prototype[ method ], "should not override " + method );
37 | });
38 | });
39 | }
40 | }
41 |
42 | function testBasicUsage( widget ) {
43 | test( "basic usage", function() {
44 | var defaultElement = $[ namespace ][ widget ].prototype.defaultElement;
45 | $( defaultElement ).appendTo( "body" )[ widget ]().remove();
46 | ok( true, "initialized on element" );
47 |
48 | $( defaultElement )[ widget ]().remove();
49 | ok( true, "initialized on disconnected DOMElement - never connected" );
50 |
51 | $( defaultElement ).appendTo( "body" ).remove()[ widget ]().remove();
52 | ok( true, "initialized on disconnected DOMElement - removed" );
53 | });
54 | }
55 |
56 | window.commonWidgetTests = function( widget, settings ) {
57 | module( widget + ": common widget" );
58 |
59 | testWidgetDefaults( widget, settings.defaults );
60 | testWidgetOverrides( widget );
61 | testBasicUsage( widget );
62 | test( "version", function() {
63 | ok( "version" in $[ namespace ][ widget ].prototype, "version property exists" );
64 | });
65 | };
66 |
67 | /*
68 | * Experimental assertion for comparing DOM objects.
69 | *
70 | * Serializes an element and some attributes and it's children if any, otherwise the text.
71 | * Then compares the result using deepEqual.
72 | */
73 | window.domEqual = function( selector, modifier, message ) {
74 | var attributes = ["class", "role", "id", "tabIndex", "aria-activedescendant"];
75 |
76 | function extract(value) {
77 | if (!value || !value.length) {
78 | QUnit.push( false, actual, expected, "domEqual failed, can't extract " + selector + ", message was: " + message );
79 | return;
80 | }
81 | var result = {};
82 | result.nodeName = value[0].nodeName;
83 | $.each(attributes, function(index, attr) {
84 | result[attr] = value.attr(attr);
85 | });
86 | result.children = [];
87 | var children = value.children();
88 | if (children.length) {
89 | children.each(function() {
90 | result.children.push(extract($(this)));
91 | });
92 | } else {
93 | result.text = value.text();
94 | }
95 | return result;
96 | }
97 | var expected = extract($(selector));
98 | modifier($(selector));
99 |
100 | var actual = extract($(selector));
101 | QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
102 | };
103 |
104 | })();
--------------------------------------------------------------------------------
/tests/unit/wizard/wizard_core.js:
--------------------------------------------------------------------------------
1 | /*
2 | * wizard unit tests
3 | */
4 | (function( $ ) {
5 |
6 | module( "wizard: core" );
7 |
8 | test( "widget method - empty collection", function() {
9 | expect( 1 );
10 |
11 | $( "#nonExist" ).wizard();
12 | ok( !$( ".ui-wizard" ).length, "Not initialized on an empty collection" );
13 | });
14 |
15 | test( "widget method", function() {
16 | expect( 1 );
17 |
18 | var $wizard = $( "#wizard" ).wizard();
19 | $wizard = $wizard.wizard( "widget" );
20 |
21 | deepEqual( $( "#wizard" )[0], $wizard[0] );
22 | });
23 |
24 | test( "widget form", function() {
25 | $( ".wizard" ).wizard();
26 | var $wizard = $( ".wizard" );
27 |
28 | expect( $wizard.length );
29 |
30 | $wizard.each(function() {
31 | var $this = $( this );
32 |
33 | ok( $this.wizard( "form" ).length,
34 | "Form found for wizard: #" + $this.attr( "id" ) );
35 | });
36 | });
37 |
38 | test( "wizard classes", function() {
39 | expect( 5 );
40 |
41 | var $wizard = $( "#wizard" ).wizard();
42 |
43 | ok( $wizard.hasClass( "wizard" ), "Wizard has 'wizard' class" );
44 |
45 | $.each({
46 | header: "> :header:first",
47 | form: "form",
48 | step: ".step",
49 | branch: ".branch"
50 | }, function(k, v) {
51 | ok( $wizard.find( v ).hasClass( "wizard-" + k ),
52 | "Wizard (" + v + ") has wizard-" + k + " class" );
53 | });
54 | });
55 |
56 | test( "wizard disabled", function() {
57 | expect( 3 );
58 |
59 | var $wizard = $( "#wizard" ).wizard({
60 | disabled: true,
61 | initialStep: 1
62 | });
63 |
64 | equal( $wizard.wizard( "forward" ).wizard( "stepIndex" ), 1,
65 | "Forward was cancelled because wizard is disabled" );
66 |
67 | equal( $wizard.wizard( "backward" ).wizard( "stepIndex" ), 1,
68 | "Backward was cancelled because wizard is disabled" );
69 |
70 | equal( $wizard.wizard( "select", 2 ).wizard( "stepIndex" ), 1,
71 | "Select was cancelled because wizard is disabled" );
72 | });
73 |
74 | test( "wizard update", function() {
75 | expect( 8 );
76 |
77 | var $wizard = $( "#wizard2" ).wizard({
78 | backward: ".previous",
79 | forward: ".next",
80 | stepClasses: {
81 | exclude: "wizardExclude",
82 | stop: "wizardStop",
83 | submit: "wizardSubmit",
84 | unidirectional: "wizardNoBackward"
85 | }
86 | }),
87 | wizard = $wizard.data( "kf-wizard" );
88 |
89 | ok( wizard.elements.backward.is( ":disabled" ),
90 | "Backward button disabled on first step" );
91 |
92 | ok( wizard.elements.forward.is( ":enabled" ),
93 | "Forward step is enabled on first step" );
94 |
95 | ok( wizard.elements.submit.is( ":disabled" ),
96 | "Submit step is disabled because 'submit' stepClass is not present and enableSubmit is false" );
97 |
98 | $wizard.wizard( "select", 3 );
99 |
100 | ok( wizard.elements.backward.is( ":enabled" ),
101 | "Backward button enabled on third step" );
102 |
103 | ok( wizard.elements.forward.is( ":disabled" ),
104 | "Forward button disabled because of 'stop' stepClass" );
105 |
106 | $wizard.wizard( "select", -1 );
107 |
108 | ok( wizard.elements.backward.is( ":disabled" ),
109 | "Backward is disabled because of 'unidirectional' stepClass" );
110 |
111 | ok( wizard.elements.forward.is( ":disabled" ),
112 | "Forward is disabled on last step in branch without a transition state" );
113 |
114 | ok( wizard.elements.submit.is( ":enabled" ),
115 | "Submit is enabled because of the 'submit' stepClass" );
116 | });
117 |
118 | })( jQuery );
--------------------------------------------------------------------------------
/tests/unit/wizard/wizard_defaults.js:
--------------------------------------------------------------------------------
1 | /*
2 | * wizard defaults unit tests
3 | */
4 |
5 | (function( $ ) {
6 |
7 | var defaultsToTest = {
8 | defaults: {
9 | animations: {
10 | show: {
11 | options: {
12 | duration: 0
13 | },
14 | properties: {
15 | opacity: "show"
16 | }
17 | },
18 | hide: {
19 | options: {
20 | duration: 0
21 | },
22 | properties: {
23 | opacity: "hide"
24 | }
25 | }
26 | },
27 | backward: ".backward",
28 | branches: ".branch",
29 | disabled: false,
30 | enableSubmit: false,
31 | forward: ".forward",
32 | header: ":header:first",
33 | initialStep: 0,
34 | stateAttribute: "data-state",
35 | stepClasses: {
36 | current: "current",
37 | exclude: "exclude",
38 | stop: "stop",
39 | submit: "submit",
40 | unidirectional: "unidirectional"
41 | },
42 | steps: ".step",
43 | submit: ":submit",
44 | transitions: {},
45 | unidirectional: false,
46 |
47 | /* callbacks */
48 | afterBackward: null,
49 | afterDestroy: null,
50 | afterForward: null,
51 | afterSelect: null,
52 | beforeBackward: null,
53 | beforeDestroy: null,
54 | beforeForward: null,
55 | beforeSelect: null,
56 | create: null
57 | }
58 | };
59 |
60 | commonWidgetTests( "wizard", defaultsToTest );
61 |
62 | })( jQuery );
--------------------------------------------------------------------------------
/tests/unit/wizard/wizard_events.js:
--------------------------------------------------------------------------------
1 | /*
2 | * wizard events unit tests
3 | */
4 |
5 | (function( $ ) {
6 |
7 | var callback = function( e ) {
8 | ok( true, e.type + " triggered" );
9 | };
10 |
11 | module( "wizard: events" );
12 |
13 | test( "backward", function() {
14 | var i = 0,
15 | $w = $( "#wizard" );
16 |
17 | expect( 4 );
18 |
19 | $w
20 | .bind( "wizardbeforebackward", callback )
21 | .bind( "wizardafterbackward", callback )
22 | .wizard({
23 | // Issue #19 - asynchronous events
24 | beforeBackward: function( event, state, update ) {
25 | var async = i > 0;
26 |
27 | if (async) {
28 | stop();
29 | setTimeout(function() {
30 | update( true );
31 | start();
32 |
33 | // Can't go back on first step
34 | $w.wizard( "backward" );
35 | }, 1);
36 | }
37 |
38 | i++;
39 | return !async;
40 | }
41 | })
42 | .wizard( "forward", 2 )
43 | .wizard( "backward" )
44 | .wizard( "backward" );
45 | });
46 |
47 | test( "cancel backward", function() {
48 | expect( 0 );
49 |
50 | $( "#wizard" )
51 | .bind( "wizardafterbackward", callback )
52 | .wizard({
53 | beforeBackward: function() {
54 | return false;
55 | }
56 | })
57 | .wizard( "forward" )
58 | .wizard( "backward" )
59 | .wizard( "backward" );
60 | });
61 |
62 | test( "destroy", function() {
63 | expect( 2 );
64 |
65 | $( "#wizard" )
66 | .bind( "wizardbeforedestroy", callback )
67 | .bind( "wizardafterdestroy", callback )
68 | .wizard()
69 | .wizard( "destroy" );
70 | });
71 |
72 | test( "cancel destroy", function() {
73 | expect( 0 );
74 |
75 | $( "#wizard" )
76 | .bind( "wizardafterdestroy", callback )
77 | .wizard({
78 | beforeDestroy: function() {
79 | return false;
80 | }
81 | })
82 | .wizard( "destroy" );
83 | });
84 |
85 | test( "forward", function() {
86 | expect( 4 );
87 |
88 | $( "#wizard" )
89 | .bind( "wizardbeforeforward", callback )
90 | .bind( "wizardafterforward", callback )
91 | .wizard()
92 | .wizard( "forward" )
93 | .wizard( "select", -1 )
94 | // Can't go forward on last step
95 | .wizard( "forward" );
96 | });
97 |
98 | test( "cancel forward", function() {
99 | expect( 0 );
100 |
101 | $( "#wizard" )
102 | .bind( "wizardafterforward", callback )
103 | .wizard({
104 | beforeForward: function() {
105 | return false;
106 | }
107 | })
108 | .wizard( "forward" );
109 | });
110 |
111 | test( "select", function() {
112 | expect( 10 );
113 |
114 | $( "#wizard" )
115 | .bind( "wizardbeforeselect", callback )
116 | .bind( "wizardafterselect", callback )
117 | .wizard()
118 | .wizard( "forward" )
119 | .wizard( "select", 3 )
120 | .wizard( "select", -1 )
121 | .wizard( "select", -2, true )
122 | .wizard( "select", null )
123 | .wizard( "select", "asdf" )
124 | .wizard( "backward" );
125 | });
126 |
127 | })( jQuery );
--------------------------------------------------------------------------------
/tests/unit/wizard/wizard_methods.js:
--------------------------------------------------------------------------------
1 | /*
2 | * wizard methods unit tests
3 | */
4 |
5 | (function( $ ) {
6 |
7 | module( "wizard: methods", {
8 | setup: function() {
9 | $w = $( "#wizard" ).wizard();
10 | }
11 | });
12 |
13 | test( "backward", function() {
14 | expect( 4 );
15 |
16 | $w.wizard( "select", -1 );
17 |
18 | equal( $w.wizard( "backward" ).wizard( "stepIndex" ), 6, "Backward" );
19 | equal( $w.wizard( "backward", $.Event( "click" ) ).wizard( "stepIndex" ), 5,
20 | "Backward, event as first argument" );
21 | equal( $w.wizard( "backward", 2 ).wizard( "stepIndex" ), 3, "Backward, multiple steps" );
22 | equal( $w.wizard( "backward", 99 ).wizard( "stepIndex" ), 0,
23 | "Backward, multiple steps, normalized to first step" );
24 | });
25 |
26 | test( "branch", function() {
27 | expect( 3 );
28 |
29 | equal( $w.wizard( "branch" ).attr( "id" ), "form", "Current branch" );
30 | equal( $w.wizard( "branch", "branch-1" ).attr( "id" ), "branch-1",
31 | "Find a specific branch via branch label" );
32 | equal( $w.wizard( "branch", 0 ).attr( "id" ), "form",
33 | "Find a specific branch via branch index" );
34 | });
35 |
36 | test( "branches", function() {
37 | expect( 2 );
38 |
39 | equal( $w.wizard( "branches" ).length, 4, "Wizard has 4 branches" );
40 | equal( $w.wizard( "branches", "branch-1" ).length, 1, "Found 1 branch inside 'branch-1'" );
41 | });
42 |
43 | test( "branchesActivated", function() {
44 | expect( 3 );
45 |
46 | equal( $w.wizard( "branchesActivated" ).length, 1, "One branch has been activated" );
47 | equal( $w.wizard( "forward" ).wizard( "branchesActivated" ).length, 2,
48 | "Two branches have been activated" );
49 | equal( $w.wizard( "select", -1 ).wizard( "branchesActivated" ).length, 4,
50 | "All branches have been activated" );
51 | });
52 |
53 | test( "destroy", function() {
54 | expect( 6 );
55 |
56 | var wizard = $w.data( "kf-wizard" );
57 | ok( $w.hasClass( "wizard" ) && wizard, "Wizard has been created" );
58 | ok( $._data( wizard.elements.backward.get(0), "events" ) != undefined, "Event bound to backward button." );
59 | ok( $._data( wizard.elements.forward.get(0), "events" ) != undefined, "Event bound to forward button." );
60 | ok( !$w.wizard( "destroy" ).hasClass( "wizard" ) && !$w.data( "kf-wizard" ), "Wizard has been destroyed" );
61 |
62 | // #35 unbind events created during initialization on destroy
63 | ok( !$._data( wizard.elements.backward.get(0), "events" ), "Event unbound from backward button." );
64 | ok( !$._data( wizard.elements.forward.get(0), "events" ), "Event unbound from forward button." );
65 | });
66 |
67 | test( "form", function() {
68 | expect( 3 );
69 |
70 | equal( $w.wizard( "form" )[0].tagName, "FORM", "#wizard has a form" );
71 | equal( $( "#wizard2" ).wizard().wizard( "form" )[0].tagName, "FORM", "#wizard2 has a form" );
72 | equal( $( "#wizard3" ).wizard().wizard( "form" )[0].tagName, "FORM", "#wizard3 has a form" );
73 | });
74 |
75 | test( "forward", function() {
76 | expect( 5 );
77 |
78 | equal( $w.wizard( "forward" ).wizard( "stepIndex" ), 1, "Forward" );
79 | equal( $w.wizard( "forward", $.Event( "click" ) ).wizard( "stepIndex" ), 2,
80 | "Forward, event as first argument" );
81 | equal( $w.wizard( "forward", 2 ).wizard( "stepIndex" ), 4, "Forward, multiple steps" );
82 | equal( $w.wizard( "forward", 99 ).wizard( "stepIndex" ), 7,
83 | "Forward, multiple steps, normalized to last step" );
84 | equal( $w.wizard( "select", 0 )
85 | .wizard( "forward", 3, false )
86 | .wizard( "stepsActivated" ).length, 2,
87 | "Forward, multiple steps, no history" );
88 | });
89 |
90 | test( "isValidStep", function() {
91 | expect( 6 );
92 |
93 | ok( $w.wizard( "isValidStep", 0 ), "Validate step by index" );
94 | ok( $w.wizard( "isValidStep", "finish" ), "Validate step by ID" );
95 | ok( $w.wizard( "isValidStep", $( "#finish" ) ), "Validate step by jQuery object" );
96 | ok( !$w.wizard( "isValidStep", $( "#wizard2 .step" ).eq( 0 ) ),
97 | "Invalidates a step that is not in the wizard" );
98 | ok( !$w.wizard( "isValidStep", 8 ), "Invalidates a faulty step index" );
99 | ok( $w.wizard( "isValidStep", -2 ), "Negative step indexes may be used" );
100 | });
101 |
102 | test( "isValidStepIndex", function() {
103 | expect( 5 );
104 |
105 | ok( $w.wizard( "isValidStepIndex", 0 ) );
106 | ok( $w.wizard( "isValidStepIndex", 7 ) );
107 | ok( !$w.wizard( "isValidStepIndex", 8 ), "Step index does not exist in wizard" );
108 | ok( !$w.wizard( "isValidStepIndex", -1 ), "Negative indexes are invalid" );
109 | ok( !$w.wizard( "isValidStepIndex", "string" ), "Invalid because index is not a number" );
110 | });
111 |
112 | test( "stepCount", function() {
113 | var $wizard = $( ".wizard" );
114 |
115 | expect( $wizard.length );
116 |
117 | $wizard.each(function() {
118 | var $this = $( this );
119 |
120 | ok( $this.wizard().wizard( "stepCount" ) > 0,
121 | "Found steps in wizard '" + $this.attr( "id" ) + "'" );
122 | });
123 | });
124 |
125 | test( "select", function() {
126 | expect( 7 );
127 |
128 | equal( $w.wizard( "select", 1 ).wizard( "stepIndex" ), 1, "Select step by index" );
129 | equal( $w.wizard( "select", -1 ).wizard( "stepIndex" ), 7, "Select step with negative index" );
130 | equal( $w.wizard( "select", "finish" ).wizard( "stepIndex" ), 7, "Select a step by ID" );
131 | equal( $w.wizard( "select", "branch-1" ).wizard( "stepIndex" ), 1,
132 | "Select a step by branch ID" );
133 | equal( $w.wizard( "select", "branch-1", 1 ).wizard( "stepIndex" ), 2,
134 | "Select a step relative to a branch" );
135 | equal( $w.wizard( "select", -2, true ).wizard( "stepIndex" ), 0,
136 | "Select a step relative to the current step" );
137 | equal( $w.wizard( "select", 2, true, false ).wizard( "stepsActivated" ).length, 2,
138 | "Select a step without keeping history" );
139 | });
140 |
141 | test( "state", function() {
142 | expect( 4 );
143 |
144 | equal( $w.wizard( "state" ).stepIndex, 0, "Current state" );
145 | equal( $w.wizard( "state", 1 ).stepIndex, 1, "State for step index 1" );
146 | equal( $w.wizard( "state", 2 ).stepsActivated.length, 2,
147 | "State for step index 2, without history" );
148 | equal( $w.wizard( "state", 2, [ 0, 1, 2 ] ).stepsActivated.length, 3,
149 | "State for step index 2, with history" );
150 | });
151 |
152 | test( "step", function() {
153 | expect( 15 );
154 |
155 | ok( $w.wizard( "step" ).length, "Find current step" );
156 | ok( $w.wizard( "step", 1 ).length, "Find a step by index" );
157 | ok( $w.wizard( "step", -1 ).length, "Find a step by negative index" );
158 | ok( $w.wizard( "step", "finish" ).length, "Find a step by ID" );
159 | ok( $w.wizard( "step", $( "#finish" ) ).length, "Find a step by jQuery object" );
160 | ok( $w.wizard( "step", $( "#finish" )[0] ).length, "Find a step by DOM element" );
161 | ok( $w.wizard( "step", "branch-1" ).length, "Find a step by branch ID" );
162 | ok( $w.wizard( "step", $( "#branch-1" ) ).length, "Find a step by branch jQuery object" );
163 | ok( $w.wizard( "step", $( "#branch-1" )[0] ).length, "Select a step by branch DOM element" );
164 | ok( $w.wizard( "step", "branch-1", 1 ).length, "Find a step within a branch" );
165 | ok( $w.wizard( "step", 1, "branch-1" ).length, "Alternative way to find a step within a branch" );
166 |
167 | ok( !$w.wizard( "step", 99 ).length, "Step index is not valid" );
168 | ok( !$w.wizard( "step", null ).length, "Null is not valid" );
169 | ok( !$w.wizard( "step", undefined ).length, "Undefined is not valid" );
170 | ok( !$w.wizard( "step", "doesnotexist" ).length, "ID is not valid" );
171 | });
172 |
173 | test( "stepIndex", function() {
174 | expect( 4 );
175 |
176 | equal( $w.wizard( "stepIndex" ), 0, "Index of current step" );
177 | equal( $w.wizard( "stepIndex", 1 ), 1, "Index of step 1" );
178 | equal( $w.wizard( "stepIndex", "branch-1", 1 ), 2,
179 | "The index of the second step in branch 'branch-1'" );
180 | equal( $w.wizard( "stepIndex", "branch-1", 1, true ), 1,
181 | "The index of the second step in branch 'branch-1' relative to the branch" );
182 | });
183 |
184 | test( "steps", function() {
185 | expect( 2 );
186 |
187 | equal( $w.wizard( "steps" ).length, 8, "Get all of the steps in the wizard" );
188 | equal( $w.wizard( "steps", "branch-1" ).length, 2,
189 | "Get all of the steps in the 'branch-1' branch" );
190 | });
191 |
192 | test( "stepsActivated", function() {
193 | expect( 3 );
194 |
195 | equal( $w.wizard( "stepsActivated" ).length, 1, "One step has been activated" );
196 | equal( $w.wizard( "forward" ).wizard( "stepsActivated" ).length, 2,
197 | "Two steps have been activated" );
198 | equal( $w.wizard( "select", -1 ).wizard( "stepsActivated" ).length, 8,
199 | "All steps have been activated" );
200 | });
201 |
202 | test( "submit", function() {
203 | expect( 1 );
204 |
205 | $w.wizard( "form" ).submit(function() {
206 | ok( true, "Form submission was successful" );
207 | return false;
208 | });
209 |
210 | $w.wizard( "submit" );
211 | });
212 |
213 | })( jQuery );
--------------------------------------------------------------------------------
/tests/unit/wizard/wizard_options.js:
--------------------------------------------------------------------------------
1 | /*
2 | * wizard options unit tests
3 | */
4 |
5 | (function( $ ) {
6 |
7 | var $w, $w2, $w3, $w4;
8 |
9 | module( "wizard: options", {
10 | setup: function() {
11 | $w = $( "#wizard" );
12 | $w2 = $( "#wizard2" );
13 | $w3 = $( "#wizard3" );
14 | $w4 = $( "#wizard4" );
15 | }
16 | });
17 |
18 | // TODO make tests for animations
19 |
20 | test( "{ backward: string }", function() {
21 | expect( 2 );
22 |
23 | equal( $w.wizard().data( "kf-wizard" ).elements.backward.length, 1 );
24 | equal( $w2.wizard({
25 | backward: ".previous"
26 | }).data( "kf-wizard" ).elements.backward.length, 1 );
27 | });
28 |
29 | test( "{ branches: string }", function() {
30 | expect( 2 );
31 |
32 | equal( $w.wizard().data( "kf-wizard" ).elements.branches.length, 4 );
33 | equal( $w2.wizard({
34 | branches: ".wizardBranch"
35 | }).data( "kf-wizard" ).elements.branches.length, 1 );
36 | });
37 |
38 | test( "{ enableSubmit: boolean }", function() {
39 | expect( 2 );
40 |
41 | ok( $w.wizard().data( "kf-wizard" ).elements.submit.is( ":disabled" ) );
42 | ok( $w2.wizard({
43 | enableSubmit: true
44 | }).data( "kf-wizard" ).elements.submit.is( ":enabled" ) );
45 | });
46 |
47 | test( "{ forward: string }", function() {
48 | expect( 2 );
49 |
50 | equal( $w.wizard().data( "kf-wizard" ).elements.forward.length, 1 );
51 | equal( $w2.wizard({
52 | forward: ".next"
53 | }).data( "kf-wizard" ).elements.forward.length, 1 );
54 | });
55 |
56 | test( "{ header: string }", function() {
57 | expect( 2 );
58 |
59 | equal( $w.wizard().data( "kf-wizard" ).elements.header.length, 1 );
60 | equal( $w2.wizard({
61 | header: "h2"
62 | }).data( "kf-wizard" ).elements.header.length, 1 );
63 | });
64 |
65 | test( "{ initialStep: number }", function() {
66 | expect( 2 );
67 |
68 | equal( $w.wizard().wizard( "stepIndex" ), 0 );
69 | equal( $w2.wizard({
70 | initialStep: 1
71 | }).wizard( "stepIndex" ), 1 );
72 | });
73 |
74 | test( "{ initialStep: string }", function() {
75 | expect( 1 );
76 |
77 | equal( $w2.wizard({
78 | initialStep: "step2"
79 | }).wizard( "stepIndex" ), 1 );
80 | });
81 |
82 | test( "{ initialStep: array }", function() {
83 | expect( 2 );
84 |
85 | equal( $w.wizard({
86 | initialStep: [ 1, "branch-1" ]
87 | }).wizard( "stepIndex" ), 2 );
88 |
89 | $w.wizard( "destroy" );
90 |
91 | // Start on step 1 but maintain history of how we got there
92 | deepEqual( $w.wizard({
93 | initialStep: [ 1, [ 0, 1 ] ]
94 | }).wizard( "state" ).stepsActivated, [ 0, 1 ] );
95 | });
96 |
97 | test( "{ stateAttribute: string }", function() {
98 | expect( 1 );
99 |
100 | equal( $w2.wizard({
101 | stateAttribute: "state"
102 | }).wizard( "forward" ).wizard( "stepIndex" ), 2 );
103 | });
104 |
105 | test( "{ stepClasses: object }", function() {
106 | expect( 5 );
107 |
108 | ok( $w.wizard({
109 | stepClasses: {
110 | current: "cur"
111 | }
112 | }).wizard( "step" ).hasClass( "cur" ),
113 | "Current step has class 'cur'" );
114 |
115 | equal( $w2.wizard({
116 | backward: ".previous",
117 | forward: ".next",
118 | stepClasses: {
119 | exclude: "wizardExclude",
120 | stop: "wizardStop",
121 | submit: "wizardSubmit",
122 | unidirectional: "wizardNoBackward"
123 | },
124 | initialStep: 3
125 | }).wizard( "state" ).stepsPossible, 3,
126 | "Step with class 'wizardExclude' is not included in stepsPossible" );
127 |
128 | ok( $w2.data( "kf-wizard" ).elements.forward.is( ":disabled" ),
129 | "Forward is disabled on step with class 'wizardStop'" );
130 | ok( $w2.wizard( "forward" ).data( "kf-wizard" ).elements.submit.is( ":enabled" ),
131 | "Submit is enabled on a step with the class 'wizardSubmit'" );
132 | ok( $w2.data( "kf-wizard" ).elements.backward.is( ":disabled" ),
133 | "Backward is disabled on a step with the class 'wizardNoBackward'" );
134 | });
135 |
136 | test( "{ steps: string }", function() {
137 | expect( 2 );
138 |
139 | equal( $w.wizard().data( "kf-wizard" ).elements.steps.length, 8 );
140 | equal( $w3.wizard({
141 | steps: ".wizardStep"
142 | }).data( "kf-wizard" ).elements.branches.length, 1 );
143 | });
144 |
145 | test( "{ submit: string }", function() {
146 | expect( 2 );
147 |
148 | equal( $w.wizard().data( "kf-wizard" ).elements.submit.length, 1 );
149 | equal( $w3.wizard({
150 | submit: ".process"
151 | }).data( "kf-wizard" ).elements.submit.length, 1 );
152 | });
153 |
154 | test( "{ transitions: object }", function() {
155 | expect( 6 );
156 |
157 | var $w4 = $( "#wizard4" );
158 |
159 | equal( $w2.wizard({
160 | stateAttribute: "state"
161 | }).wizard( "stepIndex" ), 0 );
162 |
163 | equal( $w2.wizard( "forward" ).wizard( "stepIndex" ), 2 );
164 |
165 | equal( $w4.wizard({
166 | transitions: {
167 | findNext: function( state ) {
168 | return state.step.find( "[name=next]" ).val();
169 | }
170 | }
171 | }).wizard( "stepIndex" ), 0 );
172 |
173 | equal( $w4.wizard( "forward" ).wizard( "stepIndex" ), 2,
174 | "Step with state 'findNext' transitioned correctly" );
175 | equal( $w4.wizard( "forward" ).wizard( "stepIndex" ), 3,
176 | "Default method is still present" );
177 |
178 | stop();
179 | $w4.wizard( "destroy" ).wizard({
180 | afterForward: function( event, state ) {
181 | equal( state.stepIndex, 5,
182 | "Step with state 'asyncNext' transitioned corectly" );
183 | start();
184 | },
185 | initialStep: 3,
186 | transitions: {
187 | asyncNext: function( state, action ) {
188 | setTimeout(function() {
189 | action("asyncDestination");
190 | }, 1);
191 | return false;
192 | }
193 | }
194 | }).wizard( "forward" );
195 | });
196 |
197 | test( "{ unidirectional: boolean }", function() {
198 | expect( 2 );
199 |
200 | ok( $w.wizard().wizard( "forward" ).data( "kf-wizard" ).elements.backward.is( ":enabled" ),
201 | "Backward button is enabled on non-unidirectional wizard" );
202 |
203 | ok( $w2.wizard({
204 | backward: ".previous",
205 | unidirectional: true
206 | }).wizard( "forward" ).data( "kf-wizard" ).elements.backward.is( ":disabled" ),
207 | "Backward button is disabled on unidirectional wizard" );
208 | });
209 |
210 | })( jQuery );
--------------------------------------------------------------------------------