draiodoir 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|