diff --git a/css/webform-admin.css b/css/webform-admin.css index 0476638..8076574 100644 --- a/css/webform-admin.css +++ b/css/webform-admin.css @@ -117,3 +117,57 @@ tr.webform-add-form .tabledrag-changed { #webform-components tr.webform-add-form { background-color: inherit; } + +/* Conditionals */ +.webform-conditional { + display: block; + position: relative; + padding-left: 1em; + padding-right: 8em; + max-width: 500px; +} + +.webform-conditional-if { + position: absolute; + left: -.5em; + margin-top: .2em; +} + +.webform-conditional-condition { + display: inline; +} + +.webform-conditional-operations { + position: absolute; + right: 0; + margin-top: .2em; +} + +.webform-conditional-operations input { + margin: 0 2px; +} + +#webform-conditionals-table input.progress-disabled, +.webform-conditional-operations input.progress-disabled { + float: none; +} + +#webform-conditionals-table .ahah-progress-throbber { + float: none; + display: inline; +} + +#webform-conditionals-table .ahah-progress-throbber .throbber { + float: none; + display: inline; + padding-right: 12px; +} + +.webform-conditional-andor { + display: inline; +} + +.webform-conditional-andor .form-item { + margin: 0; + padding: 0; +} diff --git a/includes/webform.components.inc b/includes/webform.components.inc index d1de2f3..e58c4dc 100644 --- a/includes/webform.components.inc +++ b/includes/webform.components.inc @@ -496,69 +496,6 @@ function webform_component_edit_form(&$form_state, $node, $component, $clone = F '#weight' => 4, ); - // Add conditional fields. - $conditional_components = array(); - $counter = 0; - $last_pagebreak_slice = 0; - foreach ($node->webform['components'] as $cid => $test_component) { - // Only components before the pagebreak can be considered. - if ($test_component['type'] == 'pagebreak') { - $last_pagebreak_slice = $counter; - } - if (isset($component['cid']) && $cid == $component['cid']) { - break; - } - if (webform_component_feature($test_component['type'], 'conditional')) { - $conditional_components[$cid] = $test_component; - } - $counter++; - } - if ($component['type'] != 'pagebreak') { - $fieldset_description = t('Create a rule to control whether or not to skip this page.'); - } - else { - $fieldset_description = t('Create a rule to control whether or not to show this form element.'); - } - $conditional_components = array_slice($conditional_components, 0, $last_pagebreak_slice, TRUE); - $form['conditional'] = array( - '#weight' => 10, - '#type' => 'fieldset', - '#title' => t('Conditional rules'), - '#collapsible' => TRUE, - '#collapsed' => TRUE, - '#description' => t('Create a rule to control whether or not to show this form element.'), - '#tree' => FALSE, - ); - $form['conditional']['extra'] = array( - '#tree' => TRUE, - ); - $form['conditional']['extra']['conditional_component'] = array( - '#type' => 'select', - '#title' => t('Component'), - '#options' => webform_component_list($node, $conditional_components, FALSE, TRUE), - '#description' => t('Select another component to decide whether to show or hide this component. You can only select components occurring before the most recent pagebreak.'), - '#default_value' => $component['extra']['conditional_component'], - ); - $form['conditional']['extra']['conditional_operator'] = array( - '#type' => 'select', - '#title' => t('Operator'), - '#options' => array( - '=' => t('Is one of'), - '!=' => t('Is not one of') - ), - '#description' => t('Determines whether the list below is inclusive or exclusive.'), - '#default_value' => $component['extra']['conditional_operator'], - ); - $form['conditional']['extra']['conditional_values'] = array( - '#type' => 'textarea', - '#title' => t('Values'), - '#description' => t('List values, one per line, that will trigger this action. If you leave this blank, this component will always display.'), - '#default_value' => $component['extra']['conditional_values'], - ); - if (empty($conditional_components)) { - $form['conditional']['#access'] = FALSE; - } - // Add the fields specific to this component type: $additional_form_elements = (array) webform_component_invoke($component['type'], 'edit', $component); if (empty($additional_form_elements)) { @@ -861,6 +798,19 @@ function webform_component_feature($type, $feature) { } /** + * Get a component property from the component definition. + * + * @see hook_webform_component_info() + */ +function webform_component_property($type, $property) { + $components = webform_components(); + $defaults = array( + 'conditional_type' => 'string', + ); + return isset($components[$type][$property]) ? $components[$type][$property] : $defaults[$property]; +} + +/** * Create a list of components suitable for a select list. * * @param $node diff --git a/includes/webform.pages.inc b/includes/webform.pages.inc index 99bc8a8..f0522b0 100644 --- a/includes/webform.pages.inc +++ b/includes/webform.pages.inc @@ -400,3 +400,61 @@ function theme_webform_advanced_redirection_form($form) { $form['redirect']['url']['#title'] = $form['redirect']['url']['#title'] . ': ' . drupal_render($form['redirect_url']); return drupal_render($form); } + +/** + * AJAX Callback to provide Drupal 6 functionality similar to AJAX in Drupal 7. + * + * This function takes the incoming $_POST request, processes the form to build + * $form and $form_state, then calls the #ahah[callback] property on the clicked + * button, making it so that #ahah can be used the same way as #ajax would in + * Drupal 7. + * + * This function is based on the AHAH example, slighly modified to call the + * original clicked button callback. + * + * @see http://api.drupal.org/api/examples/ahah_example%21ahah_example.module/function/ahah_example_callback_helper/6 + * @see http://api.drupal.org/api/drupal/developer%21topics%21forms_api_reference.html/7#ajax_callback + */ +function webform_ajax_callback() { + // We don't have any way of including files for AJAX requests through + // $form_state like we do in Drupal 7 e.g. form_load_include(), so we just + // manually include files that contain Webform form callbacks. + // TODO: Abstract inclusion mechanism if needed in the future. + module_load_include('inc', 'webform', 'includes/webform.conditionals'); + + $form_state = array( + 'storage' => NULL, + 'submitted' => FALSE, + ); + $form_build_id = $_POST['form_build_id']; + $form = form_get_cache($form_build_id, $form_state); + $args = $form['#parameters']; + $form_id = array_shift($args); + $form_state['post'] = $form['#post'] = $_POST; + // Enable the submit/validate handlers to determine whether AHAH-submittted. + $form_state['ahah_submission'] = TRUE; + $form['#programmed'] = $form['#redirect'] = FALSE; + drupal_process_form($form_id, $form, $form_state); + $form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id); + + $callback = $form_state['clicked_button']['#ahah']['callback']; + if (function_exists($callback)) { + $output = $callback($form, $form_state); + + // Add a manual fix to extend the list of AHAH element settings on the page. + $data = drupal_add_js(); + $embed_prefix = "\n\n"; + $settings = call_user_func_array('array_merge_recursive', $data['setting']); + $output .= ''; + + $output = theme('status_messages') . $output; + + drupal_json(array('status' => TRUE, 'data' => $output)); + } + else { + drupal_set_message(t('An AJAX callback was either not found or undefined.'), 'error'); + $output = theme('status_messages'); + drupal_json(array('status' => TRUE, 'data' => $output)); + } +} diff --git a/js/webform-admin.js b/js/webform-admin.js index b54783f..59a5b2b 100644 --- a/js/webform-admin.js +++ b/js/webform-admin.js @@ -14,6 +14,8 @@ Drupal.behaviors.webformAdmin = function(context) { Drupal.webform.selectCheckboxesLink(context); // Enhance the normal tableselect.js file to support indentations. Drupal.webform.tableSelectIndentation(context); + // Enhance the normal tableselect.js file to support indentations. + Drupal.webform.conditionalAdmin(context); } Drupal.webform = Drupal.webform || {}; @@ -114,3 +116,131 @@ Drupal.webform.tableSelectIndentation = function(context) { }); } +/** + * Attach behaviors for Webform conditional administration. + */ +Drupal.webform.conditionalAdmin = function(context) { + $('.webform-conditional:not(.webform-conditional-processed)').each(function() { + $(this).addClass('webform-conditional-processed'); + + // Rather than binding to click, we have to use mousedown to work with + // the AJAX handling, which disables the button and prevents "click" events. + // This handler needs a delay to let the form submit before we remove the + // table row. + $(this).find('.webform-conditional-rule-remove').mousedown(function() { + var button = this; + window.setTimeout(Drupal.webform.conditionalRemove.apply(button), 10); + }); + + $(this).find('.webform-conditional-source select').each(function() { + $(this).change(Drupal.webform.conditionalSourceChange).triggerHandler('change'); + }); + + $(this).find('.webform-conditional-operator select').each(function() { + $(this).change(Drupal.webform.conditionalOperatorChange).triggerHandler('change'); + }); + + $(this).find('.webform-conditional-andor select').each(function() { + $(this).change(Drupal.webform.conditionalAndOrChange).triggerHandler('change'); + }); + }); +} + +/** + * Event callback for the remove button next to an individual rule. + */ +Drupal.webform.conditionalRemove = function() { + // See if there are any remaining rules in this element. + var ruleCount = $(this).parents('.webform-conditional:first').find('.webform-conditional-rule-remove').length; + if (ruleCount <= 1) { + var tableRow = $(this).parents('tr:first'); + var table = $('#webform-conditionals-table'); + if (tableRow.length && table.length) { + table.find(tableRow[0]).remove(); + Drupal.webform.restripeTable(table[0]); + } + } +} + +/** + * Event callback to update the list of operators after a source change. + */ +Drupal.webform.conditionalSourceChange = function() { + var source = $(this).val(); + var dataType = Drupal.settings.webform.conditionalValues.sources[source]['data_type']; + var $operator = $(this).parents('.webform-conditional-rule:first').find('.webform-conditional-operator select'); + + // Store a the original list of all operators for all data types in the select + // list DOM element. + if (!$operator[0]['webformConditionalOriginal']) { + $operator[0]['webformConditionalOriginal'] = $operator[0].innerHTML; + } + + // Reference the original list to create a new list matching the data type. + var $originalList = $($operator[0]['webformConditionalOriginal']); + var $newList = $originalList.filter('optgroup[label=' + dataType + ']'); + $operator[0].innerHTML = $newList[0].innerHTML; + + // Fire the change event handler on the list to update the value field. + $operator.triggerHandler('change'); +} + +/** + * Event callback to update the list of operators after a source change. + */ +Drupal.webform.conditionalOperatorChange = function() { + var source = $(this).parents('.webform-conditional-rule:first').find('.webform-conditional-source select').val(); + var dataType = Drupal.settings.webform.conditionalValues.sources[source]['data_type']; + var operator = $(this).val(); + var $value = $(this).parents('.webform-conditional-rule:first').find('.webform-conditional-value'); + var value = $value.find('input, select, textarea').val(); + var name = $value.find('input, select, textarea').attr('name'); + + + // Given the dataType and operator, we can determine the form key. + var formKey = Drupal.settings.webform.conditionalValues.operators[dataType][operator]['form']; + + // Save the default field as printed on the original page. + if (!$value[0]['webformConditionalOriginal']) { + $value[0]['webformConditionalOriginal'] = $value[0].innerHTML; + } + + if (formKey === 'default') { + $value[0].innerHTML = $value[0]['webformConditionalOriginal']; + } + else { + // If there is a per-source form for this operator (e.g. option lists), use + // the specialized value form. + if (typeof Drupal.settings.webform.conditionalValues.forms[formKey] == 'object') { + $value[0].innerHTML = Drupal.settings.webform.conditionalValues.forms[formKey][source]; + } + // Otherwise all the sources use a generic field (e.g. a text field). + else { + $value[0].innerHTML = Drupal.settings.webform.conditionalValues.forms[formKey]; + } + } + + $value.find('input, select, textarea').filter(':first').val(value).attr('name', name); +} + +/** + * Event callback to make sure all group and/or operators match. + */ +Drupal.webform.conditionalAndOrChange = function() { + $(this).parents('.webform-conditional:first').find('.webform-conditional-andor select').val(this.value); +} + +/** + * Given a table's DOM element, restripe the odd/even classes. + */ +Drupal.webform.restripeTable = function(table) { + // :even and :odd are reversed because jQuery counts from 0 and + // we count from 1, so we're out of sync. + // Match immediate children of the parent element to allow nesting. + $('> tbody > tr.draggable, > tr.draggable', table) + .filter(':odd').filter('.odd') + .removeClass('odd').addClass('even') + .end().end() + .filter(':even').filter('.even') + .removeClass('even').addClass('odd'); +}; diff --git a/webform.install b/webform.install index 2ab991b..31e7333 100644 --- a/webform.install +++ b/webform.install @@ -183,6 +183,107 @@ function webform_schema() { 'primary key' => array('nid', 'cid'), ); + $schema['webform_conditional'] = array( + 'description' => 'Holds information about conditional logic.', + 'fields' => array( + 'nid' => array( + 'description' => 'The node identifier of a webform.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'rgid' => array( + 'description' => 'The rule group identifier for this group of rules.', + 'type' => 'int', + 'size' => 'small', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'andor' => array( + 'description' => 'Whether to AND or OR the actions in this group. All actions within the same crid should have the same andor value.', + 'type' => 'varchar', + 'length' => 128, + ), + 'action' => array( + 'description' => 'The action to be performed on the target. Typically "show" or "hide" for targets of type "component", and "send" for targets of type "email".', + 'type' => 'varchar', + 'length' => 128, + ), + 'target_type' => array( + 'description' => 'The type of target to be affected. Either "component" or "email". Indicates what type of ID the "target" column contains.', + 'type' => 'varchar', + 'length' => 128, + ), + 'target' => array( + 'description' => 'The ID of the target to be affected. Typically a component ID.', + 'type' => 'varchar', + 'length' => 128, + ), + 'weight' => array( + 'description' => 'Determines the position of this conditional compared to others.', + 'type' => 'int', + 'size' => 'small', + 'not null' => TRUE, + 'default' => 0, + ), + ), + 'primary key' => array('nid', 'rgid'), + ); + + $schema['webform_conditional_rules'] = array( + 'description' => 'Holds information about conditional logic.', + 'fields' => array( + 'nid' => array( + 'description' => 'The node identifier of a webform.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'rgid' => array( + 'description' => 'The rule group identifier for this group of rules.', + 'type' => 'int', + 'size' => 'small', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'rid' => array( + 'description' => 'The rule identifier for this conditional rule.', + 'type' => 'int', + 'size' => 'small', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'source_type' => array( + 'description' => 'The type of source on which the conditional is based. Currently always "component". Indicates what type of ID the "source" column contains.', + 'type' => 'varchar', + 'length' => 128, + ), + 'source' => array( + 'description' => 'The component ID being used in this condition.', + 'type' => 'int', + 'size' => 'small', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'operator' => array( + 'description' => 'Which operator (equal, contains, starts with, etc.) should be used for this comparison between the source and value?', + 'type' => 'varchar', + 'length' => 128, + ), + 'value' => array( + 'description' => 'The value to be compared with source.', + 'type' => 'text', + ), + ), + 'primary key' => array('nid', 'rgid', 'rid'), + ); + $schema['webform_emails'] = array( 'description' => 'Holds information regarding e-mails that should be sent upon submitting a webform', 'fields' => array( @@ -1511,6 +1612,119 @@ function webform_update_6331() { } /** + * Add the webform_conditional database table. + */ +function webform_update_6332() { + $ret = array(); + + $schema['webform_conditional'] = array( + 'description' => 'Holds information about conditional logic.', + 'fields' => array( + 'nid' => array( + 'description' => 'The node identifier of a webform.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'rgid' => array( + 'description' => 'The rule group identifier for this group of rules.', + 'type' => 'int', + 'size' => 'small', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'andor' => array( + 'description' => 'Whether to AND or OR the actions in this group. All actions within the same crid should have the same andor value.', + 'type' => 'varchar', + 'length' => 128, + ), + 'action' => array( + 'description' => 'The action to be performed on the target. Typically "show" or "hide" for targets of type "component", and "send" for targets of type "email".', + 'type' => 'varchar', + 'length' => 128, + ), + 'target_type' => array( + 'description' => 'The type of target to be affected. Either "component" or "email". Indicates what type of ID the "target" column contains.', + 'type' => 'varchar', + 'length' => 128, + ), + 'target' => array( + 'description' => 'The ID of the target to be affected. Typically a component ID.', + 'type' => 'varchar', + 'length' => 128, + ), + 'weight' => array( + 'description' => 'Determines the position of this conditional compared to others.', + 'type' => 'int', + 'size' => 'small', + 'not null' => TRUE, + 'default' => 0, + ), + ), + 'primary key' => array('nid', 'rgid'), + ); + + $schema['webform_conditional_rules'] = array( + 'description' => 'Holds information about conditional logic.', + 'fields' => array( + 'nid' => array( + 'description' => 'The node identifier of a webform.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'rgid' => array( + 'description' => 'The rule group identifier for this group of rules.', + 'type' => 'int', + 'size' => 'small', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'rid' => array( + 'description' => 'The rule identifier for this conditional rule.', + 'type' => 'int', + 'size' => 'small', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'source_type' => array( + 'description' => 'The type of source on which the conditional is based. Currently always "component". Indicates what type of ID the "source" column contains.', + 'type' => 'varchar', + 'length' => 128, + ), + 'source' => array( + 'description' => 'The component ID being used in this condition.', + 'type' => 'int', + 'size' => 'small', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'operator' => array( + 'description' => 'Which operator (equal, contains, starts with, etc.) should be used for this comparison between the source and value?', + 'type' => 'varchar', + 'length' => 128, + ), + 'value' => array( + 'description' => 'The value to be compared with source.', + 'type' => 'text', + ), + ), + 'primary key' => array('nid', 'rgid', 'rid'), + ); + + db_create_table($ret, 'webform_conditional', $schema['webform_conditional']); + db_create_table($ret, 'webform_conditional_rules', $schema['webform_conditional_rules']); + + return $ret; +} + +/** * Recursively delete all files and folders in the specified filepath, then * delete the containing folder. * diff --git a/webform.module b/webform.module index 27f10a4..0d5d17b 100644 --- a/webform.module +++ b/webform.module @@ -65,6 +65,9 @@ function webform_help($section = 'admin/help#webform', $arg = NULL) { $output .= '

' . t('This page displays all the components currently configured for this webform node. You may add any number of components to the form, even multiple of the same type. To add a new component, fill in a name and select a type from the fields at the bottom of the table. Submit the form to create the new component or update any changed form values.') . '

'; $output .= '

' . t('Click on any existing component\'s name to edit its settings.') . '

