1
|
<?php
|
2
|
|
3
|
/**
|
4
|
* @file
|
5
|
* This file is mostly about the field configuration.
|
6
|
*/
|
7
|
|
8
|
/**
|
9
|
* Implements hook_field_info().
|
10
|
*/
|
11
|
function makemeeting_field_info() {
|
12
|
return array(
|
13
|
'makemeeting' => array(
|
14
|
'label' => t('Makemeeting form'),
|
15
|
'description' => t('This field stores user choices about some dates in the database.'),
|
16
|
'default_widget' => 'makemeeting_choices',
|
17
|
'default_formatter' => 'makemeeting_answers',
|
18
|
),
|
19
|
);
|
20
|
}
|
21
|
|
22
|
/**
|
23
|
* Implements hook_field_widget_info().
|
24
|
*/
|
25
|
function makemeeting_field_widget_info() {
|
26
|
return array(
|
27
|
'makemeeting_choices' => array(
|
28
|
'label' => t('Makemeeting choices'),
|
29
|
'field types' => array('makemeeting'),
|
30
|
'behaviors' => array(
|
31
|
'default value' => FIELD_BEHAVIOR_NONE,
|
32
|
),
|
33
|
),
|
34
|
);
|
35
|
}
|
36
|
|
37
|
/**
|
38
|
* Implements hook_field_widget_settings_form().
|
39
|
*/
|
40
|
function makemeeting_field_widget_settings_form($field, $instance) {
|
41
|
$widget = $instance['widget'];
|
42
|
$settings = $widget['settings'];
|
43
|
|
44
|
$form = array();
|
45
|
if ($widget['type'] == 'makemeeting_choices') {
|
46
|
$form['size'] = array(
|
47
|
'#type' => 'textfield',
|
48
|
'#title' => t('Number of dates'),
|
49
|
'#default_value' => isset($settings['size']) ? $settings['size'] : 1,
|
50
|
'#element_validate' => array('element_validate_integer'),
|
51
|
'#required' => TRUE,
|
52
|
'#size' => 5,
|
53
|
'#description' => t('Default number of date choices to display. Must be positive or equal to 0.')
|
54
|
);
|
55
|
}
|
56
|
|
57
|
return $form;
|
58
|
}
|
59
|
|
60
|
/**
|
61
|
* Implements hook_field_widget_form().
|
62
|
*/
|
63
|
function makemeeting_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
|
64
|
$element += array(
|
65
|
'#type' => 'fieldset',
|
66
|
);
|
67
|
|
68
|
$item =& $items[$delta];
|
69
|
|
70
|
// Simple options form elements about the poll
|
71
|
$element['hidden'] = array(
|
72
|
'#title' => t('Hidden poll'),
|
73
|
'#description' => t('Confidential participation: only you and administrators can see the answers.'),
|
74
|
'#type' => 'checkbox',
|
75
|
'#default_value' => isset($item['hidden']) ? $item['hidden'] : '',
|
76
|
);
|
77
|
$element['one_option'] = array(
|
78
|
'#title' => t('Participant can only choose one option'),
|
79
|
'#description' => t('By default all options are selectable. This setting limits the choice to one option per participant.'),
|
80
|
'#type' => 'checkbox',
|
81
|
'#default_value' => isset($item['one_option']) ? $item['one_option'] : '',
|
82
|
);
|
83
|
$element['limit'] = array(
|
84
|
'#title' => t('Limit the number of participants per option'),
|
85
|
'#description' => t('Poll as registration form: As soon as the indicated limit has been reached, the respective option is no longer available. 0 for unlimited'),
|
86
|
'#type' => 'textfield',
|
87
|
'#default_value' => isset($item['limit']) ? $item['limit'] : 0,
|
88
|
'#element_validate' => array('element_validate_integer'),
|
89
|
);
|
90
|
$element['yesnomaybe'] = array(
|
91
|
'#title' => t('Provide a "Maybe" option'),
|
92
|
'#description' => t('Provide a third "Maybe" option in case users may be available.'),
|
93
|
'#type' => 'checkbox',
|
94
|
'#default_value' => isset($item['yesnomaybe']) ? $item['yesnomaybe'] : '',
|
95
|
// Hide if one_option is checked
|
96
|
'#states' => array(
|
97
|
'visible' => array(
|
98
|
':input[name$="[one_option]"]' => array('checked' => FALSE),
|
99
|
),
|
100
|
),
|
101
|
);
|
102
|
$element['closed'] = array(
|
103
|
'#title' => t('Closed'),
|
104
|
'#description' => t('Check this when you want to close the poll.'),
|
105
|
'#type' => 'checkbox',
|
106
|
'#default_value' => isset($item['closed']) ? $item['closed'] : '',
|
107
|
);
|
108
|
|
109
|
// Now let's take care of the choices part
|
110
|
// $process is a callback that we will attach to the wrapper in order
|
111
|
// to add parents to the form elements. This is so we can store
|
112
|
// nested values in the DB table with field storage API.
|
113
|
$fieldset_info = element_info('fieldset');
|
114
|
$process = array_merge($fieldset_info['#process'], array('_makemeeting_rebuild_parents'));
|
115
|
$element['choices_wrapper'] = array(
|
116
|
'#tree' => FALSE,
|
117
|
'#prefix' => '<div class="clearfix" id="makemeeting-choices-wrapper">',
|
118
|
'#suffix' => '</div>',
|
119
|
'#process' => $process,
|
120
|
);
|
121
|
|
122
|
// Container just for the poll choices.
|
123
|
$element['choices_wrapper']['choices'] = array(
|
124
|
'#prefix' => '<div id="makemeeting-choices">',
|
125
|
'#suffix' => '</div>',
|
126
|
'#theme' => 'makemeeting_choices',
|
127
|
);
|
128
|
|
129
|
// Fill the item values with previously submitted values
|
130
|
if (!empty($form_state['values'])) {
|
131
|
$submitted_values = drupal_array_get_nested_value($form_state['values'], $element['#field_parents']);
|
132
|
$submitted_values = $submitted_values[$element['#field_name']][$element['#language']][$element['#delta']];
|
133
|
if (isset($submitted_values['choices'])) {
|
134
|
$item['choices'] = $submitted_values['choices'];
|
135
|
}
|
136
|
}
|
137
|
|
138
|
// Calculate the suggestion count
|
139
|
if (empty($form_state['suggestion_count'])) {
|
140
|
$form_state['suggestion_count'] = 1;
|
141
|
}
|
142
|
if (isset($item['choices'])) {
|
143
|
foreach ($item['choices'] as $choice) {
|
144
|
if ($form_state['suggestion_count'] < count($choice['chsuggestions'])) {
|
145
|
$form_state['suggestion_count'] = count($choice['chsuggestions']);
|
146
|
}
|
147
|
}
|
148
|
}
|
149
|
|
150
|
// Determine choice count if not provided
|
151
|
if (!isset($form_state['choice_count'])) {
|
152
|
try {
|
153
|
list($entity_id) = entity_extract_ids($element['#entity_type'], $element['#entity']);
|
154
|
} catch (Exception $e) {
|
155
|
// Fail silently if the field is not attached to any entity yet.
|
156
|
}
|
157
|
// If the entity isn't created yet, offer the default number of choices,
|
158
|
// else the number of previous choices, or 0 if none
|
159
|
if (!isset($entity_id)) {
|
160
|
$widget = $instance['widget'];
|
161
|
$settings = $widget['settings'];
|
162
|
$form_state['choice_count'] = isset($settings['size']) ? $settings['size'] : 1;
|
163
|
}
|
164
|
else {
|
165
|
$form_state['choice_count'] = isset($item['choices']) ? count($item['choices']) : 0;
|
166
|
}
|
167
|
}
|
168
|
|
169
|
// Add the current choices to the form.
|
170
|
$delta = 0;
|
171
|
if (isset($item['choices']) && $form_state['choice_count']) {
|
172
|
// Sort choices by their dates
|
173
|
asort($item['choices']);
|
174
|
$delta = count($item['choices']);
|
175
|
foreach ($item['choices'] as $key => $choice) {
|
176
|
$element['choices_wrapper']['choices'][$key] =
|
177
|
_makemeeting_choice_form($key, $choice['chdate'], $choice['chsuggestions'], $form_state['suggestion_count']);
|
178
|
}
|
179
|
}
|
180
|
|
181
|
// Add choices as required.
|
182
|
if ($form_state['choice_count']) {
|
183
|
// Add a day to the last option's timestamp for the new default date
|
184
|
$last_option_timestamp = isset($choice['chdate']) ? _makemeeting_date_timestamp($choice['chdate']) : REQUEST_TIME;
|
185
|
$existing_delta = $delta;
|
186
|
for (; $delta < $form_state['choice_count'] ; $delta++) {
|
187
|
$additional_stamp = strtotime('+1 day', $last_option_timestamp);
|
188
|
// Build default date
|
189
|
$default_date = array(
|
190
|
'month' => date('n', $additional_stamp),
|
191
|
'day' => date('j', $additional_stamp),
|
192
|
'year' => date('Y', $additional_stamp)
|
193
|
);
|
194
|
$key = 'new:' . ($delta - $existing_delta);
|
195
|
$element['choices_wrapper']['choices'][$key] =
|
196
|
_makemeeting_choice_form($key, $default_date, NULL, $form_state['suggestion_count']);
|
197
|
// Repeat
|
198
|
$last_option_timestamp = $additional_stamp;
|
199
|
}
|
200
|
}
|
201
|
|
202
|
// We prefix our buttons with 'makemeeting' to avoid conflicts
|
203
|
// with other modules using Ajax-enabled buttons with the id 'more'.
|
204
|
$default_submit = array(
|
205
|
'#type' => 'submit',
|
206
|
'#limit_validation_errors' => array(array('choices')),
|
207
|
'#submit' => array('makemeeting_choices_submit'),
|
208
|
'#ajax' => array(
|
209
|
'callback' => 'makemeeting_choice_js',
|
210
|
'wrapper' => 'makemeeting-choices-wrapper',
|
211
|
'effect' => 'fade',
|
212
|
),
|
213
|
);
|
214
|
$element['choices_wrapper']['makemeeting_more_choices'] = $default_submit + array(
|
215
|
'#value' => t('More choices'),
|
216
|
'#attributes' => array(
|
217
|
'title' => t("If the amount of rows above isn't enough, click here to add more choices."),
|
218
|
),
|
219
|
'#weight' => 1,
|
220
|
);
|
221
|
$element['choices_wrapper']['makemeeting_more_suggestions'] = $default_submit + array(
|
222
|
'#value' => t('More suggestions'),
|
223
|
'#attributes' => array(
|
224
|
'title' => t("If the amount of boxes above isn't enough, click here to add more suggestions."),
|
225
|
),
|
226
|
'#weight' => 2,
|
227
|
);
|
228
|
if ($form_state['choice_count'] > 1) {
|
229
|
$element['choices_wrapper']['makemeeting_copy_suggestions'] = $default_submit + array(
|
230
|
'#value' => t('Copy and paste first row'),
|
231
|
'#attributes' => array(
|
232
|
'title' => t("Copy the suggestions from the first to the other rows."),
|
233
|
),
|
234
|
'#weight' => 3,
|
235
|
);
|
236
|
}
|
237
|
return $element;
|
238
|
}
|
239
|
|
240
|
/**
|
241
|
* Helper function to construct a row of the widget form
|
242
|
*
|
243
|
* @param $key
|
244
|
* @param string $value
|
245
|
* @param array $suggestions
|
246
|
* @param int $size
|
247
|
* @return array
|
248
|
*/
|
249
|
function _makemeeting_choice_form($key, $value = '', $suggestions = array(), $size = 1) {
|
250
|
$form = array(
|
251
|
'#tree' => TRUE,
|
252
|
);
|
253
|
|
254
|
// We'll manually set the #parents property of these fields so that
|
255
|
// their values appear in the $form_state['values']['choices'] array
|
256
|
// They are to be updated later in #process as we don't know here the
|
257
|
// hierarchy of the parents
|
258
|
$form['chdate'] = array(
|
259
|
'#type' => 'date',
|
260
|
'#title' => t('Date'),
|
261
|
'#title_display' => 'invisible',
|
262
|
'#default_value' => $value,
|
263
|
'#parents' => array('choices', $key, 'chdate'),
|
264
|
);
|
265
|
$form['chremove'] = array(
|
266
|
'#type' => 'submit',
|
267
|
'#parents' => array(),
|
268
|
'#submit' => array('makemeeting_choices_submit'),
|
269
|
'#limit_validation_errors' => array(array('choices')),
|
270
|
'#ajax' => array(
|
271
|
'callback' => 'makemeeting_choice_js',
|
272
|
'wrapper' => 'makemeeting-choices',
|
273
|
'effect' => 'fade',
|
274
|
),
|
275
|
'#value' => t('Remove'),
|
276
|
// Assigning key as name to make each 'Remove' button unique
|
277
|
'#name' => $key,
|
278
|
);
|
279
|
|
280
|
$form['chsuggestions'] = array(
|
281
|
'#tree' => TRUE,
|
282
|
'#parents' => array('choices', $key, 'chsuggestions'),
|
283
|
);
|
284
|
|
285
|
for ($i = 0 ; $i < $size ; $i++) {
|
286
|
$key2 = 'sugg:' . ($i);
|
287
|
$form['chsuggestions'][$key2] = array(
|
288
|
'#type' => 'textfield',
|
289
|
'#title_display' => 'invisible',
|
290
|
'#default_value' => isset($suggestions[$key2]) ? $suggestions[$key2] : '',
|
291
|
'#size' => 5,
|
292
|
'#maxlength' => 255,
|
293
|
'#parents' => array('choices', $key, 'chsuggestions', $key2),
|
294
|
);
|
295
|
}
|
296
|
return $form;
|
297
|
}
|
298
|
|
299
|
/**
|
300
|
* Helper function to update the form elements parents. This is required
|
301
|
* for the element to be saved properly by the Field API (see #process)
|
302
|
*
|
303
|
* @param $element
|
304
|
* @return mixed
|
305
|
*/
|
306
|
function _makemeeting_rebuild_parents(&$element) {
|
307
|
$parents = array_diff($element['#array_parents'], $element['#parents']);
|
308
|
$elements = array(
|
309
|
'makemeeting_more_choices',
|
310
|
'makemeeting_more_suggestions',
|
311
|
'makemeeting_copy_suggestions'
|
312
|
);
|
313
|
foreach ($elements as $e) {
|
314
|
$element[$e]['#parents'] = $parents;
|
315
|
if (isset($element[$e]['#limit_validation_errors'])) {
|
316
|
$element[$e]['#limit_validation_errors'][0] = array_merge($parents,
|
317
|
$element[$e]['#limit_validation_errors'][0]);
|
318
|
}
|
319
|
}
|
320
|
$element['makemeeting_more_suggestions']['#parents'] = $parents;
|
321
|
$element['makemeeting_copy_suggestions']['#parents'] = $parents;
|
322
|
foreach (element_children($element['choices']) as $key1) {
|
323
|
foreach (element_children($element['choices'][$key1]) as $key2) {
|
324
|
$keys = element_children($element['choices'][$key1][$key2]);
|
325
|
if (empty($keys)) {
|
326
|
$element['choices'][$key1][$key2]['#parents'] = array_merge($parents,
|
327
|
$element['choices'][$key1][$key2]['#parents']);
|
328
|
}
|
329
|
else {
|
330
|
foreach ($keys as $key3) {
|
331
|
$element['choices'][$key1][$key2][$key3]['#parents'] = array_merge($parents,
|
332
|
$element['choices'][$key1][$key2][$key3]['#parents']);
|
333
|
}
|
334
|
}
|
335
|
}
|
336
|
}
|
337
|
return $element;
|
338
|
}
|
339
|
|
340
|
/**
|
341
|
* Implements hook_field_validate().
|
342
|
*/
|
343
|
function makemeeting_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
|
344
|
foreach ($items as $delta => $item) {
|
345
|
if (isset($item['choices'])) {
|
346
|
// Verify that we do not have duplicate dates
|
347
|
$dates = array();
|
348
|
foreach ($item['choices'] as $chid => $chvalue) {
|
349
|
$date = implode('', $chvalue['chdate']);
|
350
|
if (in_array($date, $dates)) {
|
351
|
// Register an error with the choice id
|
352
|
$errors[$field['field_name']][$langcode][$delta][] = array(
|
353
|
'error' => 'duplicate_dates',
|
354
|
'message' => t('%name: you can\'t have duplicate dates.', array('%name' => $instance['label'])),
|
355
|
'chid' => $chid,
|
356
|
);
|
357
|
}
|
358
|
else {
|
359
|
$dates[] = $date;
|
360
|
}
|
361
|
}
|
362
|
}
|
363
|
}
|
364
|
}
|
365
|
|
366
|
/**
|
367
|
* Implements hook_field_widget_error().
|
368
|
*/
|
369
|
function makemeeting_field_widget_error($element, $error) {
|
370
|
// Show our error concerning duplicate dates here
|
371
|
$choices = $element['choices_wrapper']['choices'];
|
372
|
form_error($choices[$error['chid']]['chdate'], $error['message']);
|
373
|
}
|
374
|
|
375
|
|
376
|
/**
|
377
|
* Implements hook_field_is_empty().
|
378
|
*/
|
379
|
function makemeeting_field_is_empty($item) {
|
380
|
return empty($item['choices']);
|
381
|
}
|
382
|
|
383
|
/**
|
384
|
* Implements hook_field_formatter_info().
|
385
|
*/
|
386
|
function makemeeting_field_formatter_info() {
|
387
|
return array(
|
388
|
'makemeeting_answers' => array(
|
389
|
'label' => t('Makemeeting answers'),
|
390
|
'field types' => array('makemeeting'),
|
391
|
),
|
392
|
);
|
393
|
}
|
394
|
|
395
|
/**
|
396
|
* Implements hook_field_formatter_view().
|
397
|
*
|
398
|
* Build a renderable array for a field value.
|
399
|
*
|
400
|
* @param $entity_type
|
401
|
* The type of $entity.
|
402
|
* @param $entity
|
403
|
* The entity being displayed.
|
404
|
* @param $field
|
405
|
* The field structure.
|
406
|
* @param $instance
|
407
|
* The field instance.
|
408
|
* @param $langcode
|
409
|
* The language associated with $items.
|
410
|
* @param $items
|
411
|
* Array of values for this field.
|
412
|
* @param $display
|
413
|
* The display settings to use, as found in the 'display' entry of instance
|
414
|
* definitions. The array notably contains the following keys and values;
|
415
|
* - type: The name of the formatter to use.
|
416
|
* - settings: The array of formatter settings.
|
417
|
*
|
418
|
* @return array
|
419
|
* A renderable array for the $items, as an array of child elements keyed
|
420
|
*/
|
421
|
function makemeeting_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
|
422
|
$content = array();
|
423
|
foreach ($items as $delta => $item) {
|
424
|
list($entity_id) = entity_extract_ids($entity_type, $entity);
|
425
|
$instance += array(
|
426
|
'entity_id' => $entity_id,
|
427
|
'language' => $langcode,
|
428
|
'delta' => $delta
|
429
|
);
|
430
|
// Define answers hidden status here as we have $field variable available
|
431
|
$item['is_hidden'] = (bool) $item['hidden'];
|
432
|
if ($item['is_hidden']) {
|
433
|
$access = field_access('edit', $field, $entity_type, $entity);
|
434
|
if ($entity_type == 'node') {
|
435
|
$access = $access && node_access('update', $entity);
|
436
|
}
|
437
|
elseif (module_exists('entity')) {
|
438
|
$access = $access && entity_access('edit', $entity_type, $entity);
|
439
|
}
|
440
|
$item['is_hidden'] = $item['is_hidden'] && !$access;
|
441
|
}
|
442
|
$content[] = drupal_get_form('makemeeting_answers_form_' . $instance['entity_id'], $item, $instance);
|
443
|
}
|
444
|
return $content;
|
445
|
}
|
446
|
|
447
|
/**
|
448
|
* Implements hook_field_load().
|
449
|
*/
|
450
|
function makemeeting_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) {
|
451
|
// Unserialize array values
|
452
|
foreach ($entities as $id => $entity) {
|
453
|
foreach ($items[$id] as $delta => $item) {
|
454
|
if ($field['type'] == 'makemeeting' && is_string($items[$id][$delta]['choices'])) {
|
455
|
$items[$id][$delta]['choices'] = unserialize($items[$id][$delta]['choices']);
|
456
|
}
|
457
|
}
|
458
|
}
|
459
|
}
|
460
|
|
461
|
/**
|
462
|
* Implements hook_field_presave().
|
463
|
*/
|
464
|
function makemeeting_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
|
465
|
if ($field['type'] == 'makemeeting') {
|
466
|
foreach ($items as $delta => $item) {
|
467
|
if (isset($item['choices'])) {
|
468
|
// Sort the choices by date
|
469
|
$choices = array_values($item['choices']);
|
470
|
usort($choices, '_makemeeting_sort_choices');
|
471
|
// Affect timestamp as keys
|
472
|
$timestamped_choices = array();
|
473
|
foreach ($choices as $choice) {
|
474
|
$timestamped_choices[_makemeeting_date_timestamp($choice['chdate'])] = $choice;
|
475
|
}
|
476
|
// Serialize the whole array
|
477
|
$items[$delta]['choices'] = serialize($timestamped_choices);
|
478
|
}
|
479
|
}
|
480
|
}
|
481
|
}
|
482
|
|
483
|
/**
|
484
|
* Helper function to sort choice dates
|
485
|
*/
|
486
|
function _makemeeting_sort_choices($a, $b) {
|
487
|
if ($a['chdate']['year'] == $b['chdate']['year']) {
|
488
|
if ($a['chdate']['month'] == $b['chdate']['month']) {
|
489
|
if ($a['chdate']['day'] == $b['chdate']['day']) {
|
490
|
return 0;
|
491
|
}
|
492
|
else {
|
493
|
return (int) $a['chdate']['day'] < (int) $b['chdate']['day'] ? -1 : 1;
|
494
|
}
|
495
|
}
|
496
|
else {
|
497
|
return (int) $a['chdate']['month'] < (int) $b['chdate']['month'] ? -1 : 1;
|
498
|
}
|
499
|
}
|
500
|
else {
|
501
|
return (int) $a['chdate']['year'] < (int) $b['chdate']['year'] ? -1 : 1;
|
502
|
}
|
503
|
}
|
504
|
|
505
|
|
506
|
/**
|
507
|
* Submit handler to add more choices or suggestions to a poll form,
|
508
|
* or to copy the first row of suggestions to the others
|
509
|
*
|
510
|
* This handler is run regardless of whether JS is enabled or not. It makes
|
511
|
* changes to the form state. If the button was clicked with JS disabled, then
|
512
|
* the page is reloaded with the complete rebuilt form. If the button was
|
513
|
* clicked with JS enabled, then ajax_form_callback() calls makemeeting_choice_js() to
|
514
|
* return just the changed part of the form.
|
515
|
*/
|
516
|
function makemeeting_choices_submit($form, &$form_state) {
|
517
|
$clicked_button = $form_state['clicked_button'];
|
518
|
|
519
|
// Get the element
|
520
|
$element =& drupal_array_get_nested_value($form_state['input'], $clicked_button['#parents']);
|
521
|
|
522
|
// If clicked button is 'Remove', unset corresponding choice
|
523
|
if ($clicked_button['#value'] == t('Remove')) {
|
524
|
unset($element['choices'][$clicked_button['#name']]);
|
525
|
$form_state['choice_count'] = count($element['choices']);
|
526
|
}
|
527
|
|
528
|
// Affect timestamp as key to each choice
|
529
|
$choices = array();
|
530
|
if (isset($element['choices'])) {
|
531
|
foreach ($element['choices'] as $choice) {
|
532
|
$choices['choices'][_makemeeting_date_timestamp($choice['chdate'])] = $choice;
|
533
|
}
|
534
|
}
|
535
|
|
536
|
// Handle other operations
|
537
|
if (!empty($form_state['values']['op'])) {
|
538
|
switch ($form_state['values']['op']) {
|
539
|
// Add 1 more choice to the form.
|
540
|
case t('More choices'):
|
541
|
// Increment choice count
|
542
|
$form_state['choice_count'] = count($element['choices']) + 1;
|
543
|
break;
|
544
|
|
545
|
// Add 1 more suggestion to the form.
|
546
|
case t('More suggestions'):
|
547
|
$form_state['suggestion_count']++;
|
548
|
break;
|
549
|
|
550
|
// Copy first row suggestions to the other rows.
|
551
|
case t('Copy and paste first row');
|
552
|
$first = reset($choices['choices']);
|
553
|
foreach (array_keys($choices['choices']) as $key) {
|
554
|
$choices['choices'][$key]['chsuggestions'] = $first['chsuggestions'];
|
555
|
}
|
556
|
break;
|
557
|
}
|
558
|
}
|
559
|
|
560
|
// Replace submitted values by our own work
|
561
|
drupal_array_set_nested_value($form_state['input'], $clicked_button['#parents'], $choices);
|
562
|
drupal_array_set_nested_value($form_state['values'], $clicked_button['#parents'], $choices);
|
563
|
|
564
|
// Require the widget form to rebuild the choices
|
565
|
// with the values in $form_state
|
566
|
$form_state['rebuild'] = TRUE;
|
567
|
}
|
568
|
|
569
|
/**
|
570
|
* Ajax callback in response to new choices being added to the form.
|
571
|
*
|
572
|
* This returns the new page content to replace the page content made obsolete
|
573
|
* by the form submission.
|
574
|
*/
|
575
|
function makemeeting_choice_js($form, $form_state) {
|
576
|
// Get the element from the parents of the clicked button
|
577
|
$element = drupal_array_get_nested_value($form, $form_state['clicked_button']['#parents']);
|
578
|
return $element['choices_wrapper'];
|
579
|
}
|