Index: trunk/extensions/SemanticForms/libs/SemanticForms.js |
— | — | @@ -1,11 +1,13 @@ |
2 | 2 | /** |
3 | | - * sf_autocomplete() |
| 3 | + * SemanticForms.js |
4 | 4 | * |
5 | | - * Javascript utitilies for the Semantic Forms extension, mostly related to |
6 | | - * jQuery autocompletion. |
| 5 | + * Javascript utility functions for the Semantic Forms extension. |
7 | 6 | * |
| 7 | + * @author Yaron Koren |
8 | 8 | * @author Sanyam Goyal |
9 | | - * @author Yaron Koren |
| 9 | + * @author Jeffrey Stuckman |
| 10 | + * @author Harold Solbrig |
| 11 | + * @author Eugene Mednikov |
10 | 12 | */ |
11 | 13 | |
12 | 14 | function isEmpty(obj) { |
— | — | @@ -210,13 +212,34 @@ |
211 | 213 | the_div.style.display = 'none'; |
212 | 214 | } |
213 | 215 | |
| 216 | +function showIfSelectedInListBox(input_id, options_array, div_id) { |
| 217 | + the_input = document.getElementById(input_id); |
| 218 | + the_div = document.getElementById(div_id); |
| 219 | + // Show the div if any of the list box's selected options match |
| 220 | + // any of the options that point to this div |
| 221 | + // - we have to cycle through because the field "selectedOptions" is |
| 222 | + // apparently not supported on all browsers. |
| 223 | + for (var i = 0; i < the_input.options.length; i++) { |
| 224 | + if ( the_input.item(i).selected ) { |
| 225 | + cur_option = the_input.item(i).text; |
| 226 | + for (var j in options_array) { |
| 227 | + if (cur_option == options_array[j]) { |
| 228 | + the_div.style.display = ''; // return to default |
| 229 | + return; |
| 230 | + } |
| 231 | + } |
| 232 | + } |
| 233 | + } |
| 234 | + the_div.style.display = 'none'; |
| 235 | +} |
| 236 | + |
214 | 237 | // show the relevant div if any one of the relevant checkboxes are |
215 | 238 | // checked - otherwise, hide it |
216 | 239 | function showIfChecked(checkbox_inputs, div_id) { |
217 | 240 | the_div = document.getElementById(div_id); |
218 | 241 | for (var i in checkbox_inputs) { |
219 | 242 | checkbox = document.getElementById(checkbox_inputs[i]); |
220 | | - if (checkbox.checked) { |
| 243 | + if (checkbox != null && checkbox.checked) { |
221 | 244 | the_div.style.display = ''; // return to default |
222 | 245 | return; |
223 | 246 | } |
— | — | @@ -224,12 +247,393 @@ |
225 | 248 | the_div.style.display = 'none'; |
226 | 249 | } |
227 | 250 | |
| 251 | +for (var i = 0; i < sfgShowOnSelectCalls.length; i++ ) { |
| 252 | + eval(sfgShowOnSelectCalls[i]); |
| 253 | +} |
228 | 254 | |
229 | | -/* extending jquery functions */ |
230 | | - |
| 255 | +function validate_mandatory_field(field_id, info_id) { |
| 256 | + var field = document.getElementById(field_id); |
| 257 | + // if there's nothing at that field ID, ignore it - it's probably |
| 258 | + // a hidden field |
| 259 | + if (field == null) { |
| 260 | + return true; |
| 261 | + } |
| 262 | + if (field.value.replace(/\s+/, '') == '') { |
| 263 | + var info_span = document.getElementById(info_id); |
| 264 | + if ( info_span == null ) { |
| 265 | + alert ("no info span found at " + info_id + "!"); |
| 266 | + } else { |
| 267 | + info_span.innerHTML = sfgBlankErrorStr; |
| 268 | + } |
| 269 | + return false; |
| 270 | + } else { |
| 271 | + return true; |
| 272 | + } |
| 273 | +} |
231 | 274 | |
| 275 | +// special handling for radiobuttons, because what's being checked |
| 276 | +// is the first radiobutton, which has value of "None" |
| 277 | +function validate_mandatory_radiobutton(none_button_id, info_id) { |
| 278 | + none_button = document.getElementById(none_button_id); |
| 279 | + if (none_button && none_button.checked) { |
| 280 | + info_span = document.getElementById(info_id); |
| 281 | + info_span.innerHTML = sfgBlankErrorStr; |
| 282 | + return false; |
| 283 | + } else { |
| 284 | + return true; |
| 285 | + } |
| 286 | +} |
232 | 287 | |
| 288 | +function validate_mandatory_combobox(field_id, info_id) { |
| 289 | + var field = jQuery('input#' + field_id); |
| 290 | + // if there's nothing at that field ID, ignore it - it's probably |
| 291 | + // a hidden field |
| 292 | + if (field == null) { |
| 293 | + return true; |
| 294 | + } |
| 295 | + // FIXME |
| 296 | + // field.val() unfortunately doesn't work in IE - it just returns |
| 297 | + // "undefined". For now, if that happens, just exit |
| 298 | + var value = field.val(); |
| 299 | + if (value == undefined) { |
| 300 | + //alert(field.html()); |
| 301 | + return true; |
| 302 | + } |
| 303 | + if (value.replace(/\s+/, '') == '') { |
| 304 | + var info_span = document.getElementById(info_id); |
| 305 | + info_span.innerHTML = sfgBlankErrorStr; |
| 306 | + return false; |
| 307 | + } else { |
| 308 | + return true; |
| 309 | + } |
| 310 | +} |
233 | 311 | |
| 312 | +function validate_mandatory_checkboxes(field_id, info_id) { |
| 313 | + // get all checkboxes - the "field_id" in this case is the span |
| 314 | + // surrounding all the checkboxes |
| 315 | + var checkboxes = jQuery('span#' + field_id + " > span > input"); |
| 316 | + var all_unchecked = true; |
| 317 | + for (var i = 0; i < checkboxes.length; i++) { |
| 318 | + if (checkboxes[i].checked) { |
| 319 | + all_unchecked = false; |
| 320 | + } |
| 321 | + } |
| 322 | + if (all_unchecked) { |
| 323 | + info_span = document.getElementById(info_id); |
| 324 | + info_span.innerHTML = sfgBlankErrorStr; |
| 325 | + return false; |
| 326 | + } else { |
| 327 | + return true; |
| 328 | + } |
| 329 | +} |
| 330 | + |
| 331 | +// validate a mandatory field that exists across multiple instances of |
| 332 | +// a template - we have to find each one, matching on the pattern of its |
| 333 | +// ID, and validate it |
| 334 | +function validate_multiple_mandatory_fields(field_num) { |
| 335 | + var num_errors = 0; |
| 336 | + elems = document.getElementsByTagName("*"); |
| 337 | + if ( ! elems) { elems = []; } |
| 338 | + var field_pattern = new RegExp('input_(.*)_' + field_num); |
| 339 | + for (var i = 0; i < elems.length; i++) { |
| 340 | + id = elems[i].id; |
| 341 | + if (matches = field_pattern.exec(id)) { |
| 342 | + instance_num = matches[1]; |
| 343 | + var input_name = "input_" + instance_num + "_" + field_num; |
| 344 | + var info_name = "info_" + instance_num + "_" + field_num; |
| 345 | + if (! validate_mandatory_field(input_name, info_name)) { |
| 346 | + num_errors += 1; |
| 347 | + } |
| 348 | + } |
| 349 | + } |
| 350 | + return (num_errors == 0); |
| 351 | +} |
| 352 | + |
| 353 | +function validate_field_type(field_id, type, info_id) { |
| 354 | + field = document.getElementById(field_id); |
| 355 | + if (type != 'date' && field.value == '') { |
| 356 | + return true; |
| 357 | + } else { |
| 358 | + if (type == 'URL') { |
| 359 | + // code borrowed from http://snippets.dzone.com/posts/show/452 |
| 360 | + var url_regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; |
| 361 | + if (url_regexp.test(field.value)) { |
| 362 | + return true; |
| 363 | + } else { |
| 364 | + info_span = document.getElementById(info_id); |
| 365 | + info_span.innerHTML = sfgBadURLErrorStr; |
| 366 | + return false; |
| 367 | + } |
| 368 | + } else if (type == 'email') { |
| 369 | + // code borrowed from http://javascript.internet.com/forms/email-validation---basic.html |
| 370 | + var email_regexp = /^\s*\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,6})+\s*$/; |
| 371 | + if (email_regexp.test(field.value)) { |
| 372 | + return true; |
| 373 | + } else { |
| 374 | + info_span = document.getElementById(info_id); |
| 375 | + info_span.innerHTML = sfgBadEmailErrorStr; |
| 376 | + return false; |
| 377 | + } |
| 378 | + } else if (type == 'number') { |
| 379 | + if (field.value.match(/^\s*\-?[\d\.,]+\s*$/)) { |
| 380 | + return true; |
| 381 | + } else { |
| 382 | + info_span = document.getElementById(info_id); |
| 383 | + info_span.innerHTML = sfgBadNumberErrorStr; |
| 384 | + return false; |
| 385 | + } |
| 386 | + } else if (type == 'date') { |
| 387 | + // validate only if day and year fields are both filled in |
| 388 | + day_field = document.getElementById(field_id + "_day"); |
| 389 | + year_field = document.getElementById(field_id + "_year"); |
| 390 | + if (day_field.value == '' || year_field.value == '') { |
| 391 | + return true; |
| 392 | + } else if (day_field.value.match(/^\d+$/) && |
| 393 | + day_field.value <= 31) { |
| 394 | + // no year validation, since it can also include |
| 395 | + // 'BC' and possibly other non-number strings |
| 396 | + return true; |
| 397 | + } else { |
| 398 | + info_span = document.getElementById(info_id); |
| 399 | + info_span.innerHTML = sfgBadDateErrorStr; |
| 400 | + return false; |
| 401 | + } |
| 402 | + } else { |
| 403 | + return true; |
| 404 | + } |
| 405 | + } |
| 406 | +} |
| 407 | + |
| 408 | +// same as validate_multiple_mandatory_fields(), but for type validation |
| 409 | +function validate_type_of_multiple_fields(field_num, type) { |
| 410 | + var num_errors = 0; |
| 411 | + elems = document.getElementsByTagName("*"); |
| 412 | + if ( ! elems) { elems = []; } |
| 413 | + var field_pattern = new RegExp('input_(.*)_' + field_num); |
| 414 | + for (var i = 0; i < elems.length; i++) { |
| 415 | + id = elems[i].id; |
| 416 | + if (matches = field_pattern.exec(id)) { |
| 417 | + instance_num = matches[1]; |
| 418 | + var input_name = "input_" + instance_num + "_" + field_num; |
| 419 | + var info_name = "info_" + instance_num + "_" + field_num; |
| 420 | + if (! validate_field_type(input_name, type, info_name)) { |
| 421 | + num_errors += 1; |
| 422 | + } |
| 423 | + } |
| 424 | + } |
| 425 | + return (num_errors == 0); |
| 426 | +} |
| 427 | + |
| 428 | +jQuery('#sfForm').submit( function() { return validate_all(); } ); |
| 429 | + |
| 430 | +function validate_all() { |
| 431 | + var num_errors = 0; |
| 432 | + |
| 433 | + for (var i = 0; i < sfgJSValidationCalls.length; i++ ) { |
| 434 | + if (! eval(sfgJSValidationCalls[i]) ) num_errors += 1; |
| 435 | + } |
| 436 | + |
| 437 | + if (num_errors > 0) { |
| 438 | + // add error header, if it's not there already |
| 439 | + if (! document.getElementById("form_error_header")) { |
| 440 | + var errorMsg = document.createElement('div'); |
| 441 | + errorMsg.innerHTML = '<div id="form_error_header" class="warningMessage" style="font-size: medium">' + sfgFormErrorsHeader + '</div>'; |
| 442 | + document.getElementById("contentSub").appendChild(errorMsg); |
| 443 | + } |
| 444 | + scroll(0, 0); |
| 445 | + } |
| 446 | + return (num_errors == 0); |
| 447 | +} |
| 448 | + |
| 449 | +var num_elements = 0; |
| 450 | + |
| 451 | +for (var i = 0; i < sfgAdderButtons.length; i++) { |
| 452 | + var components = sfgAdderButtons[i].split(','); |
| 453 | + adderID = components[0]; |
| 454 | + templateName = components[1]; |
| 455 | + fieldNum = components[2]; |
| 456 | + jQuery('#' + adderID).click( addInstanceEventHandler(templateName, fieldNum) ); |
| 457 | +} |
| 458 | + |
| 459 | +function addInstanceEventHandler(templateName, fieldNum) { |
| 460 | + return function() { |
| 461 | + addInstance('starter_' + templateName, 'main_' + templateName, fieldNum); |
| 462 | + } |
| 463 | +} |
| 464 | + |
| 465 | +function addInstance(starter_div_id, main_div_id, tab_index) |
| 466 | +{ |
| 467 | + var starter_div = document.getElementById(starter_div_id); |
| 468 | + var main_div = document.getElementById(main_div_id); |
| 469 | + num_elements++; |
| 470 | + |
| 471 | + //Create the new instance |
| 472 | + var new_div = starter_div.cloneNode(true); |
| 473 | + var div_id = 'div_gen_' + num_elements; |
| 474 | + new_div.className = 'multipleTemplate'; |
| 475 | + new_div.id = div_id; |
| 476 | + new_div.style.display = 'block'; |
| 477 | + |
| 478 | + // make internal ID unique for the relevant divs and spans, and replace |
| 479 | + // the [num] index in the element names with an actual unique index |
| 480 | + var children = new_div.getElementsByTagName('*'); |
| 481 | + // this array is needed to counteract an IE bug |
| 482 | + var orig_children = starter_div.getElementsByTagName('*'); |
| 483 | + var fancybox_ids = new Array(); |
| 484 | + var x; |
| 485 | + for (x = 0; x < children.length; x++) { |
| 486 | + if (children[x].name) |
| 487 | + children[x].name = children[x].name.replace(/\[num\]/g, '[' + num_elements + ']'); |
| 488 | + if (children[x].id) |
| 489 | + children[x].id = children[x].id |
| 490 | + .replace(/input_/g, 'input_' + num_elements + '_') |
| 491 | + .replace(/info_/g, 'info_' + num_elements + '_') |
| 492 | + .replace(/div_/g, 'div_' + num_elements + '_'); |
| 493 | + if (children[x].href) |
| 494 | + children[x].href = children[x].href |
| 495 | + .replace(/input_/g, 'input_' + num_elements + '_'); |
| 496 | + if (children[x].id.match("^fancybox")) { |
| 497 | + fancybox_ids.push(children[x].id); |
| 498 | + } |
| 499 | + |
| 500 | + // for dropdowns, copy over selectedIndex from original div, |
| 501 | + // to get around a bug in IE |
| 502 | + if (children[x].type == 'select-one') { |
| 503 | + children[x].selectedIndex = orig_children[x].selectedIndex; |
| 504 | + } |
| 505 | + } |
| 506 | + if (children[x]) { |
| 507 | + //We clone the last object |
| 508 | + if (children[x].href) { |
| 509 | + children[x].href = children[x].href |
| 510 | + .replace(/input_/g, 'input_' + num_elements + '_') |
| 511 | + .replace(/info_/g, 'info_' + num_elements + '_') |
| 512 | + .replace(/div_/g, 'div_' + num_elements + '_'); |
| 513 | + } |
| 514 | + } |
| 515 | + // Since we clone the first object and we have uploadable field |
| 516 | + // we must replace the input_ in order to let the printer return |
| 517 | + // the value into the right field |
| 518 | + //Create remove button |
| 519 | + var remove_button = document.createElement('input'); |
| 520 | + remove_button.type = 'button'; |
| 521 | + remove_button.value = sfgRemoveText; |
| 522 | + remove_button.tabIndex = tab_index; |
| 523 | + remove_button.onclick = removeInstanceEventHandler(div_id); |
| 524 | + new_div.appendChild(remove_button); |
| 525 | + |
| 526 | + //Add the new instance |
| 527 | + main_div.appendChild(new_div); |
| 528 | + attachAutocompleteToAllFields(new_div); |
| 529 | + |
| 530 | + // For each 'upload file' link in this latest instance, |
| 531 | + // add a call to fancybox() |
| 532 | + for (x = 0; x < fancybox_ids.length; x++) { |
| 533 | + jQuery("#" + fancybox_ids[x]).fancybox({ |
| 534 | + 'width' : '75%', |
| 535 | + 'height' : '75%', |
| 536 | + 'autoScale' : false, |
| 537 | + 'transitionIn' : 'none', |
| 538 | + 'transitionOut' : 'none', |
| 539 | + 'type' : 'iframe', |
| 540 | + 'overlayColor' : '#222', |
| 541 | + 'overlayOpacity' : '0.8' |
| 542 | + }); |
| 543 | + } |
| 544 | +} |
| 545 | + |
| 546 | +for (var i = 0; i < sfgRemoverButtons.length; i++) { |
| 547 | + var components = sfgRemoverButtons[i].split(','); |
| 548 | + removerID = components[0]; |
| 549 | + wrapperID = components[1]; |
| 550 | + jQuery('#' + removerID).click( removeInstanceEventHandler(wrapperID) ); |
| 551 | +} |
| 552 | + |
| 553 | +function removeInstanceEventHandler(divID) |
| 554 | +{ |
| 555 | + return function() { |
| 556 | + jQuery('#' + divID).remove(); |
| 557 | + }; |
| 558 | +} |
| 559 | + |
| 560 | +//Activate autocomplete functionality for every field on the document |
| 561 | +function attachAutocompleteToAllDocumentFields() |
| 562 | +{ |
| 563 | + var forms = document.getElementsByTagName("form"); |
| 564 | + var x; |
| 565 | + for (x = 0; x < forms.length; x++) { |
| 566 | + if (forms[x].name == "createbox") { |
| 567 | + attachAutocompleteToAllFields(forms[x]); |
| 568 | + } |
| 569 | + } |
| 570 | +} |
| 571 | + |
| 572 | +//Activate autocomplete functionality for every field under the specified element |
| 573 | +function attachAutocompleteToAllFields(base) |
| 574 | +{ |
| 575 | + var inputs = base.getElementsByTagName("input"); |
| 576 | + var y; |
| 577 | + for (y = 0; y < inputs.length; y++) { |
| 578 | + attachAutocompleteToField(inputs[y].id); |
| 579 | + } |
| 580 | + // don't forget the textareas |
| 581 | + inputs = base.getElementsByTagName("textarea"); |
| 582 | + for (y = 0; y < inputs.length; y++) { |
| 583 | + attachAutocompleteToField(inputs[y].id); |
| 584 | + } |
| 585 | +} |
| 586 | + |
| 587 | +//Activate autocomplete functionality for the specified field |
| 588 | +function attachAutocompleteToField(input_id) |
| 589 | +{ |
| 590 | + //Check input id for the proper format, to ensure this is for SF |
| 591 | + if (input_id.substr(0,6) == 'input_') |
| 592 | + { |
| 593 | + //Extract the field ID number from the input field |
| 594 | + var field_num = parseInt(input_id.substring(input_id.lastIndexOf('_') + 1, input_id.length),10); |
| 595 | + //Add the autocomplete string, if a mapping exists. |
| 596 | + var field_string = sfgAutocompleteMappings[field_num]; |
| 597 | + if (field_string) { |
| 598 | + var div_id = input_id.replace(/input_/g, 'div_'); |
| 599 | + var field_values = new Array(); |
| 600 | + field_values = field_string.split(','); |
| 601 | + var delimiter = null; |
| 602 | + var data_source = field_values[0]; |
| 603 | + if (field_values[1] == 'list') { |
| 604 | + delimiter = ","; |
| 605 | + if (field_values[2] != null) { |
| 606 | + delimiter = field_values[2]; |
| 607 | + } |
| 608 | + } |
| 609 | + if (sfgAutocompleteValues[field_string] != null) { |
| 610 | + sf_autocomplete(input_id, div_id, sfgAutocompleteValues[field_string], null, null, delimiter, data_source); |
| 611 | + } else { |
| 612 | + sf_autocomplete(input_id, div_id, null, wgScriptPath + "/api.php", sfgAutocompleteDataTypes[field_string], delimiter, data_source); |
| 613 | + } |
| 614 | + } |
| 615 | + } |
| 616 | +} |
| 617 | + |
| 618 | +for (var i = 0; i < sfgComboBoxInputs.length; i++ ) { |
| 619 | + var input_num = sfgComboBoxInputs[i]; |
| 620 | + jQuery(function() { |
| 621 | + jQuery("#input_" + input_num).combobox(); |
| 622 | + }); |
| 623 | +} |
| 624 | + |
| 625 | +jQuery.event.add(window, "load", attachAutocompleteToAllDocumentFields); |
| 626 | + |
| 627 | +for (var i = 0; i < sfgAutogrowInputs.length; i++ ) { |
| 628 | + var input_num = sfgAutogrowInputs[i]; |
| 629 | + jQuery(document).ready(function() { |
| 630 | + jQuery("#" + input_num).autoGrow(); |
| 631 | + }); |
| 632 | +} |
| 633 | + |
| 634 | + |
| 635 | + |
| 636 | +/* extending jquery functions */ |
| 637 | + |
234 | 638 | (function(jQuery) { |
235 | 639 | |
236 | 640 | jQuery.widget("ui.combobox", { |
— | — | @@ -275,7 +679,7 @@ |
276 | 680 | minLength: 0 |
277 | 681 | }) |
278 | 682 | .addClass("ui-widget ui-widget-content ui-corner-left"); |
279 | | - jQuery("<button type=\"button\"> </button>") |
| 683 | + jQuery('<button type="button"> </button>') |
280 | 684 | .attr("tabIndex", -1) |
281 | 685 | .attr("title", "Show All Items") |
282 | 686 | .insertAfter(input) |