Projet

Général

Profil

Révision ba09eb79

Ajouté par Assos Assos il y a presque 9 ans

Weekly update of contrib modules

Voir les différences:

drupal7/sites/all/modules/webform/components/grid.inc
37 37
  );
38 38
}
39 39

  
40

  
41 40
/**
42 41
 * Implements _webform_theme_component().
43 42
 */
......
60 59
function _webform_edit_grid($component) {
61 60
  $form = array();
62 61

  
62
  $form['help'] = array(
63
    '#type' => 'fieldset',
64
    '#collapsible' => TRUE,
65
    '#collapsed' => !empty($component['cid']),
66
    '#title' => t('About options and questions…'),
67
    '#description' => t('Options and questions may be configured here, in additional nested Select Options components, or even both.'),
68
    '#weight' => -4,
69
    'pros_and_cons' => array(
70
      '#theme' => 'table',
71
      '#header' => array('', t('Options and questions configured <strong>here</strong>'), t('Configured in additional <strong>nested</strong> components'), t('Both')),
72
      '#rows' => array(
73
        array(t('Questions'), t('Enter the questions below.'), t('Configure and save this grid, then add additional Select Options components nested (indented) below this grid.'), t('Additional questions from nested components will be displayed below any questions configured here.')),
74
        array(t('Options'), t('Enter options below.'), t('May be different for each question. Initially the same as defined below.'), t('Options from additional nested components will be merged with any options configured here.')),
75
        array(t('Checkboxes'), t('No. Radio buttons only.'), t('Yes. Some or all questions may be multiple choice with check boxes.'), ''),
76
        array(t('Default'), t('Yes. Must be same for all questions.'), t('Yes. May all be the same or different.'), ''),
77
        array(t('Pre-built option lists'), t('No.'), t('Yes.'), ''),
78
        array(t('Required'), t('Yes. Must be same for all questions.'), t('Yes. May all be the same or different.'), ''),
79
        array(t('Question conditionals'), t('No.'), t('Yes. Individual questions may be used in conditional rules and/or actions.'), t('The whole grid may be conditionally shown or required.')),
80
        array(t('Other types of nested components'), t('No.'), t('Yes. Other component types may also be included in the grid. They will be displayed where the options would normally be.'), ''),
81
      ),
82
    ),
83
  );
84

  
63 85
  if (module_exists('options_element')) {
64 86
    $form['options'] = array(
65 87
      '#type' => 'fieldset',
66 88
      '#title' => t('Options'),
67 89
      '#collapsible' => TRUE,
68
      '#description' => t('Options to select across the top. Usually these are ratings such as "poor" through "excellent" or "strongly disagree" through "strongly agree".'),
69 90
      '#attributes' => array('class' => array('webform-options-element')),
70 91
      '#element_validate' => array('_webform_edit_validate_options'),
92
      '#weight' => -3,
71 93
    );
72 94
    $form['options']['options'] = array(
73 95
      '#type' => 'options',
......
79 101
      '#key_type_toggle' => t('Customize option keys (Advanced)'),
80 102
      '#key_type_toggled' => $component['extra']['custom_option_keys'],
81 103
      '#default_value_pattern' => '^%.+\[.+\]$',
104
      '#description' => t('<strong>Options to select across the top</strong>, such as "Poor" through "Excellent". Indicate the default to the left of the desired item. Use of only alphanumeric characters and underscores is recommended in keys.') . ' ' . theme('webform_token_help'),
82 105
    );
83 106

  
84 107
    $form['questions'] = array(
85 108
      '#type' => 'fieldset',
86 109
      '#title' => t('Questions'),
87 110
      '#collapsible' => TRUE,
88
      '#description' => t('Questions list down the side of the grid.'),
89 111
      '#attributes' => array('class' => array('webform-options-element')),
90 112
      '#element_validate' => array('_webform_edit_validate_options'),
113
      '#weight' => -2,
91 114
    );
92 115
    $form['questions']['options'] = array(
93 116
      '#type' => 'options',
......
98 121
      '#key_type' => 'mixed',
99 122
      '#key_type_toggle' => t('Customize question keys (Advanced)'),
100 123
      '#key_type_toggled' => $component['extra']['custom_question_keys'],
124
      '#description' => t('<strong>Questions list down the side of the grid.</strong> For a heading column on the right, append "|" and the right-side heading. Use of only alphanumeric characters and underscores is recommended in keys.') . ' ' . theme('webform_token_help'),
101 125
    );
102 126
  }
103 127
  else {
......
105 129
      '#type' => 'textarea',
106 130
      '#title' => t('Options'),
107 131
      '#default_value' => $component['extra']['options'],
108
      '#description' => t('Options to select across the top. One option per line. <strong>Key-value pairs MUST be specified as "safe_key|Some readable option"</strong>. Use of only alphanumeric characters and underscores is recommended in keys.') . ' ' . theme('webform_token_help'),
132
      '#description' => t('Options to select across the top, such as "Poor" through "Excellent" or "Stronly Disagree" through "Strongly Agree".') .
133
                          '<p>' . t('One key-value option per line. <strong>Key-value pairs MUST be specified as "safe_key|Some readable option"</strong>. Use of only alphanumeric characters and underscores is recommended in keys.') . '</p>' . theme('webform_token_help'),
109 134
      '#cols' => 60,
110 135
      '#rows' => 5,
111 136
      '#weight' => -3,
112
      '#required' => TRUE,
113 137
      '#wysiwyg' => FALSE,
114 138
      '#element_validate' => array('_webform_edit_validate_select'),
115 139
    );
......
117 141
      '#type' => 'textarea',
118 142
      '#title' => t('Questions'),
119 143
      '#default_value' => $component['extra']['questions'],
120
      '#description' => t('Questions list down the side of the grid. One question per line. <strong>Key-value pairs MUST be specified as "safe_key|Some readable question"</strong>. For a heading column on the right, append "|" and the right-side heading. Use of only alphanumeric characters and underscores is recommended in keys.') . ' ' . theme('webform_token_help'),
144
      '#description' => t('Questions list down the side of the grid. One question per line. <strong>Key-value pairs MUST be specified as "safe_key|Some readable question"</strong>. For a heading column on the right, append "|" and the right-side heading. Use of only alphanumeric characters and underscores is recommended in keys.') . ' ' . theme('webform_token_help') . ' ' .
145
                        '<p>' . t('<strong>Or for more control</strong> over the appearance and configuration, create additional additional Select Options or other type components nested under this grid. They will operate as separate components, but be displayed within this grid.') . '</p>',
121 146
      '#cols' => 60,
122 147
      '#rows' => 5,
123 148
      '#weight' => -2,
124
      '#required' => TRUE,
125 149
      '#wysiwyg' => FALSE,
126 150
      '#element_validate' => array('_webform_edit_validate_select'),
127 151
    );
