[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/modules/webform/includes/ -> webform.components.inc (source)

   1  <?php
   2  // $Id: webform.components.inc,v 1.25.2.23 2010/10/01 00:57:30 quicksketch Exp $
   3  
   4  /**
   5   * @file
   6   * Webform module component handling.
   7   */
   8  
   9  /**
  10   * Provides interface and database handling for editing components of a webform.
  11   *
  12   * @author Nathan Haug <nate@lullabot.com>
  13   */
  14  
  15  /**
  16   * Overview page of all components for this webform.
  17   */
  18  function webform_components_page($node) {
  19    $form = drupal_get_form('webform_components_form', $node);
  20    return theme('webform_components_page', $node, $form);
  21  }
  22  
  23  /**
  24   * Theme the output of the main components page.
  25   *
  26   * This theming provides a way to toggle between the editing modes if Form
  27   * Builder module is available.
  28   */
  29  function theme_webform_components_page($node, $form) {
  30    // Add CSS and JS. Don't preprocess because these files are used rarely.
  31    drupal_add_css(drupal_get_path('module', 'webform') . '/css/webform-admin.css', 'theme', 'all', FALSE);
  32    drupal_add_js(drupal_get_path('module', 'webform') . '/js/webform-admin.js', 'module', 'header', FALSE, TRUE, FALSE);
  33  
  34    return $form;
  35  }
  36  
  37  /**
  38   * The table-based listing of all components for this webform.
  39   */
  40  function webform_components_form($form_state, $node) {
  41    $form = array(
  42      '#tree' => TRUE,
  43      '#node' => $node,
  44      'components' => array(),
  45    );
  46  
  47    $form['nid'] = array(
  48      '#type' => 'value',
  49      '#value' => $node->nid,
  50    );
  51  
  52    $options = array();
  53    foreach ($node->webform['components'] as $cid => $component) {
  54      $options[$cid] = check_plain($component['name']);
  55      $form['components'][$cid]['cid'] = array(
  56        '#type' => 'hidden',
  57        '#default_value' => $component['cid'],
  58      );
  59      $form['components'][$cid]['pid'] = array(
  60        '#type' => 'hidden',
  61        '#default_value' => $component['pid'],
  62      );
  63      $form['components'][$cid]['weight'] = array(
  64        '#type' => 'textfield',
  65        '#size' => 4,
  66        '#title' => t('Weight'),
  67        '#default_value' => $component['weight'],
  68      );
  69      $form['components'][$cid]['mandatory'] = array(
  70        '#type' => 'checkbox',
  71        '#title' => t('Mandatory'),
  72        '#default_value' => $component['mandatory'],
  73        '#access' => webform_component_feature($component['type'], 'required'),
  74      );
  75    }
  76  
  77    $form['add']['name'] = array(
  78      '#type' => 'textfield',
  79      '#size' => 24,
  80    );
  81  
  82    $form['add']['type'] = array(
  83      '#type' => 'select',
  84      '#options' => webform_component_options(),
  85      '#weight' => 3,
  86      '#default_value' => (isset($_GET['cid']) && isset($node->webform['components'][$_GET['cid']])) ? $node->webform['components'][$_GET['cid']]['type'] : 'textfield',
  87    );
  88    $form['add']['mandatory'] = array(
  89      '#type' => 'checkbox',
  90    );
  91    $form['add']['cid'] = array(
  92      '#type' => 'hidden',
  93      '#default_value' => '',
  94    );
  95    $form['add']['pid'] = array(
  96      '#type' => 'hidden',
  97      '#default_value' => (isset($_GET['cid']) && isset($node->webform['components'][$_GET['cid']])) ? $node->webform['components'][$_GET['cid']]['pid'] : 0,
  98    );
  99    $form['add']['weight'] = array(
 100      '#type' => 'weight',
 101      '#delta' => count($node->webform['components']) > 10 ? count($node->webform['components']) : 10,
 102      '#default_value' => (isset($_GET['cid']) && isset($node->webform['components'][$_GET['cid']])) ? $node->webform['components'][$_GET['cid']]['weight'] + 1: count($node->webform['components']),
 103    );
 104  
 105    $form['add']['add'] = array(
 106      '#type' => 'submit',
 107      '#value' => t('Add'),
 108      '#weight' => 45,
 109    );
 110  
 111    $form['submit'] = array(
 112      '#type' => 'submit',
 113      '#value' => t('Submit'),
 114      '#weight' => 45,
 115    );
 116  
 117    return $form;
 118  }
 119  
 120  /**
 121   * Theme the node components form. Use a table to organize the components.
 122   *
 123   * @param $form
 124   *   The form array.
 125   * @return
 126   *   Formatted HTML form, ready for display.
 127   */
 128  function theme_webform_components_form($form) {
 129    // Add CSS to display submission info. Don't preprocess because this CSS file is used rarely.
 130    drupal_add_css(drupal_get_path('module', 'webform') . '/css/webform-admin.css', 'theme', 'all', FALSE);
 131    drupal_add_js(drupal_get_path('module', 'webform') . '/js/webform-admin.js', 'module', 'header', FALSE, TRUE, FALSE);
 132  
 133    drupal_add_tabledrag('webform-components', 'order', 'sibling', 'webform-weight');
 134    drupal_add_tabledrag('webform-components', 'match', 'parent', 'webform-pid', 'webform-pid', 'webform-cid');
 135  
 136    $node = $form['#node'];
 137  
 138    $header = array(t('Name'), t('Type'), t('Value'), t('Mandatory'), t('Weight'), array('data' => t('Operations'), 'colspan' => 3));
 139    $rows = array();
 140  
 141    // Add a row containing form elements for a new item.
 142    unset($form['add']['name']['#title'], $form['add_type']['#description']);
 143    $form['add']['name']['#attributes']['rel'] = t('New component name');
 144    $form['add']['name']['#attributes']['class'] = 'webform-default-value';
 145    $form['add']['cid']['#attributes']['class'] = 'webform-cid';
 146    $form['add']['pid']['#attributes']['class'] = 'webform-pid';
 147    $form['add']['weight']['#attributes']['class'] = 'webform-weight';
 148    $row_data = array(
 149      drupal_render($form['add']['name']),
 150      drupal_render($form['add']['type']),
 151      '',
 152      drupal_render($form['add']['mandatory']),
 153      drupal_render($form['add']['cid']) . drupal_render($form['add']['pid']) . drupal_render($form['add']['weight']),
 154      array('colspan' => 3, 'data' => drupal_render($form['add']['add'])),
 155    );
 156    $add_form = array('data' => $row_data, 'class' => 'draggable webform-add-form');
 157    $form_rendered = FALSE;
 158  
 159    if (!empty($node->webform['components'])) {
 160      $component_tree = array();
 161      $page_count = 1;
 162      _webform_components_tree_build($node->webform['components'], $component_tree, 0, $page_count);
 163      $component_tree = _webform_components_tree_sort($component_tree);
 164      // Build the table rows.
 165      function _webform_components_form_rows($node, $cid, $component, $level, &$form, &$rows, &$add_form) {
 166        // Create presentable values.
 167        if (drupal_strlen($component['value']) > 30) {
 168          $component['value'] = drupal_substr($component['value'], 0, 30);
 169          $component['value'] .= '...';
 170        }
 171        $component['value'] = check_plain($component['value']);
 172  
 173        // Remove individual titles from the mandatory and weight fields.
 174        unset($form['components'][$cid]['mandatory']['#title']);
 175        unset($form['components'][$cid]['pid']['#title']);
 176        unset($form['components'][$cid]['weight']['#title']);
 177  
 178        // Add special classes for weight and parent fields.
 179        $form['components'][$cid]['cid']['#attributes']['class'] = 'webform-cid';
 180        $form['components'][$cid]['pid']['#attributes']['class'] = 'webform-pid';
 181        $form['components'][$cid]['weight']['#attributes']['class'] = 'webform-weight';
 182  
 183        // Build indentation for this row.
 184        $indents = '';
 185        for ($n = 1; $n <= $level; $n++) {
 186          $indents .= '<div class="indentation">&nbsp;</div>';
 187        }
 188  
 189        // Add each component to a table row.
 190        $row_data = array(
 191          $indents . filter_xss($component['name']),
 192          t($component['type']),
 193          ($component['value'] == '') ? '-' : $component['value'],
 194          drupal_render($form['components'][$cid]['mandatory']),
 195          drupal_render($form['components'][$cid]['cid']) . drupal_render($form['components'][$cid]['pid']) . drupal_render($form['components'][$cid]['weight']),
 196          l(t('Edit'), 'node/' . $node->nid . '/webform/components/' . $cid, array('query' => drupal_get_destination())),
 197          l(t('Clone'), 'node/' . $node->nid . '/webform/components/' . $cid . '/clone', array('query' => drupal_get_destination())),
 198          l(t('Delete'), 'node/' . $node->nid . '/webform/components/' . $cid . '/delete', array('query' => drupal_get_destination())),
 199        );
 200        $row_class = 'draggable';
 201        if (!webform_component_feature($component['type'], 'group')) {
 202          $row_class .= ' tabledrag-leaf';
 203        }
 204        if ($component['type'] == 'pagebreak') {
 205          $row_class .= ' tabledrag-root webform-pagebreak';
 206          $row_data[0] = array('class' => 'webform-pagebreak', 'data' => $row_data[0]);
 207        }
 208        $rows[] = array('data' => $row_data, 'class' => $row_class);
 209        if (isset($component['children']) && is_array($component['children'])) {
 210          foreach ($component['children'] as $cid => $component) {
 211            _webform_components_form_rows($node, $cid, $component, $level + 1, $form, $rows, $add_form);
 212          }
 213        }
 214  
 215        // Add the add form if this was the last edited component.
 216        if (isset($_GET['cid']) && $component['cid'] == $_GET['cid'] && $add_form) {
 217          $add_form['data'][0] = $indents . $add_form['data'][0];
 218          $rows[] = $add_form;
 219          $add_form = FALSE;
 220        }
 221      }
 222      foreach ($component_tree['children'] as $cid => $component) {
 223        _webform_components_form_rows($node, $cid, $component, 0, $form, $rows, $add_form);
 224      }
 225    }
 226    else {
 227      $rows[] = array(array('data' => t('No Components, add a component below.'), 'colspan' => 9));
 228    }
 229  
 230    // Append the add form if not already printed.
 231    if ($add_form) {
 232      $rows[] = $add_form;
 233    }
 234  
 235    $output = '';
 236    $output .= theme('table', $header, $rows, array('id' => 'webform-components'));
 237    $output .= drupal_render($form);
 238    return $output;
 239  }
 240  
 241  function webform_components_form_validate($form, &$form_state) {
 242    // Check that the entered component name is valid.
 243    if ($form_state['values']['op'] == t('Add') && drupal_strlen(trim($form_state['values']['add']['name'])) <= 0) {
 244      form_error($form['add']['name'], t('When adding a new component, the name field is required.'));
 245    }
 246  
 247    // Check that no two components end up with the same form key.
 248    $duplicates = array();
 249    $parents = array();
 250    if (isset($form_state['values']['components'])) {
 251      foreach ($form_state['values']['components'] as $cid => $component) {
 252        $form_key = $form['#node']->webform['components'][$cid]['form_key'];
 253        if (isset($parents[$component['pid']]) && ($existing = array_search($form_key, $parents[$component['pid']])) && $existing !== FALSE) {
 254          if (!isset($duplicates[$component['form_key']])) {
 255            $duplicates[$component['form_key']] = array($existing);
 256          }
 257          $duplicates[$component['form_key']][] = $cid;
 258        }
 259        $parents[$component['pid']][$cid] = $form_key;
 260      }
 261    }
 262  
 263    if (!empty($duplicates)) {
 264      $error = t('The form order failed to save because the following elements have same form keys and are under the same parent. Edit each component and give them a unique form key, then try moving them again.');
 265      $items = array();
 266      foreach ($duplicates as $form_key => $cids) {
 267        foreach ($cids as $cid) {
 268          $items[] = $form['#node']->webform['components'][$cid]['name'];
 269        }
 270      }
 271  
 272      form_error($form['components'], $error . theme('item_list', $items));
 273    }
 274  }
 275  
 276  function webform_components_form_submit($form, &$form_state) {
 277    $node = node_load($form_state['values']['nid']);
 278  
 279    // Update all mandatory and weight values.
 280    foreach ($node->webform['components'] as $cid => $component) {
 281      if ($component['pid'] != $form_state['values']['components'][$cid]['pid'] || $component['weight'] != $form_state['values']['components'][$cid]['weight'] || $component['mandatory'] != $form_state['values']['components'][$cid]['mandatory']) {
 282        $component['weight'] = $form_state['values']['components'][$cid]['weight'];
 283        $component['mandatory'] = $form_state['values']['components'][$cid]['mandatory'];
 284        $component['pid'] = $form_state['values']['components'][$cid]['pid'];
 285        $component['nid'] = $node->nid;
 286        webform_component_update($component);
 287      }
 288    }
 289  
 290    if (isset($_POST['op']) && $_POST['op'] == t('Publish')) {
 291      $node->status = 1;
 292      node_save($node);
 293      drupal_set_message(t('Your webform has been published.'));
 294      return 'node/' . $node->nid;
 295    }
 296    elseif (isset($_POST['op']) && $_POST['op'] == t('Add')) {
 297      $component = $form_state['values']['add'];
 298      $form_state['redirect'] = array('node/' . $node->nid . '/webform/components/new/' . $component['type'], 'name=' . urlencode($component['name']) . '&mandatory=' . $component['mandatory'] . '&pid=' . $component['pid'] . '&weight=' . $component['weight']);
 299    }
 300    else {
 301      drupal_set_message(t('The component positions and mandatory values have been updated.'));
 302  
 303      // Since Webform components have been updated but the node itself has not
 304      // been saved, it is necessary to explicitly clear the cache to make sure
 305      // the updated webform is visible to anonymous users.
 306      cache_clear_all();
 307    }
 308  }
 309  
 310  function webform_component_edit_form(&$form_state, $node, $component, $clone = FALSE) {
 311    drupal_set_title(t('Edit component: @name', array('@name' => $component['name'])));
 312    drupal_add_css(drupal_get_path('module', 'webform') . '/css/webform-admin.css', 'theme', 'all', FALSE);
 313  
 314    // Print the correct field type specification.
 315    // We always need: name and description.
 316    $form = array(
 317      '#tree' => TRUE,
 318    );
 319    $form['type'] = array(
 320      '#type' => 'value',
 321      '#value' => $component['type'],
 322    );
 323    $form['nid'] = array(
 324      '#type' => 'value',
 325      '#value' => $node->nid,
 326    );
 327    $form['cid'] = array(
 328      '#type' => 'value',
 329      '#value' => isset($component['cid']) ? $component['cid'] : NULL,
 330    );
 331    $form['clone'] = array(
 332      '#type' => 'value',
 333      '#value' => $clone,
 334    );
 335    $form['name'] = array(
 336      '#type' => 'textfield',
 337      '#default_value' => $component['name'],
 338      '#title' => t('Label'),
 339      '#description' => t('This is used as a descriptive label when displaying this form element.'),
 340      '#required' => TRUE,
 341      '#weight' => -10,
 342      '#maxlength' => 255,
 343    );
 344    $form['form_key'] = array(
 345      '#type' => 'textfield',
 346      '#default_value' => empty($component['form_key']) ? _webform_safe_name($component['name']) : $component['form_key'],
 347      '#title' => t('Field Key'),
 348      '#description' => t('Enter a machine readable key for this form element. May contain only lowercase alphanumeric characters and underscores. This key will be used as the name attribute of the form element. This value has no effect on the way data is saved, but may be helpful if doing custom form processing.'),
 349      '#required' => TRUE,
 350      '#weight' => -9,
 351    );
 352    $form['extra']['description'] = array(
 353      '#type' => 'textarea',
 354      '#default_value' => isset($component['extra']['description']) ? $component['extra']['description'] : '',
 355      '#title' => t('Description'),
 356      '#description' => t('A short description of the field used as help for the user when he/she uses the form.') . theme('webform_token_help'),
 357      '#weight' => -1,
 358    );
 359  
 360    // Display settings.
 361    $form['display'] = array(
 362      '#type' => 'fieldset',
 363      '#title' => t('Display'),
 364      '#collapsible' => TRUE,
 365      '#collapsed' => FALSE,
 366      '#weight' => 8,
 367    );
 368    $form['display']['title_display'] = array(
 369      '#type' => 'checkbox',
 370      '#title' => t('Hide component title'),
 371      '#default_value' => !empty($component['extra']['title_display']),
 372      '#return_value' => 'none',
 373      '#description' => t('Do not display the title or label of this field in the form.'),
 374      '#weight' => 8,
 375      '#parents' => array('extra', 'title_display'),
 376    );
 377  
 378    // Validation settings.
 379    $form['validation'] = array(
 380      '#type' => 'fieldset',
 381      '#title' => t('Validation'),
 382      '#collapsible' => TRUE,
 383      '#collapsed' => FALSE,
 384      '#weight' => 5,
 385    );
 386    if (webform_component_feature($component['type'], 'required')) {
 387      $form['validation']['mandatory'] = array(
 388        '#type' => 'checkbox',
 389        '#title' => t('Mandatory'),
 390        '#default_value' => ($component['mandatory'] == '1' ? TRUE : FALSE),
 391        '#description' => t('Check this option if the user must enter a value.'),
 392        '#weight' => -1,
 393        '#parents' => array('mandatory'),
 394      );
 395    }
 396  
 397    // Position settings, only shown if JavaScript is disabled.
 398    $form['position'] = array(
 399      '#type' => 'fieldset',
 400      '#title' => t('Position'),
 401      '#collapsible' => TRUE,
 402      '#collapsed' => TRUE,
 403      '#tree' => FALSE,
 404      '#weight' => 20,
 405      '#attributes' => array('class' => 'webform-position'),
 406    );
 407  
 408    if (variable_get('webform_enable_fieldset', TRUE) && is_array($node->webform['components'])) {
 409      $options = array('0' => t('Root'));
 410      foreach ($node->webform['components'] as $existing_cid => $value) {
 411        if (webform_component_feature($value['type'], 'group') && (!isset($component['cid']) || $existing_cid != $component['cid'])) {
 412          $options[$existing_cid] = $value['name'];
 413        }
 414      }
 415      $form['position']['pid'] = array(
 416        '#type' => 'select',
 417        '#title' => t('Parent Fieldset'),
 418        '#default_value' => $component['pid'],
 419        '#description' => t('Optional. You may organize your form by placing this component inside another fieldset.'),
 420        '#options' => $options,
 421        '#weight' => 3,
 422      );
 423    }
 424    $form['position']['weight'] = array(
 425      '#type' => 'textfield',
 426      '#size' => 4,
 427      '#title' => t('Weight'),
 428      '#default_value' => $component['weight'],
 429      '#description' => t('Optional. In the menu, the heavier items will sink and the lighter items will be positioned nearer the top.'),
 430      '#weight' => 4,
 431    );
 432  
 433    // Add conditional fields.
 434    $conditional_components = array();
 435    $counter = 0;
 436    $last_pagebreak_slice = 0;
 437    foreach ($node->webform['components'] as $cid => $test_component) {
 438      // Only components before the pagebreak can be considered.
 439      if ($test_component['type'] == 'pagebreak') {
 440        $last_pagebreak_slice = $counter;
 441      }
 442      if (isset($component['cid']) && $cid == $component['cid']) {
 443        break;
 444      }
 445      if (webform_component_feature($test_component['type'], 'conditional')) {
 446        $conditional_components[$cid] = $test_component;
 447      }
 448      $counter++;
 449    }
 450    if ($component['type'] != 'pagebreak') {
 451      $fieldset_description = t('Create a rule to control whether or not to skip this page.');
 452    }
 453    else {
 454      $fieldset_description = t('Create a rule to control whether or not to show this form element.');
 455    }
 456    $conditional_components = array_slice($conditional_components, 0, $last_pagebreak_slice, TRUE);
 457    $form['conditional'] = array(
 458      '#weight' => 10,
 459      '#type' => 'fieldset',
 460      '#title' => t('Conditional rules'),
 461      '#collapsible' => TRUE,
 462      '#collapsed' => TRUE,
 463      '#description' => t('Create a rule to control whether or not to show this form element.'),
 464      '#tree' => FALSE,
 465    );
 466    $form['conditional']['extra'] = array(
 467      '#tree' => TRUE,
 468    );
 469    $form['conditional']['extra']['conditional_component'] = array(
 470      '#type' => 'select',
 471      '#title' => t('Component'),
 472      '#options' => webform_component_list($node, $conditional_components, FALSE, TRUE),
 473      '#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.'),
 474      '#default_value' => $component['extra']['conditional_component'],
 475    );
 476    $form['conditional']['extra']['conditional_operator'] = array(
 477      '#type' => 'select',
 478      '#title' => t('Operator'),
 479      '#options' => array(
 480        '=' => t('Is one of'),
 481        '!=' => t('Is not one of')
 482      ),
 483      '#description' => t('Determines whether the list below is inclusive or exclusive.'),
 484      '#default_value' => $component['extra']['conditional_operator'],
 485    );
 486    $form['conditional']['extra']['conditional_values'] = array(
 487      '#type' => 'textarea',
 488      '#title' => t('Values'),
 489      '#description' => t('List values, one per line, that will trigger this action. If you leave this blank, this component will always display.'),
 490      '#default_value' => $component['extra']['conditional_values'],
 491    );
 492    if (empty($conditional_components)) {
 493      $form['conditional']['#access'] = FALSE;
 494    }
 495  
 496    // Add the fields specific to this component type:
 497    $additional_form_elements = (array) webform_component_invoke($component['type'], 'edit', $component);
 498    if (empty($additional_form_elements)) {
 499      drupal_set_message(t('The webform component of type @type does not have an edit function defined.', array('@type' => $component['type'])));
 500    }
 501  
 502    // Merge the additional fields with the current fields:
 503    if (isset($additional_form_elements['extra'])) {
 504      $form['extra'] = array_merge($form['extra'], $additional_form_elements['extra']);
 505      unset($additional_form_elements['extra']);
 506    }
 507    if (isset($additional_form_elements['position'])) {
 508      $form['position'] = array_merge($form['position'], $additional_form_elements['position']);
 509      unset($additional_form_elements['position']);
 510    }
 511    if (isset($additional_form_elements['display'])) {
 512      $form['display'] = array_merge($form['display'], $additional_form_elements['display']);
 513      unset($additional_form_elements['display']);
 514    }
 515    if (isset($additional_form_elements['validation'])) {
 516      $form['validation'] = array_merge($form['validation'], $additional_form_elements['validation']);
 517      unset($additional_form_elements['validation']);
 518    }
 519    elseif (count(element_children($form['validation'])) == 0) {
 520      unset($form['validation']);
 521    }
 522    $form = array_merge($form, $additional_form_elements);
 523  
 524    // Add the submit button.
 525    $form['submit'] = array(
 526      '#type' => 'submit',
 527      '#value' => t('Submit'),
 528      '#weight' => 50,
 529    );
 530  
 531    return $form;
 532  }
 533  
 534  /**
 535   * Field name validation for the webform unique key. Must be alphanumeric.
 536   */
 537  function webform_component_edit_form_validate($form, &$form_state) {
 538    $node = node_load($form_state['values']['nid']);
 539  
 540    if (!preg_match('!^[a-z0-9_]+$!', $form_state['values']['form_key'])) {
 541      form_set_error('form_key', t('The field key %field_key is invalid. Please include only lowercase alphanumeric characters and underscores.', array('%field_key' => $form_state['values']['form_key'])));
 542    }
 543  
 544    foreach ($node->webform['components'] as $cid => $component) {
 545      if (($component['cid'] != $form_state['values']['cid'] || $form_state['values']['clone']) && ($component['pid'] == $form_state['values']['pid']) && (strcasecmp($component['form_key'], $form_state['values']['form_key']) == 0)) {
 546        form_set_error('form_key', t('The field key %field_key is already in use by the field labeled %existing_field. Please use a unique key.', array('%field_key' => $form_state['values']['form_key'], '%existing_field' => $component['name'])));
 547      }
 548    }
 549  }
 550  
 551  function webform_component_edit_form_submit($form, &$form_state) {
 552    $node = node_load($form_state['values']['nid']);
 553  
 554    // Remove empty extra values.
 555    if (isset($form_state['values']['extra'])) {
 556      foreach ($form_state['values']['extra'] as $key => $value) {
 557        if ($value  === '') {
 558          unset($form_state['values']['extra'][$key]);
 559        }
 560      }
 561    }
 562  
 563    // Remove empty attribute values.
 564    if (isset($form_state['values']['extra']['attributes'])) {
 565      foreach ($form_state['values']['extra']['attributes'] as $key => $value) {
 566        if ($value === '') {
 567          unset($form_state['values']['extra']['attributes'][$key]);
 568        }
 569      }
 570    }
 571  
 572    if ($form_state['values']['clone']) {
 573      drupal_set_message(t('Component %name cloned.', array('%name' => $form_state['values']['name'])));
 574      webform_component_clone($node, $form_state['values']);
 575    }
 576    elseif (!empty($form_state['values']['cid'])) {
 577      drupal_set_message(t('Component %name updated.', array('%name' => $form_state['values']['name'])));
 578      webform_component_update($form_state['values']);
 579    }
 580    else {
 581      drupal_set_message(t('New component %name added.', array('%name' => $form_state['values']['name'])));
 582      $cid = webform_component_insert($form_state['values']);
 583    }
 584  
 585    // Since Webform components have been updated but the node itself has not
 586    // been saved, it is necessary to explicitly clear the cache to make sure
 587    // the updated webform is visible to anonymous users.
 588    cache_clear_all();
 589  
 590    $form_state['redirect'] = array('node/' . $form_state['values']['nid'] . '/webform/components', isset($cid) ? 'cid=' . $cid : '');
 591  }
 592  
 593  function webform_component_delete_form($form_state, $node, $component) {
 594    $cid = $component['cid'];
 595  
 596    $form = array();
 597    $form['node'] = array(
 598      '#type' => 'value',
 599      '#value' => $node,
 600    );
 601    $form['component'] = array(
 602      '#type' => 'value',
 603      '#value' => $component,
 604    );
 605  
 606    if (webform_component_feature($node->webform['components'][$cid]['type'], 'group')) {
 607      $question = t('Delete the %name fieldset?', array('%name' => $node->webform['components'][$cid]['name']));
 608      $description = t('This will immediately delete the %name fieldset and all children elements within %name from the %webform webform. This cannot be undone.', array('%name' => $node->webform['components'][$cid]['name'], '%webform' => $node->title));
 609    }
 610    else {
 611      $question = t('Delete the %name component?', array('%name' => $node->webform['components'][$cid]['name']));
 612      $description = t('This will immediately delete the %name component from the %webform webform. This cannot be undone.', array('%name' => $node->webform['components'][$cid]['name'], '%webform' => $node->title));
 613    }
 614  
 615    return confirm_form($form, $question, 'node/' . $node->nid . '/webform/components', $description, t('Delete'));
 616  }
 617  
 618  function webform_component_delete_form_submit($form, &$form_state) {
 619    drupal_set_message(t('Component %name deleted.', array('%name' => $form_state['values']['component']['name'])));
 620    webform_component_delete($form_state['values']['node'], $form_state['values']['component']);
 621    $form_state['redirect'] = 'node/' . $form_state['values']['node']->nid . '/webform/components';
 622  }
 623  
 624  /**
 625   * Insert a new component into the database.
 626   *
 627   * @param $component
 628   *   A full component containing fields from the component form.
 629   */
 630  function webform_component_insert(&$component) {
 631    // Allow modules to modify the component before saving.
 632    foreach (module_implements('webform_component_presave') as $module) {
 633      $function = $module . '_webform_component_presave';
 634      $function($component);
 635    }
 636  
 637    db_lock_table('webform_component');
 638    $component['cid'] = isset($component['cid']) ? $component['cid'] : db_result(db_query('SELECT MAX(cid) FROM {webform_component} WHERE nid = %d', $component['nid'])) + 1;
 639    $component['value'] = isset($component['value']) ? $component['value'] : NULL;
 640    $component['mandatory'] = isset($component['mandatory']) ? $component['mandatory'] : 0;
 641    db_query("INSERT INTO {webform_component} (nid, cid, pid, form_key, name, type, value, extra, mandatory, weight) VALUES (%d, %d, %d, '%s', '%s', '%s', '%s', '%s', %d, %d)", $component['nid'], $component['cid'], $component['pid'], $component['form_key'], $component['name'], $component['type'], $component['value'], serialize($component['extra']), $component['mandatory'], $component['weight']);
 642    db_unlock_tables();
 643  
 644    // Post-insert actions.
 645    module_invoke_all('webform_component_insert', $component);
 646  
 647    return $component['cid'];
 648  }
 649  
 650  /**
 651   * Update an existing component with new values.
 652   *
 653   * @param $component
 654   *   A full component containing a nid, cid, and all other fields from the
 655   *   component form. Additional properties are stored in the extra array.
 656   */
 657  function webform_component_update($component) {
 658    // Allow modules to modify the component before saving.
 659    foreach (module_implements('webform_component_presave') as $module) {
 660      $function = $module . '_webform_component_presave';
 661      $function($component);
 662    }
 663  
 664    $component['value'] = isset($component['value']) ? $component['value'] : NULL;
 665    $component['mandatory'] = isset($component['mandatory']) ? $component['mandatory'] : 0;
 666    $success = db_query("UPDATE {webform_component} SET pid = %d, form_key = '%s', name = '%s', type = '%s', value = '%s', extra = '%s', mandatory = %d, weight = %d WHERE nid = %d AND cid = %d", $component['pid'], $component['form_key'], $component['name'], $component['type'], $component['value'], serialize($component['extra']), $component['mandatory'], $component['weight'], $component['nid'], $component['cid']);
 667  
 668    // Post-update actions.
 669    module_invoke_all('webform_component_update', $component);
 670  
 671    return $success;
 672  }
 673  
 674  function webform_component_delete($node, $component) {
 675    // Check if a delete function is available for this component. If so,
 676    // load all submissions and allow the component to delete each one.
 677  
 678    webform_component_include($component['type']);
 679    $delete_function = '_webform_delete_' . $component['type'];
 680    if (function_exists($delete_function)) {
 681      module_load_include('inc', 'webform', 'includes/webform.submissions');
 682      $submissions = webform_get_submissions($node->nid);
 683      foreach ($submissions as $submission) {
 684        if (isset($submission->data[$component['cid']])) {
 685          webform_component_invoke($component['type'], 'delete', $component, $submission->data[$component['cid']]['value']);
 686        }
 687      }
 688    }
 689  
 690    // Remove database entries.
 691    db_query('DELETE FROM {webform_component} WHERE nid = %d AND cid = %d', $node->nid, $component['cid']);
 692    db_query('DELETE FROM {webform_submitted_data} WHERE nid = %d AND cid = %d', $node->nid, $component['cid']);
 693  
 694    // Delete all elements under this element.
 695    $result = db_query('SELECT cid FROM {webform_component} WHERE nid = %d AND pid = %d', $node->nid, $component['cid']);
 696    while ($row = db_fetch_object($result)) {
 697      $child_component = $node->webform['components'][$row->cid];
 698      webform_component_delete($node, $child_component);
 699    }
 700  
 701    // Post-delete actions.
 702    module_invoke_all('webform_component_delete', $component);
 703  }
 704  
 705  /**
 706   * Recursively insert components into the database.
 707   * @param $node
 708   *   The node object containing the current webform.
 709   * @param $component
 710   *   A full component containing fields from the component form.
 711   */
 712  function webform_component_clone(&$node, &$component) {
 713    $original_cid = $component['cid'];
 714    unset($component['cid']);
 715    $new_cid = webform_component_insert($component);
 716    if (webform_component_feature($component['type'], 'group')) {
 717      foreach ($node->webform['components'] as $cid => $child_component) {
 718        if ($child_component['pid'] == $original_cid) {
 719          $child_component['pid'] = $new_cid;
 720          webform_component_clone($node, $child_component);
 721        }
 722      }
 723    }
 724    return $new_cid;
 725  }
 726  
 727  /**
 728   * Check if a component has a particular feature.
 729   */
 730  function webform_component_feature($type, $feature) {
 731    $components = webform_components();
 732    $defaults = array(
 733      'csv' => TRUE,
 734      'email' => TRUE,
 735      'email_address' => FALSE,
 736      'email_name' => FALSE,
 737      'required' => TRUE,
 738      'conditional' => TRUE,
 739      'spam_analysis' => FALSE,
 740      'group' => FALSE,
 741    );
 742    return isset($components[$type]['features'][$feature]) ? $components[$type]['features'][$feature] : !empty($defaults[$feature]);
 743  }
 744  
 745  /**
 746   * Create a list of components suitable for a select list.
 747   *
 748   * @param $node
 749   *   The webform node.
 750   * @param $component_filter
 751   *   Either an array of components, or a string containing a feature name (csv,
 752   *   email, required, conditional) on which this list of components will be
 753   *   restricted.
 754   * @param $indent
 755   *   Indent components placed under fieldsets with hyphens.
 756   * @param $optgroups
 757   *   Determine if pagebreaks should be converted to option groups in the
 758   *   returned list of options.
 759   */
 760  function webform_component_list($node, $component_filter = NULL, $indent = TRUE, $optgroups = FALSE) {
 761    $options = array();
 762    $page_names = array();
 763  
 764    $components = is_array($component_filter) ? $component_filter : $node->webform['components'];
 765    $feature = is_string($component_filter) ? $component_filter : NULL;
 766  
 767    foreach ($components as $cid => $component) {
 768      if (!isset($feature) || webform_component_feature($component['type'], $feature) || ($indent && webform_component_feature($component['type'], 'group'))) {
 769        $prefix = '';
 770        $page_num = $component['page_num'];
 771        $page_index = 'p' . $page_num;
 772        if ($indent && ($parent_count = count(webform_component_parent_keys($node, $component)) - 1)) {
 773          $prefix = str_repeat('-', $parent_count);
 774        }
 775        if ($optgroups && $component['type'] == 'pagebreak') {
 776          $page_names[$page_index] = $component['name'];
 777        }
 778        elseif ($optgroups && $page_num > 1) {
 779          $options[$page_index][$cid] = $prefix . $component['name'];
 780        }
 781        else {
 782          $options[$cid] = $prefix . $component['name'];
 783        }
 784      }
 785    }
 786  
 787    if ($optgroups) {
 788      $grouped_options = $options;
 789      $options = array();
 790      foreach ($grouped_options as $key => $values) {
 791        if (is_array($values) && isset($page_names[$key])) {
 792          $options[$page_names[$key]] = $values;
 793        }
 794        else {
 795          $options[$key] = $values;
 796        }
 797      }
 798    }
 799  
 800    return $options;
 801  }
 802  
 803  /**
 804   * A Form API process function to expand a component list into checkboxes.
 805   */
 806  function webform_component_select($element) {
 807    // Split the select list into checkboxes.
 808    foreach ($element['#options'] as $key => $label) {
 809      $indents = 0;
 810      $label = preg_replace('/^([\-])+/', '', $label, -1, $indents);
 811      $element[$key] = array(
 812        '#title' => $label,
 813        '#type' => 'checkbox',
 814        '#default_value' => array_search($key, $element['#value']) !== FALSE,
 815        '#parents' => array_merge($element['#parents'], array($key)),
 816        '#indent' => $indents,
 817      );
 818    }
 819  
 820    $element['#type'] = 'webform_component_select';
 821    $element['#theme'] = 'webform_component_select';
 822  
 823    return $element;
 824  }
 825  
 826  /**
 827   * Theme the contents of a Webform component select element.
 828   */
 829  function theme_webform_component_select($element) {
 830    drupal_add_js('misc/tableselect.js');
 831    drupal_add_js(drupal_get_path('module', 'webform') . '/js/webform-admin.js', 'module', 'header', FALSE, TRUE, FALSE);
 832  
 833    $rows = array();
 834    $header = array();
 835    if (!isset($element['#all_checkbox']) || $element['#all_checkbox']) {
 836      $header = array(array('class' => 'select-all', 'data' => ' ' . t('Include all components')));
 837    }
 838    foreach (element_children($element) as $key) {
 839      $rows[] = array(
 840        theme('indentation', $element[$key]['#indent']) . drupal_render($element[$key]),
 841      );
 842    }
 843  
 844    $element['#collapsible'] = isset($element['#collapsible']) ? $element['#collapsible'] : TRUE;
 845    $element['#collapsed'] = isset($element['#collapsed']) ? $element['#collapsed'] : TRUE;
 846  
 847    $element['#attributes']['class'] = 'webform-component-select-table';
 848    if (empty($rows)) {
 849      $element['#children'] = t('No available components.');
 850    }
 851    else {
 852      $element['#children'] = '<div class="webform-component-select-wrapper">' . theme('table', $header, $rows) . '</div>';
 853    }
 854  
 855    $element['#value'] = NULL;
 856  
 857    return theme('fieldset', $element);
 858  }
 859  
 860  /**
 861   * Find a components parents within a node.
 862   */
 863  function webform_component_parent_keys($node, $component) {
 864    $parents = array($component['form_key']);
 865    $pid = $component['pid'];
 866    while ($pid) {
 867      $parents[] = $node->webform['components'][$pid]['form_key'];
 868      $pid = $node->webform['components'][$pid]['pid'];
 869    }
 870    return array_reverse($parents);
 871  }
 872  
 873  /**
 874   * Populate a component with the defaults for that type.
 875   */
 876  function webform_component_defaults(&$component) {
 877    if ($defaults = webform_component_invoke($component['type'], 'defaults')) {
 878      foreach ($defaults as $key => $default) {
 879        if (!isset($component[$key])) {
 880          $component[$key] = $default;
 881        }
 882      }
 883      foreach ($defaults['extra'] as $extra => $default) {
 884        if (!isset($component['extra'][$extra])) {
 885          $component['extra'][$extra] = $default;
 886        }
 887      }
 888      $component['extra'] += array(
 889        'conditional_component' => '',
 890        'conditional_operator' => '=',
 891        'conditional_values' => '',
 892      );
 893    }
 894  }
 895  
 896  /**
 897   * Validate an element value is unique with no duplicates in the database.
 898   */
 899  function webform_validate_unique($element, $form_state) {
 900    $nid = $form_state['values']['details']['nid'];
 901    $sid = $form_state['values']['details']['sid'];
 902    $count = db_result(db_query("SELECT count(*) FROM {webform_submitted_data} WHERE nid = %d AND cid = %d AND sid <> %d AND LOWER(data) = '%s'", $nid, $element['#webform_component']['cid'], $sid, $element['#value']));
 903    if ($count) {
 904      form_error($element, t('The value %value has already been submitted once for the %title field. You may have already submitted this form, or you need to use a different value.', array('%value' => $element['#value'], '%title' => $element['#title'])));
 905    }
 906  }


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7