bootstrap-application-wizard-rails-sass 13.3.5
Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1048 @@
|
|
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));
|
1048
|
+
|
@@ -0,0 +1,146 @@
|
|
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
|
+
}
|
146
|
+
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bootstrap-application-wizard-rails-sass
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 13.3.5
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Thomas A. de Ruiter
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-09-25 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: sass-rails
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '3.2'
|
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'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: coffee-rails
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 3.2.1
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.2.1
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: bundler
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.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: '1.0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rails
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '3.0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '3.0'
|
94
|
+
description: The Bootstrap Application Wizard is a Bootstrap addon that allows multi-step
|
95
|
+
forms to progress in a natural order while remaining flexible. This gem integrates
|
96
|
+
it with the Rails asset pipeline for easy of use.
|
97
|
+
email:
|
98
|
+
- thomas.deruiter@gimiscale.com
|
99
|
+
executables: []
|
100
|
+
extensions: []
|
101
|
+
extra_rdoc_files: []
|
102
|
+
files:
|
103
|
+
- lib/bootstrap-application-wizard-rails.rb
|
104
|
+
- vendor/assets/javascripts/bootstrap-wizard.js
|
105
|
+
- vendor/assets/stylesheets/bootstrap-wizard.css.scss
|
106
|
+
homepage:
|
107
|
+
licenses: []
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
none: false
|
120
|
+
requirements:
|
121
|
+
- - ! '>='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 1.8.23
|
127
|
+
signing_key:
|
128
|
+
specification_version: 3
|
129
|
+
summary: Integrate Bootstrap Application Wizard with the Rails asset pipeline
|
130
|
+
test_files: []
|
131
|
+
has_rdoc:
|