Index: trunk/extensions/SemanticForms/libs/SemanticForms.js |
— | — | @@ -209,25 +209,36 @@ |
210 | 210 | * Functions for handling 'show on select' |
211 | 211 | */ |
212 | 212 | |
213 | | -// show the relevant div if any one of the relevant options are passed in |
214 | | -// to the relevant dropdown - otherwise, hide it |
| 213 | +// Display a div that would otherwise be hidden by "show on select". |
| 214 | +function showDiv(div_id) { |
| 215 | + jQuery('#' + div_id).find("input, select, textarea").removeClass('hiddenBySF'); |
| 216 | + jQuery('#' + div_id).show(); |
| 217 | +} |
| 218 | + |
| 219 | +// Hide a div due to "show on select". The CSS class is there so that SF can |
| 220 | +// ignore the div's contents when the form is submitted. |
| 221 | +function hideDiv(div_id) { |
| 222 | + jQuery('#' + div_id).find("input, select, textarea").addClass('hiddenBySF'); |
| 223 | + jQuery('#' + div_id).hide(); |
| 224 | +} |
| 225 | + |
| 226 | +// Used for the dropdown input only. |
| 227 | +// Show the relevant div if any one of the relevant options are passed in |
| 228 | +// to this dropdown - otherwise, hide it |
215 | 229 | function showIfSelected(input_id, options_array, div_id) { |
216 | | - the_input = document.getElementById(input_id); |
217 | | - the_div = document.getElementById(div_id); |
218 | | - if ( the_div == null ) { return; } |
| 230 | + input_val = jQuery('#' + input_id).val(); |
219 | 231 | for (var i in options_array) { |
220 | | - if (the_input.value == options_array[i]) { |
221 | | - the_div.style.display = ''; // return to default |
| 232 | + if (input_val == options_array[i]) { |
| 233 | + showDiv(div_id); |
222 | 234 | return; |
223 | 235 | } |
224 | 236 | } |
225 | | - the_div.style.display = 'none'; |
| 237 | + hideDiv(div_id); |
226 | 238 | } |
227 | 239 | |
228 | 240 | // Like showIfSelected(), but only for list boxes |
229 | 241 | function showIfSelectedInListBox(input_id, options_array, div_id) { |
230 | 242 | the_input = document.getElementById(input_id); |
231 | | - the_div = document.getElementById(div_id); |
232 | 243 | // Show the div if any of the list box's selected options match |
233 | 244 | // any of the options that point to this div |
234 | 245 | // - we have to cycle through because the field "selectedOptions" is |
— | — | @@ -237,28 +248,27 @@ |
238 | 249 | cur_option = the_input.item(i).text; |
239 | 250 | for (var j in options_array) { |
240 | 251 | if (cur_option == options_array[j]) { |
241 | | - the_div.style.display = ''; // return to default |
| 252 | + showDiv(div_id); |
242 | 253 | return; |
243 | 254 | } |
244 | 255 | } |
245 | 256 | } |
246 | 257 | } |
247 | | - the_div.style.display = 'none'; |
| 258 | + hideDiv(div_id); |
248 | 259 | } |
249 | 260 | |
250 | | -// show the relevant div if any one of the relevant checkboxes are |
251 | | -// checked - otherwise, hide it |
| 261 | +// Used for checkboxes and radiobuttons. |
| 262 | +// Show the relevant div if any one of the relevant selections are |
| 263 | +// checked - otherwise, hide it. |
252 | 264 | function showIfChecked(checkbox_inputs, div_id) { |
253 | | - the_div = document.getElementById(div_id); |
254 | | - if ( the_div == null ) { return; } |
255 | 265 | for (var i in checkbox_inputs) { |
256 | 266 | checkbox = document.getElementById(checkbox_inputs[i]); |
257 | 267 | if (checkbox != null && checkbox.checked) { |
258 | | - the_div.style.display = ''; // return to default |
| 268 | + showDiv(div_id); |
259 | 269 | return; |
260 | 270 | } |
261 | 271 | } |
262 | | - the_div.style.display = 'none'; |
| 272 | + hideDiv(div_id); |
263 | 273 | } |
264 | 274 | |
265 | 275 | // Evaluate an array of passed-in JS calls - this is a hack, but I can't |
— | — | @@ -267,31 +277,24 @@ |
268 | 278 | eval(sfgShowOnSelectCalls[i]); |
269 | 279 | } |
270 | 280 | |
271 | | -function existsAndVisible(field) { |
272 | | - // there's a major bug in the current implementation, which is that |
273 | | - // it ignores fields hidden by the Header Tabs extension and others - |
274 | | - // for now, we'll just override the attempted smartness and say that |
275 | | - // everything is visible. |
276 | | - return true; |
277 | | - //return (field && field.offsetWidth); |
278 | | -} |
279 | | - |
280 | 281 | function validate_mandatory_field(field_id, info_id) { |
281 | | - var field = document.getElementById(field_id); |
282 | | - // if there's nothing at that field ID, ignore it - it's probably |
283 | | - // a hidden field |
284 | | - if (!existsAndVisible(field)) { |
| 282 | + // if the field was hidden via "show on select", ignore it |
| 283 | + if (jQuery('#' + field_id).hasClass('hiddenBySF')) { |
285 | 284 | return true; |
286 | 285 | } |
287 | | - if (field.value.replace(/\s+/, '') == '') { |
288 | | - var info_span = document.getElementById(info_id); |
289 | | - if ( info_span == null ) { |
290 | | - alert ("no info span found at " + info_id + "!"); |
291 | | - } else { |
292 | | - info_span.innerHTML = sfgBlankErrorStr; |
293 | | - } |
| 286 | + var fieldVal = jQuery('#' + field_id).val(); |
| 287 | + if (fieldVal == null) { |
| 288 | + var isEmpty = true; |
| 289 | + } else if (jQuery.isArray(fieldVal)) { |
| 290 | + var isEmpty = (fieldVal.length == 0); |
| 291 | + } else { |
| 292 | + var isEmpty = (fieldVal.replace(/\s+/, '') == ''); |
| 293 | + } |
| 294 | + if (isEmpty) { |
| 295 | + jQuery('#' + info_id).html(sfgBlankErrorStr); |
294 | 296 | return false; |
295 | 297 | } else { |
| 298 | + jQuery('#' + info_id).html(''); |
296 | 299 | return true; |
297 | 300 | } |
298 | 301 | } |
— | — | @@ -299,55 +302,28 @@ |
300 | 303 | // Special handling for radiobuttons, because what's being checked |
301 | 304 | // is the first radiobutton, which has value of "None" |
302 | 305 | function validate_mandatory_radiobutton(none_button_id, info_id) { |
303 | | - none_button = document.getElementById(none_button_id); |
304 | | - if (none_button && none_button.checked) { |
305 | | - info_span = document.getElementById(info_id); |
306 | | - info_span.innerHTML = sfgBlankErrorStr; |
307 | | - return false; |
308 | | - } else { |
| 306 | + // if the field was hidden via "show on select", ignore it |
| 307 | + if (jQuery('#' + none_button_id).hasClass('hiddenBySF')) { |
309 | 308 | return true; |
310 | 309 | } |
311 | | -} |
312 | | - |
313 | | -function validate_mandatory_combobox(field_id, info_id) { |
314 | | - var field = jQuery('input#' + field_id); |
315 | | - // if there's nothing at that field ID, ignore it - it's probably |
316 | | - // a hidden field |
317 | | - if (!existsAndVisible(field)) { |
318 | | - return true; |
319 | | - } |
320 | | - // FIXME |
321 | | - // field.val() unfortunately doesn't work in IE - it just returns |
322 | | - // "undefined". For now, if that happens, just exit |
323 | | - var value = field.val(); |
324 | | - if (value == undefined) { |
325 | | - //alert(field.html()); |
326 | | - return true; |
327 | | - } |
328 | | - if (value.replace(/\s+/, '') == '') { |
329 | | - var info_span = document.getElementById(info_id); |
330 | | - info_span.innerHTML = sfgBlankErrorStr; |
| 310 | + if (jQuery('#' + none_button_id).is(':checked')) { |
| 311 | + jQuery('#' + info_id).html(sfgBlankErrorStr); |
331 | 312 | return false; |
332 | 313 | } else { |
| 314 | + jQuery('#' + info_id).html(''); |
333 | 315 | return true; |
334 | 316 | } |
335 | 317 | } |
336 | 318 | |
337 | 319 | function validate_mandatory_checkboxes(field_id, info_id) { |
338 | | - // get all checkboxes - the "field_id" in this case is the span |
339 | | - // surrounding all the checkboxes |
340 | | - var checkboxes = jQuery('span#' + field_id + " > span > input"); |
341 | | - var all_unchecked = true; |
342 | | - for (var i = 0; i < checkboxes.length; i++) { |
343 | | - if (checkboxes[i].checked) { |
344 | | - all_unchecked = false; |
345 | | - } |
346 | | - } |
347 | | - if (all_unchecked) { |
348 | | - info_span = document.getElementById(info_id); |
349 | | - info_span.innerHTML = sfgBlankErrorStr; |
| 320 | + // Get the number of checked checkboxes within this span - the |
| 321 | + // "field_id" in this case is the span surrounding all the checkboxes. |
| 322 | + var numChecked = jQuery('span#' + field_id + " > span > input:checked").size(); |
| 323 | + if (numChecked == 0) { |
| 324 | + jQuery('#' + info_id).html(sfgBlankErrorStr); |
350 | 325 | return false; |
351 | 326 | } else { |
| 327 | + jQuery('#' + info_id).html(''); |
352 | 328 | return true; |
353 | 329 | } |
354 | 330 | } |
— | — | @@ -375,52 +351,52 @@ |
376 | 352 | } |
377 | 353 | |
378 | 354 | function validate_field_type(field_id, type, info_id) { |
379 | | - field = document.getElementById(field_id); |
380 | | - if (type != 'date' && field.value == '') { |
| 355 | + fieldVal = jQuery('#' + field_id).val(); |
| 356 | + if (type != 'date' && fieldVal == '') { |
381 | 357 | return true; |
382 | 358 | } else { |
383 | 359 | if (type == 'URL') { |
384 | 360 | // code borrowed from http://snippets.dzone.com/posts/show/452 |
385 | 361 | var url_regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; |
386 | | - if (url_regexp.test(field.value)) { |
| 362 | + if (url_regexp.test(fieldVal)) { |
| 363 | + jQuery('#' + info_id).html(''); |
387 | 364 | return true; |
388 | 365 | } else { |
389 | | - info_span = document.getElementById(info_id); |
390 | | - info_span.innerHTML = sfgBadURLErrorStr; |
| 366 | + jQuery('#' + info_id).html(sfgBadURLErrorStr); |
391 | 367 | return false; |
392 | 368 | } |
393 | 369 | } else if (type == 'email') { |
394 | 370 | // code borrowed from http://javascript.internet.com/forms/email-validation---basic.html |
395 | 371 | var email_regexp = /^\s*\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,6})+\s*$/; |
396 | | - if (email_regexp.test(field.value)) { |
| 372 | + if (email_regexp.test(fieldVal)) { |
| 373 | + jQuery('#' + info_id).html(''); |
397 | 374 | return true; |
398 | 375 | } else { |
399 | | - info_span = document.getElementById(info_id); |
400 | | - info_span.innerHTML = sfgBadEmailErrorStr; |
| 376 | + jQuery('#' + info_id).html(sfgBadEmailErrorStr); |
401 | 377 | return false; |
402 | 378 | } |
403 | 379 | } else if (type == 'number') { |
404 | | - if (field.value.match(/^\s*\-?[\d\.,]+\s*$/)) { |
| 380 | + if (fieldVal.match(/^\s*\-?[\d\.,]+\s*$/)) { |
| 381 | + jQuery('#' + info_id).html(''); |
405 | 382 | return true; |
406 | 383 | } else { |
407 | | - info_span = document.getElementById(info_id); |
408 | | - info_span.innerHTML = sfgBadNumberErrorStr; |
| 384 | + jQuery('#' + info_id).html(sfgBadNumberErrorStr); |
409 | 385 | return false; |
410 | 386 | } |
411 | 387 | } else if (type == 'date') { |
412 | 388 | // validate only if day and year fields are both filled in |
413 | | - day_field = document.getElementById(field_id + "_day"); |
414 | | - year_field = document.getElementById(field_id + "_year"); |
415 | | - if (day_field.value == '' || year_field.value == '') { |
| 389 | + dayVal = jQuery('#' + field_id + "_day").val(); |
| 390 | + yearVal = jQuery('#' + field_id + "_year").val(); |
| 391 | + if (dayVal == '' || yearVal == '') { |
| 392 | + jQuery('#' + info_id).html(''); |
416 | 393 | return true; |
417 | | - } else if (day_field.value.match(/^\d+$/) && |
418 | | - day_field.value <= 31) { |
| 394 | + } else if (dayVal.match(/^\d+$/) && dayVal <= 31) { |
419 | 395 | // no year validation, since it can also include |
420 | 396 | // 'BC' and possibly other non-number strings |
| 397 | + jQuery('#' + info_id).html(''); |
421 | 398 | return true; |
422 | 399 | } else { |
423 | | - info_span = document.getElementById(info_id); |
424 | | - info_span.innerHTML = sfgBadDateErrorStr; |
| 400 | + jQuery('#' + info_id).html(sfgBadDateErrorStr); |
425 | 401 | return false; |
426 | 402 | } |
427 | 403 | } else { |
— | — | @@ -463,24 +439,14 @@ |
464 | 440 | if (num_errors > 0) { |
465 | 441 | // add error header, if it's not there already |
466 | 442 | if (! document.getElementById("form_error_header")) { |
467 | | - var errorMsg = document.createElement('div'); |
468 | | - errorMsg.innerHTML = '<div id="form_error_header" class="warningMessage" style="font-size: medium">' + sfgFormErrorsHeader + '</div>'; |
469 | | - document.getElementById("contentSub").appendChild(errorMsg); |
| 443 | + jQuery("#contentSub").append('<div id="form_error_header" class="warningMessage" style="font-size: medium">' + sfgFormErrorsHeader + '</div>'); |
470 | 444 | } |
471 | 445 | scroll(0, 0); |
| 446 | + } else { |
| 447 | + // Disable inputs hidden due to "show on select", so that |
| 448 | + // they aren't submitted by the form. |
| 449 | + jQuery("form.createbox").find('.hiddenBySF').attr('disabled', 'disabled'); |
472 | 450 | } |
473 | | - else |
474 | | - { |
475 | | - // Ensure that invisible fields, e.g. due to "show on select", |
476 | | - // are not submitted in the HTTP POST, by setting them to |
477 | | - // "disabled". Don't disable hidden fields, though (used e.g. |
478 | | - // for edit timestamp). |
479 | | - var inputs = jQuery("form.createbox").find("input, select, textarea"); |
480 | | - for (var i = 0; i < inputs.length; i++) { |
481 | | - input = inputs[i]; |
482 | | - input.disabled = input.type != "hidden" && !existsAndVisible(input); |
483 | | - } |
484 | | - } |
485 | 451 | return (num_errors == 0); |
486 | 452 | } |
487 | 453 | |
— | — | @@ -563,7 +529,7 @@ |
564 | 530 | |
565 | 531 | //Add the new instance |
566 | 532 | main_div.appendChild(new_div); |
567 | | - attachAutocompleteToAllFields(new_div); |
| 533 | + new_div.attachAutocompleteToAllFields; |
568 | 534 | |
569 | 535 | // For each 'upload file' link in this latest instance, |
570 | 536 | // add a call to fancybox() |
— | — | @@ -596,66 +562,49 @@ |
597 | 563 | } |
598 | 564 | |
599 | 565 | // Activate autocomplete functionality for every field on the document |
600 | | -function attachAutocompleteToAllDocumentFields() |
601 | | -{ |
602 | | - var forms = document.getElementsByTagName("form"); |
603 | | - var x; |
604 | | - for (x = 0; x < forms.length; x++) { |
605 | | - if (forms[x].name == "createbox") { |
606 | | - attachAutocompleteToAllFields(forms[x]); |
607 | | - } |
608 | | - } |
| 566 | +function attachAutocompleteToAllDocumentFields() { |
| 567 | + jQuery('form[name="createbox"]').attachAutocompleteToAllFields(); |
609 | 568 | } |
610 | 569 | |
611 | | -// Activate autocomplete functionality for every field under the specified |
612 | | -// element |
613 | | -function attachAutocompleteToAllFields(base) |
614 | | -{ |
615 | | - var inputs = base.getElementsByTagName("input"); |
616 | | - var y; |
617 | | - for (y = 0; y < inputs.length; y++) { |
618 | | - attachAutocompleteToField(inputs[y].id); |
619 | | - } |
620 | | - // don't forget the textareas |
621 | | - inputs = base.getElementsByTagName("textarea"); |
622 | | - for (y = 0; y < inputs.length; y++) { |
623 | | - attachAutocompleteToField(inputs[y].id); |
624 | | - } |
| 570 | +// Activate autocomplete functionality for every SF input field within the |
| 571 | +// specified element |
| 572 | +jQuery.fn.attachAutocompleteToAllFields = function() { |
| 573 | + this.find("input[id^=input_], textarea[id^=input_]").each( |
| 574 | + function() { |
| 575 | + attachAutocompleteToField(this); |
| 576 | + } |
| 577 | + ); |
625 | 578 | } |
626 | 579 | |
627 | 580 | // Activate autocomplete functionality for the specified field |
628 | | -function attachAutocompleteToField(input_id) |
629 | | -{ |
630 | | - // Check input id for the proper format, to ensure this is for SF |
631 | | - if (input_id.substr(0,6) == 'input_') |
632 | | - { |
633 | | - // Extract the field ID number from the input field |
634 | | - var field_num = parseInt(input_id.substring(input_id.lastIndexOf('_') + 1, input_id.length),10); |
635 | | - // Add the autocomplete string, if a mapping exists. |
636 | | - var field_string = sfgAutocompleteMappings[field_num]; |
637 | | - if (field_string) { |
638 | | - var div_id = input_id.replace(/input_/g, 'div_'); |
639 | | - var field_values = field_string.split(','); |
640 | | - var delimiter = null; |
641 | | - var data_source = field_values[0]; |
642 | | - if (field_values[1] == 'list') { |
643 | | - delimiter = ","; |
644 | | - if (field_values[2] != null) { |
645 | | - delimiter = field_values[2]; |
646 | | - } |
| 581 | +function attachAutocompleteToField(input) { |
| 582 | + input_id = input.id; |
| 583 | + // Extract the field ID number from the input field |
| 584 | + var field_num = parseInt(input_id.substring(input_id.lastIndexOf('_') + 1, input_id.length),10); |
| 585 | + // Add the autocomplete string, if a mapping exists. |
| 586 | + var field_string = sfgAutocompleteMappings[field_num]; |
| 587 | + if (field_string) { |
| 588 | + var div_id = input_id.replace(/input_/g, 'div_'); |
| 589 | + var field_values = field_string.split(','); |
| 590 | + var delimiter = null; |
| 591 | + var data_source = field_values[0]; |
| 592 | + if (field_values[1] == 'list') { |
| 593 | + delimiter = ","; |
| 594 | + if (field_values[2] != null) { |
| 595 | + delimiter = field_values[2]; |
647 | 596 | } |
648 | | - if (sfgAutocompleteValues[field_string] != null) { |
649 | | - sf_autocomplete(input_id, div_id, sfgAutocompleteValues[field_string], null, null, delimiter, data_source); |
650 | | - } else { |
651 | | - sf_autocomplete(input_id, div_id, null, wgScriptPath + "/api.php", sfgAutocompleteDataTypes[field_string], delimiter, data_source); |
652 | | - } |
653 | 597 | } |
| 598 | + if (sfgAutocompleteValues[field_string] != null) { |
| 599 | + sf_autocomplete(input_id, div_id, sfgAutocompleteValues[field_string], null, null, delimiter, data_source); |
| 600 | + } else { |
| 601 | + sf_autocomplete(input_id, div_id, null, wgScriptPath + "/api.php", sfgAutocompleteDataTypes[field_string], delimiter, data_source); |
| 602 | + } |
654 | 603 | } |
655 | 604 | } |
656 | 605 | |
657 | 606 | for (var i = 0; i < sfgComboBoxInputs.length; i++ ) { |
658 | 607 | var input_num = sfgComboBoxInputs[i]; |
659 | | - jQuery(function() { |
| 608 | + jQuery(document).ready(function() { |
660 | 609 | jQuery("#input_" + input_num).combobox(); |
661 | 610 | }); |
662 | 611 | } |
— | — | @@ -670,7 +619,6 @@ |
671 | 620 | } |
672 | 621 | |
673 | 622 | |
674 | | - |
675 | 623 | /* extending jquery functions */ |
676 | 624 | |
677 | 625 | (function(jQuery) { |
— | — | @@ -684,6 +632,7 @@ |
685 | 633 | var curval = select[0].options[0].value; |
686 | 634 | var input = jQuery("<input id=\"" + id + "\" type=\"text\" name=\" " + name + " \" value=\"" + curval + "\">") |
687 | 635 | .insertAfter(select) |
| 636 | + .attr("tabIndex", select.attr("tabIndex")) |
688 | 637 | .autocomplete({ |
689 | 638 | source: function(request, response) { |
690 | 639 | if ( autocompleteOnAllChars ) { |