bootstrap-application-wizard-rails 13.3.3
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/lib/bootstrap-application-wizard-rails.rb +11 -0
- data/lib/bootstrap-application-wizard-rails/engine.rb +6 -0
- data/lib/bootstrap-application-wizard-rails/railtie.rb +6 -0
- data/lib/bootstrap-application-wizard-rails/version.rb +5 -0
- data/vendor/assets/javascripts/bootstrap-application-wizard-rails.js +1 -0
- data/vendor/assets/javascripts/bootstrap-wizard.js +1047 -0
- data/vendor/assets/stylesheets/bootstrap-application-wizard-rails.scss +3 -0
- data/vendor/assets/stylesheets/bootstrap-wizard.css +145 -0
- metadata +119 -0
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'bootstrap-application-wizard-rails/version'
|
2
|
+
|
3
|
+
module BootstrapApplicationWizard
|
4
|
+
module Rails
|
5
|
+
if ::Rails.version < '3.1'
|
6
|
+
require 'bootstrap-application-wizard-rails/railtie'
|
7
|
+
else
|
8
|
+
require 'bootstrap-application-wizard-rails/engine'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require bootstrap-wizard
|
@@ -0,0 +1,1047 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (C) 2013 Panopta, Andrew Moffat
|
3
|
+
*
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
9
|
+
* furnished to do so, subject to the following conditions:
|
10
|
+
*
|
11
|
+
* The above copyright notice and this permission notice shall be included in
|
12
|
+
* all copies or substantial portions of the Software.
|
13
|
+
*
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
* SOFTWARE.
|
21
|
+
*/
|
22
|
+
|
23
|
+
(function ($) {
|
24
|
+
$.fn.wizard = function(args) {
|
25
|
+
return new Wizard(this, args);
|
26
|
+
};
|
27
|
+
|
28
|
+
$.fn.wizard.logging = false;
|
29
|
+
|
30
|
+
|
31
|
+
WizardCard = function(wizard, card, index, prev, next) {
|
32
|
+
this.wizard = wizard;
|
33
|
+
this.index = index;
|
34
|
+
this.prev = prev;
|
35
|
+
this.next = next;
|
36
|
+
this.el = card;
|
37
|
+
this.title = card.find("h3").first().text();
|
38
|
+
this.name = card.data("cardname") || this.title;
|
39
|
+
|
40
|
+
this.nav = this._createNavElement(this.title, index);
|
41
|
+
|
42
|
+
this._disabled = false;
|
43
|
+
this._loaded = false;
|
44
|
+
this._events = {};
|
45
|
+
}
|
46
|
+
|
47
|
+
WizardCard.prototype = {
|
48
|
+
|
49
|
+
select: function() {
|
50
|
+
this.log("selecting");
|
51
|
+
if (!this.isSelected()) {
|
52
|
+
this.nav.addClass("active");
|
53
|
+
this.el.show();
|
54
|
+
|
55
|
+
if (!this._loaded) {
|
56
|
+
this.trigger("loaded");
|
57
|
+
this.reload();
|
58
|
+
}
|
59
|
+
|
60
|
+
this.trigger("selected");
|
61
|
+
}
|
62
|
+
|
63
|
+
|
64
|
+
/*
|
65
|
+
* this is ugly, but we're handling the changing of the wizard's
|
66
|
+
* buttons here, in the WizardCard select. so when a card is
|
67
|
+
* selected, we're figuring out if we're the first card or the
|
68
|
+
* last card and changing the wizard's buttons via the guts of
|
69
|
+
* the wizard
|
70
|
+
*
|
71
|
+
* ideally this logic should be encapsulated by some wizard methods
|
72
|
+
* that we can call from here, instead of messing with the guts
|
73
|
+
*/
|
74
|
+
var w = this.wizard;
|
75
|
+
if (this.index >= w._cards.length-1) {
|
76
|
+
this.log("on last card, changing next button to submit");
|
77
|
+
|
78
|
+
w.changeNextButton(w.args.buttons.submitText, "btn-success");
|
79
|
+
w._readyToSubmit = true;
|
80
|
+
w.trigger("readySubmit");
|
81
|
+
}
|
82
|
+
else {
|
83
|
+
w._readyToSubmit = false;
|
84
|
+
if (this.index == 0) {
|
85
|
+
w.backButton.toggleClass("disabled", true);
|
86
|
+
}
|
87
|
+
else {
|
88
|
+
w.backButton.toggleClass("disabled", false);
|
89
|
+
}
|
90
|
+
w.changeNextButton(w.args.buttons.nextText, "btn-primary");
|
91
|
+
}
|
92
|
+
|
93
|
+
return this;
|
94
|
+
},
|
95
|
+
|
96
|
+
// <li><a href="#" data-navindex="0">
|
97
|
+
// <i class="icon-chevron-right"></i>
|
98
|
+
// Name & FQDN
|
99
|
+
// </a></li>
|
100
|
+
_createNavElement: function(name, i) {
|
101
|
+
var li = $('<li class="wizard-nav-item"></li>');
|
102
|
+
var a = $('<a class="wizard-nav-link"></a>');
|
103
|
+
a.data("navindex", i);
|
104
|
+
li.append(a);
|
105
|
+
a.append('<i class="icon-chevron-right"></i>')
|
106
|
+
a.append(name);
|
107
|
+
return li;
|
108
|
+
},
|
109
|
+
|
110
|
+
markVisited: function() {
|
111
|
+
this.log("marking as visited");
|
112
|
+
this.nav.addClass("already-visited");
|
113
|
+
this.trigger("markVisited");
|
114
|
+
return this;
|
115
|
+
},
|
116
|
+
|
117
|
+
unmarkVisited: function() {
|
118
|
+
this.log("unmarking as visited");
|
119
|
+
this.nav.removeClass("already-visited");
|
120
|
+
this.trigger("unmarkVisited");
|
121
|
+
return this;
|
122
|
+
},
|
123
|
+
|
124
|
+
deselect: function() {
|
125
|
+
this.nav.removeClass("active");
|
126
|
+
this.el.hide();
|
127
|
+
this.trigger("deselect");
|
128
|
+
return this;
|
129
|
+
},
|
130
|
+
|
131
|
+
enable: function() {
|
132
|
+
this.log("enabling");
|
133
|
+
this.nav.addClass("active");
|
134
|
+
this._disabled = false;
|
135
|
+
this.trigger("enabled");
|
136
|
+
return this;
|
137
|
+
},
|
138
|
+
|
139
|
+
disable: function(hideCard) {
|
140
|
+
this.log("disabling");
|
141
|
+
this._disabled = true;
|
142
|
+
this.nav.removeClass("active already-visited");
|
143
|
+
if (hideCard) {this.el.hide();}
|
144
|
+
this.trigger("disabled");
|
145
|
+
return this;
|
146
|
+
},
|
147
|
+
|
148
|
+
isDisabled: function() {
|
149
|
+
return this._disabled;
|
150
|
+
},
|
151
|
+
|
152
|
+
alreadyVisited: function() {
|
153
|
+
return this.nav.hasClass("already-visited");
|
154
|
+
},
|
155
|
+
|
156
|
+
isSelected: function() {
|
157
|
+
return this.nav.hasClass("active");
|
158
|
+
},
|
159
|
+
|
160
|
+
reload: function() {
|
161
|
+
this._loaded = true;
|
162
|
+
this.trigger("reload");
|
163
|
+
return this;
|
164
|
+
},
|
165
|
+
|
166
|
+
on: function() {
|
167
|
+
return this.wizard.on.apply(this, arguments);
|
168
|
+
},
|
169
|
+
|
170
|
+
trigger: function() {
|
171
|
+
this.callListener("on"+arguments[0]);
|
172
|
+
return this.wizard.trigger.apply(this, arguments);
|
173
|
+
},
|
174
|
+
|
175
|
+
/*
|
176
|
+
* displays an alert box on the current card
|
177
|
+
*/
|
178
|
+
toggleAlert: function(msg, toggle) {
|
179
|
+
this.log("toggling alert to: " + toggle);
|
180
|
+
|
181
|
+
toggle = typeof(toggle) == "undefined" ? true : toggle;
|
182
|
+
|
183
|
+
if (toggle) {this.trigger("showAlert");}
|
184
|
+
else {this.trigger("hideAlert");}
|
185
|
+
|
186
|
+
var div;
|
187
|
+
var alert = this.el.children("h3").first().next("div.alert");
|
188
|
+
|
189
|
+
if (alert.length == 0) {
|
190
|
+
/*
|
191
|
+
* we're hiding anyways, so no need to create anything.
|
192
|
+
* we'll do that if we ever are actually showing the alert
|
193
|
+
*/
|
194
|
+
if (!toggle) {return this;}
|
195
|
+
|
196
|
+
this.log("couldn't find existing alert div, creating one");
|
197
|
+
div = $("<div />");
|
198
|
+
div.addClass("alert");
|
199
|
+
div.addClass("hide");
|
200
|
+
div.insertAfter(this.el.find("h3").first());
|
201
|
+
}
|
202
|
+
else {
|
203
|
+
this.log("found existing alert div");
|
204
|
+
div = alert.first();
|
205
|
+
}
|
206
|
+
|
207
|
+
if (toggle) {
|
208
|
+
if (msg != null) {
|
209
|
+
this.log("setting alert msg to", msg);
|
210
|
+
div.html(msg);
|
211
|
+
}
|
212
|
+
div.show();
|
213
|
+
}
|
214
|
+
else {
|
215
|
+
div.hide();
|
216
|
+
}
|
217
|
+
return this;
|
218
|
+
},
|
219
|
+
|
220
|
+
/*
|
221
|
+
* this looks for event handlers embedded into the html of the
|
222
|
+
* wizard card itself, in the form of a data- attribute
|
223
|
+
*/
|
224
|
+
callListener: function(name) {
|
225
|
+
// a bug(?) in jquery..can't access data-<name> if name is camelCase
|
226
|
+
name = name.toLowerCase();
|
227
|
+
|
228
|
+
this.log("looking for listener " + name);
|
229
|
+
var listener = window[this.el.data(name)];
|
230
|
+
if (listener) {
|
231
|
+
this.log("calling listener " + name);
|
232
|
+
var wizard = this.wizard;
|
233
|
+
|
234
|
+
try {
|
235
|
+
var vret = listener(this);
|
236
|
+
}
|
237
|
+
catch (e) {
|
238
|
+
this.log("exception calling listener " + name + ": ", e);
|
239
|
+
}
|
240
|
+
}
|
241
|
+
else {
|
242
|
+
this.log("didn't find listener " + name);
|
243
|
+
}
|
244
|
+
},
|
245
|
+
|
246
|
+
problem: function(toggle) {
|
247
|
+
this.nav.find("a").toggleClass("wizard-step-error", toggle);
|
248
|
+
},
|
249
|
+
|
250
|
+
validate: function() {
|
251
|
+
var failures = false;
|
252
|
+
var self = this;
|
253
|
+
|
254
|
+
/*
|
255
|
+
* run all the validators embedded on the inputs themselves
|
256
|
+
*/
|
257
|
+
this.el.find("[data-validate]").each(function(i, el) {
|
258
|
+
self.log("validating individiual inputs");
|
259
|
+
el = $(el);
|
260
|
+
|
261
|
+
var v = el.data("validate");
|
262
|
+
if (!v) {return;}
|
263
|
+
|
264
|
+
var ret = {
|
265
|
+
status: true,
|
266
|
+
title: "Error",
|
267
|
+
msg: ""
|
268
|
+
};
|
269
|
+
|
270
|
+
var vret = window[v](el);
|
271
|
+
$.extend(ret, vret);
|
272
|
+
|
273
|
+
if (!ret.status) {
|
274
|
+
failures = true;
|
275
|
+
el.parent(".control-group").toggleClass("error", true);
|
276
|
+
self.wizard.errorPopover(el, ret.msg);
|
277
|
+
}
|
278
|
+
else {
|
279
|
+
el.parent(".control-group").toggleClass("error", false);
|
280
|
+
try {
|
281
|
+
el.popover("destroy");
|
282
|
+
}
|
283
|
+
/*
|
284
|
+
* older versions of bootstrap don't have a destroy call
|
285
|
+
* for popovers
|
286
|
+
*/
|
287
|
+
catch (e) {
|
288
|
+
el.popover("hide");
|
289
|
+
}
|
290
|
+
}
|
291
|
+
});
|
292
|
+
this.log("after validating inputs, failures is", failures);
|
293
|
+
|
294
|
+
/*
|
295
|
+
* run the validator embedded in the card
|
296
|
+
*/
|
297
|
+
var cardValidator = window[this.el.data("validate")];
|
298
|
+
if (cardValidator) {
|
299
|
+
this.log("running html-embedded card validator");
|
300
|
+
var cardValidated = cardValidator(this);
|
301
|
+
if (typeof(cardValidated) == "undefined" || cardValidated == null) {
|
302
|
+
cardValidated = true;
|
303
|
+
}
|
304
|
+
if (!cardValidated) failures = true;
|
305
|
+
this.log("after running html-embedded card validator, failures\
|
306
|
+
is", failures);
|
307
|
+
}
|
308
|
+
|
309
|
+
/*
|
310
|
+
* run the validate listener
|
311
|
+
*/
|
312
|
+
this.log("running listener validator");
|
313
|
+
var listenerValidated = this.trigger("validate");
|
314
|
+
if (typeof(listenerValidated) == "undefined" || listenerValidated == null) {
|
315
|
+
listenerValidated = true;
|
316
|
+
}
|
317
|
+
if (!listenerValidated) failures = true;
|
318
|
+
this.log("after running listener validator, failures is", failures);
|
319
|
+
|
320
|
+
var validated = !failures;
|
321
|
+
if (validated) {
|
322
|
+
this.log("validated, calling listeners");
|
323
|
+
this.trigger("validated");
|
324
|
+
}
|
325
|
+
else {
|
326
|
+
this.log("invalid");
|
327
|
+
this.trigger("invalid");
|
328
|
+
}
|
329
|
+
return validated;
|
330
|
+
},
|
331
|
+
|
332
|
+
log: function() {
|
333
|
+
if (!window.console || !$.fn.wizard.logging) {return;}
|
334
|
+
var prepend = "card '"+this.name+"': ";
|
335
|
+
var args = [prepend];
|
336
|
+
args.push.apply(args, arguments);
|
337
|
+
|
338
|
+
console.log.apply(console, args);
|
339
|
+
},
|
340
|
+
|
341
|
+
isActive: function() {
|
342
|
+
return this.nav.hasClass("active");
|
343
|
+
},
|
344
|
+
};
|
345
|
+
|
346
|
+
|
347
|
+
Wizard = function(markup, args) {
|
348
|
+
var wizard_template = [
|
349
|
+
'<div class="modal hide wizard-modal" role="dialog">',
|
350
|
+
'<div class="wizard-modal-header modal-header">',
|
351
|
+
'<button class="wizard-close close" type="button">x</button>',
|
352
|
+
'<h3 class="wizard-title"></h3>',
|
353
|
+
'<span class="wizard-subtitle"></span>',
|
354
|
+
'</div>',
|
355
|
+
'<div class="pull-left wizard-steps">',
|
356
|
+
'<div class="wizard-nav-container">',
|
357
|
+
'<ul class="nav nav-list" style="padding-bottom:30px;">',
|
358
|
+
'</ul>',
|
359
|
+
'</div>',
|
360
|
+
|
361
|
+
'<div class="wizard-progress-container">',,
|
362
|
+
'<div class="progress progress-striped">',
|
363
|
+
'<div class="bar"></div>',
|
364
|
+
'</div>',
|
365
|
+
'</div>',
|
366
|
+
|
367
|
+
'</div>',
|
368
|
+
|
369
|
+
'<form>',
|
370
|
+
'<div class="wizard-cards">',
|
371
|
+
'<div class="wizard-card-container">',
|
372
|
+
'</div>',
|
373
|
+
'<div class="wizard-modal-footer">',
|
374
|
+
'<div class="wizard-buttons-container">',
|
375
|
+
'<button class="btn wizard-back" type="button">Back</button>',
|
376
|
+
'<button class="btn btn-primary wizard-next" type="button">Next</button>',
|
377
|
+
'</div>',
|
378
|
+
'</div>',
|
379
|
+
'</div>',
|
380
|
+
'</form>',
|
381
|
+
'</div>'
|
382
|
+
];
|
383
|
+
|
384
|
+
this.args = {
|
385
|
+
submitUrl: "",
|
386
|
+
width: 750,
|
387
|
+
progressBarCurrent: false,
|
388
|
+
increaseHeight: 0,
|
389
|
+
buttons: {
|
390
|
+
nextText: "Next",
|
391
|
+
backText: "Back",
|
392
|
+
submitText: "Submit",
|
393
|
+
submittingText: "Submitting...",
|
394
|
+
}
|
395
|
+
};
|
396
|
+
$.extend(this.args, args || {});
|
397
|
+
|
398
|
+
this.markup = $(markup);
|
399
|
+
this.submitCards = this.markup.find(".wizard-error,.wizard-failure,\
|
400
|
+
.wizard-success,.wizard-loading");
|
401
|
+
this.el = $(wizard_template.join("\n"));
|
402
|
+
this.el.find(".wizard-card-container")
|
403
|
+
.append(this.markup.find(".wizard-card"))
|
404
|
+
.append(this.submitCards);
|
405
|
+
$("body").append(this.el);
|
406
|
+
|
407
|
+
this.closeButton = this.el.find("button.wizard-close");
|
408
|
+
this.footer = this.el.find(".wizard-modal-footer");
|
409
|
+
this.backButton = this.footer.find(".wizard-back");
|
410
|
+
this.nextButton = this.footer.find(".wizard-next");
|
411
|
+
this.progress = this.el.find(".progress");
|
412
|
+
this._cards = [];
|
413
|
+
this.cards = {};
|
414
|
+
this._readyToSubmit = false;
|
415
|
+
this.percentComplete = 0;
|
416
|
+
this._submitting = false;
|
417
|
+
this._events = {};
|
418
|
+
this._firstShow = true;
|
419
|
+
|
420
|
+
|
421
|
+
// construction
|
422
|
+
|
423
|
+
|
424
|
+
this._createCards();
|
425
|
+
|
426
|
+
this.nextButton.click(this, this._handleNextClick);
|
427
|
+
this.backButton.click(this, this._handleBackClick);
|
428
|
+
|
429
|
+
this.backButton.text(this.args.buttons.backText);
|
430
|
+
this.nextButton.text(this.args.buttons.nextText);
|
431
|
+
|
432
|
+
|
433
|
+
|
434
|
+
/*
|
435
|
+
* adjust the height of the modal, and everything associated with
|
436
|
+
* adjusting the height
|
437
|
+
*/
|
438
|
+
var baseHeight = 360;
|
439
|
+
var navHeight = baseHeight + this.args.increaseHeight;
|
440
|
+
|
441
|
+
this.el.find(".wizard-nav-container").css("height", navHeight);
|
442
|
+
this.el.find(".wizard-steps").css("height", (navHeight+65)+"px");
|
443
|
+
this.el.find(".wizard-card").css("height", (navHeight-60)+"px");
|
444
|
+
this.submitCards.css("height", (navHeight-60)+"px");
|
445
|
+
|
446
|
+
this.el.css("margin-top", -(this.el.height() / 2));
|
447
|
+
|
448
|
+
|
449
|
+
/*
|
450
|
+
* adjust the width of the modal
|
451
|
+
*/
|
452
|
+
this.el.css("width", this.args.width);
|
453
|
+
this.el.css("margin-left", -(this.args.width / 2));
|
454
|
+
|
455
|
+
|
456
|
+
|
457
|
+
/*
|
458
|
+
* set up slimScroll for our nav, if slimScroll is installed
|
459
|
+
*/
|
460
|
+
if ($.fn.slimScroll && false) {
|
461
|
+
var slimScrollArgs = {
|
462
|
+
position: "left",
|
463
|
+
height: "360px",
|
464
|
+
size: "8px",
|
465
|
+
distance: "5px",
|
466
|
+
railVisible: true,
|
467
|
+
disableFadeOut: true,
|
468
|
+
};
|
469
|
+
$.extend(slimScrollArgs, this.args.slimScroll || {});
|
470
|
+
this.el.find(".wizard-nav-container").slimScroll(slimScrollArgs);
|
471
|
+
}
|
472
|
+
|
473
|
+
/*
|
474
|
+
* if the close X is clicked, reset the wizard
|
475
|
+
*/
|
476
|
+
var self = this;
|
477
|
+
this.closeButton.click(function() {
|
478
|
+
self.reset();
|
479
|
+
self.close();
|
480
|
+
})
|
481
|
+
|
482
|
+
this.el.find(".wizard-steps").on(
|
483
|
+
"click", "li.already-visited a.wizard-nav-link", this,
|
484
|
+
function(event) {
|
485
|
+
var index = parseInt($(event.target).data("navindex"));
|
486
|
+
event.data.setCard(index);
|
487
|
+
});
|
488
|
+
|
489
|
+
var title = this.markup.children("h1").first();
|
490
|
+
if (title.length) {this.setTitle(title.text());}
|
491
|
+
|
492
|
+
this.on("submit", this._defaultSubmit);
|
493
|
+
}
|
494
|
+
|
495
|
+
Wizard.prototype = {
|
496
|
+
|
497
|
+
errorPopover: function(el, msg) {
|
498
|
+
this.log("launching popover on", el);
|
499
|
+
var popover = el.popover({
|
500
|
+
content: msg,
|
501
|
+
trigger: "manual"
|
502
|
+
}).popover("show").next(".popover");
|
503
|
+
|
504
|
+
popover.addClass("error-popover");
|
505
|
+
return popover;
|
506
|
+
},
|
507
|
+
|
508
|
+
destroyPopover: function(pop) {
|
509
|
+
pop = $(pop);
|
510
|
+
pop.parent(".control-group").toggleClass("error", false);
|
511
|
+
|
512
|
+
/*
|
513
|
+
* this is the element that the popover was created for
|
514
|
+
*/
|
515
|
+
var el = pop.prev();
|
516
|
+
|
517
|
+
try {
|
518
|
+
el.popover("destroy");
|
519
|
+
}
|
520
|
+
/*
|
521
|
+
* older versions of bootstrap don't have a destroy call
|
522
|
+
* for popovers
|
523
|
+
*/
|
524
|
+
catch (e) {
|
525
|
+
el.popover("hide");
|
526
|
+
}
|
527
|
+
},
|
528
|
+
|
529
|
+
hidePopovers: function(el, msg) {
|
530
|
+
this.log("hiding all popovers");
|
531
|
+
var self = this;
|
532
|
+
this.el.find(".error-popover").each(function (i, popover) {
|
533
|
+
self.destroyPopover(popover);
|
534
|
+
});
|
535
|
+
},
|
536
|
+
|
537
|
+
eachCard: function(fn) {
|
538
|
+
$.each(this._cards, fn);
|
539
|
+
return this;
|
540
|
+
},
|
541
|
+
|
542
|
+
getActiveCard: function() {
|
543
|
+
this.log("getting active card");
|
544
|
+
var currentCard = null;
|
545
|
+
|
546
|
+
$.each(this._cards, function(i, card) {
|
547
|
+
if (card.isActive()) {
|
548
|
+
currentCard = card;
|
549
|
+
return false;
|
550
|
+
}
|
551
|
+
});
|
552
|
+
if (currentCard) {this.log("found active card", currentCard);}
|
553
|
+
else {this.log("couldn't find an active card");}
|
554
|
+
return currentCard;
|
555
|
+
},
|
556
|
+
|
557
|
+
setTitle: function(title) {
|
558
|
+
this.log("setting title to", title);
|
559
|
+
this.el.find(".wizard-title").first().text(title);
|
560
|
+
return this;
|
561
|
+
},
|
562
|
+
|
563
|
+
setSubtitle: function(title) {
|
564
|
+
this.log("setting subtitle to", title);
|
565
|
+
this.el.find(".wizard-subtitle").first().text(title);
|
566
|
+
return this;
|
567
|
+
},
|
568
|
+
|
569
|
+
changeNextButton: function(text, cls) {
|
570
|
+
this.log("changing next button, text: " + text, "class: " + cls);
|
571
|
+
if (typeof(cls) != "undefined") {
|
572
|
+
this.nextButton.removeClass("btn-success btn-primary");
|
573
|
+
}
|
574
|
+
|
575
|
+
if (cls) {
|
576
|
+
this.nextButton.addClass(cls);
|
577
|
+
}
|
578
|
+
this.nextButton.text(text);
|
579
|
+
return this;
|
580
|
+
},
|
581
|
+
|
582
|
+
hide: function() {
|
583
|
+
this.log("hiding");
|
584
|
+
this.el.modal("hide");
|
585
|
+
return this;
|
586
|
+
},
|
587
|
+
|
588
|
+
close: function() {
|
589
|
+
this.log("closing");
|
590
|
+
this.el.modal("hide");
|
591
|
+
return this;
|
592
|
+
},
|
593
|
+
|
594
|
+
|
595
|
+
show: function() {
|
596
|
+
this.log("showing");
|
597
|
+
if (this._firstShow) {
|
598
|
+
this.setCard(0);
|
599
|
+
this._firstShow = false;
|
600
|
+
}
|
601
|
+
this.el.modal();
|
602
|
+
return this;
|
603
|
+
},
|
604
|
+
|
605
|
+
on: function(name, fn) {
|
606
|
+
this.log("adding listener to event " + name);
|
607
|
+
this._events[name] = fn;
|
608
|
+
return this;
|
609
|
+
},
|
610
|
+
|
611
|
+
trigger: function() {
|
612
|
+
var name = arguments[0];
|
613
|
+
var args = Array.prototype.slice.call(arguments);
|
614
|
+
args.shift();
|
615
|
+
args.unshift(this);
|
616
|
+
|
617
|
+
this.log("firing event " + name);
|
618
|
+
var handler = this._events[name];
|
619
|
+
var ret = null;
|
620
|
+
|
621
|
+
if (typeof(handler) == "function") {
|
622
|
+
this.log("found event handler, calling " + name);
|
623
|
+
try {
|
624
|
+
ret = handler.apply(this, args);
|
625
|
+
}
|
626
|
+
catch (e) {
|
627
|
+
this.log("event handler " + name + " had an exception");
|
628
|
+
}
|
629
|
+
}
|
630
|
+
else {
|
631
|
+
this.log("couldn't find an event handler for " + name);
|
632
|
+
}
|
633
|
+
return ret;
|
634
|
+
},
|
635
|
+
|
636
|
+
|
637
|
+
reset: function() {
|
638
|
+
this.log("resetting");
|
639
|
+
|
640
|
+
this.updateProgressBar(0);
|
641
|
+
this.hideSubmitCards();
|
642
|
+
|
643
|
+
this.setCard(0);
|
644
|
+
this.lockCards();
|
645
|
+
|
646
|
+
this.enableNextButton();
|
647
|
+
this.showButtons();
|
648
|
+
|
649
|
+
this.hidePopovers();
|
650
|
+
|
651
|
+
this.trigger("reset");
|
652
|
+
return this;
|
653
|
+
},
|
654
|
+
|
655
|
+
log: function() {
|
656
|
+
if (!window.console || !$.fn.wizard.logging) {return;}
|
657
|
+
var prepend = "wizard "+this.el.id+": ";
|
658
|
+
var args = [prepend];
|
659
|
+
args.push.apply(args, arguments);
|
660
|
+
console.log.apply(console, args);
|
661
|
+
},
|
662
|
+
|
663
|
+
|
664
|
+
/*
|
665
|
+
* this handles switching to the next card or previous card, taking
|
666
|
+
* care to skip over disabled cards
|
667
|
+
*/
|
668
|
+
_abstractIncrementStep: function(direction, getNext) {
|
669
|
+
var current = this.getActiveCard();
|
670
|
+
var next;
|
671
|
+
|
672
|
+
if (current) {
|
673
|
+
/*
|
674
|
+
* loop until we find a card that isn't disabled
|
675
|
+
*/
|
676
|
+
this.log("searching for valid next card");
|
677
|
+
while (true) {
|
678
|
+
next = getNext(current);
|
679
|
+
if (next) {
|
680
|
+
this.log("looking at card", next.index);
|
681
|
+
if (next.isDisabled()) {
|
682
|
+
this.log("card " + next.index + " is disabled/locked, continuing");
|
683
|
+
current = next;
|
684
|
+
continue;
|
685
|
+
}
|
686
|
+
else {
|
687
|
+
return this.setCard(current.index+direction);
|
688
|
+
}
|
689
|
+
}
|
690
|
+
else {
|
691
|
+
this.log("next card is not defined, breaking");
|
692
|
+
break;
|
693
|
+
}
|
694
|
+
}
|
695
|
+
}
|
696
|
+
else {
|
697
|
+
this.log("current card is undefined");
|
698
|
+
}
|
699
|
+
},
|
700
|
+
|
701
|
+
|
702
|
+
incrementCard: function() {
|
703
|
+
this.log("incrementing card");
|
704
|
+
var card = this._abstractIncrementStep(1, function(current){return current.next;});
|
705
|
+
this.trigger("incrementCard");
|
706
|
+
return card;
|
707
|
+
},
|
708
|
+
|
709
|
+
decrementCard: function() {
|
710
|
+
this.log("decrementing card");
|
711
|
+
var card = this._abstractIncrementStep(-1, function(current){return current.prev;});
|
712
|
+
this.trigger("decrementCard");
|
713
|
+
return card;
|
714
|
+
},
|
715
|
+
|
716
|
+
setCard: function(i) {
|
717
|
+
this.log("setting card to " + i);
|
718
|
+
this.hideSubmitCards();
|
719
|
+
var currentCard = this.getActiveCard();
|
720
|
+
|
721
|
+
if (this._submitting) {
|
722
|
+
this.log("we're submitting the wizard already, can't change cards");
|
723
|
+
return currentCard;
|
724
|
+
}
|
725
|
+
|
726
|
+
var newCard = this._cards[i];
|
727
|
+
if (newCard) {
|
728
|
+
if (newCard.isDisabled()) {
|
729
|
+
this.log("new card is currently disabled, returning");
|
730
|
+
return currentCard;
|
731
|
+
}
|
732
|
+
|
733
|
+
if (currentCard) {
|
734
|
+
|
735
|
+
/*
|
736
|
+
* here, we're only validating if we're going forward,
|
737
|
+
* not if we're going backwards in a step
|
738
|
+
*/
|
739
|
+
if (i > currentCard.index) {
|
740
|
+
var cardToValidate = currentCard;
|
741
|
+
var ok = false;
|
742
|
+
|
743
|
+
/*
|
744
|
+
* we need to loop over every card between our current
|
745
|
+
* card and the card that we clicked, and re-validate
|
746
|
+
* them. if there's an error, we need to select the
|
747
|
+
* first card to have an error
|
748
|
+
*/
|
749
|
+
while (cardToValidate.index != newCard.index) {
|
750
|
+
/*
|
751
|
+
* unless we're validating the card that we're
|
752
|
+
* leaving, we need to select the card, so that
|
753
|
+
* any validators that trigger errorPopovers can
|
754
|
+
* display correctly
|
755
|
+
*/
|
756
|
+
if (cardToValidate.index != currentCard.index) {
|
757
|
+
cardToValidate.prev.deselect();
|
758
|
+
cardToValidate.prev.markVisited();
|
759
|
+
cardToValidate.select();
|
760
|
+
}
|
761
|
+
ok = cardToValidate.validate();
|
762
|
+
if (!ok) {
|
763
|
+
return cardToValidate;
|
764
|
+
}
|
765
|
+
cardToValidate = cardToValidate.next;
|
766
|
+
}
|
767
|
+
|
768
|
+
cardToValidate.prev.deselect();
|
769
|
+
cardToValidate.prev.markVisited();
|
770
|
+
}
|
771
|
+
|
772
|
+
currentCard.deselect();
|
773
|
+
currentCard.markVisited();
|
774
|
+
}
|
775
|
+
|
776
|
+
newCard.select();
|
777
|
+
|
778
|
+
if (this.args.progressBarCurrent) {
|
779
|
+
var last_percent = this.percentComplete;
|
780
|
+
this.percentComplete = i * 100.0 / this._cards.length;
|
781
|
+
this.updateProgressBar(this.percentComplete);
|
782
|
+
}
|
783
|
+
else {
|
784
|
+
var last_percent = this.percentComplete;
|
785
|
+
this.percentComplete = i * 100.0 / this._cards.length;
|
786
|
+
this.percentComplete = Math.max(last_percent, this.percentComplete);
|
787
|
+
this.updateProgressBar(this.percentComplete);
|
788
|
+
}
|
789
|
+
|
790
|
+
return newCard;
|
791
|
+
}
|
792
|
+
else {
|
793
|
+
this.log("couldn't find card " + i);
|
794
|
+
}
|
795
|
+
},
|
796
|
+
|
797
|
+
updateProgressBar: function(percent) {
|
798
|
+
this.log("updating progress to " + percent + "%");
|
799
|
+
this.progress.find(".bar").css({width: percent + "%"});
|
800
|
+
this.percentComplete = percent;
|
801
|
+
|
802
|
+
this.trigger("progressBar", percent);
|
803
|
+
|
804
|
+
if (percent == 100) {
|
805
|
+
this.log("progress is 100, animating progress bar");
|
806
|
+
this.progress.addClass("active");
|
807
|
+
}
|
808
|
+
else if (percent == 0) {
|
809
|
+
this.log("progress is 0, disabling animation");
|
810
|
+
this.progress.removeClass("active");
|
811
|
+
}
|
812
|
+
},
|
813
|
+
|
814
|
+
getNextCard: function() {
|
815
|
+
var currentCard = this.getActiveCard();
|
816
|
+
if (currentCard) return currentCard.next;
|
817
|
+
},
|
818
|
+
|
819
|
+
lockCards: function() {
|
820
|
+
this.log("locking nav cards");
|
821
|
+
this.eachCard(function(i,card){card.unmarkVisited();});
|
822
|
+
return this;
|
823
|
+
},
|
824
|
+
|
825
|
+
disableCards: function() {
|
826
|
+
this.log("disabling all nav cards");
|
827
|
+
this.eachCard(function(i,card){card.disable();});
|
828
|
+
return this;
|
829
|
+
},
|
830
|
+
|
831
|
+
enableCards: function() {
|
832
|
+
this.log("enabling all nav cards");
|
833
|
+
this.eachCard(function(i,card){card.enable();});
|
834
|
+
return this;
|
835
|
+
},
|
836
|
+
|
837
|
+
hideCards: function() {
|
838
|
+
this.log("hiding cards");
|
839
|
+
this.eachCard(function(i,card){card.deselect();});
|
840
|
+
this.hideSubmitCards();
|
841
|
+
return this;
|
842
|
+
},
|
843
|
+
|
844
|
+
hideButtons: function() {
|
845
|
+
this.log("hiding buttons");
|
846
|
+
this.nextButton.hide();
|
847
|
+
this.backButton.hide();
|
848
|
+
return this;
|
849
|
+
},
|
850
|
+
|
851
|
+
showButtons: function() {
|
852
|
+
this.log("showing buttons");
|
853
|
+
this.nextButton.show();
|
854
|
+
this.backButton.show();
|
855
|
+
return this;
|
856
|
+
},
|
857
|
+
|
858
|
+
getCard: function(el) {
|
859
|
+
var cardDOMEl = $(el).parents(".wizard-card").first()[0];
|
860
|
+
if (cardDOMEl) {
|
861
|
+
var foundCard = null;
|
862
|
+
this.eachCard(function(i, card) {
|
863
|
+
if (cardDOMEl == card.el[0]) {
|
864
|
+
foundCard = card;
|
865
|
+
return false;
|
866
|
+
}
|
867
|
+
return true;
|
868
|
+
});
|
869
|
+
return foundCard;
|
870
|
+
}
|
871
|
+
else {
|
872
|
+
return null;
|
873
|
+
}
|
874
|
+
},
|
875
|
+
|
876
|
+
_createCards: function() {
|
877
|
+
var prev = null;
|
878
|
+
var next = null;
|
879
|
+
var current_i = 0;
|
880
|
+
var currentCard = null;
|
881
|
+
var wizard = this;
|
882
|
+
var self = this;
|
883
|
+
|
884
|
+
var cards = this.el.find(".wizard-cards .wizard-card");
|
885
|
+
$.each(cards, function(i, card) {
|
886
|
+
card = $(card);
|
887
|
+
|
888
|
+
prev = currentCard;
|
889
|
+
currentCard = new WizardCard(wizard, card, i, prev, next);
|
890
|
+
self._cards.push(currentCard);
|
891
|
+
if (currentCard.name) {
|
892
|
+
self.cards[currentCard.name] = currentCard;
|
893
|
+
}
|
894
|
+
if (prev) {prev.next = currentCard;}
|
895
|
+
|
896
|
+
self.el.find(".wizard-steps .nav-list").append(currentCard.nav);
|
897
|
+
});
|
898
|
+
},
|
899
|
+
|
900
|
+
showSubmitCard: function(name) {
|
901
|
+
this.log("showing "+name+" submit card");
|
902
|
+
|
903
|
+
var card = this.el.find(".wizard-"+name);
|
904
|
+
if (card.length) {
|
905
|
+
this.hideCards();
|
906
|
+
this.el.find(".wizard-"+name).show();
|
907
|
+
}
|
908
|
+
else {
|
909
|
+
this.log("couldn't find submit card "+name);
|
910
|
+
}
|
911
|
+
},
|
912
|
+
|
913
|
+
hideSubmitCard: function(name) {
|
914
|
+
this.log("hiding "+name+" submit card");
|
915
|
+
this.el.find(".wizard-"+name).hide();
|
916
|
+
},
|
917
|
+
|
918
|
+
hideSubmitCards: function() {
|
919
|
+
var wizard = this;
|
920
|
+
$.each(["success", "error", "failure", "loading"], function(i, name) {
|
921
|
+
wizard.hideSubmitCard(name);
|
922
|
+
});
|
923
|
+
},
|
924
|
+
|
925
|
+
enableNextButton: function() {
|
926
|
+
this.log("enabling next button");
|
927
|
+
this.nextButton.removeAttr("disabled");
|
928
|
+
return this;
|
929
|
+
},
|
930
|
+
|
931
|
+
disableNextButton: function() {
|
932
|
+
this.log("disabling next button");
|
933
|
+
this.nextButton.attr("disabled", "disabled");
|
934
|
+
return this;
|
935
|
+
},
|
936
|
+
|
937
|
+
serializeArray: function() {
|
938
|
+
var form = this.el.children("form").first();
|
939
|
+
return form.serializeArray();
|
940
|
+
},
|
941
|
+
|
942
|
+
serialize: function() {
|
943
|
+
var form = this.el.children("form").first();
|
944
|
+
return form.serialize();
|
945
|
+
},
|
946
|
+
|
947
|
+
|
948
|
+
/*
|
949
|
+
* the next 3 functions are to be called by the custom submit event
|
950
|
+
* handler. the idea is that after you make an ajax call to submit
|
951
|
+
* your wizard data (or whatever it is you want to do at the end of
|
952
|
+
* the wizard), you call one of these 3 handlers to display a specific
|
953
|
+
* card for either success, failure, or error
|
954
|
+
*/
|
955
|
+
submitSuccess: function() {
|
956
|
+
this.log("submit success");
|
957
|
+
this._submitting = false;
|
958
|
+
this.showSubmitCard("success");
|
959
|
+
this.trigger("submitSuccess");
|
960
|
+
},
|
961
|
+
|
962
|
+
submitFailure: function() {
|
963
|
+
this.log("submit failure");
|
964
|
+
this._submitting = false;
|
965
|
+
this.showSubmitCard("failure");
|
966
|
+
this.trigger("submitFailure");
|
967
|
+
},
|
968
|
+
|
969
|
+
submitError: function() {
|
970
|
+
this.log("submit error");
|
971
|
+
this._submitting = false;
|
972
|
+
this.showSubmitCard("error");
|
973
|
+
this.trigger("submitError");
|
974
|
+
},
|
975
|
+
|
976
|
+
|
977
|
+
_submit: function() {
|
978
|
+
this.log("submitting wizard");
|
979
|
+
this._submitting = true;
|
980
|
+
|
981
|
+
this.lockCards();
|
982
|
+
this.backButton.hide();
|
983
|
+
|
984
|
+
this.showSubmitCard("loading");
|
985
|
+
this.updateProgressBar(100);
|
986
|
+
|
987
|
+
this.changeNextButton(this.args.buttons.submittingText, false);
|
988
|
+
this.disableNextButton();
|
989
|
+
|
990
|
+
var ret = this.trigger("submit");
|
991
|
+
this.trigger("loading");
|
992
|
+
},
|
993
|
+
|
994
|
+
_onNextClick: function() {
|
995
|
+
this.log("handling 'next' button click");
|
996
|
+
var currentCard = this.getActiveCard();
|
997
|
+
if (this._readyToSubmit && currentCard.validate()) {
|
998
|
+
this._submit();
|
999
|
+
}
|
1000
|
+
else {
|
1001
|
+
currentCard = this.incrementCard();
|
1002
|
+
}
|
1003
|
+
},
|
1004
|
+
|
1005
|
+
_onBackClick: function() {
|
1006
|
+
this.log("handling 'back' button click");
|
1007
|
+
var currentCard = this.decrementCard();
|
1008
|
+
},
|
1009
|
+
|
1010
|
+
|
1011
|
+
_handleNextClick: function(event) {
|
1012
|
+
var wizard = event.data;
|
1013
|
+
wizard._onNextClick.call(wizard);
|
1014
|
+
},
|
1015
|
+
|
1016
|
+
_handleBackClick: function(event) {
|
1017
|
+
var wizard = event.data;
|
1018
|
+
wizard._onBackClick.call(wizard);
|
1019
|
+
},
|
1020
|
+
|
1021
|
+
|
1022
|
+
/*
|
1023
|
+
* this function is attached by default to the wizard's "submit" event.
|
1024
|
+
* if you choose to implement your own custom submit logic, you should
|
1025
|
+
* copy how this function works
|
1026
|
+
*/
|
1027
|
+
_defaultSubmit: function(wizard) {
|
1028
|
+
$.ajax({
|
1029
|
+
type: "POST",
|
1030
|
+
url: wizard.args.submitUrl,
|
1031
|
+
data: wizard.serialize(),
|
1032
|
+
dataType: "json",
|
1033
|
+
success: function(resp) {
|
1034
|
+
wizard.submitSuccess();
|
1035
|
+
wizard.hideButtons();
|
1036
|
+
wizard.updateProgressBar(0);
|
1037
|
+
},
|
1038
|
+
error: function() {
|
1039
|
+
wizard.submitFailure();
|
1040
|
+
wizard.hideButtons();
|
1041
|
+
},
|
1042
|
+
});
|
1043
|
+
}
|
1044
|
+
|
1045
|
+
};
|
1046
|
+
|
1047
|
+
}(window.jQuery));
|
@@ -0,0 +1,145 @@
|
|
1
|
+
.wizard {
|
2
|
+
display:none;
|
3
|
+
}
|
4
|
+
.wizard-modal form {
|
5
|
+
margin:0;
|
6
|
+
padding:0;
|
7
|
+
}
|
8
|
+
.wizard-modal.modal {
|
9
|
+
width:750px;
|
10
|
+
margin-left:-375px;
|
11
|
+
top:50%;
|
12
|
+
}
|
13
|
+
.wizard-modal-footer {
|
14
|
+
padding: 0px;
|
15
|
+
text-align:right;
|
16
|
+
}
|
17
|
+
.wizard-modal-header.modal-header h3 {
|
18
|
+
line-height:35px;
|
19
|
+
display:inline
|
20
|
+
}
|
21
|
+
.wizard-modal-header.modal-header {
|
22
|
+
border-bottom: 0;
|
23
|
+
}
|
24
|
+
|
25
|
+
.wizard-subtitle {
|
26
|
+
font-weight:bold;
|
27
|
+
color: #AFAFAF;
|
28
|
+
padding-left:20px;
|
29
|
+
}
|
30
|
+
|
31
|
+
.wizard-error,
|
32
|
+
.wizard-failure,
|
33
|
+
.wizard-success,
|
34
|
+
.wizard-loading,
|
35
|
+
.wizard-card {
|
36
|
+
position:relative;
|
37
|
+
padding:35px;
|
38
|
+
padding-top:20px;
|
39
|
+
overflow-y: auto;
|
40
|
+
height:300px;
|
41
|
+
display:none;
|
42
|
+
border-top: 1px solid #EEE;
|
43
|
+
margin-right: 5px;
|
44
|
+
}
|
45
|
+
|
46
|
+
.wizard-nav-link .icon-chevron-right {
|
47
|
+
float: right;
|
48
|
+
margin-top: 12px;
|
49
|
+
margin-right: -6px;
|
50
|
+
opacity: .25;
|
51
|
+
}
|
52
|
+
|
53
|
+
li.wizard-nav-item.active .icon-chevron-right {
|
54
|
+
opacity: 1;
|
55
|
+
}
|
56
|
+
|
57
|
+
li.wizard-nav-item {
|
58
|
+
line-height:40px;
|
59
|
+
}
|
60
|
+
|
61
|
+
.wizard-modal.modal .nav-list > li > a {
|
62
|
+
background-color:#f5f5f5;
|
63
|
+
padding: 3px 15px 3px 20px;
|
64
|
+
cursor: default;
|
65
|
+
color:#B4B4B4;
|
66
|
+
}
|
67
|
+
|
68
|
+
.wizard-modal.modal .nav-list li.active > a {
|
69
|
+
background-color:#08C;
|
70
|
+
}
|
71
|
+
|
72
|
+
.wizard-modal.modal .nav-list > li.already-visited > a.wizard-nav-link {
|
73
|
+
color: #08C;
|
74
|
+
cursor: pointer;
|
75
|
+
}
|
76
|
+
|
77
|
+
.wizard-modal.modal .nav-list > li.active > a.wizard-nav-link {
|
78
|
+
color:white;
|
79
|
+
}
|
80
|
+
|
81
|
+
.already-visited > a.wizard-nav-link:hover {
|
82
|
+
background-color: #E4E4E4;
|
83
|
+
}
|
84
|
+
|
85
|
+
.wizard-card > h3 {
|
86
|
+
margin-top: 0;
|
87
|
+
margin-bottom: 20px;
|
88
|
+
font-size: 21px;
|
89
|
+
line-height: 40px;
|
90
|
+
font-weight: normal;
|
91
|
+
}
|
92
|
+
|
93
|
+
.wizard-progress {
|
94
|
+
padding:15px;
|
95
|
+
bottom:0;
|
96
|
+
}
|
97
|
+
.wizard-progress-container {
|
98
|
+
padding:20px;
|
99
|
+
}
|
100
|
+
|
101
|
+
.wizard-steps {
|
102
|
+
width:28%;
|
103
|
+
height:425px;
|
104
|
+
background-color:#f5f5f5;
|
105
|
+
}
|
106
|
+
|
107
|
+
.wizard-nav-container {
|
108
|
+
height:360px;
|
109
|
+
}
|
110
|
+
|
111
|
+
.nav > li > a.wizard-step-error {
|
112
|
+
background-color:#F2DEDE;
|
113
|
+
color:#B94A48;
|
114
|
+
font-weight:bold;
|
115
|
+
}
|
116
|
+
|
117
|
+
.wizard-step-error .icon-chevron-right {
|
118
|
+
opacity: 0;
|
119
|
+
}
|
120
|
+
|
121
|
+
.wizard-input-section {
|
122
|
+
margin-bottom:20px;
|
123
|
+
}
|
124
|
+
|
125
|
+
.wizard-buttons-container {
|
126
|
+
padding:20px;
|
127
|
+
}
|
128
|
+
|
129
|
+
.wizard-modal .popover.error-popover {
|
130
|
+
background-color:#F2DEDE;
|
131
|
+
color:#B94A48;
|
132
|
+
border-color:#953B39;
|
133
|
+
}
|
134
|
+
|
135
|
+
.wizard-modal .popover.error-popover .arrow::after {
|
136
|
+
border-right-color:#F2DEDE;
|
137
|
+
}
|
138
|
+
|
139
|
+
.wizard-modal .popover.error-popover .popover-title {
|
140
|
+
display:none;
|
141
|
+
}
|
142
|
+
|
143
|
+
.wizard-modal .popover.error-popover .arrow {
|
144
|
+
border-right-color:#953B39;
|
145
|
+
}
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bootstrap-application-wizard-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 13.3.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Thomas A. de Ruiter
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-20 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: railties
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: coffee-rails
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 3.2.1
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 3.2.1
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: bundler
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rails
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '3.0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '3.0'
|
78
|
+
description: The Bootstrap Application Wizard is a Bootstrap addon that allows multi-step
|
79
|
+
forms to progress in a natural order while remaining flexible. This gem integrates
|
80
|
+
it with the Rails asset pipeline for easy of use.
|
81
|
+
email:
|
82
|
+
- thomas.deruiter@gimiscale.com
|
83
|
+
executables: []
|
84
|
+
extensions: []
|
85
|
+
extra_rdoc_files: []
|
86
|
+
files:
|
87
|
+
- lib/bootstrap-application-wizard-rails.rb
|
88
|
+
- lib/bootstrap-application-wizard-rails/version.rb
|
89
|
+
- lib/bootstrap-application-wizard-rails/engine.rb
|
90
|
+
- lib/bootstrap-application-wizard-rails/railtie.rb
|
91
|
+
- vendor/assets/javascripts/bootstrap-wizard.js
|
92
|
+
- vendor/assets/stylesheets/bootstrap-wizard.css
|
93
|
+
- vendor/assets/javascripts/bootstrap-application-wizard-rails.js
|
94
|
+
- vendor/assets/stylesheets/bootstrap-application-wizard-rails.scss
|
95
|
+
homepage:
|
96
|
+
licenses: []
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ! '>='
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
|
+
none: false
|
109
|
+
requirements:
|
110
|
+
- - ! '>='
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
requirements: []
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 1.8.25
|
116
|
+
signing_key:
|
117
|
+
specification_version: 3
|
118
|
+
summary: Integrate Bootstrap Application Wizard with the Rails asset pipeline
|
119
|
+
test_files: []
|