......
218 242
function webform_expand_grid($element) {
219 243
  $options = $element['#grid_options'];
220 244
  $questions = $element['#grid_questions'];
245
  $weights = array();
221 246

  
222
  if (!empty($element['#optrand'])) {
223
    _webform_shuffle_options($options);
224
  }
225

  
226
  if (!empty($element['#qrand'])) {
227
    _webform_shuffle_options($questions);
247
  // Process questions and options from nested components.
248
  foreach (element_children($element) as $key) {
249
    $question = $element[$key];
250
    // Both forms and grid displays have #webform_component.
251
    if (isset($question['#webform_component']) &&
252
        $question['#webform_component']['type'] == 'select' &&
253
        !$question['#webform_component']['extra']['aslist'] &&
254
        !$question['#webform_component']['extra']['other_option']) {
255
      $options = webform_grid_merge_options($options, $question['#options']);
256
      $weights[$key] = $question['#weight'];
257
    }
228 258
  }
229 259

  
260
  // Add the internal grid questions.
261
  $weight = -1000;
262
  $value = isset($element['#default_value']) ? $element['#default_value'] : array();
230 263
  foreach ($questions as $key => $question) {
231 264
    if ($question != '') {
265
      $question_value = isset($value[$key]) && $value[$key] !== '' ? $value[$key] : NULL;
232 266
      $element[$key] = array(
267
        '#grid_question' => TRUE,
233 268
        '#title' => $question,
234 269
        '#required' => $element['#required'],
235
        '#options' => $options,
270
        '#options' => $element['#grid_options'],
236 271
        '#type' => 'radios',
272
        '#default_value' => $question_value,
273
        '#value' => $question_value,
237 274
        '#process' => array('form_process_radios', 'webform_expand_select_ids'),
238 275

  
239 276
        // Webform handles validation manually.
240 277
        '#validated' => TRUE,
241 278
        '#webform_validated' => FALSE,
242 279
        '#translatable' => array('title'),
280
        '#weight' => $weight,
243 281
      );
244 282

  
245 283
      // Add HTML5 required attribute, if needed.
246 284
      if ($element['#required']) {
247 285
        $element[$key]['#attributes']['required'] = 'required';
248 286
      }
287

  
288
      $weights[$key] = $weight;
289
      $weight++;
249 290
    }
250 291
  }
251 292

  
252
  $value = isset($element['#default_value']) ? $element['#default_value'] : array();
253
  foreach (element_children($element) as $key) {
254
    if (isset($value[$key])) {
255
      $element[$key]['#default_value'] = ($value[$key] !== '') ? $value[$key] : NULL;
293
  if (!empty($element['#optrand'])) {
294
    _webform_shuffle_options($options);
295
  }
296
  $element['#grid_options'] = $options;
297

  
298
  asort($weights);
299
  if (!empty($element['#qrand'])) {
300
    _webform_shuffle_options($weights);
301
  }
302
  $weight = min($weights);
303
  foreach ($weights as $key => $old_weight) {
304
    $element[$key]['#options'] = webform_grid_remove_options($options, $element[$key]['#options']);
305
    $element[$key]['#weight'] = $weight++;
306
    $element['#grid_questions'][$key] = $element[$key]['#title'];
307
  }
308

  
309
  return $element;
310
}
311

  
312
/**
313
 * Helper. Merge select component options in order.
314
 *
315
 * @param array $existing
316
 *   An array of existing values into which any values from $new that aren't in
317
 *   $existing are inserted.
318
 * @param array $new
319
 *   Values to be inserted into $existing.
320
 * @return array
321
 *   The merged array.
322
 */
323
function webform_grid_merge_options($existing, $new) {
324
  $insert = NULL;
325
  $queue = array();
326
  foreach ($new as $key => $value) {
327
    if (isset($existing[$key])) {
328
      // Insert the queue before the found item.
329
      $insert = array_search($key, array_keys($existing));
330
      if ($queue) {
331
        $existing = array_slice($existing, 0, $insert, TRUE) +
332
                    $queue +
333
                    array_slice($existing, $insert, NULL, TRUE);
334
        $insert += count($queue);
335
        $queue = array();
336
      }
337
      $insert++;
338
    }
339
    elseif (is_null($insert)) {
340
      // It is not yet clear yet where to put this item. Add it to the queue.
341
      $queue[$key] = $value;
256 342
    }
257 343
    else {
258
      $element[$key]['#default_value'] = NULL;
344
      // PHP array_splice does not preserved the keys of the inserted array,
345
      // but array_slice does (if the preserve keys parameter is TRUE).
346
      $existing = array_slice($existing, 0, $insert, TRUE) +
347
                  array($key => $value) +
348
                  array_slice($existing, $insert, NULL, TRUE);
349
      $insert++;
259 350
    }
260 351
  }
352
  // Append any left over queued items.
353
  $existing += $queue;
354
  return $existing;
355
}
261 356

  
262
  return $element;
357
/**
358
 * Helper. Replace missing options with empty values.
359
 *
360
 * @param array $header
361
 *   An array of options to be used at the grid table header.
362
 * @param array $row_options
363
 *   An array of options to be used for this row.
364
 * @return array
365
 *   The $row_options with any missing options replaced with empty values.
366
 **/
367
function webform_grid_remove_options($header, $row_options) {
368
  foreach ($header as $key => $value) {
369
    if (!isset($row_options[$key])) {
370
      $header[$key] = '';
371
    }
372
  }
373
  return $header;
263 374
}
264 375

  
265 376
/**
......
279 390
    '#format' => $format,
280 391
    '#grid_questions' => $questions,
281 392
    '#grid_options' => $options,
393
    '#default_value' => $value,
282 394
    '#sticky' => $component['extra']['sticky'],
283 395
    '#theme' => 'webform_display_grid',
284 396
    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
......
299 411
  return $element;
300 412
}
301 413

  
414
/**
415
 * Preprocess function for displaying a grid component.
416
 */
417
function template_preprocess_webform_display_grid(&$variables) {
418
  $element =& $variables['element'];
419
  // Expand the grid, suppressing randomization. This builds the grid
420
  // questions and options.
421
  $element['#qrand'] = FALSE;
422
  $element['#optrand'] = FALSE;
423
  $element['#required'] = FALSE;
424
  $element = webform_expand_grid($element);
425
}
426

  
302 427
/**
303 428
 * Format the text output for this component.
304 429
 */
......
311 436
  if ($format == 'html') {
312 437
    $right_titles = _webform_grid_right_titles($element);
313 438
    $rows = array();
314
    $title = array('data' => '', 'class' => array('webform-grid-question'));
315
    $header = array($title);
316
    foreach ($element['#grid_options'] as $option) {
317
      $header[] = array('data' => webform_filter_xss($option), 'class' => array('checkbox', 'webform-grid-option'));
318
    }
319
    if ($right_titles) {
320
      $header[] = $title;
321
    }
322
    foreach ($element['#grid_questions'] as $question_key => $question) {
439

  
440
    // Set the header for the table.
441
    $header = _webform_grid_header($element, $right_titles);
442

  
443
    foreach (element_children($element) as $question_key) {
444
      $question_element = $element[$question_key];
323 445
      $row = array();
324
      $questions = explode('|', $question, 2);
446
      $questions = explode('|', $question_element['#title'], 2);
447
      $values = $question_element['#value'];
448
      $values = is_array($values) ? $values : array($values);
325 449
      $row[] = array('data' => webform_filter_xss($questions[0]), 'class' => array('webform-grid-question'));
326
      foreach ($element['#grid_options'] as $option_value => $option_label) {
327
        if (strcmp($element[$question_key]['#value'], $option_value) == 0) {
328
          $row[] = array('data' => '<strong>X</strong>', 'class' => array('checkbox', 'webform-grid-option'));
329
        }
330
        else {
331
          $row[] = array('data' => '&nbsp;', 'class' => array('checkbox', 'webform-grid-option'));
450
      if (isset($element['#grid_questions'][$question_key])) {
451
        foreach ($element['#grid_options'] as $option_value => $option_label) {
452
          if (in_array($option_value, $values)) {
453
            $row[] = array('data' => '<strong>X</strong>', 'class' => array('checkbox', 'webform-grid-option'));
454
          }
455
          else {
456
            $row[] = array('data' => '&nbsp;', 'class' => array('checkbox', 'webform-grid-option'));
457
          }
332 458
        }
333 459
      }
460
      else {
461
        $question_element['#title_display'] = 'none';
462
        $row[] = array(
463
          'data' => drupal_render($question_element),
464
          'colspan' => count($element['#grid_options']),
465
        );
466
      }
334 467
      if ($right_titles) {
335 468
        $row[] = array('data' => isset($questions[1]) ? webform_filter_xss($questions[1]) : '', 'class' => array('webform-grid-question'));
336 469
      }
......
342 475
  }
343 476
  else {
344 477
    $items = array();
345
    foreach (element_children($element) as $key) {
346
      $items[] = ' - ' . _webform_grid_question_header($element[$key]['#title']) . ': ' .
347
                 (isset($element['#grid_options'][$element[$key]['#value']]) ? $element['#grid_options'][$element[$key]['#value']] : '');
348
    }
478
    foreach (element_children($element) as $question_key) {
479
      $question_element = $element[$question_key];
480
      if (isset($element['#grid_questions'][$question_key])) {
481
        $values = $question_element['#value'];
482
        $values = is_array($values) ? $values : array($values);
483
        foreach ($values as $value_key => $value) {
484
          if (isset($element['#grid_options'][$value])) {
485
            $values[$value_key] = $element['#grid_options'][$value];
486
          }
487
          else {
488
            unset($values[$value_key]);
489
          }
490
        }
491
        $value = implode(', ', $values);
492
      } else {
493
        $element[$question_key]['#title'] = '';
494
        $value = drupal_render($element[$question_key]);
495
      }
496
      $items[] = ' - ' . _webform_grid_question_header($question_element['#title']) . ': ' . $value;
497
   }
349 498
    $output = implode("\n", $items);
350 499
  }
351 500

  
......
405 554
    $rows[] = $row;
406 555
  }
407 556

  
408
  return array(
409
    'table_header' => $header,
410
    'table_rows' => $rows,
411
  );
557
  // Return return the table unless there are no internal questions in the grid.
558
  if ($rows) {
559
    return array(
560
      'table_header' => $header,
561
      'table_rows' => $rows,
562
    );
563
  }
412 564
}
413 565

  
414 566
/**
......
429 581
    }
430 582
  }
431 583

  
432
  return $output;
584
  // Return output if the grid contains internal questions.
585
  if (count($questions)) {
586
    return $output;
587
  }
433 588
}
434 589

  
435 590
/**
......
484 639
 * A Form API element validate function to check that all choices are unique.
485 640
 */
486 641
function _webform_edit_grid_unique_validate($element) {
487
  $nr_unique = count(array_unique($element['#value']));
488
  $nr_values = count($element['#value']);
642
  // Grids may contain nested multiple value select components.
643
  // Create a flat array of values.
644
  $values = array();
645
  array_walk_recursive($element['#value'], function($a) use (&$values) { $values[] = $a; });
646

  
647
  $nr_unique = count(array_unique($values));
648
  $nr_values = count($values);
489 649
  $nr_possible = count($element['#grid_options']);
490 650
  if (strlen($element['#grid_default']) && isset($element['#grid_options'][$element['#grid_default']])) {
491 651
    // A default is defined and is one of the options. Don't count default values
......
509 669
  $right_titles = _webform_grid_right_titles($element);
510 670

  
511 671
  $rows = array();
512
  $title = array('data' => '', 'class' => array('webform-grid-question'));
513
  $header = array($title);
672

  
514 673
  // Set the header for the table.
515
  foreach ($element['#grid_options'] as $option) {
516
    $header[] = array('data' => webform_filter_xss($option), 'class' => array('checkbox', 'webform-grid-option'));
517
  }
518
  if ($right_titles) {
519
    $header[] = $title;
520
  }
674
  $header = _webform_grid_header($element, $right_titles);
521 675

  
522 676
  foreach (element_children($element) as $key) {
523 677
    $question_element = $element[$key];
524
    $question_titles = explode('|', $question_element['#title'], 2);
678
    $title_element =& $question_element;
679
    if ($question_element['#type'] == 'select_or_other') {
680
      $title_element =& $question_element['select'];
681
    }
682
    $question_titles = explode('|', $title_element['#title'], 2);
525 683

  
526 684
    // Create a row with the question title.
527
    $title = array('data' => webform_filter_xss($question_titles[0]), 'class' => array('webform-grid-question'));
528
    $row = array($title);
685
    $required = !empty($question_element['#required']) ? theme('form_required_marker', array('element' => $question_element)) : '';
686
    $row = array(array('data' => t('!title !required', array('!title' => webform_filter_xss($question_titles[0]), '!required' => $required)), 'class' => array('webform-grid-question')));
529 687

  
530 688
    // Render each radio button in the row.
531
    $radios = form_process_radios($question_element);
532
    foreach (element_children($radios) as $key) {
533
      $radio_title = $radios[$key]['#title'];
534
      $radios[$key]['#title'] = $question_element['#title'] . ' - ' . $radio_title;
535
      $radios[$key]['#title_display'] = 'invisible';
536
      $row[] = array('data' => drupal_render($radios[$key]), 'class' => array('checkbox', 'webform-grid-option'), 'data-label' => array($radio_title));
689
    if ($question_element['#type'] == 'radios' || $question_element['#type'] == 'checkboxes') {
690
      $radios = form_process_radios($question_element);
691
      foreach (element_children($radios) as $key) {
692
        $radio_title = $radios[$key]['#title'];
693
        if (!strlen($radio_title)) {
694
          $row[] = '&nbsp;';
695
        }
696
        else {
697
          $radios[$key]['#title'] = $question_element['#title'] . ' - ' . $radio_title;
698
          $radios[$key]['#title_display'] = 'invisible';
699
          $row[] = array('data' => drupal_render($radios[$key]), 'class' => array('checkbox', 'webform-grid-option'), 'data-label' => array($radio_title));
700
        }
701
      }
702
    }
703
    else {
704
      $title_element['#title_display'] = 'none';
705
      $row[] = array(
706
        'data' => drupal_render($question_element),
707
        'colspan' => count($element['#grid_options']),
708
      );
537 709
    }
538 710
    if ($right_titles) {
539 711
      $row[] = array('data' => isset($question_titles[1]) ? webform_filter_xss($question_titles[1]) : '', 'class' => array('webform-grid-question'));
540 712
    }
541
    $rows[] = $row;
713

  
714
    // Convert the parents array into a string, excluding the "submitted" wrapper.
715
    $nested_level = $question_element['#parents'][0] == 'submitted' ? 1 : 0;
716
    $parents = str_replace('_', '-', implode('--', array_slice($question_element['#parents'], $nested_level)));
717

  
718
    $rows[] = array(
719
      'data' => $row,
720
      'class' => empty($question_element['#grid_question'])
721
                    ? array('webform-component', 'webform-component-' . str_replace('_', '-', $question_element['#type']), 'webform-component--' . $parents)
722
                    : array(),
723
    );
542 724
  }
543 725

  
544 726
  $option_count = count($header) - 1;
545 727
  return theme('table', array('header' => $header, 'rows' => $rows, 'sticky' => $element['#sticky'], 'attributes' => array('class' => array('webform-grid', 'webform-grid-' . $option_count))));
546 728
}
547 729

  
730
/**
731
 * Generate a table header suitable for form or html display.
732
 */
733
function _webform_grid_header($element, $right_titles) {
734
  $titles = explode('|', $element['#title'], 2);
735
  $header = array(array('data' => _webform_grid_header_title($element, $titles[0]), 'class' => array('webform-grid-question')));
736
  foreach ($element['#grid_options'] as $option) {
737
    $header[] = array('data' => webform_filter_xss($option), 'class' => array('checkbox', 'webform-grid-option'));
738
  }
739
  if ($right_titles) {
740
    $header[] = array('data' => _webform_grid_header_title($element, isset($titles[1]) ? $titles[1] : ''), 'class' => array('webform-grid-question'));
741
  }
742
  return $header;
743
}
744

  
745
/**
746
 * Create internal component title for table header, if any.
747
 */
748
function _webform_grid_header_title($element, $title) {
749
  $header_title = '';
750
  if ($element['#title_display'] == 'internal') {
751
    $variables = array('element' => $element);
752
    $variables['element']['#title_display'] = 'before';
753
    $variables['element']['#title'] = $title;
754
    $header_title = theme('form_element_label', $variables);
755
  }
756
  return $header_title;
757
}
758

  
548 759
/**
549 760
 * Determine if a right-side title column has been specified.
550 761
 */
551 762
function _webform_grid_right_titles($element) {
763
  if ($element['#title_display'] == 'internal' && substr_count($element['#title'], '|')) {
764
    return TRUE;
765
  }
552 766
  foreach ($element['#grid_questions'] as $question_key => $question) {
553 767
    if (substr_count($question, '|')) {
554 768
      return TRUE;
......
563 777
function _webform_grid_question_header($text) {
564 778
  return implode('/', array_filter(explode('|', $text)));
565 779
}
566

  

Formats disponibles : Unified diff