'; break; + case 'node/%/webform/conditionals': + $output .= '

' . t('Conditionals may be used to hide or show certain components (or entire pages!) based on the value of other components.') . '

'; + break; case 'node/%/submission/%/resend': $output .= '

' . t('This form may be used to resend e-mails configured for this webform. Check the e-mails that need to be sent and click Resend e-mails to send these e-mails again.') . '

'; break; @@ -131,6 +134,16 @@ function webform_menu() { 'weight' => 0, 'type' => MENU_DEFAULT_LOCAL_TASK, ); + $items['node/%webform_menu/webform/conditionals'] = array( + 'title' => 'Conditionals', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('webform_conditionals_form', 1), + 'access callback' => 'node_access', + 'access arguments' => array('update', 1), + 'file' => 'includes/webform.conditionals.inc', + 'weight' => 1, + 'type' => MENU_LOCAL_TASK, + ); $items['node/%webform_menu/webform/configure'] = array( 'title' => 'Form settings', 'page callback' => 'drupal_get_form', @@ -138,7 +151,7 @@ function webform_menu() { 'access callback' => 'node_access', 'access arguments' => array('update', 1), 'file' => 'includes/webform.pages.inc', - 'weight' => 2, + 'weight' => 5, 'type' => MENU_LOCAL_TASK, ); @@ -150,7 +163,7 @@ function webform_menu() { 'access callback' => 'node_access', 'access arguments' => array('update', 1), 'file' => 'includes/webform.emails.inc', - 'weight' => 1, + 'weight' => 4, 'type' => MENU_LOCAL_TASK, ); $items['node/%webform_menu/webform/emails/%webform_menu_email'] = array( @@ -210,6 +223,14 @@ function webform_menu() { 'type' => MENU_CALLBACK, ); + // AJAX callback placeholder for Drupal 6 AHAH callbacks. + $items['webform/ajax/callback'] = array( + 'page callback' => 'webform_ajax_callback', + 'access callback' => TRUE, + 'file' => 'includes/webform.pages.inc', + 'type' => MENU_CALLBACK, + ); + // Node webform results. $items['node/%webform_menu/webform-results'] = array( 'title' => 'Results', @@ -578,6 +599,15 @@ function webform_theme() { 'arguments' => array('element' => NULL), 'file' => 'includes/webform.components.inc', ), + // webform.conditionals.inc. + 'webform_conditional_groups' => array( + 'arguments' => array('element' => NULL), + 'file' => 'includes/webform.conditionals.inc', + ), + 'webform_conditional' => array( + 'arguments' => array('element' => NULL), + 'file' => 'includes/webform.conditionals.inc', + ), // webform.pages.inc. 'webform_advanced_redirection_form' => array( 'arguments' => array('form' => NULL), @@ -687,6 +717,13 @@ function webform_elements() { '#step' => NULL, ); + $elements['webform_conditional'] = array( + '#input' => TRUE, + '#theme' => 'webform_conditional', + '#default_value' => NULL, + '#process' => array('webform_conditional_expand'), + ); + return $elements; } @@ -699,9 +736,9 @@ function webform_webform_component_info() { 'label' => t('Date'), 'description' => t('Presents month, day, and year fields.'), 'features' => array( - 'conditional' => FALSE, ), 'file' => 'components/date.inc', + 'conditional_type' => 'date', ), 'email' => array( 'label' => t('E-mail'), @@ -779,11 +816,13 @@ function webform_webform_component_info() { 'features' => array( ), 'file' => 'components/number.inc', + 'conditional_type' => 'numeric', ), 'pagebreak' => array( 'label' => t('Page break'), 'description' => t('Organize forms into multiple pages.'), 'features' => array( + 'conditional' => FALSE, 'csv' => FALSE, 'default_value' => FALSE, 'description' => FALSE, @@ -802,6 +841,7 @@ function webform_webform_component_info() { 'email_address' => TRUE, 'email_name' => TRUE, ), + 'conditional_type' => 'select', ), 'textarea' => array( 'label' => t('Textarea'), @@ -825,14 +865,22 @@ function webform_webform_component_info() { 'label' => t('Time'), 'description' => t('Presents the user with hour and minute fields. Optional am/pm fields.'), 'features' => array( - 'conditional' => FALSE, ), 'file' => 'components/time.inc', + 'conditional_type' => 'time', ), ); } /** + * Implements hook_webform_conditional_operator_info(). + */ +function webform_webform_conditional_operator_info() { + module_load_include('inc', 'webform', 'includes/webform.conditionals'); + return _webform_conditional_operator_info(); +} + +/** * Implements hook_forms(). * * All webform_client_form forms share the same form handler @@ -998,6 +1046,15 @@ function webform_node_insert($node) { } } + // Insert conditionals. Also used with clone.module. + if (isset($node->webform['conditionals']) && !empty($node->webform['conditionals'])) { + foreach ($node->webform['conditionals'] as $rgid => $conditional) { + $conditional['nid'] = $node->nid; + $conditional['rgid'] = $rgid; + webform_conditional_insert($conditional); + } + } + // Insert emails. Also used with clone.module. if (isset($node->webform['emails']) && !empty($node->webform['emails'])) { foreach ($node->webform['emails'] as $eid => $email) { @@ -1062,6 +1119,24 @@ function webform_node_update($node) { } } + // Compare the webform conditionals and don't do anything if it's not needed. + if ($original->webform['conditionals'] != $node->webform['conditionals']) { + module_load_include('inc', 'webform', 'includes/webform.conditionals'); + + // Conditionals don't have unique site-wide IDs or configuration, so our + // update here is a bit more aggressive than for components and e-mails. + foreach ($original->webform['conditionals'] as $rgid => $conditional) { + if (!isset($node->webform['conditionals'][$rgid]) || $original->webform['conditionals'][$rgid] != $node->webform['conditionals'][$rgid]) { + webform_conditional_delete($node, $conditional); + } + } + foreach ($node->webform['conditionals'] as $rgid => $conditional) { + $conditional['nid'] = $node->nid; + $conditional['rgid'] = $rgid; + webform_conditional_insert($conditional); + } + } + // Compare the webform e-mails and don't do anything if it's not needed. if ($original->webform['emails'] != $node->webform['emails']) { module_load_include('inc', 'webform', 'includes/webform.emails'); @@ -1113,6 +1188,8 @@ function webform_node_delete($node) { // Remove any trace of webform data from the database. db_query('DELETE FROM {webform} WHERE nid = %d', $node->nid); db_query('DELETE FROM {webform_component} WHERE nid = %d', $node->nid); + db_query('DELETE FROM {webform_conditional} WHERE nid = %d', $node->nid); + db_query('DELETE FROM {webform_conditional_rules} WHERE nid = %d', $node->nid); db_query('DELETE FROM {webform_emails} WHERE nid = %d', $node->nid); db_query('DELETE FROM {webform_roles} WHERE nid = %d', $node->nid); db_query('DELETE FROM {webform_submissions} WHERE nid = %d', $node->nid); @@ -1229,6 +1306,17 @@ function webform_node_load($node) { _webform_components_tree_build($additions['webform']['components'], $component_tree, 0, $page_count); $additions['webform']['components'] = _webform_components_tree_flatten($component_tree['children']); } + + $additions['webform']['conditionals'] = array(); + $result = db_query('SELECT * FROM {webform_conditional} WHERE nid = %d ORDER BY weight ASC', $node->nid); + while ($c = db_fetch_array($result)) { + $additions['webform']['conditionals'][$c['rgid']] = $c; + } + $result = db_query('SELECT * FROM {webform_conditional_rules} WHERE nid = %d ORDER BY rgid ASC, rid ASC', $node->nid); + while ($r = db_fetch_array($result)) { + $additions['webform']['conditionals'][$r['rgid']]['rules'][$r['rid']] = $r; + } + return $additions; } @@ -3368,6 +3456,14 @@ function webform_component_implements($type, $callback) { } /** + * Form API #process function to expand a webform conditional element. + */ +function webform_conditional_expand($element) { + module_load_include('inc', 'webform', 'includes/webform.conditionals'); + return _webform_conditional_expand($element); +} + +/** * Disable the Drupal page cache. */ function webform_disable_page_cache() {