Projet

Général

Profil

Paste
Télécharger (19,7 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / webform / components / grid.inc @ cb17e347

1
<?php
2

    
3
/**
4
 * @file
5
 * Webform module grid component.
6
 */
7

    
8
// Grid depends on functions provided by select.
9
webform_component_include('select');
10

    
11
/**
12
 * Implements _webform_defaults_component().
13
 */
14
function _webform_defaults_grid() {
15
  return array(
16
    'name' => '',
17
    'form_key' => NULL,
18
    'required' => 0,
19
    'pid' => 0,
20
    'weight' => 0,
21
    'value' => '',
22
    'extra' => array(
23
      'options' => '',
24
      'questions' => '',
25
      'optrand' => 0,
26
      'qrand' => 0,
27
      'unique' => 0,
28
      'title_display' => 0,
29
      'custom_option_keys' => 0,
30
      'custom_question_keys' => 0,
31
      'sticky' => TRUE,
32
      'description' => '',
33
      'private' => FALSE,
34
      'analysis' => TRUE,
35
    ),
36
  );
37
}
38

    
39

    
40
/**
41
 * Implements _webform_theme_component().
42
 */
43
function _webform_theme_grid() {
44
  return array(
45
    'webform_grid' => array(
46
      'render element' => 'element',
47
      'file' => 'components/grid.inc',
48
    ),
49
    'webform_display_grid' => array(
50
      'render element' => 'element',
51
      'file' => 'components/grid.inc',
52
    ),
53
  );
54
}
55

    
56
/**
57
 * Implements _webform_edit_component().
58
 */
59
function _webform_edit_grid($component) {
60
  $form = array();
61

    
62
  if (module_exists('options_element')) {
63
    $form['options'] = array(
64
      '#type' => 'fieldset',
65
      '#title' => t('Options'),
66
      '#collapsible' => TRUE,
67
      '#description' => t('Options to select across the top. Usually these are ratings such as "poor" through "excellent" or "strongly disagree" through "strongly agree".'),
68
      '#attributes' => array('class' => array('webform-options-element')),
69
      '#element_validate' => array('_webform_edit_validate_options'),
70
    );
71
    $form['options']['options'] = array(
72
      '#type' => 'options',
73
      '#options' => _webform_select_options_from_text($component['extra']['options'], TRUE),
74
      '#default_value' => $component['value'],
75
      '#default_value_allowed' => TRUE,
76
      '#optgroups' => FALSE,
77
      '#key_type' => 'mixed',
78
      '#key_type_toggle' => t('Customize option keys (Advanced)'),
79
      '#key_type_toggled' => $component['extra']['custom_option_keys'],
80
      '#default_value_pattern' => '^%.+\[.+\]$',
81
    );
82

    
83
    $form['questions'] = array(
84
      '#type' => 'fieldset',
85
      '#title' => t('Questions'),
86
      '#collapsible' => TRUE,
87
      '#description' => t('Questions list down the side of the grid.'),
88
      '#attributes' => array('class' => array('webform-options-element')),
89
      '#element_validate' => array('_webform_edit_validate_options'),
90
    );
91
    $form['questions']['options'] = array(
92
      '#type' => 'options',
93
      '#options' => _webform_select_options_from_text($component['extra']['questions'], TRUE),
94
      '#optgroups' => FALSE,
95
      '#default_value' => FALSE,
96
      '#default_value_allowed' => FALSE,
97
      '#key_type' => 'mixed',
98
      '#key_type_toggle' => t('Customize question keys (Advanced)'),
99
      '#key_type_toggled' => $component['extra']['custom_question_keys'],
100
    );
101
  }
102
  else {
103
    $form['extra']['options'] = array(
104
      '#type' => 'textarea',
105
      '#title' => t('Options'),
106
      '#default_value' => $component['extra']['options'],
107
      '#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'),
108
      '#cols' => 60,
109
      '#rows' => 5,
110
      '#weight' => -3,
111
      '#required' => TRUE,
112
      '#wysiwyg' => FALSE,
113
      '#element_validate' => array('_webform_edit_validate_select'),
114
    );
115
    $form['extra']['questions'] = array(
116
      '#type' => 'textarea',
117
      '#title' => t('Questions'),
118
      '#default_value' => $component['extra']['questions'],
119
      '#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'),
120
      '#cols' => 60,
121
      '#rows' => 5,
122
      '#weight' => -2,
123
      '#required' => TRUE,
124
      '#wysiwyg' => FALSE,
125
      '#element_validate' => array('_webform_edit_validate_select'),
126
    );
127
    $form['value'] = array(
128
      '#type' => 'textfield',
129
      '#title' => t('Default value'),
130
      '#default_value' => $component['value'],
131
      '#description' => t('The default option of the grid identified by its key.') . ' ' . theme('webform_token_help'),
132
      '#size' => 60,
133
      '#maxlength' => 1024,
134
      '#weight' => 1,
135
    );
136
  }
