draiodoir 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +674 -0
- data/README.md +74 -0
- data/Rakefile +2 -0
- data/draiodoir.gemspec +22 -0
- data/example/account_wizard.css +78 -0
- data/example/account_wizard.html +76 -0
- data/example/validator.js +92 -0
- data/lib/draiodoir.rb +2 -0
- data/lib/draiodoir/version.rb +3 -0
- data/src/wizard.js +252 -0
- metadata +77 -0
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
Draíodóir
|
2
|
+
=========
|
3
|
+
|
4
|
+
A javascript that turns web-pages into Wizards.
|
5
|
+
|
6
|
+
|
7
|
+
Usage
|
8
|
+
-----
|
9
|
+
|
10
|
+
- Include (in a `<script>` tag) on your *HTML5* page
|
11
|
+
- Make the form a Wizard, with `new Wizard("my_form");`
|
12
|
+
|
13
|
+
Example
|
14
|
+
-------
|
15
|
+
|
16
|
+
<!DOCTYPE html>
|
17
|
+
<html>
|
18
|
+
<head>
|
19
|
+
<meta content-type='UTF-8'>
|
20
|
+
<script type='text/javascript' src='wizard.js'></src>
|
21
|
+
<script>
|
22
|
+
addEventListener('load', function(e) {
|
23
|
+
new Wizard('my_form');
|
24
|
+
}, false);
|
25
|
+
</script>
|
26
|
+
<title>Draíodóir Test</title>
|
27
|
+
</head>
|
28
|
+
<body>
|
29
|
+
<form id='my_form' action='javascript:alert("Submitting form");'>
|
30
|
+
<fieldset>
|
31
|
+
<label for='name'>Name</label>
|
32
|
+
<input id='name' type='text' required>
|
33
|
+
</fieldset>
|
34
|
+
<fieldset>
|
35
|
+
<label for='age'>Age</label>
|
36
|
+
<input id='age' type='number' minimum='18' maximum='80' required>
|
37
|
+
</fieldset>
|
38
|
+
<input type='submit' value='Go'>
|
39
|
+
</form>
|
40
|
+
</body>
|
41
|
+
</html>
|
42
|
+
|
43
|
+
Caveats
|
44
|
+
-------
|
45
|
+
|
46
|
+
*Draíodóir* relies on [validation][validation] being fully implemented by
|
47
|
+
the browser. This is almost never the case (as of this writing), so you'll
|
48
|
+
probably need to include another library which performs validation properly,
|
49
|
+
such as [Bailitheoir][bailitheoir].
|
50
|
+
|
51
|
+
The library is targeted, therefore, at the [more][firefox] [modern][chrome]
|
52
|
+
[browsers][safari], so don't expect it to work out of the box in [those][ie]
|
53
|
+
that are, err, less [standards][w3c] compliant.
|
54
|
+
|
55
|
+
Author(s)
|
56
|
+
---------
|
57
|
+
|
58
|
+
- JJ Buckley <jj@bjjb.org>
|
59
|
+
|
60
|
+
Copyright
|
61
|
+
---------
|
62
|
+
|
63
|
+
This software is released under the [GPL][gpl], so feel free to steal and
|
64
|
+
destroy - just comply with the terms of that license. I accept no
|
65
|
+
responsibilty for anything.
|
66
|
+
|
67
|
+
[validation]: http://www.w3.org/TR/html5/association-of-controls-and-forms.html#constraints
|
68
|
+
[bailitheoir]: http://jjbuckley.github.com/bailitheoir
|
69
|
+
[firefox]: http://www.mozilla.com/firefox
|
70
|
+
[chrome]: http://www.google.com/chrome
|
71
|
+
[safari]: http://www.apple.com/safari
|
72
|
+
[ie]: http://www.microsoft.com/ie
|
73
|
+
[w3c]: http://www.w3.org
|
74
|
+
[gpl]: http://www.gnu.org/licenses/gpl.html
|
data/Rakefile
ADDED
data/draiodoir.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "draiodoir/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "draiodoir"
|
7
|
+
s.version = Draiodoir::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["JJ Buckley"]
|
10
|
+
s.email = ["jj@bjjb.org"]
|
11
|
+
s.homepage = "http://jjbuckley.github.com/draiodoir"
|
12
|
+
s.summary = %q{A JavaScript multi-step form helper}
|
13
|
+
s.description = %q{Draíodóir lets you take a regular HTML5 page, and turn it
|
14
|
+
into a multi-step wizard.}
|
15
|
+
|
16
|
+
s.rubyforge_project = "draiodoir"
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
/**
|
2
|
+
* Example account signup form.
|
3
|
+
*/
|
4
|
+
body {
|
5
|
+
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
6
|
+
min-width: 620px;
|
7
|
+
}
|
8
|
+
form {
|
9
|
+
display: block;
|
10
|
+
width: 500px;
|
11
|
+
padding: 50px;
|
12
|
+
margin: auto;
|
13
|
+
|
14
|
+
background-color: #ccddaa;
|
15
|
+
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(255,255,235,0.9)), to(rgba(20,20,20,0.0)));
|
16
|
+
background-image: -moz-linear-gradient(90deg, rgba(255,255,235,0.9), rgba(20,20,0,0.0));
|
17
|
+
|
18
|
+
border: 5px solid #889966;
|
19
|
+
-webkit-border-radius: 10px;
|
20
|
+
-moz-border-radius: 10px;
|
21
|
+
-o-border-radius: 1em;
|
22
|
+
border-radius: 10px;
|
23
|
+
-webkit-box-shadow: 0 0 5px #112200;
|
24
|
+
-moz-box-shadow: 0 0 0.5em #112200;
|
25
|
+
-o-box-shadow: 0 0 5px #112200;
|
26
|
+
box-shadow: 0 0 5px #112200;
|
27
|
+
}
|
28
|
+
|
29
|
+
label {
|
30
|
+
float: left;
|
31
|
+
height: 2em;
|
32
|
+
line-height: 2em;
|
33
|
+
width: 150px;
|
34
|
+
text-align: right;
|
35
|
+
}
|
36
|
+
|
37
|
+
input,select {
|
38
|
+
margin-left: 170px;
|
39
|
+
display: block;
|
40
|
+
clear: right;
|
41
|
+
padding: 5px;
|
42
|
+
font-weight: bold;
|
43
|
+
}
|
44
|
+
|
45
|
+
input:invalid,select:invalid {
|
46
|
+
color: red;
|
47
|
+
-webkit-box-shadow: inset 1px 1px 7px red;
|
48
|
+
-moz-box-shadow: inset 0 0 7px red;
|
49
|
+
box-shadow: inset 0 0 7px red;
|
50
|
+
}
|
51
|
+
|
52
|
+
fieldset {
|
53
|
+
border: none;
|
54
|
+
margin: 0;
|
55
|
+
padding: 0;
|
56
|
+
position: relative;
|
57
|
+
display: block;
|
58
|
+
}
|
59
|
+
fieldset[hidden] {
|
60
|
+
display: none;
|
61
|
+
}
|
62
|
+
legend {
|
63
|
+
display: block;
|
64
|
+
padding: 5px;
|
65
|
+
border: 5px solid #889966;
|
66
|
+
border: 5px solid #889966;
|
67
|
+
-webkit-border-radius: 10px;
|
68
|
+
-moz-border-radius: 10px;
|
69
|
+
-o-border-radius: 1em;
|
70
|
+
border-radius: 10px;
|
71
|
+
position: absolute;
|
72
|
+
font-size: 30px;
|
73
|
+
font-weight: bold;
|
74
|
+
color: #334400;
|
75
|
+
text-shadow: 0px 0px 4px #999999;
|
76
|
+
top: -77px;
|
77
|
+
background-color: #ccddaa;
|
78
|
+
}
|
@@ -0,0 +1,76 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>New Account</title>
|
4
|
+
<script type="text/javascript" src="validator.js"></script>
|
5
|
+
<script type="text/javascript" src="../draiodoir.js"></script>
|
6
|
+
<script type="text/javascript">
|
7
|
+
addEventListener('load', function(event) {
|
8
|
+
var form = document.getElementById('new_account');
|
9
|
+
new Validator(form);
|
10
|
+
new Wizard(form, {
|
11
|
+
labels: {
|
12
|
+
next: {
|
13
|
+
personal: "That's me...",
|
14
|
+
tastes: "That all I'm telling you."
|
15
|
+
}
|
16
|
+
}
|
17
|
+
});
|
18
|
+
}, false);
|
19
|
+
</script>
|
20
|
+
<link rel="stylesheet" type="text/css" href="account_wizard.css">
|
21
|
+
</head>
|
22
|
+
<body>
|
23
|
+
<h1>New Account</h1>
|
24
|
+
<form id="new_account" name="account" method="POST"
|
25
|
+
action="javascript:alert('Submitting form!');"
|
26
|
+
enctype="application/x-www-form-urlencoded">
|
27
|
+
|
28
|
+
<!-- The fields here are required, so the submit button does nothing
|
29
|
+
(except retrigger validation) until validation passes. -->
|
30
|
+
<fieldset name="personal">
|
31
|
+
<legend>Personal Details</legend>
|
32
|
+
|
33
|
+
<label for="account_name">Name</label>
|
34
|
+
<input type="text" id="account_name" name="account[name]"
|
35
|
+
placeholder="Your full name" required="required" />
|
36
|
+
<br />
|
37
|
+
<label for="account_dob">Date of Birth</label>
|
38
|
+
<input type="date" id="account_dob" name="account[dob]"
|
39
|
+
placeholder="YYYY-mm-dd" required="required"
|
40
|
+
min="1900-01-01" max="1990-12-12" />
|
41
|
+
</fieldset>
|
42
|
+
|
43
|
+
<!-- Everything in this fieldset is optional. It will be shown, but the
|
44
|
+
submit button should be enabled already. -->
|
45
|
+
<fieldset name="tastes">
|
46
|
+
<legend>Some additional info</legend>
|
47
|
+
<label for="account_favourite_film">Your favourite film</label>
|
48
|
+
<select id="account_favourite_film" name="account[favourite_film]">
|
49
|
+
<option value="">Pick one...</option>
|
50
|
+
<option value="1">Fight Club</option>
|
51
|
+
<option value="2">True Romance</option>
|
52
|
+
</select>
|
53
|
+
|
54
|
+
<label for="account_favourite_music">Your favourite music</label>
|
55
|
+
<select id="account_favourite_music" name="account[favourite_music]">
|
56
|
+
<option value="">Select from...</option>
|
57
|
+
<option value="1">Skip James</option>
|
58
|
+
<option value="2">Pond</option>
|
59
|
+
<option value="3">Antonio Vivaldi</option>
|
60
|
+
</select>
|
61
|
+
</fieldset>
|
62
|
+
|
63
|
+
<!-- This is the last step, so it should trigger the submit! -->
|
64
|
+
<fieldset name='plan'>
|
65
|
+
<legend>Select your plan</legend>
|
66
|
+
<select id="account_plan" name="account[plan]" required='required'>
|
67
|
+
<option value="">Please Choose...</option>
|
68
|
+
<option value="1">Bronze</option>
|
69
|
+
<option value="2">Silver</option>
|
70
|
+
<option value="3">Gold</option>
|
71
|
+
</select>
|
72
|
+
</fieldset>
|
73
|
+
<input type='submit' value="Continue" />
|
74
|
+
</form>
|
75
|
+
</body>
|
76
|
+
</html>
|
@@ -0,0 +1,92 @@
|
|
1
|
+
/**
|
2
|
+
* A basic implementation of the W3's HTML5 constraints.
|
3
|
+
* (http://www.w3.org/TR/html5/association-of-controls-and-forms.html#constraints)
|
4
|
+
*
|
5
|
+
* Usage
|
6
|
+
* -----
|
7
|
+
*
|
8
|
+
* new Validator(form);
|
9
|
+
* form.addEventListener('invalid', function() {
|
10
|
+
* alert("Detected an invalid field!");
|
11
|
+
* }, false);
|
12
|
+
*
|
13
|
+
* Copyright
|
14
|
+
* ---------
|
15
|
+
*
|
16
|
+
* Copyright (c) 2010 JJ Buckley (jj@bjjb.org)
|
17
|
+
*
|
18
|
+
* This program is free software: you can redistribute it and/or modify
|
19
|
+
* it under the terms of the GNU General Public License as published by
|
20
|
+
* the Free Software Foundation, either version 3 of the License, or
|
21
|
+
* (at your option) any later version.
|
22
|
+
*
|
23
|
+
* This program is distributed in the hope that it will be useful,
|
24
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
25
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
26
|
+
* GNU General Public License for more details.
|
27
|
+
*
|
28
|
+
* You should have received a copy of the GNU General Public License
|
29
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
30
|
+
*/
|
31
|
+
function Validator(form) {
|
32
|
+
var fields = [];
|
33
|
+
function Validator(field) {
|
34
|
+
function Validity() {
|
35
|
+
this.valueMissing = false;
|
36
|
+
this.typeMismatch = false;
|
37
|
+
this.patternMismatch = false;
|
38
|
+
this.tooLong = false;
|
39
|
+
this.rangeUnderflow = false;
|
40
|
+
this.rangeOverflow = false;
|
41
|
+
this.stepMismatch = false;
|
42
|
+
this.customError = false;
|
43
|
+
this.valid = true;
|
44
|
+
};
|
45
|
+
field.willValidate = !!(~['INPUT', 'SELECT', 'TEXTAREA'].indexOf(field.tagName));
|
46
|
+
field.setCustomValidity = function(message) {
|
47
|
+
if (message == "") {
|
48
|
+
field.validity.customError = false;
|
49
|
+
}
|
50
|
+
else {
|
51
|
+
field.validity.customError = true;
|
52
|
+
field.validationMessage = message;
|
53
|
+
}
|
54
|
+
};
|
55
|
+
field.checkValidity = function() {
|
56
|
+
if (this.willValidate) {
|
57
|
+
this.validity.valueMissing = (this.hasAttribute('required') && this.value.trim() == "");
|
58
|
+
this.validity.typeMismatch = ((this.type == 'email' && this.value && !this.value.match(/.+@.+\..+/)) ||
|
59
|
+
(this.type == 'number' && this.value && !this.value.match(/^\d+/)) ||
|
60
|
+
(this.type == 'date' && false && this.value && !this.value.match(/\d{4}-\d{2}-\d{2}/)) ||
|
61
|
+
(this.type == 'url' && this.value && !this.value.match(/.+\..+/)));
|
62
|
+
this.validity.tooLong = (this.hasAttribute('maxlength') && this.value > this.getAttribute('maxlength'));
|
63
|
+
this.validity.rangeUnderflow = (this.hasAttribute('min') && this.value < this.getAttribute('min'));
|
64
|
+
this.validity.rangeOverflow = (this.type == 'number' && this.hasAttribute('max') && this.value < this.getAttribute('max'));
|
65
|
+
this.validity.stepMismatch = false; // TODO
|
66
|
+
this.valid = !(this.validity.valueMissing ||
|
67
|
+
this.validity.typeMismatch ||
|
68
|
+
this.validity.tooLong ||
|
69
|
+
this.validity.rangeUnderflow ||
|
70
|
+
this.validity.rangeOverflow ||
|
71
|
+
this.validity.stepMismatch ||
|
72
|
+
this.validity.customError);
|
73
|
+
if (!this.valid) {
|
74
|
+
var event = document.createEvent('Events');
|
75
|
+
event.initEvent('invalid', true, true);
|
76
|
+
field.dispatchEvent(event);
|
77
|
+
return false;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
return true;
|
81
|
+
};
|
82
|
+
field.validity = new Validity();
|
83
|
+
console.debug("Added a validator (%o) on %o", this, field);
|
84
|
+
}
|
85
|
+
['input', 'select', 'textarea'].forEach(function(tag) {
|
86
|
+
var elements = form.getElementsByTagName(tag);
|
87
|
+
for (var i = 0; i < elements.length; i++) {
|
88
|
+
new Validator(elements[i]);
|
89
|
+
}
|
90
|
+
});
|
91
|
+
}
|
92
|
+
|
data/lib/draiodoir.rb
ADDED
data/src/wizard.js
ADDED
@@ -0,0 +1,252 @@
|
|
1
|
+
/**
|
2
|
+
* Draíodóir
|
3
|
+
* =========
|
4
|
+
*
|
5
|
+
* Turns a HTML5 <form> into a wizard.
|
6
|
+
*
|
7
|
+
* The form *must* be marked up in a particular way, but it's pretty standard
|
8
|
+
* HTML. Basically, each fieldset is a step in the form, and (by default) the
|
9
|
+
* submit button is used as the control for moving forward. If the elements in
|
10
|
+
* a fieldset don't validate (either on a modern browser, or using a compatible
|
11
|
+
* JavaScript validation library, such as
|
12
|
+
* bailitheoir(http://jjbuckley.github.com/bailitheoir), then the Wizard won't
|
13
|
+
* allow you to progress.
|
14
|
+
*
|
15
|
+
* To hide all steps except the current, *Draíodóir* sets the "hidden"
|
16
|
+
* attribute on the fieldset. Since most browsers can't handle this properly
|
17
|
+
* yet, you need to either add a CSS rule such as
|
18
|
+
*
|
19
|
+
* fieldset[hidden] { display: none; }
|
20
|
+
*
|
21
|
+
* or listen for the `wizard:step:show` and `wizard:step:hide` events, and
|
22
|
+
* take appropriate action, such as setting a style attribute, on the event's
|
23
|
+
* target.
|
24
|
+
*
|
25
|
+
* Usage
|
26
|
+
* -----
|
27
|
+
*
|
28
|
+
* form = document.getElementById('my_form');
|
29
|
+
* new Wizard(form);
|
30
|
+
*
|
31
|
+
* A new Wizard immediately hides all steps except the first one.
|
32
|
+
*
|
33
|
+
* You can pass in an options object as a second argumens (all optional):
|
34
|
+
*
|
35
|
+
* Options
|
36
|
+
* -------
|
37
|
+
*
|
38
|
+
* next:: Identifies the control used to move forwards in the form. The
|
39
|
+
* default is the first "submit".
|
40
|
+
* previous:: Identifies the control to be used to move backwards in the form.
|
41
|
+
* If a suitable element can't be found, it is created (as a
|
42
|
+
* <button>), and given the value "Back" (though you can override
|
43
|
+
* this with a label for any or all steps). An auto-generated
|
44
|
+
* previous control is inserted immediately before the "next"
|
45
|
+
* control.
|
46
|
+
* labels:: Used to display text (or HTML) in certain elements at various
|
47
|
+
* steps. Valid values are "next" and "previous", which indicate the
|
48
|
+
* next and previous controls. Each value can either be a string
|
49
|
+
* (which is applied to the control for every step), or an object
|
50
|
+
* containing keys for the step names. For example:
|
51
|
+
*
|
52
|
+
* new Wizard(form, {
|
53
|
+
* previous: 'back_button',
|
54
|
+
* labels: {
|
55
|
+
* next: {
|
56
|
+
* step1: "To Step 2", step2: "Step 3, please", step3: "Go!",
|
57
|
+
* },
|
58
|
+
* previous: "Back"
|
59
|
+
* }
|
60
|
+
* });
|
61
|
+
*
|
62
|
+
* The wizard has 3 steps, fieldsets with names "step1", "step2" and
|
63
|
+
* step3. On step1, the next button says "To Step 2", and on step2,
|
64
|
+
* it says "Step 3, please". On the last step, it says "Go!". If this
|
65
|
+
* were left blank, it would revert to the original value of the
|
66
|
+
* submit field.
|
67
|
+
* On all steps (besides the first), the 'previous' control says
|
68
|
+
* "Back". It's hidden and disabled on the first step.
|
69
|
+
*
|
70
|
+
* Hook into the wizard by listening for the events it generates, or by using
|
71
|
+
* its "next()", "previous()", "first()" and "last()" methods.
|
72
|
+
*
|
73
|
+
* Caveats
|
74
|
+
* -------
|
75
|
+
*
|
76
|
+
* *Draíodóir* has been tested on Google Chrome 6.0.472.63, Mozilla Firefox
|
77
|
+
* 3.6.10, and Sarari on iPhone OS v4.1. I hardly expect it to work in any
|
78
|
+
* current version of Microsoft Explorer, but that will hopefully change.
|
79
|
+
* For more information, see the *Draíodóir* homepage at
|
80
|
+
* http://jjbuckley.github.com/draiodoir. And feel free to fork the project,
|
81
|
+
* and improve it!
|
82
|
+
*
|
83
|
+
* Events
|
84
|
+
* ------
|
85
|
+
*
|
86
|
+
* These Events are fired by a Wizard:
|
87
|
+
*
|
88
|
+
* wizard:load:: the wizard is set up
|
89
|
+
* wizard:next:: the next step is being shown
|
90
|
+
* wizard:previous:: the previous step is being shown
|
91
|
+
* wizard:first:: the first step is being shown
|
92
|
+
* wizard:last:: the last step is being shown
|
93
|
+
* wizard:invalid:: validation failed on the current step
|
94
|
+
* wizard:valid:: validation passed on all steps
|
95
|
+
* wizard:submit:: the form is being submitted
|
96
|
+
* wizard:step:show:: a step is being shown
|
97
|
+
* wizard:step:hide:: a step is being hidden
|
98
|
+
*
|
99
|
+
* Copyright
|
100
|
+
* ---------
|
101
|
+
*
|
102
|
+
* Copyright (c) 2010 JJ Buckley (jj@bjjb.org)
|
103
|
+
*
|
104
|
+
* This program is free software: you can redistribute it and/or modify
|
105
|
+
* it under the terms of the GNU General Public License as published by
|
106
|
+
* the Free Software Foundation, either version 3 of the License, or
|
107
|
+
* (at your option) any later version.
|
108
|
+
*
|
109
|
+
* This program is distributed in the hope that it will be useful,
|
110
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
111
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
112
|
+
* GNU General Public License for more details.
|
113
|
+
*
|
114
|
+
* You should have received a copy of the GNU General Public License
|
115
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
116
|
+
*/
|
117
|
+
function Wizard(form, options) {
|
118
|
+
if (typeof(form) == "string") {
|
119
|
+
form = document.getElementById(form);
|
120
|
+
}
|
121
|
+
|
122
|
+
var self = this;
|
123
|
+
form.addEventListener('submit', function(event) {
|
124
|
+
if (!self.submit()) {
|
125
|
+
event.preventDefault();
|
126
|
+
return false;
|
127
|
+
}
|
128
|
+
}, false);
|
129
|
+
|
130
|
+
form.addEventListener('wizard:step:hide', function(event) {
|
131
|
+
// A step has been hidden.
|
132
|
+
}, false);
|
133
|
+
|
134
|
+
form.addEventListener('wizard:step:show', function(event) {
|
135
|
+
for (var i = 0; i < steps.length; i++) {
|
136
|
+
if (i !== index) {
|
137
|
+
steps[i].hide();
|
138
|
+
}
|
139
|
+
}
|
140
|
+
}, false);
|
141
|
+
|
142
|
+
function getSubmit() {
|
143
|
+
elements = form.getElementsByTagName('input');
|
144
|
+
for (var i = 0; i < elements.length; i++) {
|
145
|
+
if (elements[i].type == 'submit') {
|
146
|
+
return elements[i];
|
147
|
+
}
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
function Step(fieldset, options) {
|
152
|
+
this.name = fieldset.getAttribute('name');
|
153
|
+
this.toString = function() {
|
154
|
+
return "Step:" + this.name;
|
155
|
+
};
|
156
|
+
var fields = [];
|
157
|
+
['input', 'select', 'textarea'].forEach(function(tag) {
|
158
|
+
elements = fieldset.getElementsByTagName(tag);
|
159
|
+
for (var i = 0; i < elements.length; i++) {
|
160
|
+
elements[i].addEventListener('invalid', function(event) {
|
161
|
+
console.debug("%o is invalid! (%o)", this, this.validity);
|
162
|
+
fieldset.valid = false;
|
163
|
+
}, false);
|
164
|
+
fields.push(elements[i]);
|
165
|
+
}
|
166
|
+
});
|
167
|
+
this.hide = function() {
|
168
|
+
fieldset.setAttribute('hidden', 'hidden');
|
169
|
+
var event = document.createEvent('Events');
|
170
|
+
event.initEvent('wizard:step:hide', true, true);
|
171
|
+
event.step = this;
|
172
|
+
return fieldset.dispatchEvent(event);
|
173
|
+
};
|
174
|
+
this.show = function() {
|
175
|
+
fieldset.removeAttribute('hidden');
|
176
|
+
var event = document.createEvent('Events');
|
177
|
+
event.initEvent('wizard:step:show', true, true);
|
178
|
+
event.step = this;
|
179
|
+
return fieldset.dispatchEvent(event);
|
180
|
+
};
|
181
|
+
this.validate = function() {
|
182
|
+
return fields.every(function(field) {
|
183
|
+
return field.checkValidity();
|
184
|
+
});
|
185
|
+
};
|
186
|
+
}
|
187
|
+
|
188
|
+
var steps = [];
|
189
|
+
var index = 0;
|
190
|
+
var submit = getSubmit();
|
191
|
+
var submit_text = submit.value;
|
192
|
+
|
193
|
+
var fieldsets = form.getElementsByTagName('FIELDSET');
|
194
|
+
for (var i = 0; i < fieldsets.length; i++) {
|
195
|
+
var step = new Step(fieldsets[i]);
|
196
|
+
steps.push(step);
|
197
|
+
}
|
198
|
+
|
199
|
+
function showStep(index) {
|
200
|
+
// TODO - set the label
|
201
|
+
if (steps[index]) {
|
202
|
+
steps[index].show();
|
203
|
+
}
|
204
|
+
};
|
205
|
+
showStep(0);
|
206
|
+
|
207
|
+
this.next = function() {
|
208
|
+
if (steps[index]) {
|
209
|
+
if (steps[index].validate()) {
|
210
|
+
var event = document.createEvent('Events');
|
211
|
+
event.initEvent('wizard:next', true, true);
|
212
|
+
event.step = steps[index];
|
213
|
+
event.index = index;
|
214
|
+
event.wizard = this;
|
215
|
+
form.dispatchEvent(event);
|
216
|
+
showStep(++index);
|
217
|
+
}
|
218
|
+
else {
|
219
|
+
var event = document.createEvent('Events');
|
220
|
+
event.initEvent('wizard:complete', true, true);
|
221
|
+
event.step = steps[index];
|
222
|
+
event.index = index;
|
223
|
+
event.wizard = this;
|
224
|
+
form.dispatchEvent(event);
|
225
|
+
}
|
226
|
+
}
|
227
|
+
else {
|
228
|
+
var event = document.createEvent('Events');
|
229
|
+
event.initEvent('wizard:invalid', true, true);
|
230
|
+
event.step = steps[index];
|
231
|
+
event.index = index;
|
232
|
+
event.wizard = this;
|
233
|
+
form.dispatchEvent(event);
|
234
|
+
return false;
|
235
|
+
}
|
236
|
+
};
|
237
|
+
|
238
|
+
this.submit = function() {
|
239
|
+
this.next();
|
240
|
+
if (index == steps.length) {
|
241
|
+
var event = document.createEvent('Events');
|
242
|
+
event.initEvent('wizard:submit', true, true);
|
243
|
+
event.wizard = this;
|
244
|
+
event.index = index;
|
245
|
+
event.step = steps[index];
|
246
|
+
form.dispatchEvent(event);
|
247
|
+
return true;
|
248
|
+
}
|
249
|
+
return false;
|
250
|
+
};
|
251
|
+
};
|
252
|
+
|