| [ Index ] |
PHP Cross Reference of Drupal 6 (yi-drupal) |
[Summary view] [Print] [Text view]
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);
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Jul 9 18:01:44 2012 | Cross-referenced by PHPXref 0.7 |