137

    
138
  $form['display']['optrand'] = array(
139
    '#type' => 'checkbox',
140
    '#title' => t('Randomize Options'),
141
    '#default_value' => $component['extra']['optrand'],
142
    '#description' => t('Randomizes the order of options on the top when they are displayed in the form.'),
143
    '#parents' => array('extra', 'optrand')
144
  );
145
  $form['display']['qrand'] = array(
146
    '#type' => 'checkbox',
147
    '#title' => t('Randomize Questions'),
148
    '#default_value' => $component['extra']['qrand'],
149
    '#description' => t('Randomize the order of the questions on the side when they are displayed in the form.'),
150
    '#parents' => array('extra', 'qrand')
151
  );
152
  $form['display']['sticky'] = array(
153
    '#type' => 'checkbox',
154
    '#title' => t('Sticky table header'),
155
    '#default_value' => $component['extra']['sticky'],
156
    '#description' => t('Use a sticky (non-scrolling) table header.'),
157
    '#parents' => array('extra', 'sticky')
158
  );
159

    
160
  $form['validation']['unique'] = array(
161
    '#type' => 'checkbox',
162
    '#title' => t('Unique'),
163
    '#return_value' => 1,
164
    '#description' => t('Check that all entered values for this field are unique. The same value is not allowed to be used twice.'),
165
    '#weight' => 1,
166
    '#default_value' => $component['extra']['unique'],
167
    '#parents' => array('extra', 'unique'),
168
  );
169

    
170
  return $form;
171
}
172

    
173
/**
174
 * Implements _webform_render_component().
175
 */
176
function _webform_render_grid($component, $value = NULL, $filter = TRUE, $submission = NULL) {
177
  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
178

    
179
  $questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
180
  $options = _webform_select_options_from_text($component['extra']['options'], TRUE);
181
  if ($filter) {
182
    $questions = _webform_select_replace_tokens($questions, $node);
183
    $options = _webform_select_replace_tokens($options, $node);
184
  }
185

    
186
  $element = array(
187
    '#type' => 'webform_grid',
188
    '#title' => $filter ? webform_filter_xss($component['name']) : $component['name'],
189
    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
190
    '#required' => $component['required'],
191
    '#weight' => $component['weight'],
192
    '#description' => $filter ? webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
193
    '#grid_questions' => $questions,
194
    '#grid_options' => $options,
195
    '#default_value' => isset($value) || !strlen($component['value']) ? $value : array_fill_keys(array_keys($questions), $component['value']),
196
    '#grid_default' => $component['value'],
197
    '#optrand' => $component['extra']['optrand'],
198
    '#qrand' => $component['extra']['qrand'],
199
    '#sticky' => $component['extra']['sticky'],
200
    '#theme' => 'webform_grid',
201
    '#theme_wrappers' => array('webform_element'),
202
    '#process' => array('webform_expand_grid'),
203
    '#translatable' => array('title', 'description', 'grid_options', 'grid_questions'),
204
  );
205

    
206
  // Enforce uniqueness.
207
  if ($component['extra']['unique']) {
208
    $element['#element_validate'][] = '_webform_edit_grid_unique_validate';
209
  }
210

    
211
  return $element;
212
}
213

    
214
/**
215
 * A Form API #process function for Webform grid fields.
216
 */
