1/*! 2 * jQuery Stepy - A Wizard Plugin - http://wbotelhos.com/stepy 3 * ------------------------------------------------------------------------------------ 4 * 5 * jQuery Stepy is a plugin based on FormToWizard that generates a customizable wizard. 6 * 7 * Licensed under The MIT License 8 * 9 * @version 1.0.0 10 * @since 2010.07.03 11 * @author Washington Botelho 12 * @documentation wbotelhos.com/stepy 13 * @twitter twitter.com/wbotelhos 14 * 15 * Usage with default values: 16 * ------------------------------------------------------------------------------------ 17 * $('#step').stepy(); 18 * 19 * <form id="step"> 20 * <fieldset title="Step 1"> 21 * <legend>description one</legend> 22 * <!-- input fields --> 23 * </fieldset> 24 * 25 * <fieldset title="Step 2"> 26 * <legend>description one</legend> 27 * <!-- input fields --> 28 * </fieldset> 29 * 30 * <input type="submit" class="finish" value="Finish!"/> 31 * </form> 32 * 33 */ 34 35;(function($) { 36 37 var methods = { 38 init: function(options) { 39 return this.each(function() { 40 41 var opt = $.extend({}, $.fn.stepy.defaults, options), 42 $this = $(this).data('options', opt), 43 id = $this.attr('id'); 44 45 if (id === undefined || id == '') { 46 id = 'stepy-' + $('.' + $this.attr('class')).index(this); 47 $this.attr('id', id); 48 } 49 50 var $titlesWrapper = $('<ul/>', { id: id + '-titles', 'class': 'stepy-titles' }); 51 52 if (opt.titleTarget) { 53 $(opt.titleTarget).html($titlesWrapper); 54 } else { 55 $titlesWrapper.insertBefore($this); 56 } 57 58 if (opt.validate) { 59 jQuery.validator.setDefaults({ ignore: opt.ignore }); 60 61 } 62 63 var $steps = $this.children('fieldset'), 64 $step = undefined, 65 $legend = undefined, 66 description = '', 67 title = ''; 68 69 $steps.each(function(index) { 70 $step = $(this); 71 72 $step 73 .addClass('step') 74 .attr('id', id + '-step-' + index) 75 .append('<p id="' + id + '-buttons-' + index + '" class="' + id + '-buttons"/>'); 76 77 $legend = $step.children('legend'); 78 79 if (!opt.legend) { 80 $legend.hide(); 81 } 82 83 description = ''; 84 85 if (opt.description) { 86 if ($legend.length) { 87 description = '<span>' + $legend.html() + '</span>'; 88 } else { 89 $.error(id + ': the legend element of the step ' + (index + 1) + ' is required to set the description!'); 90 } 91 } 92 93 title = $step.attr('title'); 94 title = (title != '') ? '<div>' + title + '</div>': '--'; 95 96 $titlesWrapper.append('<li id="' + id + '-title-' + index + '">' + title + description + '</li>'); 97 98 if (index == 0) { 99 if ($steps.length > 1) { 100 methods.createNextButton.call($this, index); 101 } 102 } else { 103 methods.createBackButton.call($this, index); 104 105 $step.hide(); 106 107 if (index < $steps.length - 1) { 108 methods.createNextButton.call($this, index); 109 } 110 } 111 }); 112 113 var $titles = $titlesWrapper.children(); 114 115 $titles.first().addClass('current-step'); 116 117 var $finish = $this.children('.finish'); 118 119 if (opt.finishButton) { 120 if ($finish.length) { 121 var isForm = $this.is('form'), 122 onSubmit = undefined; 123 124 if (opt.finish && isForm) { 125 onSubmit = $this.attr('onsubmit'); 126 $this.attr('onsubmit', 'return false;'); 127 } 128 129 $finish.click(function(evt) { 130 if (opt.finish && !methods.execute.call($this, opt.finish, $steps.length - 1)) { 131 evt.preventDefault(); 132 } else { 133 if (isForm) { 134 if (onSubmit) { 135 $this.attr('onsubmit', onSubmit); 136 } else { 137 $this.removeAttr('onsubmit'); 138 } 139 140 //var isSubmit = $finish.attr('type') == 'submit'; 141 142 //if (!isSubmit && (!opt.validate || methods.validate.call($this, $steps.length - 1))) { 143 //$this.submit(); 144 //} 145 } 146 } 147 });
148 $finish.appendTo($this.find('p:last')); 149 } else { 150 $.error(id + ': element with class name "finish" missing!'); 151 } 152 } 153 154 if (opt.titleClick) { 155 $titles.click(function() { 156 var array = $titles.filter('.current-step').attr('id').split('-'), // TODO: try keep the number in an attribute. 157 current = parseInt(array[array.length - 1], 10), 158 clicked = $(this).index(); 159 160 if (clicked > current) { 161 if (opt.next && !methods.execute.call($this, opt.next, clicked)) { 162 return false; 163 } 164 } else if (clicked < current) { 165 if (opt.back && !methods.execute.call($this, opt.back, clicked)) { 166 return false; 167 } 168 } 169 170 if (clicked != current) { 171 methods.step.call($this, (clicked) + 1); 172 } 173 }); 174 } else { 175 $titles.css('cursor', 'default'); 176 } 177 178 $steps.delegate('input[type="text"], input[type="password"]', 'keypress', function(evt) { 179 var key = (evt.keyCode ? evt.keyCode : evt.which); 180 181 if (key == 13) { 182 evt.preventDefault(); 183 184 var $buttons = $(this).parent().children('.' + id + '-buttons'); 185 186 if ($buttons.length) { 187 var $next = $buttons.children('.button-next'); 188 189 if ($next.length) { 190 $next.click(); 191 } else { 192 var $finish = $buttons.children('.finish'); 193 194 if ($finish.length) { 195 $finish.click(); 196 } 197 } 198 } 199 } 200 }); 201 202 $steps.first().find(':input:visible:enabled').first().select().focus(); 203 }); 204 }, createBackButton: function(index) { 205 var $this = this, 206 id = this.attr('id'), 207 opt = this.data('options'); 208 $('<a/>', { id: id + '-back-' + index, href: 'javascript:void(0);', 'class': 'button-back', html: opt.backLabel }).click(function() { 209 if (!opt.back || methods.execute.call($this, opt.back, index - 1)) { 210 methods.step.call($this, (index - 1) + 1); 211 } 212 }).appendTo($('#' + id + '-buttons-' + index)); 213 }, createNextButton: function(index) { 214 var $this = this, 215 id = this.attr('id'), 216 opt = this.data('options'); 217 218 $('<a/>', { id: id + '-next-' + index, href: 'javascript:void(0);', 'class': 'button-next', html: opt.nextLabel }).click(function() { 219 if (!opt.next || methods.execute.call($this, opt.next, index + 1)) { 220 methods.step.call($this, (index + 1) + 1); 221 } 222 }).appendTo($('#' + id + '-buttons-' + index)); 223 }, execute: function(callback, index) { 224 var isValid = callback.call(this, index + 1); 225 226 return isValid || isValid === undefined; 227 }, step: function(index) { 228 index--; 229 230 var $steps = this.children('fieldset'); 231 232 if (index > $steps.length - 1) { 233 index = $steps.length - 1; 234 } 235 236 var opt = this.data('options'); 237 max = index; 238 239 if (opt.validate) { 240 var isValid = true; 241 242 for (var i = 0; i < index; i++) { 243 isValid &= methods.validate.call(this, i); 244 245 if (opt.block && !isValid) { 246 max = i; 247 break; 248 } 249 } 250 } 251 252 $steps.hide().eq(max).show(); 253 254 var $titles = $('#' + this.attr('id') + '-titles').children(); 255 256 $titles.removeClass('current-step').eq(max).addClass('current-step'); 257 258 if (this.is('form')) { 259 var $fields = undefined; 260 261 if (max == index) { 262 $fields = $steps.eq(max).find(':input:enabled:visible'); 263 } else { 264 $fields = $steps.eq(max).find('.error').select().focus(); 265 } 266 267 $fields.first().select().focus(); 268 } 269 270 if (opt.select) { 271 opt.select.call(this, max + 1); 272 } 273 274 return this; 275 }, validate: function(index) { 276 if (!this.is('form')) { 277 return true; 278 } 279 280 var $step = this.children('fieldset').eq(index), 281 isValid = true, 282 $title = $('#' + this.attr('id') + '-titles').children().eq(index), 283 opt = this.data('options'), 284 $validate = this.validate(); 285 286 $($step.find(':input:enabled').get().reverse()).each(function() { 287 var fieldIsValid = $validate.element($(this)); 288 289 if (fieldIsValid === undefined) { 290 fieldIsValid = true; 291 } 292 293 isValid &= fieldIsValid; 294 295 if (isValid) { 296 if (opt.errorImage) { 297 $title.removeClass('error-image'); 298 } 299 } else { 300 if (opt.errorImage) { 301 $title.addClass('error-image'); 302 } 303 304 $validate.focusInvalid(); 305 } 306 }); 307 308 return isValid; 309 } 310 }; 311 312 $.fn.stepy = function(method) { 313 if (methods[method]) { 314 return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 315 } else if (typeof method === 'object' || !method) { 316 return methods.init.apply(this, arguments); 317 } else { 318 $.error('Method ' + method + ' does not exist!'); 319 } 320 }; 321 322 $.fn.stepy.defaults = { 323 back: undefined, 324 block: false, 325 description: true, 326 errorImage: false, 327 finish: undefined, 328 finishButton: true, 329 legend: true, 330 ignore: '', 331 next: undefined, 332 nextLabel: 'Next >', 333 titleClick: false, 334 titleTarget: undefined, 335 validate: false, 336 select: undefined 337 }; 338 339})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.