commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / webform_civicrm / includes / wf_crm_admin_component.inc
1 <?php
2
3 /**
4 * @file
5 * Webform CiviCRM module's alterations to webform component form.
6 */
7 module_load_include('inc', 'webform_civicrm', 'includes/utils');
8
9 // FIXME: Temporary workaround for https://www.drupal.org/node/2389537
10 variable_set('webform_table', TRUE);
11
12 class wf_crm_admin_component {
13 private $form;
14 private $form_state;
15 private $node;
16 private $data;
17 private $component;
18 private $field;
19 private $hasOptionsTable;
20
21 function __construct(&$form, &$form_state) {
22 civicrm_initialize();
23 $this->form = &$form;
24 $this->form_state = &$form_state;
25 $this->node = node_load($form['nid']['#value']);
26 $this->data = wf_crm_aval($this->node, 'webform_civicrm:data');
27 $this->component = wf_crm_aval($this->node, 'webform:components:' . $this->form['cid']['#value']);
28 }
29
30 /**
31 * Alter back-end webform component edit forms.
32 * Called by hook_form_alter() whenever editing a webform component.
33 */
34 public function alterForm() {
35 $fid = $this->form['form_key']['#default_value'];
36 $pieces = wf_crm_explode_key($fid);
37 // Is this a crm component of a CiviCRM-enabled webform?
38 if (!$this->data || !$pieces) {
39 return;
40 }
41 list(, $i, $ent, $n, $table, $name) = $pieces;
42 $this->field = wf_crm_aval(wf_crm_get_fields(), $table . '_' . $name);
43 // Is this a crm field or fieldset?
44 if (!$this->field && $table != 'fieldset') {
45 return;
46 }
47 $this->form['#attached']['css'][] = drupal_get_path('module', 'webform_civicrm') . '/css/webform_civicrm_admin.css';
48
49 if (empty($this->form['clone']['#value']) || $name == 'fieldset') {
50 // Prevent users from editing the form_key and breaking things
51 $this->form['form_key']['#disabled'] = TRUE;
52 $this->form['form_key']['#value'] = $fid;
53 $this->form['form_key']['#description'] = NULL;
54 $this->form['form_key']['#attributes']['title'] = t('Automatically set for use by CiviCRM processing.');
55
56 // Clone an entire contact when cloning their fieldset
57 if (!empty($this->form['clone']['#value'])) {
58 $this->form['actions']['submit']['#value'] = t('Clone Contact');
59 $new = count($this->data['contact']) + 1;
60 $this->form['form_key']['#value'] = implode('_', array('civicrm', $new, $ent, $n, $table, $name));
61 $this->form['name']['#default_value'] = wf_crm_contact_label($new, array(), 'plain');
62 ++$this->form['position']['weight']['#default_value'];
63 array_unshift($this->form['#submit'], 'wf_crm_contact_clone');
64 if (empty($this->form_state['input'])) {
65 $types = wf_crm_get_contact_types();
66 $type = $types[0][$this->data['contact'][$i]['contact'][1]['contact_type']];
67 drupal_set_message(t('Press the "Clone Contact" button below and a new @type will be added to the form with all the settings for !contact. All fields within this fieldset will be cloned (be careful, that may include non-contact fields).', array('@type' => $type, '!contact' => wf_crm_contact_label($i, $this->data))), 'status', FALSE);
68 }
69 }
70 }
71 elseif (empty($this->form_state['input'])) {
72 // Clone a single CiviCRM field
73 drupal_set_message(t('You are cloning a CiviCRM component. Refer to the Webform CiviCRM instructions for how to set the key if you want the new field to be processed by CiviCRM. You can also clone an entire contact by clicking the clone button by their fieldset.'), 'status', FALSE);
74 }
75
76 // Show dropdown list of states
77 if ($table === 'address' && $name === 'state_province_id') {
78 $this->form['validation']['maxlength']['#type'] = 'hidden';
79 $this->form['validation']['maxlength']['#value'] = 5;
80 $this->form['value']['#type'] = 'select';
81 unset($this->form['value']['#size'], $this->form['value']['#maxlength'], $this->form['value']['#description']);
82 $this->form['value']['#options'] = wf_crm_get_states();
83 $this->form['value']['#empty_value'] = '';
84 }
85
86 elseif ($name == 'contribution_page_id') {
87 $this->form['value']['#access'] = FALSE;
88 $this->form['#prefix'] = '<p>' . t('This is a placeholder for a Contribution Page.') . '</p>';
89 }
90
91 // Interface for managing options
92 elseif (($this->component['type'] === 'hidden' || $this->component['type'] === 'select')) {
93 $this->hasOptionsTable = $this->buildOptionsTable();
94 }
95
96 // Customize options_element a bit
97 if (!$this->hasOptionsTable && $this->component['type'] === 'select') {
98 $this->alterOptionsElement();
99 }
100
101 // Money fields
102 if (!$this->hasOptionsTable && wf_crm_aval($this->field, 'data_type') == 'Money') {
103 $this->moneyOptions();
104 }
105
106 // Simplify form for hidden fields
107 elseif (($name === 'contact_id' || $name === 'external_identifier') && $this->component['type'] === 'hidden') {
108 $this->form['value']['#value'] = '';
109 $this->form['value']['#access'] = FALSE;
110 $this->form['#prefix'] = '<p>'
111 . t('There are no configuration options for this hidden field. You can use it for post processing, for example to include a link to the CiviCRM contact in an email.')
112 . '</p><p>'
113 . t('The webform token for this field is:')
114 . '<br /><strong>' . $this->componentToken($this->form['cid']['#value'])
115 . '</strong><br /><em>'
116 . t('Note: this token will change if you move the field in or out of a fieldset.')
117 . '</em></p>';
118 }
119 // Customize form for checksum element
120 elseif ($name == 'cs') {
121 $this->form['value']['#title'] = t('Checksum Lifespan');
122 $this->form['value']['#required'] = TRUE;
123 $this->form['value']['#type'] = 'textfield';
124 $this->form['value']['#description'] = t('Enter the number of days for which this checksum will be valid. Enter 0 to never expire.');
125 $this->form['#validate'][] = 'wf_crm_cs_validate';
126 $enabled = wf_crm_enabled_fields($this->node);
127 $this->form['#prefix'] = '<p>'
128 . t('This field will generate a checksum for !contact after the form is submitted. You could use its webform token to create a personalized link for anonymous users.', array('!contact' => wf_crm_contact_label($i, $this->data)))
129 . '</p><p>';
130 if ($cid_field = wf_crm_aval($enabled, 'civicrm_' . $i . '_contact_1_contact_contact_id')) {
131 $this->form['#prefix'] .= t('Example: to link users back to this form, place this line in a webform-generated email:')
132 . '<br /><code>'
133 . url('node/' . $this->node->nid, array('absolute' => TRUE)) . '?cid' . $i . '=';
134 $this->form['#prefix'] .= $this->componentToken($cid_field)
135 . '&amp;cs' . $i . '=' . $this->componentToken($this->form['cid']['#value'])
136 . '</code></p>';
137 $this->form['#prefix'] .= '<p>' . t('Example: to redirect to a contribution page, paste this into the redirect field on the Webform "Form Settings" tab (change id from 1 to the real id of your contribution page):')
138 . '<br /><code>'
139 . 'civicrm/contribute/transact?reset=1&amp;id=1'
140 . '&amp;cid=' . $this->componentToken($cid_field)
141 . '&amp;cs=' . $this->componentToken($this->form['cid']['#value'])
142 . '</code></p>';
143 }
144 else {
145 $this->form['#prefix'] .= t('Consider enabling the hidden contact_id field - hashed links usually require this value.') . '</p>';
146 }
147 }
148 // Alter weights for contact component
149 if ($this->form['type']['#value'] == 'civicrm_contact') {
150 $this->form['display']['#weight'] = -1;
151 }
152 // Allow widget to be altered, unless it's a contact or file
153 elseif ($this->field && !in_array($this->field['type'], array('civicrm_contact', 'file')) && empty($_GET['type'])) {
154 $unusable_widgets = array('civicrm_contact', 'pagebreak', 'markup', 'layout_box', 'fieldset');
155 $widgets = array_diff_key(webform_component_options(), array_flip($unusable_widgets));
156 if ($this->form['type']['#value'] == 'textfield' && $table === 'address') {
157 if ($name === 'state_province_id' || $name === 'county_id') {
158 $widgets['textfield'] = t('Textfield / AJAX Select');
159 }
160 }
161 $this->form['widget'] = array(
162 '#type' => 'fieldset',
163 '#title' => t('Widget: %type', array('%type' => wf_crm_aval($widgets, $this->form['type']['#value'], t('Unknown')))),
164 '#description' => t('The default widget for this %type field is %widget. You may change it if you wish - for example, a hidden field allows you to set the value without exposing this field to the form.<br />Note: Not all widgets may be compatible with this CiviCRM field - test your form after changing widgets.', array('%type' => str_replace('#', '', $this->field['name']), '%widget' => wf_crm_aval($widgets, $this->field['type'], t('Disabled')))),
165 '#collapsible' => TRUE,
166 '#collapsed' => TRUE,
167 );
168 $this->form['widget']['type'] = array(
169 '#type' => 'select',
170 '#options' => $widgets,
171 '#default_value' => $this->form['type']['#value'],
172 );
173 $this->form['widget']['change_widget'] = array(
174 '#type' => 'submit',
175 '#value' => t('Change Widget'),
176 '#submit' => array('webform_component_edit_form_submit', 'wf_crm_change_widget'),
177 '#states' => array(
178 'invisible' => array(
179 'select[name="widget[type]"]' => array('value' => $this->form['type']['#value']),
180 ),
181 'disabled' => array(
182 'select[name="widget[type]"]' => array('value' => $this->form['type']['#value']),
183 ),
184 )
185 );
186 }
187 }
188
189 /**
190 * Ensure page breaks are not placed after contribution page
191 */
192 public function adjustPageBreak() {
193 $components = $this->node->webform['components'];
194 foreach ($components as $cid => $component) {
195 if ($component['form_key'] == 'civicrm_1_contribution_1_contribution_contribution_page_id') {
196 // Iterate up through parents
197 while ($component['pid']) {
198 $component = $components[$component['pid']];
199 }
200 $min = $component['weight'];
201 }
202 }
203 if (isset($min)) {
204 $weight = $this->form['position']['weight']['#default_value'];
205 $this->form['position']['weight'] = array('#type' => 'value');
206 if ($weight >= $min) {
207 $weight = $min - 1;
208 }
209 $this->form['position']['weight']['#value'] = $weight;
210 }
211 }
212
213 /**
214 * Interface similar to options_element module
215 * but with the important difference that options already exist in the civi db
216 * so this does not allow create/delete of options
217 *
218 * @return bool
219 */
220 private function buildOptionsTable() {
221 $options = $sort = wf_crm_field_options($this->component, 'component_edit', $this->data);
222 if (!$options) {
223 return FALSE;
224 }
225 $this->form['#attached']['js'] = array(drupal_get_path('module', 'webform_civicrm') . '/js/webform_civicrm_options.js');
226
227 $defaults_selected = array();
228 if (isset($this->component['value']) && strlen($this->component['value'])) {
229 foreach (explode(',', trim($this->component['value'])) as $v) {
230 $defaults_selected[] = '_web_civi_option_selected_' . $v;
231 }
232 }
233 // Get rid of stuff related to options_element module
234 unset($this->form['items']);
235
236 $this->form['value']['#type'] = 'hidden';
237 $this->form['civicrm_options_fieldset'] = array(
238 '#type' => 'fieldset',
239 '#title' => t('Options'),
240 '#id' => 'wf-crm-options-fieldset',
241 '#theme' => 'webform_civicrm_options_table',
242 );
243 $option_keys = array();
244 foreach ($options as $k => $v) {
245 $option_keys['_web_civi_option_selected_' . $k] = '';
246 $this->form['civicrm_options_fieldset']['civicrm_option_name_' . $k] = array(
247 '#markup' => '<span class="civicrm-option-name">' . $v . '</span>',
248 );
249 }
250 if ($this->component['type'] === 'select') {
251 $this->form['civicrm_options_fieldset']['civicrm_live_options'] = array(
252 '#type' => 'radios',
253 '#options' => array(t('<strong>Static Options</strong> (fully configurable)'), t('<strong>Live Options</strong> (update automatically)')),
254 '#default_value' => (int) !empty($this->component['extra']['civicrm_live_options']),
255 '#parents' => array('extra', 'civicrm_live_options'),
256 );
257 $this->form['civicrm_options_fieldset']['intro'] = array(
258 '#markup' => '<p><div class="live-options-hide">' .
259 t('Drag the arrows to re-order these options. Click the "enabled" checkbox to show/remove an item from the form. Set the label as you want it to appear on the form.') .
260 '</div><div class="live-options-show">' .
261 t('You cannot control the presentation of live options. They will be loaded from the CiviCRM database every time the form is displayed.') .
262 '</div><div>' .
263 t('Check the "default" box for an option to be selected by default when a user views the form.') .
264 '</div></p>',
265 );
266 // Special instructions for contact reference fields
267 if (wf_crm_aval($this->field, 'data_type') == 'ContactReference') {
268 $this->form['civicrm_options_fieldset']['intro'] = array(
269 '#markup' => '<p>' . t('This is a contact reference field. It points to another contact on the webform. You can configure how that contact is presented by editing their "Existing Contact" field.') . '</p>' .
270 '<p>' . t("Note: In most cases it is not desirable to have the selection of webform contacts exposed to the end-user so you may wish to set this field's value on the CiviCRM tab instead.") . '</p>',
271 );
272 }
273 $options_selected = wf_crm_str2array($this->component['extra']['items']);
274 // Sort weights. Unselected options will be at the bottom.
275 $option_keys = $option_selected_keys = array();
276 foreach ($options_selected as $k => $v) {
277 if (isset($options[$k])) {
278 $option_keys['_web_civi_option_selected_' . $k] = '';
279 $option_selected_keys[] = '_web_civi_option_selected_' . $k;
280 unset($sort[$k]);
281 }
282 }
283 foreach ($sort as $k => $v) {
284 $option_keys['_web_civi_option_selected_' . $k] = '';
285 }
286 $this->form['extra']['items']['#type'] = 'hidden';
287 $this->form['extra']['items']['#required'] = FALSE;
288 $this->form['extra']['items']['#value'] = $this->component['extra']['items'];
289 $this->form['extra']['options_source']['#access'] = FALSE;
290 $this->form['civicrm_options_fieldset']['civicrm_options'] = array(
291 '#type' => 'checkboxes',
292 '#required' => TRUE,
293 '#options' => $option_keys,
294 '#default_value' => $option_selected_keys,
295 );
296 $w = 0;
297 foreach ($option_keys as $k => $v) {
298 $k = str_replace('_web_civi_option_selected_', '', $k);
299 $this->form['civicrm_options_fieldset']['civicrm_option_label_' . $k] = array(
300 '#type' => 'textfield',
301 '#size' => 30,
302 '#default_value' => !empty($options_selected[$k]) ? $options_selected[$k] : $options[$k],
303 );
304 $this->form['civicrm_options_fieldset']['civicrm_option_weight_' . $k] = array(
305 '#type' => 'textfield',
306 '#size' => 3,
307 '#default_value' => ++$w,
308 );
309 }
310 }
311 $this->form['civicrm_options_fieldset']['civicrm_defaults'] = array(
312 '#type' => 'checkboxes',
313 '#options' => array('' => '') + $option_keys,
314 '#default_value' => $defaults_selected,
315 );
316 // Auto set multi-value option for single-valued entities
317 if (empty($this->field['extra']['multiple']) && $this->component['type'] === 'select') {
318 $this->form['extra']['multiple']['#type'] = 'hidden';
319 $this->form['extra']['multiple']['#value'] = 0;
320 }
321 // Restore multiple checkbox in case options_element module removed it
322 elseif ($this->component['type'] === 'select') {
323 $this->form['extra']['multiple']['#type'] = 'checkbox';
324 $this->form['extra']['multiple']['#title'] = t('Multiple');
325 $this->form['extra']['multiple']['#description'] = t('Check this option if the user should be allowed to choose multiple values.');
326 $this->form['extra']['multiple']['#default_value'] = !empty($this->component['extra']['multiple']);
327 }
328 else {
329 $this->form['extra']['multiple']['#type'] = 'hidden';
330 $this->form['extra']['multiple']['#value'] = (int) !empty($this->field['extra']['multiple']);
331 }
332 array_unshift($this->form['#submit'], 'wf_crm_process_options_selection');
333 return TRUE;
334 }
335
336 /**
337 * When a CiviCRM field has no options but is rendered as a select
338 * Customize the options_element form
339 */
340 private function alterOptionsElement() {
341 $this->form['items']['options']['#key_type_toggle'] = t('Show CiviCRM values (keys)');
342 $this->form['items']['options']['#key_type_toggled'] = TRUE;
343 }
344
345 /**
346 * options_element alterations for when a currency field (e.g. contribution amount, event fee) is rendered as a select
347 */
348 private function moneyOptions() {
349 form_load_include($this->form_state, 'inc', 'webform_civicrm', 'includes/wf_crm_admin_component');
350 $this->form['#validate'][] = 'wf_crm_money_validate';
351 if ($this->component['type'] === 'grid') {
352 $this->form['options']['#title'] = t('Amounts (columns)');
353 $this->form['options']['#description'] = t('Options to select across the top. Usually these are quantities. Keys must be numeric');
354 $this->form['questions']['#title'] = t('Items (rows)');
355 $this->form['questions']['#description'] = t('Items down the side of the grid. Usually the keys represent item price, which will be multiplied with the amount column.') .
356 '<br />' . t('Use non-numeric keys to use the price from the amount column as-is with no multiplication.');
357 }
358 elseif ($this->component['type'] === 'select') {
359 $this->form['items']['options']['option_settings']['options_source']['#access'] = FALSE;
360 $this->form['items']['#description'] = t('Enter item labels and prices. If you allow the user to select multiple items their amounts will be added together.');
361 }
362 foreach (array('items', 'options', 'questions') as $field) {
363 if (!empty($this->form[$field]['options']['#key_type_toggle'])) {
364 $this->form[$field]['options']['#key_type_toggle'] = t('Show Prices');
365 $this->form[$field]['options']['#key_type_toggled'] = TRUE;
366 }
367 }
368 // CSS trick to add currency symbol to options element keys
369 $symbol = wf_crm_aval(CRM_Core_Config::singleton(), 'defaultCurrencySymbol', '$');
370 drupal_add_css('
371 .option-key-cell:before {
372 content:"' . $symbol . '";
373 }
374 .options-widget .form-text.option-key {
375 width: 50%;
376 margin-left: .3em;
377 }',
378 'inline');
379 }
380
381 /**
382 * Custom Processing for CiviCRM webform component option lists
383 */
384 public function postProcess() {
385 $vals = &$this->form_state['values'];
386 $vals['value'] = '';
387 foreach ($vals['civicrm_options_fieldset']['civicrm_defaults'] as $k) {
388 if ($k) {
389 $vals['value'] .= ($vals['value'] ? ',' : '') . str_replace('_web_civi_option_selected_', '', $k);
390 }
391 }
392 if (isset($vals['civicrm_options_fieldset']['civicrm_options'])) {
393 if (empty($vals['extra']['civicrm_live_options'])) {
394 $items = array();
395 foreach ($vals['civicrm_options_fieldset']['civicrm_options'] as $k) {
396 if ($k) {
397 $v = str_replace('_web_civi_option_selected_', '', $k);
398 if (!($label = $vals['civicrm_options_fieldset']['civicrm_option_label_' . $v])) {
399 $label = $this->form['civicrm_options_fieldset']['civicrm_option_name_' . $v]['#value'];
400 }
401 $items[$vals['civicrm_options_fieldset']['civicrm_option_weight_' . $v]] = $v . '|' . $label;
402 }
403 }
404 ksort($items);
405 $vals['extra']['items'] = implode("\n", $items);
406
407 // A single static radio should be shown as a checkbox
408 if (count($items) == 1 && empty($vals['extra']['aslist'])) {
409 $vals['extra']['multiple'] = 1;
410 }
411 }
412 else {
413 $items = wf_crm_field_options($vals, 'live_options', $this->data);
414 $items += wf_crm_str2array($vals['extra']['items']);
415 $vals['extra']['items'] = wf_crm_array2str($items);
416 }
417 }
418 }
419
420 /**
421 * Look-up the webform token for a field
422 * @param $cid
423 * @return string
424 */
425 private function componentToken($cid) {
426 module_load_include('inc', 'webform', 'includes/webform.components');
427 $component = $this->node->webform['components'][$cid];
428 $parents = webform_component_parent_keys($this->node, $component);
429
430 return '[submission:values:' . implode(':', $parents) . ':nolabel]';
431 }
432
433 /**
434 * Add CiviCRM info and theming to webform components form.
435 * @param array $form
436 * @param array $rows
437 * @param stdClass $node
438 */
439 static function preprocessComponentsForm(&$form, &$rows, $node) {
440 // Prepare for CiviCRM processing
441 $enabled = $data = array();
442 if (!empty($node->webform_civicrm)) {
443 civicrm_initialize();
444 $enabled = wf_crm_enabled_fields($node);
445 $data = $node->webform_civicrm['data'];
446 $form['components']['#attached']['css'][] = drupal_get_path('module', 'webform_civicrm') . '/css/webform_civicrm_admin.css';
447 }
448 foreach ($rows as &$row) {
449 // Empty message when no components have been added
450 if (!empty($row[0]['colspan'])) {
451 if (empty($node->webform['components']) && wf_crm_admin_access($node)) {
452 $form['components']['#attached']['js'][] = drupal_get_path('module', 'webform_civicrm') . '/js/webform_tab.js';
453 $row[0]['data'] = t(
454 'Add a webform component below, or click the <a class="webform-civicrm-tab-link" href="!url">CiviCRM tab</a> to add CRM fields.',
455 (array('!url' => url("node/{$node->nid}/civicrm")))
456 );
457 }
458 }
459 // Add-component row - re-render select element without civicrm_contact option
460 elseif (in_array('webform-add-form', $row['class'])) {
461 unset($form['add']['type']['#options']['civicrm_contact']);
462 $form['add']['type']['#printed'] = FALSE;
463 $row['data'][1] = drupal_render($form['add']['type']);
464 }
465 // Component row
466 elseif (!empty($row['data-cid']) && isset($node->webform['components'][$row['data-cid']])) {
467 $cid = $row['data-cid'];
468 $component = $node->webform['components'][$cid];
469 $type = &$row['data'][2]['data'];
470 if ($component['type'] == 'civicrm_contact') {
471 $types = array(
472 'autocomplete' => t('Contact - Autocomplete'),
473 'select' => t('Contact - Select List'),
474 'hidden' => $component['extra']['show_hidden_contact'] ? t('Contact - Static') : t('Contact - Hidden'),
475 );
476 $type = $types[$component['extra']['widget']];
477 }
478 elseif ($component['type'] == 'select') {
479 if ($component['extra']['aslist']) {
480 $type = $component['extra']['multiple'] ? t('Multi-select') : t('Select');
481 }
482 else {
483 $type = $component['extra']['multiple'] ? t('Checkboxes') : t('Radio buttons');
484 }
485 }
486 if (in_array($cid, $enabled)) {
487 $fields = wf_crm_get_fields();
488 $sets = wf_crm_get_fields('sets');
489 $class = 'civi-icon';
490 list( , $c, $ent, $n, $table, $name) = explode('_', $component['form_key'], 6);
491 $field = wf_crm_aval($fields, $table . '_' . $name, array('type' => 'fieldset'));
492 // Don't allow CiviCRM fields to be cloned
493 $row['data'][7]['data'] = '';
494 if ($component['type'] == 'fieldset') {
495 $title = t('Contact !num', array('!num' => $c));
496 $type = t('Fieldset for !contact', array('!contact' => wf_crm_contact_label($c, $data)));
497 $row['data'][7]['data'] = l(t('Clone Contact'), "node/{$node->nid}/webform/components/$cid/clone", array(
498 'attributes' => array('title' => t('Add a new contact to the form with the same fields and settings')
499 )));
500 $class .= ' fieldset';
501 }
502 elseif ($ent == 'contact') {
503 $field_type = ($table == 'contact' || $table == 'other') ? $field['name'] : $sets[$table]['label'];
504 $title = t('!type Field for !contact', array('!contact' => wf_crm_contact_label($c, $data), '!type' => $field_type));
505 }
506 else {
507 $title = t('Field for !type', array('!type' => $sets[$table]['label']));
508 }
509 if ($table === 'address' && $component['type'] === 'textfield') {
510 if ($name === 'state_province_id' || $name === 'county_id') {
511 $type = t('AJAX Select');
512 }
513 }
514 if ($component['type'] == 'civicrm_contact' || $component['type'] == 'fieldset') {
515 $class .= ' ' . $node->webform_civicrm['data']['contact'][$c]['contact'][1]['contact_type'];
516 }
517 if ($component['type'] == 'select') {
518 $type .= ' (' . (empty($component['extra']['civicrm_live_options']) ? t('static') : t('live')) . ')';
519 }
520 // Show defaults with labels instead of keys
521 if ($component['type'] == 'civicrm_contact') {
522 if ($component['extra']['default'] == 'contact_id') {
523 $row['data'][3]['data'] = check_plain(wf_crm_display_name($component['extra']['default_contact_id']));
524 }
525 elseif ($component['extra']['default'] == 'user') {
526 $row['data'][3]['data'] = t('Current User');
527 }
528 elseif ($component['extra']['default'] == 'auto') {
529 $row['data'][3]['data'] = t('Auto - From Filters');
530 }
531 elseif ($component['extra']['default'] == 'relationship' && $component['extra']['default_relationship']) {
532 $row['data'][3]['data'] = t('Relationship to !contact', array('!contact' => wf_crm_contact_label(1, $data)));
533 }
534 }
535 elseif (isset($component['value']) && strlen($component['value']) && ($field['type'] == 'select' || !empty($field['expose_list']))) {
536 if ($component['type'] == 'select') {
537 $items = wf_crm_str2array($component['extra']['items']);
538 }
539 else {
540 $items = wf_crm_field_options($component, 'components_form', $node->webform_civicrm['data']);
541 }
542 $val = '';
543 foreach (explode(',', $component['value']) as $v) {
544 if (isset($items[trim($v)])) {
545 $val .= ($val ? ', ' : '') . $items[trim($v)];
546 }
547 }
548 $row['data'][3]['data'] = $val;
549 }
550 // Contribution page - link to civicrm config form instead of component edit form
551 if ($name == 'contribution_page_id') {
552 $type = t('CiviCRM Billing Fields');
553 $class .= ' contribution';
554 $row['data'][6]['data'] = l(t('Configure'), 'civicrm/admin/contribute/settings', array(
555 'query' => array(
556 'reset' => 1,
557 'action' => 'update',
558 'id' => $component['value'],
559 ),
560 'attributes' => array(
561 'title' => t('Edit Contribution Page in CiviCRM'),
562 )
563 ));
564 }
565 $type = '<span class="' . $class . '"> </span>' . $type;
566 $row['data'][2]['title'] = $title;
567 }
568 }
569 }
570 }
571
572 /**
573 * Ensure billing fields are not on same page as event/member amounts
574 * @param stdClass $node
575 */
576 static function checkBillingPagination($node) {
577 civicrm_initialize();
578 $enabled = wf_crm_enabled_fields($node);
579 $field_ids = array(
580 'membership_membership_type_id',
581 'membership_num_terms',
582 'membership_fee_amount',
583 'participant_fee_amount',
584 'participant_event_id',
585 );
586 foreach ($node->webform['components'] as $cid => $component) {
587 if (in_array($cid, $enabled)) {
588 list( , , , , $key) = explode('_', $component['form_key'], 5);
589 if (in_array($key, $field_ids)) {
590 $payment_fields[$cid] = $component;
591 }
592 elseif ($key == 'contribution_contribution_page_id') {
593 $contribution_page_page = $component['page_num'];
594 }
595 }
596 }
597 // Warning if payment fields are on same page as billing fields
598 $message = '';
599 if (isset($contribution_page_page) && !empty($payment_fields)) {
600 foreach ($payment_fields as $component) {
601 if ($component['page_num'] >= $contribution_page_page) {
602 $message .= '<li>' . $component['name'] . '</li>';
603 }
604 }
605 }
606 if ($message) {
607 $message = t('In order for line-items to be displayed correctly to the user, it is recommended to add a page break in-between Contribution Billing Fields and the following:') .
608 '<ul>' . $message . '</ul>';
609 drupal_set_message($message, 'warning', FALSE);
610 }
611 }
612 }
613
614 /**
615 * Drupal theme callback
616 * Format civicrm options form as a table
617 */
618 function theme_webform_civicrm_options_table($variables) {
619 $element = $variables['element'];
620 $element['civicrm_defaults']['']['#attributes']['class'][] = 'select-all-civi-defaults';
621 $default_box = drupal_render($element['civicrm_defaults']['']);
622 $select_box = '<input class="select-all-civi-options" type="checkbox" checked="checked" title="' . t('Select All') . '"> ';
623 $table = array(
624 'rows' => array(),
625 'attributes' => array('id' => 'civicrm-options-table'),
626 'sticky' => FALSE,
627 );
628 if (empty($element['civicrm_options'])) {
629 $table['header'] = array(t('Item'), $default_box . t('Selected'));
630 }
631 else {
632 $table['header'] = array(
633 t('Item'),
634 t('Weight'),
635 array('data' => $select_box . t('Enabled'), 'class' => array('live-options-hide')),
636 array('data' => t('Label'), 'class' => array('live-options-hide')),
637 $default_box . t('Default'),
638 );
639 drupal_add_tabledrag('civicrm-options-table', 'order', 'self', 'civicrm-option-weight');
640 }
641 foreach (element_children($element['civicrm_defaults']) as $k) {
642 if ($k) {
643 $v = str_replace('_web_civi_option_selected_', '', $k);
644 $row = array(drupal_render($element['civicrm_option_name_' . $v]));
645 if (!empty($element['civicrm_options'])) {
646 $element['civicrm_option_weight_' . $v]['#attributes']['class'] = array('civicrm-option-weight');
647 $element['civicrm_options'][$k]['#attributes']['class'] = array('civicrm-enabled');
648 $element['civicrm_option_label_' . $v]['#attributes']['class'] = array('civicrm-label');
649 $row[] = drupal_render($element['civicrm_option_weight_' . $v]);
650 $row[] = array('data' => drupal_render($element['civicrm_options'][$k]), 'class' => array('live-options-hide'));
651 $row[] = array('data' => drupal_render($element['civicrm_option_label_' . $v]), 'class' => array('live-options-hide'));
652 }
653 $element['civicrm_defaults'][$k]['#attributes']['class'] = array('civicrm-default');
654 $row[] = drupal_render($element['civicrm_defaults'][$k]);
655 $table['rows'][] = array(
656 'data' => $row,
657 'class' => array('draggable'),
658 );
659 }
660 }
661 return drupal_render_children($element) . theme('table', $table);
662 }
663
664 /**
665 * Drupal FAPI validate callback
666 * Validate checksum lifespan
667 */
668 function wf_crm_cs_validate($form, &$form_state) {
669 if (!is_numeric($form_state['values']['value']) || $form_state['values']['value'] < 0) {
670 form_error($form['value'], t('Please enter a valid number of days.'));
671 }
672 }
673
674 /**
675 * Drupal FAPI validate callback
676 * Validate money options & default value
677 */
678 function wf_crm_money_validate($form, &$form_state) {
679 $vals = $form_state['values'];
680 if (!empty($vals['value']) && !is_numeric($vals['value'])) {
681 form_error($form['value'], t('This is a CiviCRM currency field. @field must be a number.', array('@field' => $form['value']['#title'])));
682 }
683 foreach (array('items', 'options') as $field) {
684 if (!empty($vals['extra'][$field])) {
685 foreach (wf_crm_str2array($vals['extra'][$field]) as $key => $val) {
686 if (!is_numeric($key)) {
687 form_error($form, t('This is a CiviCRM currency field. @field keys must be numeric.', array('@field' => $form[$field]['#title'])));
688 break;
689 }
690 }
691 }
692 }
693 }
694
695 /**
696 * Drupal FAPI submit callback
697 * Alter a webform component type.
698 */
699 function wf_crm_change_widget($form, &$form_state) {
700 // Get rid of default message
701 unset($_SESSION['messages']['status']);
702 drupal_set_message(t('Click "Save component" to change this field to %type (or go back to cancel). Test your form to ensure that the new widget works with this CiviCRM field.', array('%type' => $form['widget']['type']['#options'][$form_state['values']['widget']['type']])));
703 // Set redirect to current form with 'type' arg to trigger type change
704 // @see webform_civicrm_node_load
705 $form_state['redirect'] = array(
706 $_GET['q'],
707 array('query' => array(
708 'type' => $form_state['values']['widget']['type'])
709 )
710 );
711 // Prevent 'destination' arg from overriding redirect
712 unset($_GET['destination']);
713 }
714
715 /**
716 * Drupal FAPI submit callback for single-component form
717 */
718 function wf_crm_process_options_selection($form, &$form_state) {
719 $admin_form = new wf_crm_admin_component($form, $form_state);
720 $admin_form->postProcess();
721 }
722
723 /**
724 * Drupal FAPI validation callback for all-components form
725 */
726 function wf_crm_components_form_validate($form, &$form_state) {
727 $components = wf_crm_aval($form_state, 'values:components', array());
728 foreach ($components as $cid => $component) {
729 $component += $form['#node']->webform['components'][$cid];
730 if ($component['form_key'] == 'civicrm_1_contribution_1_contribution_contribution_page_id') {
731 // Iterate up through parents
732 while ($component['pid']) {
733 $component = $components[$component['pid']];
734 }
735 $weight = $component['weight'];
736 }
737 }
738 if (isset($weight)) {
739 foreach ($components as $cid => $component) {
740 $component += $form['#node']->webform['components'][$cid];
741 if ($component['type'] == 'pagebreak' && $component['weight'] > $weight) {
742 form_error($form['components'], t('CiviCRM Contribution Billing Fields <em>must</em> be on the last page of the form.'));
743 }
744 }
745 }
746 }