217
function webform_expand_grid($element) {
218
  $options = $element['#grid_options'];
219
  $questions = $element['#grid_questions'];
220

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

    
225
  if (!empty($element['#qrand'])) {
226
    _webform_shuffle_options($questions);
227
  }
228

    
229
  foreach ($questions as $key => $question) {
230
    if ($question != '') {
231
      $element[$key] = array(
232
        '#title' => $question,
233
        '#required' => $element['#required'],
234
        '#options' => $options,
235
        '#type' => 'radios',
236
        '#process' => array('form_process_radios', 'webform_expand_select_ids'),
237

    
238
        // Webform handles validation manually.
239
        '#validated' => TRUE,
240
        '#webform_validated' => FALSE,
241
        '#translatable' => array('title'),
242
      );
243

    
244
      // Add HTML5 required attribute, if needed.
245
      if ($element['#required']) {
246
        $element[$key]['#attributes']['required'] = 'required';
247
      }
248
    }
249
  }
250

    
251
  $value = isset($element['#default_value']) ? $element['#default_value'] : array();
252
  foreach (element_children($element) as $key) {
253
    if (isset($value[$key])) {
254
      $element[$key]['#default_value'] = ($value[$key] !== '') ? $value[$key] : NULL;
255
    }
256
    else {
257
      $element[$key]['#default_value'] = NULL;
258
    }
259
  }
260

    
261
  return $element;
262
}
263

    
264
/**
265
 * Implements _webform_display_component().
266
 */
267
function _webform_display_grid($component, $value, $format = 'html', $submission = array()) {
268
  $node = node_load($component['nid']);
269
  $questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
270
  $questions = _webform_select_replace_tokens($questions, $node);
271
  $options = _webform_select_options_from_text($component['extra']['options'], TRUE);
272
  $options = _webform_select_replace_tokens($options, $node);
273

    
274
  $element = array(
275
    '#title' => $component['name'],
276
    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
277
    '#weight' => $component['weight'],
278
    '#format' => $format,
279
    '#grid_questions' => $questions,
280
    '#grid_options' => $options,
281
    '#sticky' => $component['extra']['sticky'],
282
    '#theme' => 'webform_display_grid',
283
    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
284
    '#sorted' => TRUE,
285
    '#translatable' => array('#title', '#grid_questions', '#grid_options'),
286
  );
287

    
288
  foreach ($questions as $key => $question) {
289
    if ($question !== '') {
290
      $element[$key] = array(
291
        '#title' => $question,
292
        '#value' => isset($value[$key]) ? $value[$key] : NULL,
293
        '#translatable' => array('#title', '#value'),
294
      );
295
    }
296
  }
297

    
298
  return $element;
299
}
300

    
301
/**
302
 * Format the text output for this component.
303
 */
304
function theme_webform_display_grid($variables) {
305
  $element = $variables['element'];
306

    
307
  $component = $element['#webform_component'];
308
  $format = $element['#format'];
309

    
310
  if ($format == 'html') {
311
    $right_titles = _webform_grid_right_titles($element);
312
    $rows = array();
313
    $title = array('data' => '', 'class' => array('webform-grid-question'));
314
    $header = array($title);
315
    foreach ($element['#grid_options'] as $option) {
316
      $header[] = array('data' => webform_filter_xss($option), 'class' => array('checkbox', 'webform-grid-option'));
317
    }
318
    if ($right_titles) {
319
      $header[] = $title;
320
    }
321
    foreach ($element['#grid_questions'] as $question_key => $question) {
322
      $row = array();
323
      $questions = explode('|', $question, 2);
324
      $row[] = array('data' => webform_filter_xss($questions[0]), 'class' => array('webform-grid-question'));
325
      foreach ($element['#grid_options'] as $option_value => $option_label) {
326
        if (strcmp($element[$question_key]['#value'], $option_value) == 0) {
327
          $row[] = array('data' => '<strong>X</strong>', 'class' => array('checkbox', 'webform-grid-option'));
328
        }
329
        else {
330
          $row[] = array('data' => '&nbsp;', 'class' => array('checkbox', 'webform-grid-option'));
331
        }
332
      }
333
      if ($right_titles) {
334
        $row[] = array('data' => isset($questions[1]) ? webform_filter_xss($questions[1]) : '', 'class' => array('webform-grid-question'));
335
      }
336
      $rows[] = $row;
337
    }
338

    
339
    $option_count = count($header) - 1;
340
    $output = theme('table', array('header' => $header, 'rows' => $rows, 'sticky' => $element['#sticky'], 'attributes' => array('class' => array('webform-grid', 'webform-grid-' . $option_count))));
341
  }
342
  else {
343
    $items = array();
344
    foreach (element_children($element) as $key) {
345
      $items[] = ' - ' . _webform_grid_question_header($element[$key]['#title']) . ': ' .
346
                 (isset($element['#grid_options'][$element[$key]['#value']]) ? $element['#grid_options'][$element[$key]['#value']] : '');
347
    }
348
    $output = implode("\n", $items);
349
  }
350

    
351
  return $output;
352
}
353

    
354
/**
355
 * Implements _webform_analysis_component().
356
 */
