[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

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

   1  
   2  (function($) {
   3  
   4  /**
   5   * @file form_builder.js
   6   * Provide enhancements to the form building user interface.
   7   */
   8  
   9  Drupal.behaviors.formBuilderElement = function(context) {
  10    var $wrappers = $('div.form-builder-wrapper:not(.form-builder-processed)', context);
  11    var $elements = $('div.form-builder-element:not(.form-builder-processed)', context);
  12  
  13    // If the context itself is a wrapper, add it to the list.
  14    if ($(context).is('div.form-builder-wrapper:not(.form-builder-processed)')) {
  15      $wrappers = $wrappers.add(context);
  16    }
  17    // If the context itself is an element, add to the list.
  18    else if ($(context).is('div.form-builder-element:not(.form-builder-processed)')) {
  19      $elements = $elements.add(context);
  20    }
  21  
  22    // Add a guard class.
  23    $wrappers.addClass('form-builder-processed');
  24    $elements.addClass('form-builder-processed');
  25  
  26    // Add over effect on rollover.
  27    // The .hover() method is not used to avoid issues with nested hovers.
  28    $wrappers.not('div.form-builder-empty-placeholder')
  29      .bind('mouseover', Drupal.formBuilder.addHover)
  30      .bind('mouseout', Drupal.formBuilder.removeHover);
  31  
  32    // Add AJAX to edit links.
  33    $wrappers.find('span.form-builder-links a.configure').click(Drupal.formBuilder.editField);
  34  
  35    // Add AJAX to remove links.
  36    $wrappers.find('span.form-builder-links a.remove').click(Drupal.formBuilder.editField);
  37  
  38    // Add AJAX to entire field for easy editing.
  39    $elements.each(function() {
  40      if ($(this).children('fieldset.form-builder-fieldset').length == 0) {
  41        var link = $(this).parents('div.form-builder-wrapper:first').find('a.configure').get(0);
  42        if (link) {
  43          $(this).click(Drupal.formBuilder.clickField).addClass('form-builder-clickable');
  44          $(this).find('div.form-builder-element label').click(Drupal.formBuilder.clickField);
  45        }
  46        else {
  47          $(this).addClass('form-builder-draggable');
  48        }
  49      }
  50    });
  51  
  52    // Disable field functionality on click.
  53    $elements.find('input, textarea').bind('mousedown', Drupal.formBuilder.disableField);
  54  };
  55  
  56  /**
  57   * Behavior to disable preview fields and instead open up the configuration.
  58   */
  59  Drupal.behaviors.formBuilderFields = function(context) {
  60    // Bind a function to all elements to update the preview on change.
  61    var $configureForm = $('#form-builder-field-configure');
  62  
  63    $configureForm.find('input, textarea, select')
  64      .not('.form-builder-field-change')
  65      .addClass('form-builder-field-change')
  66      .bind('change', Drupal.formBuilder.elementPendingChange);
  67  
  68    $configureForm.find('input.form-text, textarea')
  69      .not('.form-builder-field-keyup')
  70      .addClass('form-builder-field-keyup')
  71      .bind('keyup', Drupal.formBuilder.elementPendingChange);
  72  };
  73  
  74  /**
  75   * Behavior for the entire form builder. Add drag and drop to elements.
  76   */
  77  Drupal.behaviors.formBuilder = function(context) {
  78    var $formbuilder = $('#form-builder');
  79    var $elements = $('.form-builder-wrapper').not('.form-builder-empty-placeholder').not('.ui-draggable');
  80    $elements.draggable({
  81      distance: 4, // Pixels before dragging starts.
  82      handle: 'div.form-builder-title-bar, div.form-builder-element',
  83      helper: 'clone',
  84      appendTo: $formbuilder,
  85      opacity: 0.8,
  86      scope: 'form-builder',
  87      scroll: true,
  88      scrollSensitivity: 50,
  89      zIndex: 100,
  90      start: Drupal.formBuilder.startDrag,
  91      stop: Drupal.formBuilder.stopDrag
  92    });
  93  
  94    // This sets the height of the drag target to be at least as high as the field
  95    // palette so that field can be more easily dropped into an empty form.  IE6
  96    // does not respect min-height but does treat height in the same manner that
  97    // min-height would be expected.  So a check for browser and version is needed
  98    // here.
  99    var property = $.browser.msie && $.browser.version < 7 ? 'height' : 'min-height';
 100    $formbuilder.css(property, $('#form-builder-fields').height());
 101  
 102    // Add the placeholder for an empty form.
 103    Drupal.formBuilder.checkForm();
 104  };
 105  
 106  /**
 107   * Behavior that renders fieldsets as tabs within the field configuration form.
 108   */
 109  Drupal.behaviors.formBuilderTabs = function(context) {
 110    var $fieldsets = $('fieldset.form-builder-group:not(.form-builer-tabs-processed)', context);
 111    var $close = $('<a class="close" href="#">' + Drupal.t('Close') + '</a>');
 112    var $tabs;
 113    var tabs = '';
 114  
 115    // Convert fieldsets to tabs.
 116    tabs = '<ul class="form-builder-tabs tabs clear-block">';
 117    $fieldsets.children('legend').each(function() {
 118      tabs += '<li>' + this.innerHTML + '</li>';
 119      $(this).remove();
 120    });
 121    tabs += '</ul>';
 122  
 123    // Add the new tabs to the page.
 124    $tabs = $(tabs);
 125    $fieldsets.filter(':first').before($close).before($tabs);
 126  
 127    // Remove 'fieldset-legend' class from tabs.
 128    $tabs.find('.fieldset-legend').removeClass('fieldset-legend');
 129  
 130    // Set clear-block on the parent div.
 131    $tabs.parent().addClass('clear-block');
 132  
 133    // Wrap each fieldset's content. This is only needed in D6.
 134    $fieldsets.wrapInner('<div class="fieldset-wrapper"></div>');
 135  
 136    // Hide all the fieldsets except the first.
 137    $fieldsets.not(':first').css('display', 'none');
 138    $tabs.find('li:first').addClass('active').click(Drupal.formBuilder.clickCancel);
 139  
 140    // Enable tab switching by clicking on each tab.
 141    $tabs.find('li:not(.close)').each(function(index) {
 142      $(this).click(function() {
 143        $fieldsets.filter(':visible').css('display', 'none');
 144        $fieldsets.eq(index).css('display', 'block');
 145        $tabs.find('li.active').removeClass('active').unbind('click', Drupal.formBuilder.clickCancel);
 146        $(this).addClass('active').click(Drupal.formBuilder.clickCancel);
 147        Drupal.formBuilder.fixTableDragTabs($fieldsets.eq(index).get(0));
 148      });
 149    });
 150  
 151    $close.click(Drupal.formBuilder.clickCancel);
 152  
 153    // Add guard class.
 154    $fieldsets.addClass('form-builer-tabs-processed');
 155  };
 156  
 157  /**
 158   * Submit the delete form via AJAX or close the form with the cancel link.
 159   */
 160  Drupal.behaviors.formBuilderDeleteConfirmation = function(context) {
 161    var $confirmForm = $('form.confirmation', context);
 162  
 163    // If the confirmation form is the context.
 164    if ($(context).is('form.confirmation')) {
 165      $confirmForm = $(context);
 166    }
 167  
 168    if ($confirmForm.length) {
 169      $confirmForm.submit(Drupal.formBuilder.deleteField);
 170      $confirmForm.find('a').click(Drupal.formBuilder.clickCancel);
 171    }
 172  };
 173  
 174  /**
 175   * Keeps record of if a mouse button is pressed.
 176   */
 177  Drupal.behaviors.formBuilderMousePress = function(context) {
 178    if (context == document) {
 179      $('body').mousedown(function() { Drupal.formBuilder.mousePressed = 1; });
 180      $('body').mouseup(function() { Drupal.formBuilder.mousePressed = 0; });
 181    }
 182  };
 183  
 184  /**
 185   * Scrolls the add new field block with the window.
 186   */
 187  Drupal.behaviors.formBuilderBlockScroll = function(context) {
 188    var $list = $('ul.form-builder-fields', context);
 189  
 190    if ($list.length) {
 191      var $block = $list.parents('div.block:first').css('position', 'relative');
 192      var blockScrollStart = $block.offset().top;
 193  
 194      function blockScroll() {
 195        // Do not move the palette while dragging a field.
 196        if (Drupal.formBuilder.activeDragUi) {
 197          return;
 198        }
 199  
 200        var toolbarHeight = parseInt($('body.toolbar').css('padding-top'));
 201        var windowOffset = $(window).scrollTop() + (toolbarHeight ? toolbarHeight : 0);
 202        var blockHeight = $block.height();
 203        var formBuilderHeight = $('#form-builder').height();
 204        if (windowOffset - blockScrollStart > 0) {
 205          // Do not scroll beyond the bottom of the editing area.
 206          var newTop = Math.min(windowOffset - blockScrollStart + 20, formBuilderHeight - blockHeight);
 207          $block.animate({ top: (newTop + 'px') }, 'fast');
 208        }
 209        else {
 210          $block.animate({ top: '0px' }, 'fast');
 211        }
 212      }
 213  
 214      var timeout = false;
 215      function scrollTimeout() {
 216        if (timeout) {
 217          clearTimeout(timeout);
 218        }
 219        timeout = setTimeout(blockScroll, 100);
 220      }
 221  
 222      $(window).scroll(scrollTimeout);
 223    }
 224  };
 225  
 226  /**
 227   * Behavior for the Add a field block.
 228   * @param {Object} context
 229   */
 230  Drupal.behaviors.formBuilderNewField = function(context) {
 231    var $list = $('ul.form-builder-fields', context);
 232  
 233    if ($list.length) {
 234      // Allow items to be copied from the list of new fields.
 235      $list.children('li:not(.ui-draggable)').draggable({
 236        opacity: 0.8,
 237        helper: 'clone',
 238        scope: 'form-builder',
 239        scroll: true,
 240        scrollSensitivity: 50,
 241        tolerance: 'pointer',
 242        zIndex: 100,
 243        start: Drupal.formBuilder.startDrag,
 244        stop: Drupal.formBuilder.stopDrag
 245      });
 246    }
 247  };
 248  
 249  Drupal.formBuilder = {
 250    // Variable to prevent multiple requests.
 251    updatingElement: false,
 252    // Variables to allow delayed updates on textfields and textareas.
 253    updateDelayElement: false,
 254    updateDelay: false,
 255    // Variable holding the actively edited element (if any).
 256    activeElement: false,
 257    // Variable holding the active drag object (if any).
 258    activeDragUi: false,
 259    // Variables to keep trak of the current and previous drop target. Used to
 260    // prevent overlapping targets from being shown as active at the same time.
 261    activeDropzone: false,
 262    previousDropzones: [],
 263    // Variable of the time of the last update, used to prevent old data from
 264    // replacing newer updates.
 265    lastUpdateTime: 0,
 266    // Status of mouse click.
 267    mousePressed: 0,
 268    // Selector for a custom field configuration form.
 269    fieldConfigureForm: false
 270  };
 271  
 272  /**
 273   * Event callback for mouseover of fields. Adds hover class.
 274   */
 275  Drupal.formBuilder.addHover = function() {
 276    // Do not add hover effect while dragging over other fields.
 277    if (!Drupal.formBuilder.activeDragUi && !Drupal.formBuilder.mousePressed) {
 278      if ($(this).find('div.form-builder-hover').length == 0) {
 279        $(this).addClass('form-builder-hover');
 280      }
 281    }
 282  };
 283  
 284  /**
 285   * Event callback for mouseout of fields. Removes hover class.
 286   */
 287  Drupal.formBuilder.removeHover = function() {
 288    // Do not add hover effect while dragging over other fields.
 289    if (!Drupal.formBuilder.activeDragUi && !Drupal.formBuilder.mousePressed) {
 290      $(this).removeClass('form-builder-hover');
 291    }
 292  };
 293  
 294  /**
 295   * Click handler for fields.
 296   *
 297   * Note this is applied to both the entire field and to the labels within the
 298   * field, as they have special browser behavior that needs to be overridden.
 299   */
 300  Drupal.formBuilder.clickField = function(e) {
 301    // Allow select lists to be clicked on without opening the edit options.
 302    if ($(e.target).is('select')) {
 303      return;
 304    }
 305  
 306    // Find the first configure link for this field, ensuring we don't get a link
 307    // belonging to a nested form element within this element.
 308    var $wrapper = $(this).parents('.form-builder-wrapper:first');
 309    var link = $wrapper.find('a.configure').not($wrapper.find('.form-builder-element .form-builder-element a')).get(0);
 310    Drupal.formBuilder.editField.apply(link);
 311  
 312    return false;
 313  };
 314  
 315  /**
 316   * Mousedown event on element previews.
 317   */
 318  Drupal.formBuilder.disableField = function(e) {
 319    return false;
 320  };
 321  
 322  /**
 323   * Load the edit form from the server.
 324   */
 325  Drupal.formBuilder.editField = function() {
 326    var $element = $(this).parents('div.form-builder-wrapper');
 327    var $link = $(this);
 328  
 329    // Prevent duplicate clicks from taking effect if already handling a click.
 330    if (Drupal.formBuilder.updatingElement) {
 331      return false;
 332    }
 333  
 334    // Show loading indicators.
 335    $link.addClass('progress');
 336  
 337    // If clicking on the link a second time, close the form instead of open.
 338    if ($element.get(0) == Drupal.formBuilder.activeElement && $link.get(0) == Drupal.formBuilder.activeLink) {
 339      Drupal.formBuilder.closeActive(function() {
 340        $link.removeClass('progress');
 341      });
 342      Drupal.formBuilder.unsetActive();
 343      return false;
 344    }
 345  
 346    var getForm = function() {
 347      if (Drupal.formBuilder.fieldConfigureForm) {
 348        $(Drupal.formBuilder.fieldConfigureForm).html(Drupal.settings.formBuilder.fieldLoading);
 349      }
 350  
 351      $.ajax({
 352        url: $link.attr('href'),
 353        type: 'GET',
 354        dataType: 'json',
 355        data: 'js=1',
 356        success: Drupal.formBuilder.displayForm
 357      });
 358    };
 359  
 360    Drupal.formBuilder.updatingElement = true;
 361    Drupal.formBuilder.closeActive(getForm);
 362    Drupal.formBuilder.setActive($element.get(0), $link.get(0));
 363  
 364    return false;
 365  };
 366  
 367  /**
 368   * Click handler for deleting a field.
 369   */
 370  Drupal.formBuilder.deleteField = function() {
 371    $(this).parents('div.form-builder-wrapper:first').animate({ height: 'hide', opacity: 'hide' }, 'normal', function() {
 372      // If this is a unique field, show the field in the palette again.
 373      var elementId = $(this).find('div.form-builder-element').attr('id');
 374      $('ul.form-builder-fields').find('li.' + elementId).show('slow');
 375      // Remove the field from the form.
 376      $(this).remove();
 377  
 378      // Check for an entirely empty form and for empty fieldsets.
 379      Drupal.formBuilder.checkForm();
 380      Drupal.formBuilder.checkFieldsets([], true);
 381    });
 382  };
 383  
 384  Drupal.formBuilder.clickCancel = function() {
 385    Drupal.formBuilder.closeActive();
 386    Drupal.formBuilder.unsetActive();
 387    return false;
 388  };
 389  
 390  /**
 391   * Display the edit form from the server.
 392   */
 393  Drupal.formBuilder.displayForm = function(response) {
 394    // Update Drupal settings.
 395    if (response.settings) {
 396      $.extend(true, Drupal.settings, response.settings);
 397    }
 398  
 399    var $preview = $('#form-builder-element-' + response.elementId);
 400    var $form = $(response.html);
 401  
 402    if (Drupal.formBuilder.fieldConfigureForm) {
 403      $(Drupal.formBuilder.fieldConfigureForm).html($form);
 404      $form.css('display', 'none');
 405    }
 406    else {
 407      $form.insertAfter($preview).css('display', 'none');
 408    }
 409  
 410    Drupal.attachBehaviors($form.get(0));
 411  
 412    $form
 413      // Add the ajaxForm behavior to the new form.
 414      .ajaxForm()
 415      // Using the 'data' $.ajaxForm property doesn't seem to work.
 416      // Manually add a hidden element to pass additional data on submit.
 417      .prepend('<input type="hidden" name="return" value="field" />')
 418      // Add in any messages from the server.
 419      .find('fieldset:first').find('.fieldset-wrapper:first').prepend(response.messages);
 420  
 421    $form.slideDown(function() {
 422      $preview.parents('div.form-builder-wrapper:first').find('a.progress').removeClass('progress');
 423      $form.find('input:visible:first').focus();
 424    });
 425  
 426    Drupal.formBuilder.updatingElement = false;
 427  };
 428  
 429  /**
 430   * Upon changing a field, submit via AJAX to the server.
 431   */
 432  Drupal.formBuilder.elementChange = function() {
 433    if (!Drupal.formBuilder.updatingElement) {
 434      $(this).parents('form:first').ajaxSubmit({
 435        success: Drupal.formBuilder.updateElement,
 436        dataType: 'json'
 437      });
 438    }
 439  
 440    // Clear any pending updates until further changes are made.
 441    if (Drupal.formBuilder.updateDelay) {
 442      clearTimeout(Drupal.formBuilder.updateDelay);
 443    }
 444  
 445    Drupal.formBuilder.updatingElement = true;
 446  };
 447  
 448  /**
 449   * Update a field after a delay.
 450   *
 451   * Similar to immediately changing a field, this field as pending changes that
 452   * will be updated after a delay. This includes textareas and textfields in
 453   * which updating continuously would be a strain the server and actually slow
 454   * down responsiveness.
 455   */
 456  Drupal.formBuilder.elementPendingChange = function(e) {
 457    // Only operate on "normal" keys, excluding special function keys.
 458    // http://protocolsofmatrix.blogspot.com/2007/09/javascript-keycode-reference-table-for.html
 459    if (e.type == 'keyup' && !(
 460      e.keyCode >= 48 && e.keyCode <= 90 || // 0-9, A-Z.
 461      e.keyCode >= 93 && e.keyCode <= 111 || // Number pad.
 462      e.keyCode >= 186 && e.keyCode <= 222 || // Symbols.
 463      e.keyCode == 8) // Backspace.
 464      ) {
 465      return;
 466    }
 467  
 468    if (Drupal.formBuilder.updateDelay) {
 469      clearTimeout(Drupal.formBuilder.updateDelay);
 470    }
 471    Drupal.formBuilder.updateDelayElement = this;
 472    Drupal.formBuilder.updateDelay = setTimeout("Drupal.formBuilder.elementChange.apply(Drupal.formBuilder.updateDelayElement, [true])", 500);
 473  };
 474  
 475  /**
 476   * After submitting the change to the server, display the updated element.
 477   */
 478  Drupal.formBuilder.updateElement = function(response) {
 479    var $configureForm = $('#form-builder-field-configure');
 480  
 481    // Do not let older requests replace newer updates.
 482    if (response.time < Drupal.formBuilder.lastUpdateTime) {
 483      return;
 484    }
 485    else {
 486      Drupal.formBuilder.lastUpdateTime = response.time;
 487    }
 488  
 489    // Update Drupal.settings.
 490    if (response.settings) {
 491      $.extend(true, Drupal.settings, response.settings);
 492    }
 493  
 494    // Set the error class on fields.
 495    $configureForm.find('.error').removeClass('error');
 496    if (response.errors) {
 497      for (var elementName in response.errors) {
 498        elementName = elementName.replace(/([a-z0-9_]+)\](.*)/, '$1$2]');
 499        $configureForm.find('[name=' + elementName + ']').addClass('error');
 500      }
 501    }
 502  
 503    // Display messages, if any.
 504    $configureForm.find('.messages').remove();
 505    if (response.messages) {
 506      $configureForm.find('fieldset:visible:first').find('.fieldset-wrapper:first').prepend(response.messages);
 507    }
 508  
 509    // Do not update the element if errors were received.
 510    if (!response.errors) {
 511      var $exisiting = $('#form-builder-element-' + response.elementId);
 512      var $new = $(response.html).find('div.form-builder-element:first');
 513      $exisiting.replaceWith($new);
 514  
 515      // Expand root level fieldsets after updating to prevent them from closing
 516      // after every update.
 517      $new.children('fieldset.collapsible').removeClass('collapsed');
 518      Drupal.attachBehaviors($new.get(0));
 519    }
 520  
 521    // Set the variable stating we're done updating.
 522    Drupal.formBuilder.updatingElement = false;
 523  };
 524  
 525  /**
 526   * When adding a new field, remove the placeholder and insert the new element.
 527   */
 528  Drupal.formBuilder.addElement = function(response) {
 529    // Update Drupal settings.
 530    if (response.settings) {
 531      $.extend(true, Drupal.settings, response.settings);
 532    }
 533  
 534    // This is very similar to the update element callback, only we replace the
 535    // entire wrapper instead of just the element.
 536    var $exisiting = $('#form-builder-element-' + response.elementId).parent();
 537    var $new = $(response.html).find('div.form-builder-element:first').parent();
 538    $exisiting.replaceWith($new);
 539    Drupal.attachBehaviors($new.get(0));
 540  
 541    // Set the variable stating we're done updating.
 542    Drupal.formBuilder.updatingElement = false;
 543  
 544    // Insert the new position form containing the new element.
 545    $('#form-builder-positions').replaceWith(response.positionForm);
 546  
 547    // Submit the new positions form to save the new element position.
 548    Drupal.formBuilder.updateElementPosition($new.get(0));
 549  };
 550  
 551  /**
 552   * Given an element, update it's position (weight and parent) on the server.
 553   */
 554  Drupal.formBuilder.updateElementPosition = function(element) {
 555    var $element = $(element);
 556  
 557    // Update weights of all children within this element's parent.
 558    $element.parent().children('div.form-builder-wrapper').each(function(index) {
 559      var child_id = $(this).children('div.form-builder-element:first').attr('id');
 560      $('#form-builder-positions input.form-builder-weight').filter('.' + child_id).val(index);
 561    });
 562  
 563    // Update this element's parent.
 564    var $parent = $element.parents('div.form-builder-element:first');
 565    var parent_id = $parent.length ? $parent.attr('id').replace(/form-builder-element-(.*)/, '$1') : 0;
 566    var child_id = $element.children('div.form-builder-element:first').attr('id');
 567    $('#form-builder-positions input.form-builder-parent').filter('.' + child_id).val(parent_id);
 568  
 569    // Submit the position form via AJAX to save the new weights and parents.
 570    $('#form-builder-positions').ajaxSubmit();
 571  };
 572  
 573  /**
 574   * Called when a field is about to be moved via Sortables.
 575   *
 576   * @param e
 577   *   The event object containing status information about the event.
 578   * @param ui
 579   *   The jQuery Sortables object containing information about the sortable.
 580   */
 581  Drupal.formBuilder.startDrag = function(e, ui) {
 582    Drupal.formBuilder.activeDragUi = ui;
 583  
 584    var $this = $(this);
 585    if ($this.hasClass('form-builder-unique') || $this.hasClass('form-builder-wrapper')) {
 586      $this.hide();
 587    }
 588  
 589    // Check fieldsets and add placeholder text if needed.
 590    Drupal.formBuilder.checkFieldsets([this, ui.helper]);
 591  
 592    // Create the drop targets in between the form elements.
 593    Drupal.formBuilder.createDropTargets(this, ui.helper);
 594  };
 595  
 596  /**
 597   * Creates drop targets for the dragged element to be dropped into.
 598   */
 599  Drupal.formBuilder.createDropTargets = function(draggable, helper) {
 600    var $placeholder = $('<div class="form-builder-placeholder"></div>');
 601    var $elements = $('#form-builder .form-builder-wrapper:not(.form-builder-empty-placeholder)').not(draggable).not(helper);
 602  
 603    if ($elements.length == 0) {
 604      // There are no form elements, insert a placeholder
 605      var $formBuilder = $('#form-builder');
 606      $placeholder.height($formBuilder.height());
 607      $placeholder.appendTo($formBuilder);
 608    }
 609    else {
 610      $elements.each(function(i) {
 611        $placeholder.clone().insertAfter(this);
 612        // If the element is the first in its container, add a drop target above it.
 613        if (this == $(this).parent().children('.form-builder-wrapper:not(.ui-draggable-dragging)').not(draggable)[0]) {
 614          $placeholder.clone().insertBefore(this);
 615        }
 616      });
 617    }
 618  
 619    // Enable the drop targets
 620    $('#form-builder').find('.form-builder-placeholder, .form-builder-empty-placeholder').droppable({
 621      greedy: true,
 622      scope: 'form-builder',
 623      tolerance: 'pointer',
 624      drop: Drupal.formBuilder.dropElement,
 625      over: Drupal.formBuilder.dropHover,
 626      out: Drupal.formBuilder.dropHover
 627    });
 628  };
 629  
 630  /**
 631   * Handles form elements being dropped onto the form.
 632   *
 633   * Existing elements will trigger a reorder, while new elements will be added in
 634   * place to the form.
 635   */
 636  Drupal.formBuilder.dropElement = function (event, ui) {
 637    var $element = ui.draggable;
 638    var $placeholder = $(this);
 639  
 640    // If the element is a new field from the palette, update it with a real field.
 641    if ($element.is('.form-builder-palette-element')) {
 642      var name = 'new_' + new Date().getTime();
 643      // If this is a "unique" element, its element ID is hard-coded.
 644      if ($element.is('.form-builder-unique')) {
 645        name = $element.get(0).className.replace(/^.*?form-builder-element-([a-z0-9_]+).*?$/, '$1');
 646      }
 647  
 648      var $ajaxPlaceholder = $('<div class="form-builder-wrapper form-builder-new-field"><div id="form-builder-element-' + name + '" class="form-builder-element"><span class="progress">' + Drupal.t('Please wait...') + '</span></div></div>');
 649  
 650      $.ajax({
 651        url: $element.find('a').attr('href'),
 652        type: 'GET',
 653        dataType: 'json',
 654        data: 'js=1&element_id=' + name,
 655        success: Drupal.formBuilder.addElement
 656      });
 657  
 658      $placeholder.replaceWith($ajaxPlaceholder);
 659  
 660      Drupal.formBuilder.updatingElement = true;
 661    }
 662    // Update the positions (weights and parents) in the form cache.
 663    else {
 664      $element.removeAttr('style');
 665      $placeholder.replaceWith($element);
 666      ui.helper.remove();
 667      Drupal.formBuilder.updateElementPosition($element.get(0));
 668    }
 669  
 670    Drupal.formBuilder.activeDragUi = false;
 671  
 672    // Scroll the palette into view.
 673    $(window).triggerHandler('scroll');
 674  };
 675  
 676  /**
 677   * Adjusts the placeholder height for drop targets as they are hovered-over.
 678   */
 679  Drupal.formBuilder.dropHover = function (event, ui) {
 680    if (event.type == 'dropover') {
 681      // In the event that two droppables overlap, the latest one acts as the drop
 682      // target. If there is previous active droppable hide it temporarily.
 683      if (Drupal.formBuilder.activeDropzone) {
 684        $(Drupal.formBuilder.activeDropzone).css('display', 'none');
 685        Drupal.formBuilder.previousDropzones.push(Drupal.formBuilder.activeDropzone);
 686      }
 687      $(this).css({ height: ui.helper.height() + 'px', display: ''}).addClass('form-builder-placeholder-hover');
 688      Drupal.formBuilder.activeDropzone = this;
 689    }
 690    else {
 691      $(this).css({ height: '', display: '' }).removeClass('form-builder-placeholder-hover');
 692  
 693      // If this was active drop target, we remove the active state.
 694      if (Drupal.formBuilder.activeDropzone && Drupal.formBuilder.activeDropzone == this) {
 695        Drupal.formBuilder.activeDropzone = false;
 696      }
 697      // If there is a previous drop target that was hidden, restore it.
 698      if (Drupal.formBuilder.previousDropzones.length) {
 699        $(Drupal.formBuilder.previousDropzones).css('display', '');
 700        Drupal.formBuilder.activeDropzone = Drupal.formBuilder.previousDropzones.pop;
 701      }
 702    }
 703  };
 704  
 705  /**
 706   * Called when a field has stopped moving via draggable.
 707   *
 708   * @param e
 709   *   The event object containing status information about the event.
 710   * @param ui
 711   *   The jQuery Sortables object containing information about the sortable.
 712   */
 713  Drupal.formBuilder.stopDrag = function(e, ui) {
 714    var $this = $(this);
 715    // If the activeDragUi is still set, we did not drop onto the form.
 716    if (Drupal.formBuilder.activeDragUi) {
 717      if ($this.hasClass('form-builder-unique') || $this.hasClass('form-builder-wrapper')) {
 718        $this.show();
 719      }
 720    }
 721  
 722    // Remove the placeholders and reset the hover state for all for elements
 723    $('#form-builder .form-builder-placeholder').remove();
 724    $('#form-builder .form-builder-hover').removeClass('form-builder-hover');
 725  
 726    Drupal.formBuilder.checkFieldsets();
 727  
 728    // Scroll the palette into view.
 729    $(window).triggerHandler('scroll');
 730  };
 731  
 732  /**
 733   * Insert DIVs into empty fieldsets so that items can be dropped within them.
 734   *
 735   * This function is called every time an element changes positions during
 736   * a drag and drop operation. Fieldsets are considered empty if they have no
 737   * immediate children or they only contain exclusions.
 738   *
 739   * @param exclusions
 740   *   An array of DOM objects within a fieldset that should not be included when
 741   *   checking if the fieldset is empty.
 742   */
 743  Drupal.formBuilder.checkFieldsets = function(exclusions, animate) {
 744    var $wrappers = $('#form-builder div.form-builder-element > fieldset.form-builder-fieldset > div.fieldset-wrapper');
 745  
 746    // Make sure exclusions is an array and always skip any description.
 747    exclusions = exclusions ? exclusions : [];
 748    exclusions.push('.description, legend');
 749  
 750    // Insert a placeholder into all empty fieldset wrappers.
 751    $wrappers.each(function() {
 752      var children = $(this).children(':visible, :not(.ui-draggable-dragging)');
 753      for (var i in exclusions) {
 754        children = children.not(exclusions[i]);
 755      }
 756  
 757      if (children.length == 0) {
 758        // No children, add a placeholder.
 759        if (animate) {
 760          $(Drupal.settings.formBuilder.emptyFieldset).css('display', 'none').appendTo(this).slideDown();
 761        }
 762        else {
 763          $(Drupal.settings.formBuilder.emptyFieldset).appendTo(this);
 764        }
 765      }
 766      else if (children.length > 1 && children.hasClass('form-builder-empty-placeholder')) {
 767        // The fieldset has at least one element besides the placeholder, remove
 768        // the placeholder.
 769        $(this).find('.form-builder-empty-placeholder').remove();
 770      }
 771    });
 772  };
 773  
 774  /**
 775   * Check the root form tag and place explanatory text if the form is empty.
 776   */
 777  Drupal.formBuilder.checkForm = function () {
 778    var $formBuilder = $('#form-builder');
 779    if ($formBuilder.children('div.form-builder-wrapper').length == 0) {
 780      $formBuilder.append(Drupal.settings.formBuilder.emptyForm);
 781    }
 782  };
 783  
 784  Drupal.formBuilder.setActive = function(element, link) {
 785    Drupal.formBuilder.unsetActive();
 786    Drupal.formBuilder.activeElement = element;
 787    Drupal.formBuilder.activeLink = link;
 788    $(Drupal.formBuilder.activeElement).addClass('form-builder-active');
 789  };
 790  
 791  Drupal.formBuilder.unsetActive = function() {
 792    if (Drupal.formBuilder.activeElement) {
 793      $(Drupal.formBuilder.activeElement).removeClass('form-builder-active');
 794      Drupal.formBuilder.activeElement = false;
 795      Drupal.formBuilder.activeLink = false;
 796    }
 797  };
 798  
 799  Drupal.formBuilder.closeActive = function(callback) {
 800    if (Drupal.formBuilder.activeElement) {
 801      var $activeForm = Drupal.formBuilder.fieldConfigureForm ? $(Drupal.formBuilder.fieldConfigureForm).find('form') : $(Drupal.formBuilder.activeElement).find('form');
 802  
 803      if ($activeForm.length) {
 804        Drupal.freezeHeight();
 805        $activeForm.slideUp(function(){
 806          $(this).remove();
 807          // Set a message in the custom configure form location if it exists.
 808          if (Drupal.formBuilder.fieldConfigureForm) {
 809            $(Drupal.formBuilder.fieldConfigureForm).html(Drupal.settings.formBuilder.noFieldSelected);
 810          }
 811          if (callback) {
 812            callback.call();
 813          }
 814        });
 815      }
 816    }
 817    else if (callback && $.isFunction(callback)) {
 818      callback.call();
 819    }
 820  
 821    return false;
 822  };
 823  
 824  /**
 825   * Work around for tabledrags within tabs. On load, if the tab was hidden the
 826   * offsets cannot be calculated correctly. Recalculate and update the tableDrag.
 827   */
 828  Drupal.formBuilder.fixTableDragTabs = function(context) {
 829    if (Drupal.tableDrag && Drupal.tableDrag.length > 1) {
 830      for (var n in Drupal.tableDrag) {
 831        if (typeof(Drupal.tableDrag[n]) == 'object') {
 832          var table = $('#' + n, context).get(0);
 833          if (table) {
 834            var indent = Drupal.theme('tableDragIndentation');
 835            var testCell = $('tr.draggable:first td:first', table).prepend(indent).prepend(indent);
 836            Drupal.tableDrag[n].indentAmount = $('.indentation', testCell).get(1).offsetLeft - $('.indentation', testCell).get(0).offsetLeft;
 837            $('.indentation', testCell).slice(0, 2).remove();
 838          }
 839        }
 840      }
 841    }
 842  };
 843  
 844  })(jQuery);


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