| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
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"> </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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |