1/*----------------------------------------------------------------------*/ 2/* wl_Form v 1.1 by revaxarts.com 3/* description: handles the serialization, unserialization and sending 4/* of a form 5/* dependency: $.confirm, wl_Number*, wl_Slider*, wl_Date*, wl_Value*, 6/* wl_Password*, wl_File* 7/* * only when fields are within the form 8/*----------------------------------------------------------------------*/ 9 10 11$.fn.wl_Form = function (method) { 12 13 var args = arguments; 14 return this.each(function () { 15 16 var $this = $(this); 17 18 if ($.fn.wl_Form.methods[method]) { 19 return $.fn.wl_Form.methods[method].apply(this, Array.prototype.slice.call(args, 1)); 20 } else if (typeof method === 'object' || !method) { 21 if ($this.data('wl_Form')) { 22 var opts = $.extend({}, $this.data('wl_Form'), method); 23 } else { 24 var opts = $.extend({}, $.fn.wl_Form.defaults, method, $this.data()); 25 } 26 } else { 27 $.error('Method "' + method + '" does not exist'); 28 } 29 30 //all fields within that form 31 var $inputs = $this.find('input,textarea,select,div.date,div.slider'), 32 //$required = $inputs.filter('[required]'), //Doenst work on IE7/8 33 $submitbtn = $this.find(opts.submitButton); 34 35 if (!$this.data('wl_Form')) { 36 37 $this.data('wl_Form', {}); 38 39 //get options from the forms nativ attributes 40 opts.action = $this.attr('action') || opts.action; 41 opts.method = $this.attr('method') || opts.method; 42 43 //prevent the forms defautl behaviour 44 $this.bind('submit.wl_Form', function (event) { 45 event.preventDefault(); 46 return false; 47 }); 48 49 //bind the click action to the submit button 50 $submitbtn.bind('click.wl_Form', function (event) { 51 $.fn.wl_Form.methods.submit.call($this[0]); 52 return false; 53 }); 54 55 //iterate thru the fields 56 $inputs.each(function () { 57 var _this = $(this), 58 _row = _this.closest('section'), 59 //the label should be nice readable 60 _label = _row.find('label').eq(0).html() || this.name || this.id || ''; 61 62 63 //This is required because IEs < 9 can't handle this as expected 64 if (_this.is('[required]') || typeof _this.prop('required') == 'string') { 65 _this.data('required', true); 66 _row.find('label').eq(0).append(' <span class="required"> </span>'); 67 } 68 69 //add the label to the field (and strip out unwanted info) 70 _this.data('wl_label', _label.replace(/<span>([^<]+)<\/span>|<([^>]+)\/?>/g, '')); 71 }); 72 73 74 //set the form status after the submit button if status is true 75 if (opts.status && !$submitbtn.closest('div').is('span.wl_formstatus')) { 76 $submitbtn.closest('div').append('<span class="wl_formstatus"></span>'); 77 } 78 79 //parse the location.search parameters 80 if (opts.parseQuery) { 81 $this.wl_Form.methods.unserialize.call(this); 82 } 83 84 } else { 85 86 } 87 88 if (opts) $.extend($this.data('wl_Form'), opts); 89 }); 90 91}; 92 93$.fn.wl_Form.defaults = { 94 submitButton: 'button:last', 95 method: 'post', 96 action: null, 97 ajax: true, 98 serialize: false, 99 parseQuery: true, 100 dataType: 'text', 101 status: true, 102 sent: false, 103 confirmSend: true, 104 text: { 105 required: 'This field is required', 106 valid: 'This field is invalid', 107 password: 'This password is to short', 108 passwordmatch: 'This password doesn\'t match', 109 fileinqueue: 'There is at least one file in the queue', 110 incomplete: 'Please fill out the form correctly!', 111 send: 'send form...', 112 sendagain: 'send again?', 113 success: 'form sent!', 114 error: 'error while sending!', 115 parseerror: 'Can\'t unserialize query string:\n %e' 116 }, 117 tooltip: { 118 gravity: 'nw' 119 }, 120 onRequireError: function (element) {}, 121 onValidError: function (element) {}, 122 onPasswordError: function (element) {}, 123 onFileError: function (element) {}, 124 onBeforeSubmit: function (data) {}, 125 onComplete: function (textStatus, jqXHR) {}, 126 onError: function (textStatus, error, jqXHR) {}, 127 onSuccess: function (data, textStatus, jqXHR) {} 128}; 129$.fn.wl_Form.version = '1.1'; 130 131 132$.fn.wl_Form.methods = { 133 disable: function () { 134 var $this = $(this), 135 _inputs = $this.find($this.data('wl_Form').submitButton + ',input,textarea,select,div.date,div.slider'); 136 //iterate thru all fields 137 _inputs.each(function () { 138 var _this = $(this); 139 if (_this.is('div')) { 140 //disable slider and datefields 141 if (_this.is('div.slider') && _this.data('wl_Slider')) { 142 _this.wl_Slider('disable'); 143 } else if (_this.is('div.date') && _this.data('wl_Date')) { 144 _this.wl_Date('disable'); 145 } 146 } else { 147 //disable normal fields 148 _this.prop('disabled', true); 149 } 150 }); 151 $this.data('wl_Form').disabled = true; 152 }, 153 enable: function () { 154 var $this = $(this), 155 _inputs = $this.find($this.data('wl_Form').submitButton + ',input,textarea,select,div.date,div.slider'); 156 //iterate thru all fields 157 _inputs.each(function () { 158 var _this = $(this); 159 if (_this.is('div')) { 160 //enable slider and datefields 161 if (_this.is('div.slider') && _this.data('wl_Slider')) { 162 _this.wl_Slider('enable'); 163 } else if (_this.is('div.date') && _this.data('wl_Date')) { 164 _this.wl_Date('enable'); 165 } 166 } else { 167 //enable normal fields 168 _this.prop('disabled', false); 169 } 170 }); 171 $this.data('wl_Form').disabled = false;
172 }, 173 submit: function () { 174 175 //collect some required info 176 var $this = $(this), 177 _data = {}, 178 _opts = $this.data('wl_Form'), 179 _inputs = $this.find('input,textarea,select,div.date,div.slider'), 180 _statusel = $this.find('.wl_formstatus'), 181 _requiredelements = Array(), 182 _validelements = Array(), 183 _passwordelements = Array(), 184 _fileelements = Array(), 185 _submit = true; 186 187 188 //status reset 189 _statusel.text(""); 190 191 //iterate thru all fields 192 _inputs.each(function (i, e) { 193 var _this = $(this), 194 _row = _this.closest('section'); 195 196 //passwords has a different error handling 197 if (_this.attr('type') != 'password' && !_this.data('wl_Password') || _this.data('wl_Password') && _this.data('wl_Password').connect) { 198 _row.removeClass('error'); 199 } 200 201 //if a placeholder is set remove the value temporary 202 if (_this.prop('placeholder') && _this.val() == _this.prop('placeholder') && !_this.data('uservalue')) { 203 _this.val(''); 204 } 205 //if field is required an a value is set or it is a checkbox and the checkbox isn't checked or it is a file upload with no files 206 if (_this.data('required')) { 207 if ((!_this.val() || _this.is(':checkbox') && !_this.is(':checked')) && !_this.data('wl_File')) { 208 _row.addClass('error'); 209 _requiredelements.push(_this); 210 _submit = false; 211 } else if (_this.data('wl_File') && !_this.data('wl_File').files.length) { 212 _row.addClass('error'); 213 //use the filepool for the tooltip 214 _requiredelements.push(_row.find('.fileuploadpool').eq(0)); 215 _submit = false; 216 217 } 218 } 219 //if it is a valid field but it isn't valid 220 if (_this.data('wl_Valid') && !_this.data('wl_Valid').valid) { 221 _row.addClass('error'); 222 _validelements.push(_this); 223 _submit = false; 224 } 225 //check if there is a file in the queue 226 if (_this.data('wl_File') && !$.isEmptyObject(_this.data('wl_File').queue)) { 227 _row.addClass('error'); 228 //use the filepool for the tooltip 229 _fileelements.push(_row.find('.fileuploadpool').eq(0)); 230 _submit = false; 231 } 232 //if it is a password 233 if (_this.data('wl_Password')) { 234 var value = _this.val(); 235 //password confirmation is set and the confirmation isn't equal the password or the password is shorter than the minlength of the password field 236 if ((_this.data('wl_Password').confirm && _this.data('wl_Password').connect && value != $('#' + _this.data('wl_Password').connect).val()) || (value && value.length < _this.data('wl_Password').minLength)) { 237 _row.addClass('error'); 238 _passwordelements.push(_this); 239 _submit = false; 240 241 } 242 }; 243 }); 244 245 //if some of the above errors occures 246 if (!_submit) { 247 248 //iterate thru all required fields 249 $.each(_requiredelements, function (i, e) { 250 251 //callback 252 _opts.onRequireError.call(e[0], e); 253 254 //use tipsy for a tooltip 255 e.tipsy($.extend({}, config.tooltip, _opts.tooltip, { 256 trigger: 'manual', 257 fallback: e.data('errortext') || _opts.text.required 258 })); 259 e.tipsy('show'); 260 261 //hide tooltip on fieldfocus or change 262 e.bind('focus.tooltip, click.tooltip, change.tooltip', function () { 263 $(this).unbind('focus.tooltip, click.tooltip, change.tooltip').tipsy('hide'); 264 }); 265 }); 266 267 268 //iterate thru all valid fields 269 $.each(_validelements, function (i, e) { 270 271 //callback 272 _opts.onValidError.call(e[0], e); 273 274 //use tipsy for a tooltip 275 e.tipsy($.extend({}, config.tooltip, _opts.tooltip, { 276 trigger: 'manual', 277 fallback: e.data('errortext') || e.data('wl_Valid').errortext || _opts.text.valid 278 })); 279 e.tipsy('show'); 280 281 //hide tooltip on fieldfocus 282 e.bind('focus.tooltip, click.tooltip', function () { 283 $(this).unbind('focus.tooltip, click.tooltip').tipsy('hide'); 284 }); 285 }); 286 287 //iterate thru all password fields 288 $.each(_passwordelements, function (i, e) { 289 var text = '', 290 value = e.val(); 291 292 //confirmation is set 293 if (e.data('wl_Password').confirm) { 294 var connect = $('#' + e.data('wl_Password').connect); 295 296 //but password is not equal confimration 297 if (value != connect.val()) { 298 299 //tipsy on the confirmation field 300 connect.tipsy($.extend({}, config.tooltip, _opts.tooltip, { 301 trigger: 'manual', 302 fallback: connect.data('errortext') || _opts.text.passwordmatch 303 })); 304 connect.tipsy('show'); 305 306 //hide tooltip in fieldfocus 307 connect.bind('focus.tooltip, click.tooltip', function () { 308 $(this).unbind('focus.tooltip, click.tooltip').tipsy('hide'); 309 }); 310 } 311 } 312 313 //length is to short 314 if (value.length < e.data('wl_Password').minLength) { 315 _opts.onPasswordError.call(e[0], e); 316 317 //tipsy
318 e.tipsy($.extend({}, config.tooltip, _opts.tooltip, { 319 trigger: 'manual', 320 fallback: e.data('errortext') || _opts.text.password 321 })); 322 e.tipsy('show'); 323 324 //hide tooltip in fieldfocus 325 e.bind('focus.tooltip, click.tooltip', function () { 326 $(this).unbind('focus.tooltip, click.tooltip').tipsy('hide'); 327 }); 328 } 329 330 }); 331 332 //iterate thru all file upload fields 333 $.each(_fileelements, function (i, e) { 334 335 //callback 336 _opts.onFileError.call(e[0], e); 337 338 //use tipsy for a tooltip 339 e.tipsy($.extend({}, config.tooltip, _opts.tooltip, { 340 trigger: 'manual', 341 fallback: e.data('errortext') || _opts.text.fileinqueue 342 })); 343 e.tipsy('show'); 344 345 //hide tooltip on fieldfocus or change 346 e.bind('focus.tooltip, click.tooltip, change.tooltip', function () { 347 $(this).unbind('focus.tooltip, click.tooltip, change.tooltip').tipsy('hide'); 348 }); 349 }); 350 //Set status message 351 _statusel.text(_opts.text.incomplete); 352 return false; 353 } 354 355 //confirmation is required if the form was allready sent 356 if (_opts.confirmSend && _opts.sent === true) { 357 $.confirm(_opts.text.sendagain, function () { 358 _opts.sent = false; 359 $.fn.wl_Form.methods.submit.call($this[0]); 360 }); 361 return false; 362 } 363 364 //iterate thru all fields and prepare data 365 _inputs.each(function (i, e) { 366 var _el = $(e), 367 key = _el.attr('name') || e.id, 368 value = null; 369 370 371 //datepicker 372 if (_el.data('wl_Date')) { 373 374 var connect = $this.find('input[data-connect=' + e.id + ']').eq(0), 375 dateobj = new Date(_el.datepicker('getDate')), 376 //format: YYYY-MM-DD 377 date = dateobj.getFullYear() + '-' + $.leadingZero(dateobj.getMonth() + 1) + '-' + $.leadingZero(dateobj.getDate()); 378 if (dateobj.getTime()) { 379 //is connected to a timefield 380 if (connect.length) { 381 value = date + ' ' + (connect.data('wl_Time').time || '00:00'); 382 } else { 383 value = date; 384 } 385 } 386 _data[key] = value; 387 388 //slider 389 } else if (_el.data('wl_Slider')) { 390 391 //if it is connected we have a input field too so skip it 392 if (!_el.is('[data-connect]')) { 393 if (_el.data('wl_Slider').range !== true) { 394 value = _el.slider('option', 'value'); 395 _data[key] = value; 396 } else { 397 value = _el.slider('option', 'values'); 398 } 399 _data[key] = value; 400 } 401 402 //wysiwyg editor 403 } else if (_el.data('wl_Editor')) { 404 405 //copy the content to the textarea 406 _el.wysiwyg('save'); 407 _data[key] = _el.val(); 408 409 //file upload 410 } else if (_el.data('wl_File')) { 411 412 _data[key] = _el.data('wl_File').files; 413 414 //if no file was uploaded value is null 415 if ($.isEmptyObject(_data[key])) _data[key] = null; 416 417 //timefield 418 } else if (_el.data('wl_Time')) { 419 420 //if it is connected we have a datefield too so skip it 421 if (!_el.is('[data-connect]')) { 422 _data[key] = _el.data('wl_Time').time; 423 } 424 425 //timefield 426 } else if (_el.is(':checkbox')) { 427 428 _data[key] = _el.is(':checked'); 429 430 //password 431 } else if (_el.is(':password')) { 432 433 _data[key] = _el.val(); 434 435 //radio buttons 436 } else if (_el.is(':radio')) { 437 438 if (_el.is(':checked')) { 439 //use the value attribute if present or id as fallback (new in 1.1) 440 _data[key] = (_el.val() != 'on') ? _el.val() : e.id; 441 } 442 443 //number field 444 } else if (_el.data('wl_Number')) { 445 446 value = parseFloat(_el.val()); 447 if (isNaN(value)) { 448 value = null; 449 } 450 _data[key] = value; 451 452 //other fields 453 } else { 454 _data[key] = _el.val(); 455 } 456 }); 457 458 //should we serialize it? (key=value&key2=value2&...) 459 if (_opts.serialize) { 460 _data = $.param(_data); 461 } 462 463 //callback can return false to prevent sending 464 if (_opts.onBeforeSubmit.call($this[0], _data) === false) { 465 return false; 466 } 467 468 //set status text 469 _statusel.text(_opts.text.send); 470 471 //send the form natively 472 if (!_opts.ajax) { 473 $this.unbind('submit.wl_Form'); 474 $this.submit(); 475 return false; 476 } 477 478 //now disable it 479 $.fn.wl_Form.methods.disable.call(this); 480 481 //send the form 482 $.ajax({ 483 url: _opts.action, 484 type: _opts.method, 485 data: _data, 486 dataType: _opts.dataType, 487 //callback on success 488 success: function (data, textStatus, jqXHR) { 489 _statusel.textFadeOut(_opts.text.success); 490 _opts.onSuccess.call($this[0], data, textStatus, jqXHR); 491 }, 492 //callback on complete 493 complete: function (jqXHR, textStatus) { 494 $.fn.wl_Form.methods.enable.call($this[0]); 495 _opts.sent = true; 496 _opts.onComplete.call($this[0], textStatus, jqXHR); 497 }, 498 //callback on error 499 error: function (jqXHR, textStatus, error) { 500 _statusel.text(_opts.text.error); 501 _opts.onError.call($this[0], textStatus, error, jqXHR); 502 } 503 }); 504 505 }, 506 unserialize: function (string) { 507 var $this = $(this), 508 _searchquery = string || location.search.substr(1); 509 510 //parse only if we have something to parse 511 if (_searchquery) { 512 513 //could throw an error because its an userinput 514 try { 515
516 //prepare string to get a clean array with with key => value 517 values = decodeURIComponent(_searchquery).split('&'); 518 519 var serialized_values = []; 520 521 $.each(values, function () { 522 var properties = this.split("="), 523 key = properties.shift(); 524 525 properties = properties.join('='); 526 527 if ((typeof key !== 'undefined') && (typeof properties !== 'undefined')) { 528 serialized_values[key.replace(/\+/g, " ")] = properties.replace(/\+/g, " "); 529 } 530 }); 531 values = serialized_values; 532 533 // Iterate thru each element 534 $("input,textarea,select,div.date,div.slider").each(function () { 535 var _this = $(this), 536 _type = _this.attr("type"), 537 tag_name = this.name || this.id; 538 539 540 541 // Set the values to field 542 if (values[tag_name] != null) { 543 544 //chechboxes 545 if (_type == "checkbox") { 546 _this.prop("checked", (values[tag_name] == 'true')); 547 548 //radio buttons 549 } else if (_type == "radio") { 550 $('input[id="' + values[tag_name] + '"]').attr("checked", true); 551 552 //password 553 } else if (_type == "password") { 554 //don't write passwords for security reasons 555 //_this.val(values[tag_name]).trigger('change') 556 //datepicker 557 } else if (_this.is('input.date')) { 558 if (/(\d\d:\d\d)$/.test(values[tag_name])) { 559 var time = values[tag_name].substr(11), 560 date = values[tag_name].substr(0, 10); 561 _this.datepicker('setDate', new Date(date)); 562 $('input[data-connect="' + tag_name + '"]').val(time).data('wl_Time').time = time; 563 } else { 564 _this.datepicker('setDate', new Date(values[tag_name])); 565 } 566 567 //inline datepicker 568 } else if (_this.is('div.date')) { 569 _this.datepicker('setDate', new Date(values[tag_name])); 570 571 //colorpicker 572 } else if (_this.is('.color')) { 573 _this.wl_Color('set', 'value', values[tag_name]); 574 575 //Slider 576 } else if (_this.is('.slider')) { 577 _this.wl_Slider('values', values[tag_name]); 578 if (_this.data('wl_Slider')) { 579 _this.wl_Slider("change"); 580 _this.wl_Slider("slide"); 581 } 582 583 //wysiwyg editor 584 } else if (_this.is('textarea.html')) { 585 _this.val(values[tag_name]); 586 if (_this.data('wl_Editor')) { 587 _this.wysiwyg("setContent", values[tag_name]); 588 } 589 590 //other fields 591 } else { 592 _this.val(values[tag_name]).trigger('change'); 593 } 594 } 595 }); 596 } catch (e) { 597 598 //call a message to prevent crashing the application 599 $.msg($this.data('wl_Form').text.parseerror.replace('%e', e)); 600 } 601 } 602 }, 603 set: function () { 604 var $this = $(this), 605 options = {}; 606 if (typeof arguments[0] === 'object') { 607 options = arguments[0]; 608 } else if (arguments[0] && arguments[1] !== undefined) { 609 options[arguments[0]] = arguments[1]; 610 } 611 $.each(options, function (key, value) { 612 if ($.fn.wl_Form.defaults[key] !== undefined && $.fn.wl_Form.defaults[key] !== null) { 613 $this.data('wl_Form')[key] = value; 614 } else { 615 $.error('Key "' + key + '" is not defined'); 616 } 617 }); 618 619 } 620};
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.