[ Index ]

PHP Cross Reference of phpwcms V1.5.0 _r431 (28.01.12)

title

Body

[close]

/include/inc_js/ -> dynamicoptionlist.js (source)

   1  /*===================================================================
   2   Author: Matt Kruse
   3   
   4   View documentation, examples, and source code at:
   5       http://www.JavascriptToolbox.com/
   6  
   7   NOTICE: You may use this code for any purpose, commercial or
   8   private, without any further permission from the author. You may
   9   remove this notice from your final code if you wish, however it is
  10   appreciated by the author if at least the web site address is kept.
  11  
  12   This code may NOT be distributed for download from script sites, 
  13   open source CDs or sites, or any other distribution method. If you
  14   wish you share this code with others, please direct them to the 
  15   web site above.
  16   
  17   Pleae do not link directly to the .js files on the server above. Copy
  18   the files to your own server for use with your site or webapp.
  19   ===================================================================*/
  20  // Global objects to keep track of DynamicOptionList objects created on the page
  21  var dynamicOptionListCount=0;
  22  var dynamicOptionListObjects = new Array();
  23  
  24  // Init call to setup lists after page load. One call to this function sets up all lists.
  25  function initDynamicOptionLists() {
  26      // init each DynamicOptionList object
  27      for (var i=0; i<dynamicOptionListObjects.length; i++) {
  28          var dol = dynamicOptionListObjects[i];
  29  
  30          // Find the form associated with this list
  31          if (dol.formName!=null) { 
  32              dol.form = document.forms[dol.formName];
  33          }
  34          else if (dol.formIndex!=null) {
  35              dol.form = document.forms[dol.formIndex];
  36          }
  37          else {
  38              // Form wasn't set manually, so go find it!
  39              // Search for the first form element name in the lists
  40              var name = dol.fieldNames[0][0];
  41              for (var f=0; f<document.forms.length; f++) {
  42                  if (typeof(document.forms[f][name])!="undefined") {
  43                      dol.form = document.forms[f];
  44                      break;
  45                  }
  46              }
  47              if (dol.form==null) {
  48                  alert("ERROR: Couldn't find form element "+name+" in any form on the page! Init aborted"); return;
  49              }
  50          }
  51  
  52          // Form is found, now set the onchange attributes of each dependent select box
  53          for (var j=0; j<dol.fieldNames.length; j++) {
  54              // For each set of field names...
  55              for (var k=0; k<dol.fieldNames[j].length-1; k++) {
  56                  // For each field in the set...
  57                  var selObj = dol.form[dol.fieldNames[j][k]];
  58                  if (typeof(selObj)=="undefined") { alert("Select box named "+dol.fieldNames[j][k]+" could not be found in the form. Init aborted"); return; }
  59                  // Map the HTML options in the first select into the options we created
  60                  if (k==0) {
  61                      if (selObj.options!=null) {
  62                          for (l=0; l<selObj.options.length; l++) {
  63                              var sopt = selObj.options[l];
  64                              var m = dol.findMatchingOptionInArray(dol.options,sopt.text,sopt.value,false);
  65                              if (m!=null) {
  66                                  var reselectForNN6 = sopt.selected;
  67                                  var m2 = new Option(sopt.text, sopt.value, sopt.defaultSelected, sopt.selected);
  68                                  m2.selected = sopt.selected; // For some reason I need to do this to make NN4 happy
  69                                  m2.defaultSelected = sopt.defaultSelected;
  70                                  m2.DOLOption = m;
  71                                  selObj.options[l] = m2;
  72                                  selObj.options[l].selected = reselectForNN6; // Reselect this option for NN6 to be happy. Yuck.
  73                              }
  74                          }
  75                      }
  76                  }
  77                  if (selObj.onchange==null) {
  78                      // We only modify the onChange attribute if it's empty! Otherwise do it yourself in your source!
  79                      selObj.onchange = new Function("dynamicOptionListObjects["+dol.index+"].change(this)");
  80                  }
  81              }
  82          }
  83      }
  84      // Set the preselectd options on page load 
  85      resetDynamicOptionLists();
  86  }
  87  
  88  // This function populates lists with the preselected values. 
  89  // It's pulled out into a separate function so it can be hooked into a 'reset' button on a form
  90  // Optionally passed a form object which should be the only form reset
  91  function resetDynamicOptionLists(theform) {
  92      // reset each DynamicOptionList object
  93      for (var i=0; i<dynamicOptionListObjects.length; i++) {
  94          var dol = dynamicOptionListObjects[i];
  95          if (typeof(theform)=="undefined" || theform==null || theform==dol.form) {
  96              for (var j=0; j<dol.fieldNames.length; j++) {
  97                  dol.change(dol.form[dol.fieldNames[j][0]],true); // Second argument says to use preselected values rather than default values
  98              }
  99          }
 100      }
 101  }
 102  
 103  // An object to represent an Option() but just for data-holding
 104  function DOLOption(text,value,defaultSelected,selected) {
 105      this.text = text;
 106      this.value = value;
 107      this.defaultSelected = defaultSelected;
 108      this.selected = selected;
 109      this.options = new Array(); // To hold sub-options
 110      return this;
 111  }
 112  
 113  // DynamicOptionList CONSTRUCTOR
 114  function DynamicOptionList() {
 115      this.form = null;// The form this list belongs to
 116      this.options = new Array();// Holds the options of dependent lists
 117      this.longestString = new Array();// Longest string that is currently a potential option (for Netscape)
 118      this.numberOfOptions = new Array();// The total number of options that might be displayed, to build dummy options (for Netscape)
 119      this.currentNode = null;// The current node that has been selected with forValue() or forText()
 120      this.currentField = null;// The current field that is selected to be used for setValue()
 121      this.currentNodeDepth = 0;// How far down the tree the currentNode is
 122      this.fieldNames = new Array();// Lists of dependent fields which use this object
 123      this.formIndex = null;// The index of the form to associate with this list
 124      this.formName = null;// The name of the form to associate with this list
 125      this.fieldListIndexes = new Object();// Hold the field lists index where fields exist
 126      this.fieldIndexes = new Object();// Hold the index within the list where fields exist
 127      this.selectFirstOption = true;// Whether or not to select the first option by default if no options are default or preselected, otherwise set the selectedIndex = -1
 128      this.numberOfOptions = new Array();// Store the max number of options for a given option list
 129      this.longestString = new Array();// Store the longest possible string 
 130      this.values = new Object(); // Will hold the preselected values for fields, by field name
 131      
 132      // Method mappings
 133      this.forValue = DOL_forValue;
 134      this.forText = DOL_forText;
 135      this.forField = DOL_forField;
 136      this.forX = DOL_forX;
 137      this.addOptions = DOL_addOptions;
 138      this.addOptionsTextValue = DOL_addOptionsTextValue;
 139      this.setDefaultOptions = DOL_setDefaultOptions;
 140      this.setValues = DOL_setValues;
 141      this.setValue = DOL_setValues;
 142      this.setFormIndex = DOL_setFormIndex;
 143      this.setFormName = DOL_setFormName;
 144      this.printOptions = DOL_printOptions;
 145      this.addDependentFields = DOL_addDependentFields;
 146      this.change = DOL_change;
 147      this.child = DOL_child;
 148      this.selectChildOptions = DOL_selectChildOptions;
 149      this.populateChild = DOL_populateChild;
 150      this.change = DOL_change;
 151      this.addNewOptionToList = DOL_addNewOptionToList;
 152      this.findMatchingOptionInArray = DOL_findMatchingOptionInArray;
 153  
 154      // Optionally pass in the dependent field names
 155      if (arguments.length > 0) {
 156          // Process arguments and add dependency groups
 157          for (var i=0; i<arguments.length; i++) {
 158              this.fieldListIndexes[arguments[i].toString()] = this.fieldNames.length;
 159              this.fieldIndexes[arguments[i].toString()] = i;
 160          }
 161          this.fieldNames[this.fieldNames.length] = arguments;
 162      }
 163      
 164      // Add this object to the global array of dynamicoptionlist objects
 165      this.index = window.dynamicOptionListCount++;
 166      window["dynamicOptionListObjects"][this.index] = this;
 167  }
 168  
 169  // Given an array of Option objects, search for an existing option that matches value, text, or both
 170  function DOL_findMatchingOptionInArray(a,text,value,exactMatchRequired) {
 171      if (a==null || typeof(a)=="undefined") { return null; }
 172      var value_match = null; // Whether or not a value has been matched
 173      var text_match = null; // Whether or not a text has been matched
 174      for (var i=0; i<a.length; i++) {
 175          var opt = a[i];
 176          // If both value and text match, return it right away
 177          if (opt.value==value && opt.text==text) { return opt; }
 178          if (!exactMatchRequired) {
 179              // If value matches, store it until we complete scanning the list
 180              if (value_match==null && value!=null && opt.value==value) {
 181                  value_match = opt;
 182              }
 183              // If text matches, store it for later
 184              if (text_match==null && text!=null && opt.text==text) {
 185                  text_match = opt;
 186              }
 187          }
 188      }
 189      return (value_match!=null)?value_match:text_match;
 190  }
 191  
 192  // Util function used by forValue and forText
 193  function DOL_forX(s,type) {
 194      if (this.currentNode==null) { this.currentNodeDepth=0; }
 195      var useNode = (this.currentNode==null)?this:this.currentNode;
 196      var o = this.findMatchingOptionInArray(useNode["options"],(type=="text")?s:null,(type=="value")?s:null,false);
 197      if (o==null) {
 198          o = new DOLOption(null,null,false,false);
 199          o[type] = s;
 200          useNode.options[useNode.options.length] = o;
 201      }
 202      this.currentNode = o;
 203      this.currentNodeDepth++;
 204      return this;
 205  }
 206  
 207  // Set the portion of the list structure that is to be used by a later operation like addOptions
 208  function DOL_forValue(s) { return this.forX(s,"value"); }
 209  
 210  // Set the portion of the list structure that is to be used by a later operation like addOptions
 211  function DOL_forText(s) { return this.forX(s,"text"); }
 212  
 213  // Set the field to be used for setValue() calls
 214  function DOL_forField(f) { this.currentField = f; return this; }
 215  
 216  // Create and add an option to a list, avoiding duplicates
 217  function DOL_addNewOptionToList(a, text, value, defaultSelected) {
 218      var o = new DOLOption(text,value,defaultSelected,false);
 219      // Add the option to the array
 220      if (a==null) { a = new Array(); }
 221      for (var i=0; i<a.length; i++) {
 222          if (a[i].text==o.text && a[i].value==o.value) {
 223              if (o.selected) { 
 224                  a[i].selected=true;
 225              }
 226              if (o.defaultSelected) {
 227                  a[i].defaultSelected = true;
 228              }
 229              return a;
 230          }
 231      }
 232      a[a.length] = o;
 233  }
 234  
 235  // Add sub-options to the currently-selected node, with the same text and value for each option
 236  function DOL_addOptions() {
 237      if (this.currentNode==null) { this.currentNode = this; }
 238      if (this.currentNode["options"] == null) { this.currentNode["options"] = new Array(); }
 239      for (var i=0; i<arguments.length; i++) {
 240          var text = arguments[i];
 241          this.addNewOptionToList(this.currentNode.options,text,text,false);
 242          if (typeof(this.numberOfOptions[this.currentNodeDepth])=="undefined") {
 243              this.numberOfOptions[this.currentNodeDepth]=0;
 244          }
 245          if (this.currentNode.options.length > this.numberOfOptions[this.currentNodeDepth]) {
 246              this.numberOfOptions[this.currentNodeDepth] = this.currentNode.options.length;
 247          }
 248          if (typeof(this.longestString[this.currentNodeDepth])=="undefined" || (text.length > this.longestString[this.currentNodeDepth].length)) {
 249              this.longestString[this.currentNodeDepth] = text;
 250          }
 251      }
 252      this.currentNode = null;
 253      this.currentNodeDepth = 0;
 254  }
 255  
 256  // Add sub-options to the currently-selected node, specifying separate text and values for each option
 257  function DOL_addOptionsTextValue() {
 258      if (this.currentNode==null) { this.currentNode = this; }
 259      if (this.currentNode["options"] == null) { this.currentNode["options"] = new Array(); }
 260      for (var i=0; i<arguments.length; i++) {
 261          var text = arguments[i++];
 262          var value = arguments[i];
 263          this.addNewOptionToList(this.currentNode.options,text,value,false);
 264          if (typeof(this.numberOfOptions[this.currentNodeDepth])=="undefined") {
 265              this.numberOfOptions[this.currentNodeDepth]=0;
 266          }
 267          if (this.currentNode.options.length > this.numberOfOptions[this.currentNodeDepth]) {
 268              this.numberOfOptions[this.currentNodeDepth] = this.currentNode.options.length;
 269          }
 270          if (typeof(this.longestString[this.currentNodeDepth])=="undefined" || (text.length > this.longestString[this.currentNodeDepth].length)) {
 271              this.longestString[this.currentNodeDepth] = text;
 272          }
 273      }
 274      this.currentNode = null;
 275      this.currentNodeDepth = 0;
 276  }
 277  
 278  // Find the first dependent list of a select box
 279  // If it's the last list in a chain, return null because there are no children
 280  function DOL_child(obj) {
 281      var listIndex = this.fieldListIndexes[obj.name];
 282      var index = this.fieldIndexes[obj.name];
 283      if (index < (this.fieldNames[listIndex].length-1)) {
 284          return this.form[this.fieldNames[listIndex][index+1]];
 285      }
 286      return null;
 287  }
 288  
 289  // Set the options which should be selected by default for a certain value in the parent
 290  function DOL_setDefaultOptions() {
 291      if (this.currentNode==null) { this.currentNode = this; }
 292      for (var i=0; i<arguments.length; i++) {
 293          var o = this.findMatchingOptionInArray(this.currentNode.options,null,arguments[i],false);
 294          if (o!=null) {
 295              o.defaultSelected = true;
 296          }
 297      }
 298      this.currentNode = null;
 299  }
 300  
 301  // Set the options which should be selected when the page loads. This is different than the default value and ONLY applies when the page LOADS
 302  function DOL_setValues() {
 303      if (this.currentField==null) { 
 304          alert("Can't call setValues() without using forField() first!");
 305          return;
 306      }
 307      if (typeof(this.values[this.currentField])=="undefined") {
 308          this.values[this.currentField] = new Object();
 309      }
 310      for (var i=0; i<arguments.length; i++) {
 311          this.values[this.currentField][arguments[i]] = true;
 312      }
 313      this.currentField = null;
 314  }
 315  
 316  // Manually set the form for the object using an index
 317  function DOL_setFormIndex(i) {
 318      this.formIndex = i;
 319  }
 320  
 321  // Manually set the form for the object using a form name
 322  function DOL_setFormName(n) {
 323      this.formName = n;
 324  }
 325  
 326  // Print blank <option> objects for Netscape4, since it refuses to grow or shrink select boxes for new options
 327  function DOL_printOptions(name) {
 328      // Only need to write out "dummy" options for Netscape4
 329      if ((navigator.appName == 'Netscape') && (parseInt(navigator.appVersion) <= 4)){
 330          var index = this.fieldIndexes[name];
 331          var ret = "";
 332          if (typeof(this.numberOfOptions[index])!="undefined") {
 333              for (var i=0; i<this.numberOfOptions[index]; i++) { 
 334                  ret += "<OPTION>";
 335              }
 336          }
 337          ret += "<OPTION>";
 338          if (typeof(this.longestString[index])!="undefined") {
 339              for (var i=0; i<this.longestString[index].length; i++) {
 340                  ret += "_";
 341              }
 342          }
 343          document.writeln(ret);
 344      }
 345  }
 346  
 347  // Add a list of field names which use this option-mapping object.
 348  // A single mapping object may be used by multiple sets of fields
 349  function DOL_addDependentFields() {
 350      for (var i=0; i<arguments.length; i++) {
 351          this.fieldListIndexes[arguments[i].toString()] = this.fieldNames.length;
 352          this.fieldIndexes[arguments[i].toString()] = i;
 353      }
 354      this.fieldNames[this.fieldNames.length] = arguments;
 355  }
 356  
 357  // Called when a parent select box is changed. It populates its direct child, then calls change on the child object to continue the population.
 358  function DOL_change(obj, usePreselected) {
 359      if (usePreselected==null || typeof(usePreselected)=="undefined") { usePreselected = false; }
 360      var changedListIndex = this.fieldListIndexes[obj.name];
 361      var changedIndex = this.fieldIndexes[obj.name];
 362      var child = this.child(obj);
 363      if (child == null) { return; } // No child, no need to continue
 364      if (obj.type == "select-one") {
 365          // Treat single-select differently so we don't have to scan the entire select list, which could potentially speed things up
 366          if (child.options!=null) {
 367              child.options.length=0; // Erase all the options from the child so we can re-populate
 368          }
 369          if (obj.options!=null && obj.options.length>0 && obj.selectedIndex>=0) {
 370              var o = obj.options[obj.selectedIndex];
 371              this.populateChild(o.DOLOption,child,usePreselected);
 372              this.selectChildOptions(child,usePreselected);
 373          }
 374      }
 375      else if (obj.type == "select-multiple") {
 376          // For each selected value in the parent, find the options to fill in for this list
 377          // Loop through the child list and keep track of options that are currently selected
 378          var currentlySelectedOptions = new Array();
 379          if (!usePreselected) {
 380              for (var i=0; i<child.options.length; i++) {
 381                  var co = child.options[i];
 382                  if (co.selected) {
 383                      this.addNewOptionToList(currentlySelectedOptions, co.text, co.value, co.defaultSelected);
 384                  }
 385              }
 386          }
 387          child.options.length=0;
 388          if (obj.options!=null) {
 389              var obj_o = obj.options;
 390              // For each selected option in the parent...
 391              for (var i=0; i<obj_o.length; i++) {
 392                  if (obj_o[i].selected) {
 393                      // if option is selected, add its children to the list
 394                       this.populateChild(obj_o[i].DOLOption,child,usePreselected);
 395                  }
 396              }
 397              // Now go through and re-select any options which were selected before
 398              var atLeastOneSelected = false;
 399              if (!usePreselected) {
 400                  for (var i=0; i<child.options.length; i++) {
 401                      var m = this.findMatchingOptionInArray(currentlySelectedOptions,child.options[i].text,child.options[i].value,true);
 402                      if (m!=null) {
 403                          child.options[i].selected = true;
 404                          atLeastOneSelected = true;
 405                      }
 406                  }
 407              }
 408              if (!atLeastOneSelected) {    
 409                  this.selectChildOptions(child,usePreselected);
 410              }
 411          }
 412      }
 413      // Change all the way down the chain
 414      this.change(child,usePreselected);
 415  }
 416  function DOL_populateChild(dolOption,childSelectObj,usePreselected) {
 417      // If this opton has sub-options, populate the child list with them
 418      if (dolOption!=null && dolOption.options!=null) {
 419          for (var j=0; j<dolOption.options.length; j++) {
 420              var srcOpt = dolOption.options[j];
 421              if (childSelectObj.options==null) { childSelectObj.options = new Array(); }
 422              // Put option into select list
 423              var duplicate = false;
 424              var preSelectedExists = false;
 425              for (var k=0; k<childSelectObj.options.length; k++) {
 426                  var csi = childSelectObj.options[k];
 427                  if (csi.text==srcOpt.text && csi.value==srcOpt.value) {
 428                      duplicate = true;
 429                      break;
 430                  }
 431              }
 432              if (!duplicate) {
 433                  var newopt = new Option(srcOpt.text, srcOpt.value, false, false);
 434                  newopt.selected = false; // Again, we have to do these two statements for NN4 to work
 435                  newopt.defaultSelected = false;
 436                  newopt.DOLOption = srcOpt;
 437                  childSelectObj.options[childSelectObj.options.length] = newopt;
 438              }
 439          }
 440      }
 441  }
 442  
 443  // Once a child select is populated, go back over it to select options which should be selected
 444  function DOL_selectChildOptions(obj,usePreselected) {
 445      // Look to see if any options are preselected=true. If so, then set then selected if usePreselected=true, otherwise set defaults
 446      var values = this.values[obj.name];
 447      var preselectedExists = false;
 448      if (usePreselected && values!=null && typeof(values)!="undefined") {
 449          for (var i=0; i<obj.options.length; i++) {
 450              var v = obj.options[i].value;
 451              if (v!=null && values[v]!=null && typeof(values[v])!="undefined") {
 452                  preselectedExists = true;
 453                  break;
 454              }
 455          }
 456      }
 457      // Go back over all the options to do the selection
 458      var atLeastOneSelected = false;
 459      for (var i=0; i<obj.options.length; i++) {
 460          var o = obj.options[i];
 461          if (preselectedExists && o.value!=null && values[o.value]!=null && typeof(values[o.value])!="undefined") {
 462              o.selected = true;
 463              atLeastOneSelected = true;
 464          }
 465          else if (!preselectedExists && o.DOLOption!=null && o.DOLOption.defaultSelected) {
 466              o.selected = true;
 467              atLeastOneSelected = true;
 468          }
 469          else {
 470              o.selected = false;
 471          }
 472      }
 473      // If nothing else was selected, select the first one by default
 474      if (this.selectFirstOption && !atLeastOneSelected && obj.options.length>0) {
 475          obj.options[0].selected = true;
 476      }
 477      else if (!atLeastOneSelected &&  obj.type=="select-one") {
 478          obj.selectedIndex = -1;
 479      }
 480  }


Generated: Sun Jan 29 16:31:14 2012 Cross-referenced by PHPXref 0.7.1