r75193 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r75192‎ | r75193 | r75194 >
Date:15:37, 22 October 2010
Author:yaron
Status:deferred
Tags:
Comment:
Greatly expanded - added Javascript that was formerly included incline (most from SF_FormUtils.php); also got "show on select" working for the "listbox" input
Modified paths:
  • /trunk/extensions/SemanticForms/libs/SemanticForms.js (modified) (history)

Diff [purge]

Index: trunk/extensions/SemanticForms/libs/SemanticForms.js
@@ -1,11 +1,13 @@
22 /**
3 - * sf_autocomplete()
 3+ * SemanticForms.js
44 *
5 - * Javascript utitilies for the Semantic Forms extension, mostly related to
6 - * jQuery autocompletion.
 5+ * Javascript utility functions for the Semantic Forms extension.
76 *
 7+ * @author Yaron Koren
88 * @author Sanyam Goyal
9 - * @author Yaron Koren
 9+ * @author Jeffrey Stuckman
 10+ * @author Harold Solbrig
 11+ * @author Eugene Mednikov
1012 */
1113
1214 function isEmpty(obj) {
@@ -210,13 +212,34 @@
211213 the_div.style.display = 'none';
212214 }
213215
 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+
214237 // show the relevant div if any one of the relevant checkboxes are
215238 // checked - otherwise, hide it
216239 function showIfChecked(checkbox_inputs, div_id) {
217240 the_div = document.getElementById(div_id);
218241 for (var i in checkbox_inputs) {
219242 checkbox = document.getElementById(checkbox_inputs[i]);
220 - if (checkbox.checked) {
 243+ if (checkbox != null && checkbox.checked) {
221244 the_div.style.display = ''; // return to default
222245 return;
223246 }
@@ -224,12 +247,393 @@
225248 the_div.style.display = 'none';
226249 }
227250
 251+for (var i = 0; i < sfgShowOnSelectCalls.length; i++ ) {
 252+ eval(sfgShowOnSelectCalls[i]);
 253+}
228254
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+}
231274
 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+}
232287
 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+}
233311
 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+
234638 (function(jQuery) {
235639
236640 jQuery.widget("ui.combobox", {
@@ -275,7 +679,7 @@
276680 minLength: 0
277681 })
278682 .addClass("ui-widget ui-widget-content ui-corner-left");
279 - jQuery("<button type=\"button\">&nbsp;</button>")
 683+ jQuery('<button type="button">&nbsp;</button>')
280684 .attr("tabIndex", -1)
281685 .attr("title", "Show All Items")
282686 .insertAfter(input)

Status & tagging log