357
function _webform_analysis_grid($component, $sids = array(), $single = FALSE, $join = NULL) {
358
  // Generate the list of options and questions.
359
  $node = node_load($component['nid']);
360
  $questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
361
  $questions = _webform_select_replace_tokens($questions, $node);
362
  $options = _webform_select_options_from_text($component['extra']['options'], TRUE);
363
  $options = _webform_select_replace_tokens($options, $node);
364

    
365
  // Generate a lookup table of results.
366
  $query = db_select('webform_submitted_data', 'wsd')
367
    ->fields('wsd', array('no', 'data'))
368
    ->condition('wsd.nid', $component['nid'])
369
    ->condition('wsd.cid', $component['cid'])
370
    ->condition('wsd.data', '', '<>')
371
    ->groupBy('wsd.no')
372
    ->groupBy('wsd.data');
373
  $query->addExpression('COUNT(wsd.sid)', 'datacount');
374

    
375
  if (count($sids)) {
376
    $query->condition('wsd.sid', $sids, 'IN');
377
  }
378

    
379
  if ($join) {
380
    $query->innerJoin($join, 'ws2_', 'wsd.sid = ws2_.sid');
381
  }
382

    
383
  $result = $query->execute();
384
  $counts = array();
385
  foreach ($result as $data) {
386
    $counts[$data->no][$data->data] = $data->datacount;
387
  }
388

    
389
  // Create an entire table to be put into the returned row.
390
  $rows = array();
391
  $header = array('');
392

    
393
  // Add options as a header row.
394
  foreach ($options as $option) {
395
    $header[] = webform_filter_xss($option);
396
  }
397

    
398
  // Add questions as each row.
399
  foreach ($questions as $qkey => $question) {
400
    $row = array(webform_filter_xss($question));
401
    foreach ($options as $okey => $option) {
402
      $row[] = !empty($counts[$qkey][$okey]) ? $counts[$qkey][$okey] : 0;
403
    }
404
    $rows[] = $row;
405
  }
406

    
407
  return array(
408
    'table_header' => $header,
409
    'table_rows' => $rows,
410
  );
411
}
412

    
413
/**
414
 * Implements _webform_table_component().
415
 */
416
function _webform_table_grid($component, $value) {
417
  $node = node_load($component['nid']);
418
  $questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
419
  $questions = _webform_select_replace_tokens($questions, $node);
420
  $options = _webform_select_options_from_text($component['extra']['options'], TRUE);
421
  $options = _webform_select_replace_tokens($options, $node);
422

    
423
  $output = '';
424
  // Set the value as a single string.
425
  foreach ($questions as $key => $label) {
426
    if (isset($value[$key]) && isset($options[$value[$key]])) {
427
      $output .= webform_filter_xss(_webform_grid_question_header($label)) . ': ' . webform_filter_xss($options[$value[$key]]) . '<br />';
428
    }
429
  }
430

    
431
  return $output;
432
}
433

    
434
/**
435
 * Implements _webform_csv_headers_component().
436
 */
437
function _webform_csv_headers_grid($component, $export_options) {
438
  $node = node_load($component['nid']);
439
  $items = _webform_select_options_from_text($component['extra']['questions'], TRUE);
440
  $items = _webform_select_replace_tokens($items, $node);
441

    
442
  $header = array();
443
  $header[0] = array('');
444
  $header[1] = array($export_options['header_keys'] ? $component['form_key'] : $component['name']);
445
  $count = 0;
446
  foreach ($items as $key => $item) {
447
    // Empty column per sub-field in main header.
448
    if ($count != 0) {
449
      $header[0][] = '';
450
      $header[1][] = '';
451
    }
452
    // The value for this option.
453
    $header[2][] = $export_options['header_keys'] ? $key : _webform_grid_question_header($item);
454
    $count++;
455
  }
456

    
457
  return $header;
458
}
459

    
460
/**
461
 * Implements _webform_csv_data_component().
462
 */
