[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/sites/all/modules/options_element/ -> options_element.js (source)

   1  
   2  /**
   3   * @file
   4   * Add JavaScript behaviors for the "options" form element type.
   5   */
   6  
   7  (function($) {
   8  
   9  Drupal.optionElements = Drupal.optionElements || {};
  10  
  11  Drupal.behaviors.optionsElement = function(context) {
  12    $('div.form-options:not(.options-element-processed)', context).each(function() {
  13      $(this).addClass('options-element-processed');
  14      var optionsElement = new Drupal.optionsElement(this);
  15      Drupal.optionElements[optionsElement.identifier] = optionsElement;
  16    });
  17  };
  18  
  19  /**
  20   * Constructor for an options element.
  21   */
  22  Drupal.optionsElement = function(element) {
  23    var self = this;
  24  
  25    // Find the original "manual" fields.
  26    this.element = element;
  27    this.manualElement = $(element).find('fieldset.options, div.fieldset.options').get(0);
  28    this.manualOptionsElement = $(element).find('textarea').get(0);
  29    this.manualDefaultValueElement = $(element).find('input.form-text').get(0);
  30    this.keyTypeToggle = $(element).find('input.key-type-toggle').get(0);
  31    this.multipleToggle = $(element).find('input.multiple-toggle').get(0);
  32  
  33    // Setup variables containing the current status of the widget.
  34    this.optgroups = $(element).is('.options-optgroups');
  35    this.multiple = $(element).is('.options-multiple');
  36    this.keyType = element.className.replace(/^.*?options-key-type-([a-z]+).*?$/, '$1');
  37    this.customKeys = Boolean(element.className.match(/options-key-custom/));
  38    this.identifier = this.manualOptionsElement.id + '-widget';
  39    this.enabled = $(this.manualOptionsElement).attr('readonly') == '';
  40    this.defaultValuePattern = $(element).find('input.default-value-pattern').val();
  41  
  42    if (this.defaultValuePattern) {
  43      this.defaultValuePattern = new RegExp(this.defaultValuePattern);
  44    }
  45  
  46    // Warning messages.
  47    this.keyChangeWarning = Drupal.t('Custom keys have been specified in this list. Removing these custom keys may change way data is stored. Are you sure you wish to remove these custom keys?');
  48  
  49    // Setup new DOM elements containing the actual options widget.
  50    this.optionsElement = $('<div></div>').get(0); // Temporary DOM object.
  51    this.optionsToggleElement = $(Drupal.theme('optionsElementToggle')).get(0);
  52    this.optionAddElement = $(Drupal.theme('optionsElementAdd')).get(0);
  53  
  54    // Add the options widget and toggle elements to the page.
  55    $(this.manualElement).css('display', 'none').before(this.optionsElement).after(this.optionsToggleElement).after(this.optionAddElement);
  56  
  57    // Enable add item link.
  58    $(this.optionAddElement).find('a').click(function() {
  59      var newOption = self.addOption($('table tr:last', self.optionsElement).get(0));
  60      $(newOption).find('input[type=text]:visible:first').focus();
  61      return false;
  62    });
  63  
  64    // Enable the toggle action for manual entry of options.
  65    $(this.optionsToggleElement).find('a').click(function() {
  66      self.toggleMode();
  67      return false;
  68    });
  69  
  70    // Add a handler for key type changes.
  71    if (this.keyTypeToggle) {
  72      $(this.keyTypeToggle).click(function() {
  73        var checked = $(this).attr('checked');
  74        // Before switching the key type, ensure we're not destroying user keys.
  75        if (!checked) {
  76          var options = self.optionsFromText();
  77          var confirm = false;
  78          if (self.keyType == 'associative') {
  79            for (var n = 0; n < options.length; n++) {
  80              if (options[n].key != options[n].value) {
  81                confirm = true;
  82                break;
  83              }
  84            }
  85          }
  86          if (confirm) {
  87            if (window.confirm(self.keyChangeWarning)) {
  88              self.setCustomKeys(false);
  89            }
  90          }
  91          else {
  92            self.setCustomKeys(false);
  93          }
  94        }
  95        else {
  96          self.setCustomKeys(true);
  97        }
  98      });
  99    }
 100  
 101    // Add a handler for multiple value changes.
 102    if (this.multipleToggle) {
 103      $(this.multipleToggle).click(function(){
 104        self.setMultiple($(this).attr('checked'));
 105      });
 106    }
 107  
 108    // Be sure to show the custom keys if we have any errors.
 109    if (Drupal.settings.optionsElement && Drupal.settings.optionsElement.errors) {
 110      this.customKeys = true;
 111    }
 112  
 113    // Update the options widget with the current state of the textarea.
 114    this.updateWidgetElements();
 115  
 116    // Highlight errors that may have occurred during Drupal validation.
 117    if (Drupal.settings.optionsElement && Drupal.settings.optionsElement.errors) {
 118      this.checkKeys(Drupal.settings.optionsElement.errors, 'error');
 119    }
 120  }
 121  
 122  /**
 123   * Update the widget element based on the current values of the manual elements.
 124   */
 125  Drupal.optionsElement.prototype.updateWidgetElements = function() {
 126    var self = this;
 127  
 128    // Create a new options element and replace the existing one.
 129    var newElement = $(Drupal.theme('optionsElement', this)).get(0);
 130    if ($(this.optionsElement).css('display') == 'none') {
 131      $(newElement).css('display', 'none');
 132    }
 133    $(this.optionsElement).replaceWith(newElement);
 134    this.optionsElement = newElement;
 135  
 136    // Manually set up table drag for the created table.
 137    Drupal.settings.tableDrag = Drupal.settings.tableDrag || {};
 138    Drupal.settings.tableDrag[this.identifier] = {
 139      'option-depth': {
 140        0: {
 141          action: 'depth',
 142          hidden: false,
 143          limit: 0,
 144          relationship: 'self',
 145          source: 'option-depth',
 146          target: 'option-depth'
 147        }
 148      }
 149    };
 150  
 151    // Allow indentation of elements if optgroups are supported.
 152    if (this.optgroups) {
 153      Drupal.settings.tableDrag[this.identifier]['option-parent'] = {
 154        0: {
 155          action: 'match',
 156          hidden: false,
 157          limit: 1,
 158          relationship: 'parent',
 159          source: 'option-value',
 160          target: 'option-parent'
 161        }
 162      };
 163    }
 164  
 165    // Enable button for adding options.
 166    $('a.add', this.optionsElement).click(function() {
 167      var newOption = self.addOption($(this).parents('tr:first').get(0));
 168      $(newOption).find('input[type=text]:visible:first').focus();
 169      return false;
 170    });
 171  
 172    // Enable button for removing options.
 173    $('a.remove', this.optionsElement).click(function() {
 174      self.removeOption($(this).parents('tr:first').get(0));
 175      return false;
 176    });
 177  
 178    // Add the same update action to all textfields and radios.
 179    $('input', this.optionsElement).change(function() {
 180      self.updateOptionElements();
 181      self.updateManualElements();
 182    });
 183  
 184    // Add a delayed update to textfields.
 185    $('input.option-value', this.optionsElement).keyup(function(e) {
 186      self.pendingUpdate(e);
 187    });
 188  
 189    // Attach behaviors as normal to the new widget.
 190    Drupal.attachBehaviors(this.optionsElement);
 191  
 192    // Add an onDrop action to the table drag instance.
 193    Drupal.tableDrag[this.identifier].onDrop = function() {
 194      // Update the checkbox/radio buttons for selecting default values.
 195      if (self.optgroups) {
 196        self.updateOptionElements();
 197      }
 198      // Update the options within the hidden text area.
 199      self.updateManualElements();
 200    };
 201  
 202    // Add an onIndent action to the table drag row instances.
 203    Drupal.tableDrag[this.identifier].row.prototype.onIndent = function() {
 204      if (this.indents) {
 205        $(this.element).addClass('indented');
 206      }
 207      else {
 208        $(this.element).removeClass('indented');
 209      }
 210    };
 211  
 212    // Update the default value and optgroups.
 213    this.updateOptionElements();
 214  }
 215  
 216  /**
 217   * Update the original form element based on the current state of the widget.
 218   */
 219  Drupal.optionsElement.prototype.updateManualElements = function() {
 220    var options = {};
 221  
 222    // Build a list of current options.
 223    var previousOption = false;
 224    $(this.optionsElement).find('input.option-value').each(function() {
 225      var $row = $(this).is('tr') ? $(this) : $(this).parents('tr:first');
 226      var depth = $row.find('input.option-depth').val();
 227      if (depth == 1 && previousOption) {
 228        if (typeof(options[previousOption]) != 'object') {
 229          options[previousOption] = {};
 230        }
 231        options[previousOption][this.value] = this.value;
 232      }
 233      else {
 234        options[this.value] = this.value;
 235        previousOption = this.value;
 236      }
 237    });
 238    this.options = options;
 239  
 240    // Update the default value.
 241    var defaultValue = this.multiple ? [] : '';
 242    var multiple = this.multiple;
 243    $(this.optionsElement).find('input.option-default').each(function() {
 244      if (this.checked && this.value) {
 245        if (multiple) {
 246          defaultValue.push(this.value);
 247        }
 248        else {
 249          defaultValue = this.value;
 250        }
 251      }
 252    });
 253    this.defaultValue = defaultValue;
 254  
 255    // Update with the new text and trigger the change action on the field.
 256    this.optionsToText();
 257  
 258    if (this.manualDefaultValueElement) {
 259      // Don't wipe out custom pattern-matched default values.
 260      defaultValue = multiple ? defaultValue.join(', ') : defaultValue;
 261      if (defaultValue || !(this.defaultValuePattern && this.defaultValuePattern.test(this.manualDefaultValueElement.value))) {
 262        this.manualDefaultValueElement.value = defaultValue;
 263        $('.default-value-pattern-match', this.element).remove();
 264      }
 265    }
 266  
 267    $(this.manualOptionsElement).change();
 268  }
 269  
 270  /**
 271   * Several maintenance routines to update all rows of the options element.
 272   *
 273   * - Disable options for optgroups if indented.
 274   * - Disable add and delete links if indented.
 275   * - Match the default value radio button value to the key of the text element.
 276   */
 277  Drupal.optionsElement.prototype.updateOptionElements = function() {
 278    var self = this;
 279    var previousRow = false;
 280    var previousElement = false;
 281    var $rows = $(this.optionsElement).find('tbody tr');
 282  
 283    $rows.each(function(index) {
 284      var optionValue = $(this).find('input.option-value').val();
 285      var optionKey = $(this).find('input.option-key').val();
 286  
 287      // Update the elements key if matching the key and value.
 288      if (self.keyType == 'associative') {
 289        $(this).find('input.option-key').val(optionValue);
 290      }
 291  
 292      // Match the default value checkbox/radio button to the option's key.
 293      $(this).find('input.option-default').val(optionKey ? optionKey : optionValue);
 294  
 295      // Hide the add/remove links the row if indented.
 296      var depth = $(this).find('input.option-depth').val();
 297      var defaultInput = $(this).find('input.option-default').get(0);
 298  
 299      if (depth == 1) {
 300        // Affect the parent row, adjusting properties for optgroup items.
 301        $(previousElement).attr('disabled', true).attr('checked', false);
 302        $(previousRow).addClass('optgroup').find('a.add, a.remove').css('display', 'none');
 303        $(this).find('a.add, a.remove').css('display', '');
 304        $(defaultInput).attr('disabled', false);
 305  
 306        // Hide the key column for the optgroup. It would be nice if hiding
 307        // columns worked in IE7, but for now this only works in IE8 and other
 308        // standards-compliant browsers.
 309        if (self.customKeys && (!$.browser.msie || $.browser.version >= 8)) {
 310          $(previousRow).find('td.option-key-cell').css('display', 'none');
 311          $(previousRow).find('td.option-value-cell').attr('colspan', 2);
 312        }
 313      }
 314      else {
 315        // Set properties for normal options that are not optgroups.
 316        $(defaultInput).attr('disabled', false);
 317        $(this).removeClass('optgroup').find('a.add, a.remove').css('display', '');
 318  
 319        // Hide the key column. See note above for compatibility concerns.
 320        if (self.customKeys && (!$.browser.msie || $.browser.version >= 8)) {
 321          $(this).find('td.option-key-cell').css('display', '');
 322          $(this).find('td.option-value-cell').attr('colspan', '');
 323        }
 324        previousElement = defaultInput;
 325        previousRow = this;
 326      }
 327    });
 328  
 329    // Do not allow the last item to be removed.
 330    if ($rows.size() == 1) {
 331      $rows.find('a.remove').css('display', 'none')
 332    }
 333  
 334    // Disable items if needed.
 335    if (this.enabled == false) {
 336      this.disable();
 337    }
 338  }
 339  
 340  /**
 341   * Add a new option below the current row.
 342   */
 343  Drupal.optionsElement.prototype.addOption = function(currentOption) {
 344    var self = this;
 345    var windowHieght = $(document).height();
 346    var newOption = $(currentOption).clone()
 347      .find('input.option-key').val(self.keyType == 'numeric' ? self.nextNumericKey() : '').end()
 348      .find('input.option-value').val('').end()
 349      .find('input.option-default').attr('checked', false).end()
 350      .find('a.tabledrag-handle').remove().end()
 351      .removeClass('drag-previous')
 352      .insertAfter(currentOption)
 353      .get(0);
 354  
 355    // Scroll down to accomidate the new option.
 356    $(window).scrollTop($(window).scrollTop() + $(document).height() - windowHieght);
 357  
 358    // Make the new option draggable.
 359    Drupal.tableDrag[this.identifier].makeDraggable(newOption);
 360  
 361    // Enable button for adding options.
 362    $('a.add', newOption).click(function() {
 363      var newOption = self.addOption($(this).parents('tr:first').get(0));
 364      $(newOption).find('input[type=text]:visible:first').focus();
 365      return false;
 366    });
 367  
 368    // Enable buttons for removing options.
 369    $('a.remove', newOption).click(function() {
 370      self.removeOption(newOption);
 371      return false;
 372    });
 373  
 374    // Add the update action to all textfields and radios.
 375    $('input', newOption).change(function() {
 376      self.updateOptionElements();
 377      self.updateManualElements();
 378    });
 379  
 380    // Add a delayed update to textfields.
 381    $('input.option-value', newOption).keyup(function(e) {
 382      self.pendingUpdate(e);
 383    });
 384  
 385    this.updateOptionElements();
 386    this.updateManualElements();
 387  
 388    return newOption;
 389  }
 390  
 391  /**
 392   * Remove the current row.
 393   */
 394  Drupal.optionsElement.prototype.removeOption = function(currentOption) {
 395    $(currentOption).remove();
 396  
 397    this.updateOptionElements();
 398    this.updateManualElements();
 399  }
 400  
 401  /**
 402   * Toggle link for switching between the JavaScript and manual entry.
 403   */
 404  Drupal.optionsElement.prototype.toggleMode = function() {
 405    if ($(this.optionsElement).is(':visible')) {
 406      var height = $(this.optionsElement).height();
 407      $(this.optionsElement).css('display', 'none');
 408      $(this.optionAddElement).css('display', 'none');
 409      $(this.manualElement).css('display', '').find('textarea').height(height);
 410      $(this.optionsToggleElement).find('a').text(Drupal.t('Normal entry'));
 411    }
 412    else {
 413      this.updateWidgetElements();
 414      $(this.optionsElement).css('display', '');
 415      $(this.optionAddElement).css('display', '');
 416      $(this.manualElement).css('display', 'none');
 417      $(this.optionsToggleElement).find('a').text(Drupal.t('Manual entry'));
 418    }
 419  }
 420  
 421  /**
 422   * Enable the changing of options.
 423   */
 424  Drupal.optionsElement.prototype.enable = function() {
 425    this.enabled = true;
 426    $(this.manualOptionsElement).attr('readonly', '');
 427    $(this.element).removeClass('options-disabled');
 428  
 429    $('a.add, a.remove, a.tabledrag-handle, div.form-option-add a', this.element).css('display', '');
 430    $('input.form-text', this.optionsElement).attr('disabled', '');
 431  };
 432  
 433  /**
 434   * Disable the changing of options.
 435   */
 436  Drupal.optionsElement.prototype.disable = function() {
 437    this.enabled = false;
 438    $(this.manualOptionsElement).attr('readonly', true);
 439    $(this.element).addClass('options-disabled');
 440  
 441    $('a.add, a.remove, a.tabledrag-handle, div.form-option-add a', this.element).css('display', 'none');
 442    $('input.form-text', this.optionsElement).attr('disabled', 'disabled');
 443  };
 444  
 445  /**
 446   * Enable entering of custom key values.
 447   */
 448  Drupal.optionsElement.prototype.setCustomKeys = function(enabled) {
 449    if (enabled) {
 450      $(this.element).addClass('options-key-custom');
 451    }
 452    else {
 453      $(this.element).removeClass('options-key-custom');
 454    }
 455  
 456    this.customKeys = enabled;
 457    // Rebuild the options widget.
 458    this.updateManualElements();
 459    this.updateWidgetElements();
 460  }
 461  
 462  /**
 463   * Change the current key type (associative, custom, numeric, none).
 464   */
 465  Drupal.optionsElement.prototype.setKeyType = function(type) {
 466    $(this.element)
 467      .removeClass('options-key-type-' + this.keyType)
 468      .addClass('options-key-type-' + type);
 469    this.keyType = type;
 470    // Rebuild the options widget.
 471    this.updateManualElements();
 472    this.updateWidgetElements();
 473  }
 474  
 475  /**
 476   * Set the element's #multiple property. Boolean TRUE or FALSE.
 477   */
 478  Drupal.optionsElement.prototype.setMultiple = function(multiple) {
 479    if (multiple) {
 480      $(this.element).addClass('options-multiple');
 481    }
 482    else {
 483      // Unselect all default options except the first.
 484      $(this.optionsElement).find('input.option-default:checked:not(:first)').attr('checked', false);
 485      this.updateManualElements();
 486      $(this.element).removeClass('options-multiple');
 487    }
 488    this.multiple = multiple;
 489    // Rebuild the options widget.
 490    this.updateWidgetElements();
 491  };
 492  
 493  /**
 494   * Highlight duplicate keys.
 495   */
 496  Drupal.optionsElement.prototype.checkKeys = function(duplicateKeys, cssClass){
 497    $(this.optionsElement).find('input.option-key').each(function() {
 498      if (duplicateKeys[this.value]) {
 499        $(this).addClass(cssClass);
 500      }
 501    });
 502  };
 503  
 504  /**
 505   * Update a field after a delay.
 506   *
 507   * Similar to immediately changing a field, this field as pending changes that
 508   * will be updated after a delay. This includes textareas and textfields in
 509   * which updating continuously would be a strain the server and actually slow
 510   * down responsiveness.
 511   */
 512  Drupal.optionsElement.prototype.pendingUpdate = function(e) {
 513    var self = this;
 514  
 515    // Only operate on "normal" keys, excluding special function keys.
 516    // http://protocolsofmatrix.blogspot.com/2007/09/javascript-keycode-reference-table-for.html
 517    if (!(
 518      e.keyCode >= 48 && e.keyCode <= 90 || // 0-9, A-Z.
 519      e.keyCode >= 93 && e.keyCode <= 111 || // Number pad.
 520      e.keyCode >= 186 && e.keyCode <= 222 || // Symbols.
 521      e.keyCode == 8) // Backspace.
 522      ) {
 523      return;
 524    }
 525  
 526    if (this.updateDelay) {
 527      clearTimeout(this.updateDelay);
 528    }
 529  
 530    this.updateDelay = setTimeout(function(){
 531      self.updateOptionElements();
 532      self.updateManualElements();
 533    }, 500);
 534  };
 535  
 536  /**
 537   * Given an object of options, convert it to a text string.
 538   */
 539  Drupal.optionsElement.prototype.optionsToText = function() {
 540    var $rows = $('tbody tr', this.optionsElement);
 541    var output = '';
 542    var inGroup = false;
 543    var rowCount = $rows.size();
 544    var defaultValues = [];
 545  
 546    for (var rowIndex = 0; rowIndex < rowCount; rowIndex++) {
 547      var isOptgroup = $rows.eq(rowIndex).is('.optgroup');
 548      var isChild = $rows.eq(rowIndex).is('.indented');
 549      var key = $rows.eq(rowIndex).find('input.option-key').val();
 550      var value = $rows.eq(rowIndex).find('input.option-value').val();
 551  
 552      // Handle groups.
 553      if (this.optgroups && value !== '' && isOptgroup) {
 554        output += '<' + ((key !== '') ? (key + '|') : '') + value + '>' + "\n";
 555        inGroup = true;
 556      }
 557      // Typical key|value pairs.
 558      else {
 559        // Exit out of any groups.
 560        if (this.optgroups && inGroup && !isChild) {
 561          output += "<>\n";
 562          inGroup = false;
 563        }
 564  
 565        // Add the row for the option.
 566        if (this.keyType == 'none' || this.keyType == 'associative') {
 567          output += value + "\n";
 568        }
 569        else if (value == '') {
 570          output += "\n";
 571        }
 572        else {
 573          output += ((key !== '') ? (key + '|') : '') + value + "\n";
 574        }
 575      }
 576    }
 577  
 578    this.manualOptionsElement.value = output;
 579  };
 580  
 581  /**
 582   * Given a text string, convert it to an object.
 583   */
 584  Drupal.optionsElement.prototype.optionsFromText = function() {
 585    // Use jQuery val() instead of value because it fixes Windows line breaks.
 586    var rows = $(this.manualOptionsElement).val().match(/^.*$/mg);
 587    var parent = '';
 588    var options = [];
 589    var defaultValues = {};
 590  
 591    // Drop the last row if empty.
 592    if (rows.length && rows[rows.length - 1] == '') {
 593      rows.pop();
 594    }
 595  
 596    if (this.manualDefaultValueElement) {
 597      if (this.multiple) {
 598        var defaults = this.manualDefaultValueElement.value.split(',');
 599        for (var n = 0; n < defaults.length; n++) {
 600          var defaultValue = defaults[n].replace(/^[ ]*(.*?)[ ]*$/, '$1'); // trim().
 601          defaultValues[defaultValue] = defaultValue;
 602        }
 603      }
 604      else {
 605        var defaultValue = this.manualDefaultValueElement.value.replace(/^[ ]*(.*?)[ ]*$/, '$1'); // trim().
 606        defaultValues[defaultValue] = defaultValue;
 607      }
 608    }
 609  
 610    for (var n = 0; n < rows.length; n++) {
 611      var row = rows[n].replace(/^[ \r\n]*(.*?)[ \r\n]*$/, '$1'); // trim().
 612      var key = '';
 613      var value = '';
 614      var checked = false;
 615      var hasChildren = false;
 616      var groupClear = false;
 617  
 618      var matches = {};
 619      // Row is a group.
 620      if (this.optgroups && (matches = row.match(/^\<((([^>|]*)\|)?([^>]*))\>$/))) {
 621        if (matches[0] == '<>') {
 622          parent = '';
 623          groupClear = true;
 624        }
 625        else {
 626          key = matches[3] ? matches[3] : '';
 627          parent = value = matches[4];
 628          hasChildren = true;
 629        }
 630      }
 631      // Check if this row is a key|value pair.
 632      else if ((this.keyType == 'mixed' || this.keyType == 'numeric' || this.keyType == 'custom') && (matches = row.match(/^([^|]+)\|(.*)$/))) {
 633        key = matches[1];
 634        value = matches[2];
 635        checked = defaultValues[key];
 636      }
 637      // Row is a straight value.
 638      else {
 639        key = (this.keyType == 'mixed' || this.keyType == 'numeric') ? '' : row;
 640        value = row;
 641        if (!key && this.keyType == 'mixed') {
 642          checked = defaultValues[value];
 643        }
 644        else {
 645          checked = defaultValues[key];
 646        }
 647      }
 648  
 649      if (!groupClear) {
 650        options.push({
 651          key: key,
 652          value: value,
 653          parent: (value !== parent ? parent : ''),
 654          hasChildren: hasChildren,
 655          checked: (checked ? 'checked' : false)
 656        });
 657      }
 658    }
 659  
 660    // Convert options to numeric if no key is specified.
 661    if (this.keyType == 'numeric') {
 662      var nextKey = this.nextNumericKey();
 663      for (var n = 0; n < options.length; n++) {
 664        if (options[n].key == '') {
 665          options[n].key = nextKey;
 666          nextKey++;
 667        }
 668      }
 669    }
 670  
 671    return options;
 672  };
 673  
 674  /**
 675   * Utility method to get the next numeric option in a list of options.
 676   */
 677  Drupal.optionsElement.prototype.nextNumericKey = function(options) {
 678    this.keyType = 'custom';
 679    options = this.optionsFromText();
 680    this.keyType = 'numeric';
 681  
 682    var maxKey = -1;
 683    for (var n = 0; n < options.length; n++) {
 684      if (options[n].key.match(/^[0-9]+$/)) {
 685        maxKey = Math.max(maxKey, options[n].key);
 686      }
 687    }
 688    return maxKey + 1;
 689  };
 690  
 691  /**
 692   * Theme function for creating a new options element.
 693   *
 694   * @param optionsElement
 695   *   An options element object.
 696   */
 697  Drupal.theme.prototype.optionsElement = function(optionsElement) {
 698    var output = '';
 699    var options = optionsElement.optionsFromText();
 700    var hasDefault = optionsElement.manualDefaultValueElement;
 701    var defaultType = optionsElement.multiple ? 'checkbox' : 'radio';
 702    var keyType = optionsElement.customKeys ? 'textfield' : 'hidden';
 703  
 704    // Helper function to print out a single draggable option row.
 705    function tableDragRow(key, value, parent, indent, status) {
 706      var output = '';
 707      output += '<tr class="draggable' + (indent > 0 ? ' indented' : '') + '">'
 708      output += '<td class="' + (hasDefault ? 'option-default-cell' : 'option-order-cell') + '">';
 709      for (var n = 0; n < indent; n++) {
 710        output += Drupal.theme('tableDragIndentation');
 711      }
 712      output += '<input type="hidden" class="option-parent" value="' + parent.replace(/"/g, '&quot;') + '" />';
 713      output += '<input type="hidden" class="option-depth" value="' + indent + '" />';
 714      if (hasDefault) {
 715        output += '<input type="' + defaultType + '" name="' + optionsElement.identifier + '-default" class="form-radio option-default" value="' + key.replace(/"/g, '&quot;') + '"' + (status == 'checked' ? ' checked="checked"' : '') + (status == 'disabled' ? ' disabled="disabled"' : '') + ' />';
 716      }
 717      output += '</td><td class="' + (keyType == 'textfield' ? 'option-key-cell' : 'option-value-cell') +'">';
 718      output += '<input type="' + keyType + '" class="' + (keyType == 'textfield' ? 'form-text ' : '') + 'option-key" value="' + key.replace(/"/g, '&quot;') + '" />';
 719      output += keyType == 'textfield' ? '</td><td class="option-value-cell">' : '';
 720      output += '<input class="form-text option-value" type="text" value="' + value.replace(/"/g, '&quot;') + '" />';
 721      output += '</td><td class="option-actions-cell">'
 722      output += '<a class="add" title="' + Drupal.t('Add new option') + '" href="#"' + (status == 'disabled' ? ' style="display: none"' : '') + '><span class="add">' + Drupal.t('Add') + '</span></a>';
 723      output += '<a class="remove" title="' + Drupal.t('Remove option') + '" href="#"' + (status == 'disabled' ? ' style="display: none"' : '') + '><span class="remove">' + Drupal.t('Remove') + '</span></a>';
 724      output += '</td>';
 725      output += '</tr>';
 726      return output;
 727    }
 728  
 729    output += '<div class="options-widget">';
 730    output += '<table id="' + optionsElement.identifier + '">';
 731  
 732    output += '<thead><tr>';
 733    output += '<th>' + (hasDefault ? Drupal.t('Default') : '&nbsp;') + '</th>';
 734    output += keyType == 'textfield' ? '<th>' + Drupal.t('Key') + '</th>' : '';
 735    output += '<th>' + Drupal.t('Value') + '</th>';
 736    output += '<th>&nbsp;</th>';
 737    output += '</tr></thead>';
 738  
 739    output += '<tbody>';
 740  
 741    // Make sure that at least a few options exist if empty.
 742    if (!options.length) {
 743      var newOption = {
 744        key: '',
 745        value: '',
 746        parent: '',
 747        hasChildren: false,
 748        checked: false
 749      }
 750      options.push(newOption);
 751      options.push(newOption);
 752      options.push(newOption);
 753    }
 754  
 755    for (var n = 0; n < options.length; n++) {
 756      var option = options[n];
 757      var depth = option.parent === '' ? 0 : 1;
 758      var checked = !option.hasChildren && option.checked;
 759      output += tableDragRow(option.key, option.value, option.parent, depth, checked);
 760    }
 761  
 762    output += '</tbody>';
 763    output += '</table>';
 764  
 765    if (optionsElement.defaultValuePattern && optionsElement.manualDefaultValueElement && optionsElement.defaultValuePattern.test(optionsElement.manualDefaultValueElement.value)) {
 766      output += Drupal.theme('optionsElementPatternMatch', optionsElement.manualDefaultValueElement.value);
 767    }
 768  
 769    output += '</div>';
 770  
 771    return output;
 772  };
 773  
 774  Drupal.theme.prototype.optionsElementPatternMatch = function(matchedValue) {
 775    return '<div class="default-value-pattern-match"><span>' + Drupal.t('Manual default value') + '</span>: ' + matchedValue + '</div>';
 776  };
 777  
 778  Drupal.theme.prototype.optionsElementAdd = function() {
 779    return '<div class="form-option-add"><a href="#">' + Drupal.t('Add item') + '</a></div>';
 780  };
 781  
 782  Drupal.theme.prototype.optionsElementToggle = function() {
 783    return '<div class="form-options-manual"><a href="#">' + Drupal.t('Manual entry') + '</a></div>';
 784  };
 785  
 786  Drupal.theme.tableDragChangedMarker = function () {
 787    return ' ';
 788  };
 789  
 790  Drupal.theme.tableDragChangedWarning = function() {
 791    return ' ';
 792  };
 793  
 794  })(jQuery);


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7