Projet

Général

Profil

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

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

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
      'description_above' => FALSE,
34
      'private' => FALSE,
35
      'analysis' => TRUE,
36
    ),
37
  );
38
}
39

    
40

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

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

    
63
  if (module_exists('options_element')) {
64
    $form['options'] = array(
65
      '#type' => 'fieldset',
66
      '#title' => t('Options'),
67
      '#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
      '#attributes' => array('class' => array('webform-options-element')),
70
      '#element_validate' => array('_webform_edit_validate_options'),
71
    );
72
    $form['options']['options'] = array(
73
      '#type' => 'options',
74
      '#options' => _webform_select_options_from_text($component['extra']['options'], TRUE),
75
      '#default_value' => $component['value'],
76
      '#default_value_allowed' => TRUE,
77
      '#optgroups' => FALSE,
78
      '#key_type' => 'mixed',
79
      '#key_type_toggle' => t('Customize option keys (Advanced)'),
80
      '#key_type_toggled' => $component['extra']['custom_option_keys'],
81
      '#default_value_pattern' => '^%.+\[.+\]$',
82
    );
83

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

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

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

    
171
  return $form;
172
}
173

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

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

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

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

    
212
  return $element;
213
}
214

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

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

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

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

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

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

    
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;
256
    }
257
    else {
258
      $element[$key]['#default_value'] = NULL;
259
    }
260
  }
261

    
262
  return $element;
263
}
264

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

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

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

    
299
  return $element;
300
}
301

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

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

    
311
  if ($format == 'html') {
312
    $right_titles = _webform_grid_right_titles($element);
313
    $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) {
323
      $row = array();
324
      $questions = explode('|', $question, 2);
325
      $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'));
332
        }
333
      }
334
      if ($right_titles) {
335
        $row[] = array('data' => isset($questions[1]) ? webform_filter_xss($questions[1]) : '', 'class' => array('webform-grid-question'));
336
      }
337
      $rows[] = $row;
338
    }
339

    
340
    $option_count = count($header) - 1;
341
    $output = theme('table', array('header' => $header, 'rows' => $rows, 'sticky' => $element['#sticky'], 'attributes' => array('class' => array('webform-grid', 'webform-grid-' . $option_count))));
342
  }
343
  else {
344
    $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
    }
349
    $output = implode("\n", $items);
350
  }
351

    
352
  return $output;
353
}
354

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

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

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

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

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

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

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

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

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

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

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

    
432
  return $output;
433
}
434

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

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

    
458
  return $header;
459
}
460

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

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

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

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

    
511
  $rows = array();
512
  $title = array('data' => '', 'class' => array('webform-grid-question'));
513
  $header = array($title);
514
  // 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
  }
521

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

    
526
    // 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);
529

    
530
    // 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));
537
    }
538
    if ($right_titles) {
539
      $row[] = array('data' => isset($question_titles[1]) ? webform_filter_xss($question_titles[1]) : '', 'class' => array('webform-grid-question'));
540
    }
541
    $rows[] = $row;
542
  }
543

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

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

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