463
function _webform_csv_data_grid($component, $export_options, $value) {
464
  $node = node_load($component['nid']);
465
  $questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
466
  $questions = _webform_select_replace_tokens($questions, $node);
467
  $options = _webform_select_options_from_text($component['extra']['options'], TRUE);
468
  $options = _webform_select_replace_tokens($options, $node);
469

    
470
  $return = array();
471
  foreach ($questions as $key => $question) {
472
    if (isset($value[$key]) && isset($options[$value[$key]])) {
473
      $return[] = $export_options['select_keys'] ? $value[$key] : $options[$value[$key]];
474
    }
475
    else {
476
      $return[] = '';
477
    }
478
  }
479
  return $return;
480
}
481

    
482
/**
483
 * A Form API element validate function to check that all choices are unique.
484
 */
485
function _webform_edit_grid_unique_validate($element) {
486
  $nr_unique = count(array_unique($element['#value']));
487
  $nr_values = count($element['#value']);
488
  $nr_possible = count($element['#grid_options']);
489
  if (strlen($element['#grid_default']) && isset($element['#grid_options'][$element['#grid_default']])) {
490
    // A default is defined and is one of the options. Don't count default values
491
    // toward uniqueness.
492
    $nr_defaults = count(array_keys($element['#value'], $element['#grid_default']));
493
    if ($nr_defaults) {
494
      $nr_values -= $nr_defaults;
495
      $nr_unique--;
496
    }
497
  }
498
  if ($nr_unique < $nr_values && $nr_unique < $nr_possible) {
499
    // Fewer unique values than values means that at least one value is duplicated.
500
    // Fewer unique values than possible values means that there is a possible choice
501
    // that wasn't used.
502
    form_error($element, t('!title is not allowed to have the same answer for more than one question.', array('!title' => $element['#title'])));
503
  }
504
}
505

    
506
function theme_webform_grid($variables) {
507
  $element = $variables['element'];
508
  $right_titles = _webform_grid_right_titles($element);
509

    
510
  $rows = array();
511
  $title = array('data' => '', 'class' => array('webform-grid-question'));
512
  $header = array($title);
513
  // Set the header for the table.
514
  foreach ($element['#grid_options'] as $option) {
515
    $header[] = array('data' => webform_filter_xss($option), 'class' => array('checkbox', 'webform-grid-option'));
516
  }
517
  if ($right_titles) {
518
    $header[] = $title;
519
  }
520

    
521
  foreach (element_children($element) as $key) {
522
    $question_element = $element[$key];
523
    $question_titles = explode('|', $question_element['#title'], 2);
524

    
525
    // Create a row with the question title.
526
    $title = array('data' => webform_filter_xss($question_titles[0]), 'class' => array('webform-grid-question'));
527
    $row = array($title);
528

    
529
    // Render each radio button in the row.
530
    $radios = form_process_radios($question_element);
531
    foreach (element_children($radios) as $key) {
532
      $radio_title = $radios[$key]['#title'];
533
      $radios[$key]['#title'] = $question_element['#title'] . ' - ' . $radio_title;
534
      $radios[$key]['#title_display'] = 'invisible';
535
      $row[] = array('data' => drupal_render($radios[$key]), 'class' => array('checkbox', 'webform-grid-option'), 'data-label' => array($radio_title));
536
    }
537
    if ($right_titles) {
538
      $row[] = array('data' => isset($question_titles[1]) ? webform_filter_xss($question_titles[1]) : '', 'class' => array('webform-grid-question'));
539
    }
540
    $rows[] = $row;
541
  }
542

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

    
547
/**
548
 * Determine if a right-side title column has been specified.
549
 */
550
function _webform_grid_right_titles($element) {
551
  foreach ($element['#grid_questions'] as $question_key => $question) {
552
    if (substr_count($question, '|')) {
553
      return TRUE;
554
    }
555
  }
556
  return FALSE;
557
}
558

    
559
/**
560
 * Create a question header for left, right or left/right question headers.
561
 */
562
function _webform_grid_question_header($text) {
563
  return implode('/', array_filter(explode('|', $text)));
564
}
565