1 |
85ad3d82
|
Assos Assos
|
<?php
|
2 |
|
|
|
3 |
|
|
/**
|
4 |
|
|
* @file
|
5 |
|
|
* Webform module component handling.
|
6 |
|
|
*/
|
7 |
|
|
|
8 |
|
|
/**
|
9 |
|
|
* Provides interface and database handling for editing components of a webform.
|
10 |
|
|
*
|
11 |
|
|
* @author Nathan Haug <nate@lullabot.com>
|
12 |
|
|
*/
|
13 |
|
|
|
14 |
|
|
/**
|
15 |
|
|
* Overview page of all components for this webform.
|
16 |
|
|
*/
|
17 |
|
|
function webform_components_page($node, $page_number = 1) {
|
18 |
|
|
$output = drupal_get_form('webform_components_form', $node);
|
19 |
|
|
|
20 |
|
|
return array(
|
21 |
|
|
'#theme' => 'webform_components_page',
|
22 |
|
|
'#node' => $node,
|
23 |
|
|
'#form' => $output,
|
24 |
|
|
);
|
25 |
|
|
}
|
26 |
|
|
|
27 |
|
|
/**
|
28 |
|
|
* Theme the output of the main components page.
|
29 |
|
|
*
|
30 |
|
|
* This theming provides a way to toggle between the editing modes if Form
|
31 |
|
|
* Builder module is available.
|
32 |
|
|
*/
|
33 |
|
|
function theme_webform_components_page($variables) {
|
34 |
|
|
$node = $variables['node'];
|
35 |
|
|
$form = $variables['form'];
|
36 |
|
|
|
37 |
|
|
return drupal_render($form);
|
38 |
|
|
}
|
39 |
|
|
|
40 |
|
|
/**
|
41 |
|
|
* The table-based listing of all components for this webform.
|
42 |
|
|
*/
|
43 |
|
|
function webform_components_form($form, $form_state, $node) {
|
44 |
|
|
$form = array(
|
45 |
|
|
'#tree' => TRUE,
|
46 |
|
|
'#node' => $node,
|
47 |
|
|
'components' => array(),
|
48 |
|
|
);
|
49 |
|
|
|
50 |
|
|
$form['nid'] = array(
|
51 |
|
|
'#type' => 'value',
|
52 |
|
|
'#value' => $node->nid,
|
53 |
|
|
);
|
54 |
|
|
|
55 |
|
|
$options = array();
|
56 |
|
|
foreach ($node->webform['components'] as $cid => $component) {
|
57 |
|
|
$options[$cid] = check_plain($component['name']);
|
58 |
|
|
$form['components'][$cid]['cid'] = array(
|
59 |
|
|
'#type' => 'hidden',
|
60 |
|
|
'#default_value' => $component['cid'],
|
61 |
|
|
);
|
62 |
|
|
$form['components'][$cid]['pid'] = array(
|
63 |
|
|
'#type' => 'hidden',
|
64 |
|
|
'#default_value' => $component['pid'],
|
65 |
|
|
);
|
66 |
|
|
$form['components'][$cid]['weight'] = array(
|
67 |
|
|
'#type' => 'textfield',
|
68 |
|
|
'#size' => 4,
|
69 |
|
|
'#title' => t('Weight'),
|
70 |
|
|
'#default_value' => $component['weight'],
|
71 |
|
|
);
|
72 |
a45e4bc1
|
Assos Assos
|
$form['components'][$cid]['required'] = array(
|
73 |
85ad3d82
|
Assos Assos
|
'#type' => 'checkbox',
|
74 |
a45e4bc1
|
Assos Assos
|
'#title' => t('Required'),
|
75 |
|
|
'#default_value' => $component['required'],
|
76 |
85ad3d82
|
Assos Assos
|
'#access' => webform_component_feature($component['type'], 'required'),
|
77 |
|
|
);
|
78 |
|
|
if (!isset($max_weight) || $component['weight'] > $max_weight) {
|
79 |
|
|
$max_weight = $component['weight'];
|
80 |
|
|
}
|
81 |
|
|
}
|
82 |
|
|
|
83 |
|
|
$form['add']['name'] = array(
|
84 |
|
|
'#type' => 'textfield',
|
85 |
ba09eb79
|
Assos Assos
|
'#size' => 30,
|
86 |
a45e4bc1
|
Assos Assos
|
'#maxlength' => NULL,
|
87 |
85ad3d82
|
Assos Assos
|
);
|
88 |
|
|
|
89 |
|
|
$form['add']['type'] = array(
|
90 |
|
|
'#type' => 'select',
|
91 |
|
|
'#options' => webform_component_options(),
|
92 |
|
|
'#weight' => 3,
|
93 |
|
|
'#default_value' => (isset($_GET['cid']) && isset($node->webform['components'][$_GET['cid']])) ? $node->webform['components'][$_GET['cid']]['type'] : 'textfield',
|
94 |
|
|
);
|
95 |
a45e4bc1
|
Assos Assos
|
$form['add']['required'] = array(
|
96 |
85ad3d82
|
Assos Assos
|
'#type' => 'checkbox',
|
97 |
|
|
);
|
98 |
|
|
$form['add']['cid'] = array(
|
99 |
|
|
'#type' => 'hidden',
|
100 |
|
|
'#default_value' => '',
|
101 |
|
|
);
|
102 |
|
|
$form['add']['pid'] = array(
|
103 |
|
|
'#type' => 'hidden',
|
104 |
|
|
'#default_value' => (isset($_GET['cid']) && isset($node->webform['components'][$_GET['cid']])) ? $node->webform['components'][$_GET['cid']]['pid'] : 0,
|
105 |
|
|
);
|
106 |
|
|
$form['add']['weight'] = array(
|
107 |
|
|
'#type' => 'textfield',
|
108 |
|
|
'#size' => 4,
|
109 |
|
|
'#delta' => count($node->webform['components']) > 10 ? count($node->webform['components']) : 10,
|
110 |
|
|
);
|
111 |
|
|
|
112 |
|
|
if (isset($_GET['cid']) && isset($node->webform['components'][$_GET['cid']])) {
|
113 |
|
|
// Make the new component appear by default directly after the one that was
|
114 |
|
|
// just added.
|
115 |
|
|
$form['add']['weight']['#default_value'] = $node->webform['components'][$_GET['cid']]['weight'] + 1;
|
116 |
|
|
foreach (array_keys($node->webform['components']) as $cid) {
|
117 |
|
|
// Adjust all later components also, to make sure none of them have the
|
118 |
|
|
// same weight as the new component.
|
119 |
|
|
if ($form['components'][$cid]['weight']['#default_value'] >= $form['add']['weight']['#default_value']) {
|
120 |
|
|
$form['components'][$cid]['weight']['#default_value']++;
|
121 |
|
|
}
|
122 |
|
|
}
|
123 |
|
|
}
|
124 |
|
|
else {
|
125 |
|
|
// If no component was just added, the new component should appear by
|
126 |
|
|
// default at the end of the list.
|
127 |
|
|
$form['add']['weight']['#default_value'] = isset($max_weight) ? $max_weight + 1 : 0;
|
128 |
|
|
}
|
129 |
|
|
|
130 |
|
|
$form['add']['add'] = array(
|
131 |
|
|
'#type' => 'submit',
|
132 |
|
|
'#value' => t('Add'),
|
133 |
|
|
'#weight' => 45,
|
134 |
|
|
'#validate' => array('webform_components_form_add_validate', 'webform_components_form_validate'),
|
135 |
|
|
'#submit' => array('webform_components_form_add_submit'),
|
136 |
|
|
);
|
137 |
|
|
|
138 |
a45e4bc1
|
Assos Assos
|
$form['actions'] = array(
|
139 |
|
|
'#type' => 'actions',
|
140 |
|
|
'#weight' => 45,
|
141 |
|
|
);
|
142 |
3753f249
|
Assos Assos
|
$form['actions']['submit'] = array(
|
143 |
85ad3d82
|
Assos Assos
|
'#type' => 'submit',
|
144 |
|
|
'#value' => t('Save'),
|
145 |
|
|
'#access' => count($node->webform['components']) > 0,
|
146 |
|
|
);
|
147 |
a45e4bc1
|
Assos Assos
|
$form['warning'] = array(
|
148 |
|
|
'#weight' => -1,
|
149 |
|
|
);
|
150 |
|
|
webform_input_vars_check($form, $form_state, 'components', 'warning');
|
151 |
85ad3d82
|
Assos Assos
|
|
152 |
|
|
return $form;
|
153 |
|
|
}
|
154 |
|
|
|
155 |
|
|
/**
|
156 |
a45e4bc1
|
Assos Assos
|
* Preprocess variables for theming the webform components form.
|
157 |
85ad3d82
|
Assos Assos
|
*/
|
158 |
a45e4bc1
|
Assos Assos
|
function template_preprocess_webform_components_form(&$variables) {
|
159 |
85ad3d82
|
Assos Assos
|
$form = $variables['form'];
|
160 |
|
|
|
161 |
|
|
$form['components']['#attached']['library'][] = array('webform', 'admin');
|
162 |
|
|
|
163 |
|
|
// TODO: Attach these. See http://drupal.org/node/732022.
|
164 |
|
|
drupal_add_tabledrag('webform-components', 'order', 'sibling', 'webform-weight');
|
165 |
|
|
drupal_add_tabledrag('webform-components', 'match', 'parent', 'webform-pid', 'webform-pid', 'webform-cid');
|
166 |
|
|
|
167 |
|
|
$node = $form['#node'];
|
168 |
|
|
|
169 |
ba09eb79
|
Assos Assos
|
$header = array(t('Label'), t('Form key'), t('Type'), t('Value'), t('Required'), t('Weight'), array('data' => t('Operations'), 'colspan' => 3));
|
170 |
85ad3d82
|
Assos Assos
|
$rows = array();
|
171 |
|
|
|
172 |
|
|
// Add a row containing form elements for a new item.
|
173 |
|
|
unset($form['add']['name']['#title'], $form['add_type']['#description']);
|
174 |
a45e4bc1
|
Assos Assos
|
$form['add']['name']['#attributes']['placeholder'] = t('New component name');
|
175 |
|
|
$form['add']['cid']['#attributes']['class'][] = 'webform-cid';
|
176 |
|
|
$form['add']['pid']['#attributes']['class'][] = 'webform-pid';
|
177 |
|
|
$form['add']['weight']['#attributes']['class'][] = 'webform-weight';
|
178 |
85ad3d82
|
Assos Assos
|
$row_data = array(
|
179 |
ba09eb79
|
Assos Assos
|
array('data' => drupal_render($form['add']['name']), 'class' => array('webform-component-name'), 'colspan' => 2),
|
180 |
a45e4bc1
|
Assos Assos
|
array('data' => drupal_render($form['add']['type']), 'class' => array('webform-component-type')),
|
181 |
|
|
array('data' => '', 'class' => array('webform-component-value')),
|
182 |
|
|
array('data' => drupal_render($form['add']['required']), 'class' => array('webform-component-required', 'checkbox')),
|
183 |
|
|
array('data' => drupal_render($form['add']['cid']) . drupal_render($form['add']['pid']) . drupal_render($form['add']['weight'])),
|
184 |
|
|
array('colspan' => 3, 'data' => drupal_render($form['add']['add']), 'class' => array('webform-component-add')),
|
185 |
85ad3d82
|
Assos Assos
|
);
|
186 |
a45e4bc1
|
Assos Assos
|
$add_form = array('data' => $row_data, 'class' => array('draggable', 'webform-add-form', 'tabledrag-leaf'));
|
187 |
85ad3d82
|
Assos Assos
|
|
188 |
|
|
if (!empty($node->webform['components'])) {
|
189 |
|
|
$component_tree = array();
|
190 |
|
|
$page_count = 1;
|
191 |
|
|
_webform_components_tree_build($node->webform['components'], $component_tree, 0, $page_count);
|
192 |
|
|
$component_tree = _webform_components_tree_sort($component_tree);
|
193 |
a45e4bc1
|
Assos Assos
|
// Build the table rows recursively.
|
194 |
85ad3d82
|
Assos Assos
|
foreach ($component_tree['children'] as $cid => $component) {
|
195 |
|
|
_webform_components_form_rows($node, $cid, $component, 0, $form, $rows, $add_form);
|
196 |
|
|
}
|
197 |
|
|
}
|
198 |
|
|
else {
|
199 |
|
|
$rows[] = array(array('data' => t('No Components, add a component below.'), 'colspan' => 9));
|
200 |
|
|
}
|
201 |
|
|
|
202 |
|
|
// Append the add form if not already printed.
|
203 |
|
|
if ($add_form) {
|
204 |
|
|
$rows[] = $add_form;
|
205 |
|
|
}
|
206 |
|
|
|
207 |
a45e4bc1
|
Assos Assos
|
$variables['rows'] = $rows;
|
208 |
|
|
$variables['header'] = $header;
|
209 |
|
|
$variables['form'] = $form;
|
210 |
|
|
}
|
211 |
|
|
|
212 |
|
|
/**
|
213 |
|
|
* Recursive function for nesting components into a table.
|
214 |
|
|
*
|
215 |
|
|
* @see preprocess_webform_components_form()
|
216 |
|
|
*/
|
217 |
|
|
function _webform_components_form_rows($node, $cid, $component, $level, &$form, &$rows, &$add_form) {
|
218 |
|
|
// Create presentable values.
|
219 |
ba09eb79
|
Assos Assos
|
$form_key = truncate_utf8($component['form_key'], 30, FALSE, TRUE);
|
220 |
|
|
$value = truncate_utf8($component['value'], 30, TRUE, TRUE, 20);
|
221 |
a45e4bc1
|
Assos Assos
|
|
222 |
|
|
// Remove individual titles from the required and weight fields.
|
223 |
|
|
unset($form['components'][$cid]['required']['#title']);
|
224 |
|
|
unset($form['components'][$cid]['pid']['#title']);
|
225 |
|
|
unset($form['components'][$cid]['weight']['#title']);
|
226 |
|
|
|
227 |
|
|
// Add special classes for weight and parent fields.
|
228 |
|
|
$form['components'][$cid]['cid']['#attributes']['class'] = array('webform-cid');
|
229 |
|
|
$form['components'][$cid]['pid']['#attributes']['class'] = array('webform-pid');
|
230 |
|
|
$form['components'][$cid]['weight']['#attributes']['class'] = array('webform-weight');
|
231 |
|
|
|
232 |
|
|
// Build indentation for this row.
|
233 |
|
|
$indents = '';
|
234 |
|
|
for ($n = 1; $n <= $level; $n++) {
|
235 |
|
|
$indents .= '<div class="indentation"> </div>';
|
236 |
|
|
}
|
237 |
|
|
|
238 |
|
|
// Add each component to a table row.
|
239 |
|
|
$row_data = array(
|
240 |
|
|
array('data' => $indents . filter_xss($component['name']), 'class' => array('webform-component-name')),
|
241 |
ba09eb79
|
Assos Assos
|
array('data' => check_plain($form_key), 'class' => array('webform-component-formkey')) +
|
242 |
|
|
($component['form_key'] == $form_key ? array() : array('title' => $component['form_key'])),
|
243 |
a45e4bc1
|
Assos Assos
|
array('data' => $form['add']['type']['#options'][$component['type']], 'class' => array('webform-component-type')),
|
244 |
ba09eb79
|
Assos Assos
|
array('data' => ($value == '') ? '-' : check_plain($value), 'class' => array('webform-component-value')) +
|
245 |
|
|
($component['value'] == $value ? array() : array('title' => $component['value'])),
|
246 |
a45e4bc1
|
Assos Assos
|
array('data' => drupal_render($form['components'][$cid]['required']), 'class' => array('webform-component-required', 'checkbox')),
|
247 |
|
|
array('data' => drupal_render($form['components'][$cid]['cid']) . drupal_render($form['components'][$cid]['pid']) . drupal_render($form['components'][$cid]['weight'])),
|
248 |
|
|
array('data' => l(t('Edit'), 'node/' . $node->nid . '/webform/components/' . $cid, array('query' => drupal_get_destination())), 'class' => array('webform-component-edit')),
|
249 |
|
|
array('data' => l(t('Clone'), 'node/' . $node->nid . '/webform/components/' . $cid . '/clone', array('query' => drupal_get_destination())), 'class' => array('webform-component-clone')),
|
250 |
|
|
array('data' => l(t('Delete'), 'node/' . $node->nid . '/webform/components/' . $cid . '/delete', array('query' => drupal_get_destination())), 'class' => array('webform-component-delete')),
|
251 |
|
|
);
|
252 |
|
|
$row_class = array('draggable');
|
253 |
|
|
if (!webform_component_feature($component['type'], 'group')) {
|
254 |
|
|
$row_class[] = 'tabledrag-leaf';
|
255 |
|
|
}
|
256 |
|
|
if ($component['type'] == 'pagebreak') {
|
257 |
|
|
$row_class[] = 'tabledrag-root';
|
258 |
|
|
$row_class[] = 'webform-pagebreak';
|
259 |
|
|
$row_data[0]['class'][] = 'webform-pagebreak';
|
260 |
|
|
}
|
261 |
|
|
$rows[] = array('data' => $row_data, 'class' => $row_class, 'data-cid' => $cid);
|
262 |
|
|
if (isset($component['children']) && is_array($component['children'])) {
|
263 |
|
|
foreach ($component['children'] as $cid => $component) {
|
264 |
|
|
_webform_components_form_rows($node, $cid, $component, $level + 1, $form, $rows, $add_form);
|
265 |
|
|
}
|
266 |
|
|
}
|
267 |
|
|
|
268 |
|
|
// Add the add form if this was the last edited component.
|
269 |
|
|
if (isset($_GET['cid']) && $component['cid'] == $_GET['cid'] && $add_form) {
|
270 |
|
|
$add_form['data'][0]['data'] = $indents . $add_form['data'][0]['data'];
|
271 |
|
|
$rows[] = $add_form;
|
272 |
|
|
$add_form = FALSE;
|
273 |
|
|
}
|
274 |
|
|
}
|
275 |
|
|
|
276 |
|
|
/**
|
277 |
|
|
* Theme the node components form. Use a table to organize the components.
|
278 |
|
|
*
|
279 |
|
|
* @return
|
280 |
|
|
* Formatted HTML form, ready for display.
|
281 |
|
|
*/
|
282 |
|
|
function theme_webform_components_form($variables) {
|
283 |
85ad3d82
|
Assos Assos
|
$output = '';
|
284 |
a45e4bc1
|
Assos Assos
|
$output .= drupal_render_children($variables['form']['warning']);
|
285 |
|
|
$output .= theme('table', array('header' => $variables['header'], 'rows' => $variables['rows'], 'attributes' => array('id' => 'webform-components')));
|
286 |
|
|
$output .= drupal_render_children($variables['form']);
|
287 |
85ad3d82
|
Assos Assos
|
return $output;
|
288 |
|
|
}
|
289 |
|
|
|
290 |
|
|
/**
|
291 |
|
|
* Validate handler for webform_components_form().
|
292 |
|
|
*/
|
293 |
|
|
function webform_components_form_validate($form, &$form_state) {
|
294 |
|
|
// Check that no two components end up with the same form key.
|
295 |
|
|
$duplicates = array();
|
296 |
|
|
$parents = array();
|
297 |
|
|
if (isset($form_state['values']['components'])) {
|
298 |
|
|
foreach ($form_state['values']['components'] as $cid => $component) {
|
299 |
|
|
$form_key = $form['#node']->webform['components'][$cid]['form_key'];
|
300 |
|
|
if (isset($parents[$component['pid']]) && ($existing = array_search($form_key, $parents[$component['pid']])) && $existing !== FALSE) {
|
301 |
|
|
if (!isset($duplicates[$form_key])) {
|
302 |
|
|
$duplicates[$form_key] = array($existing);
|
303 |
|
|
}
|
304 |
|
|
$duplicates[$form_key][] = $cid;
|
305 |
|
|
}
|
306 |
|
|
$parents[$component['pid']][$cid] = $form_key;
|
307 |
|
|
}
|
308 |
|
|
}
|
309 |
|
|
|
310 |
|
|
if (!empty($duplicates)) {
|
311 |
|
|
$error = t('The form order failed to save because the following elements have same form keys and are under the same parent. Edit each component and give them a unique form key, then try moving them again.');
|
312 |
|
|
$items = array();
|
313 |
|
|
foreach ($duplicates as $form_key => $cids) {
|
314 |
|
|
foreach ($cids as $cid) {
|
315 |
a45e4bc1
|
Assos Assos
|
$items[] = webform_filter_xss($form['#node']->webform['components'][$cid]['name']);
|
316 |
85ad3d82
|
Assos Assos
|
}
|
317 |
|
|
}
|
318 |
|
|
|
319 |
|
|
form_error($form['components'], $error . theme('item_list', array('items' => $items)));
|
320 |
|
|
}
|
321 |
|
|
}
|
322 |
|
|
|
323 |
|
|
/**
|
324 |
|
|
* Validate handler for webform_component_form() when adding a new component.
|
325 |
|
|
*/
|
326 |
|
|
function webform_components_form_add_validate($form, &$form_state) {
|
327 |
|
|
// Check that the entered component name is valid.
|
328 |
|
|
if (drupal_strlen(trim($form_state['values']['add']['name'])) <= 0) {
|
329 |
|
|
form_error($form['add']['name'], t('When adding a new component, the name field is required.'));
|
330 |
|
|
}
|
331 |
|
|
}
|
332 |
|
|
|
333 |
|
|
/**
|
334 |
|
|
* Submit handler for webform_components_form() to save component order.
|
335 |
|
|
*/
|
336 |
|
|
function webform_components_form_submit($form, &$form_state) {
|
337 |
|
|
$node = node_load($form_state['values']['nid']);
|
338 |
|
|
|
339 |
a45e4bc1
|
Assos Assos
|
// Update all required and weight values.
|
340 |
85ad3d82
|
Assos Assos
|
$changes = FALSE;
|
341 |
|
|
foreach ($node->webform['components'] as $cid => $component) {
|
342 |
a45e4bc1
|
Assos Assos
|
if ($component['pid'] != $form_state['values']['components'][$cid]['pid'] || $component['weight'] != $form_state['values']['components'][$cid]['weight'] || $component['required'] != $form_state['values']['components'][$cid]['required']) {
|
343 |
85ad3d82
|
Assos Assos
|
$changes = TRUE;
|
344 |
|
|
$node->webform['components'][$cid]['weight'] = $form_state['values']['components'][$cid]['weight'];
|
345 |
a45e4bc1
|
Assos Assos
|
$node->webform['components'][$cid]['required'] = $form_state['values']['components'][$cid]['required'];
|
346 |
85ad3d82
|
Assos Assos
|
$node->webform['components'][$cid]['pid'] = $form_state['values']['components'][$cid]['pid'];
|
347 |
|
|
}
|
348 |
|
|
}
|
349 |
|
|
|
350 |
|
|
if ($changes) {
|
351 |
|
|
node_save($node);
|
352 |
|
|
}
|
353 |
|
|
|
354 |
a45e4bc1
|
Assos Assos
|
drupal_set_message(t('The component positions and required values have been updated.'));
|
355 |
85ad3d82
|
Assos Assos
|
}
|
356 |
|
|
|
357 |
|
|
/**
|
358 |
|
|
* Submit handler for webform_components_form() that adds a new component.
|
359 |
|
|
*/
|
360 |
|
|
function webform_components_form_add_submit($form, &$form_state) {
|
361 |
|
|
$node = node_load($form_state['values']['nid']);
|
362 |
|
|
|
363 |
|
|
$component = $form_state['values']['add'];
|
364 |
a45e4bc1
|
Assos Assos
|
|
365 |
|
|
// Set the values in the query string for the add component page.
|
366 |
|
|
$query = array(
|
367 |
|
|
'name' => $component['name'],
|
368 |
|
|
'required' => $component['required'],
|
369 |
|
|
'pid' => $component['pid'],
|
370 |
|
|
'weight' => $component['weight'],
|
371 |
|
|
);
|
372 |
|
|
|
373 |
|
|
// Forward the "destination" query string value to the next form.
|
374 |
|
|
if (isset($_GET['destination'])) {
|
375 |
|
|
$query['destination'] = $_GET['destination'];
|
376 |
|
|
unset($_GET['destination']);
|
377 |
|
|
drupal_static_reset('drupal_get_destination');
|
378 |
|
|
}
|
379 |
|
|
$form_state['redirect'] = array('node/' . $node->nid . '/webform/components/new/' . $component['type'], array('query' => $query));
|
380 |
85ad3d82
|
Assos Assos
|
}
|
381 |
|
|
|
382 |
|
|
/**
|
383 |
|
|
* Form to configure a webform component.
|
384 |
|
|
*/
|
385 |
|
|
function webform_component_edit_form($form, $form_state, $node, $component, $clone = FALSE) {
|
386 |
|
|
drupal_set_title(t('Edit component: @name', array('@name' => $component['name'])), PASS_THROUGH);
|
387 |
|
|
|
388 |
a45e4bc1
|
Assos Assos
|
$form['#node'] = $node;
|
389 |
85ad3d82
|
Assos Assos
|
$form['#tree'] = TRUE;
|
390 |
|
|
|
391 |
|
|
// Print the correct field type specification.
|
392 |
|
|
// We always need: name and description.
|
393 |
|
|
$form['type'] = array(
|
394 |
|
|
'#type' => 'value',
|
395 |
|
|
'#value' => $component['type'],
|
396 |
|
|
);
|
397 |
|
|
$form['nid'] = array(
|
398 |
|
|
'#type' => 'value',
|
399 |
|
|
'#value' => $node->nid,
|
400 |
|
|
);
|
401 |
|
|
$form['cid'] = array(
|
402 |
|
|
'#type' => 'value',
|
403 |
|
|
'#value' => isset($component['cid']) ? $component['cid'] : NULL,
|
404 |
|
|
);
|
405 |
|
|
$form['clone'] = array(
|
406 |
|
|
'#type' => 'value',
|
407 |
|
|
'#value' => $clone,
|
408 |
|
|
);
|
409 |
|
|
|
410 |
|
|
if (webform_component_feature($component['type'], 'title')) {
|
411 |
|
|
$form['name'] = array(
|
412 |
|
|
'#type' => 'textfield',
|
413 |
|
|
'#default_value' => $component['name'],
|
414 |
|
|
'#title' => t('Label'),
|
415 |
|
|
'#description' => t('This is used as a descriptive label when displaying this form element.'),
|
416 |
|
|
'#required' => TRUE,
|
417 |
|
|
'#weight' => -10,
|
418 |
a45e4bc1
|
Assos Assos
|
'#maxlength' => NULL,
|
419 |
85ad3d82
|
Assos Assos
|
);
|
420 |
|
|
}
|
421 |
|
|
|
422 |
|
|
$form['form_key'] = array(
|
423 |
|
|
'#type' => 'textfield',
|
424 |
|
|
'#default_value' => empty($component['form_key']) ? _webform_safe_name($component['name']) : $component['form_key'],
|
425 |
|
|
'#title' => t('Field Key'),
|
426 |
|
|
'#description' => t('Enter a machine readable key for this form element. May contain only alphanumeric characters and underscores. This key will be used as the name attribute of the form element. This value has no effect on the way data is saved, but may be helpful if doing custom form processing.'),
|
427 |
|
|
'#required' => TRUE,
|
428 |
|
|
'#weight' => -9,
|
429 |
|
|
);
|
430 |
|
|
|
431 |
|
|
$form['extra'] = array();
|
432 |
|
|
if (webform_component_feature($component['type'], 'description')) {
|
433 |
|
|
$form['extra']['description'] = array(
|
434 |
|
|
'#type' => 'textarea',
|
435 |
|
|
'#default_value' => isset($component['extra']['description']) ? $component['extra']['description'] : '',
|
436 |
|
|
'#title' => t('Description'),
|
437 |
a45e4bc1
|
Assos Assos
|
'#description' => t('A short description of the field used as help for the user when he/she uses the form.') . ' ' . theme('webform_token_help'),
|
438 |
85ad3d82
|
Assos Assos
|
'#weight' => -1,
|
439 |
|
|
);
|
440 |
|
|
}
|
441 |
|
|
|
442 |
|
|
// Display settings.
|
443 |
|
|
$form['display'] = array(
|
444 |
|
|
'#type' => 'fieldset',
|
445 |
|
|
'#title' => t('Display'),
|
446 |
|
|
'#collapsible' => TRUE,
|
447 |
|
|
'#collapsed' => FALSE,
|
448 |
|
|
'#weight' => 8,
|
449 |
|
|
);
|
450 |
|
|
if (webform_component_feature($component['type'], 'title_display')) {
|
451 |
|
|
if (webform_component_feature($component['type'], 'title_inline')) {
|
452 |
|
|
$form['display']['title_display'] = array(
|
453 |
|
|
'#type' => 'select',
|
454 |
|
|
'#title' => t('Label display'),
|
455 |
|
|
'#default_value' => !empty($component['extra']['title_display']) ? $component['extra']['title_display'] : 'before',
|
456 |
|
|
'#options' => array(
|
457 |
|
|
'before' => t('Above'),
|
458 |
|
|
'inline' => t('Inline'),
|
459 |
|
|
'none' => t('None'),
|
460 |
|
|
),
|
461 |
|
|
'#description' => t('Determines the placement of the component\'s label.'),
|
462 |
|
|
);
|
463 |
|
|
}
|
464 |
|
|
else {
|
465 |
|
|
$form['display']['title_display'] = array(
|
466 |
|
|
'#type' => 'checkbox',
|
467 |
|
|
'#title' => t('Hide label'),
|
468 |
|
|
'#default_value' => strcmp($component['extra']['title_display'], 'none') === 0,
|
469 |
|
|
'#return_value' => 'none',
|
470 |
|
|
'#description' => t('Do not display the label of this component.'),
|
471 |
|
|
);
|
472 |
|
|
}
|
473 |
|
|
$form['display']['title_display']['#weight'] = 8;
|
474 |
|
|
$form['display']['title_display']['#parents'] = array('extra', 'title_display');
|
475 |
|
|
}
|
476 |
|
|
|
477 |
01d522a6
|
Assos Assos
|
if (webform_component_feature($component['type'], 'description')) {
|
478 |
|
|
$form['display']['description_above'] = array(
|
479 |
|
|
'#type' => 'checkbox',
|
480 |
|
|
'#default_value' => !empty($component['extra']['description_above']),
|
481 |
|
|
'#title' => t('Description above field'),
|
482 |
|
|
'#description' => t('Place the description above — rather than below — the field.'),
|
483 |
|
|
'#weight' => 8.5,
|
484 |
|
|
'#parents' => array('extra', 'description_above'),
|
485 |
|
|
);
|
486 |
|
|
}
|
487 |
|
|
|
488 |
85ad3d82
|
Assos Assos
|
if (webform_component_feature($component['type'], 'private')) {
|
489 |
|
|
// May user mark fields as Private?
|
490 |
|
|
$form['display']['private'] = array(
|
491 |
|
|
'#type' => 'checkbox',
|
492 |
|
|
'#title' => t('Private'),
|
493 |
|
|
'#default_value' => ($component['extra']['private'] == '1' ? TRUE : FALSE),
|
494 |
|
|
'#description' => t('Private fields are shown only to users with results access.'),
|
495 |
|
|
'#weight' => 45,
|
496 |
|
|
'#parents' => array('extra', 'private'),
|
497 |
|
|
'#disabled' => empty($node->nid) ? FALSE : !webform_results_access($node),
|
498 |
|
|
);
|
499 |
|
|
}
|
500 |
|
|
|
501 |
a45e4bc1
|
Assos Assos
|
if (webform_component_feature($component['type'], 'wrapper_classes')) {
|
502 |
|
|
$form['display']['wrapper_classes'] = array(
|
503 |
|
|
'#type' => 'textfield',
|
504 |
|
|
'#title' => t('Wrapper CSS classes'),
|
505 |
|
|
'#default_value' => isset($component['extra']['wrapper_classes']) ? $component['extra']['wrapper_classes'] : '',
|
506 |
|
|
'#description' => t('Apply a class to the wrapper around both the field and its label. Separate multiple by spaces.'),
|
507 |
|
|
'#weight' => 50,
|
508 |
|
|
'#parents' => array('extra', 'wrapper_classes'),
|
509 |
|
|
);
|
510 |
|
|
}
|
511 |
|
|
if (webform_component_feature($component['type'], 'css_classes')) {
|
512 |
|
|
$form['display']['css_classes'] = array(
|
513 |
|
|
'#type' => 'textfield',
|
514 |
|
|
'#title' => t('CSS classes'),
|
515 |
|
|
'#default_value' => isset($component['extra']['css_classes']) ? $component['extra']['css_classes'] : '',
|
516 |
|
|
'#description' => t('Apply a class to the field. Separate multiple by spaces.'),
|
517 |
|
|
'#weight' => 51,
|
518 |
|
|
'#parents' => array('extra', 'css_classes'),
|
519 |
|
|
);
|
520 |
|
|
}
|
521 |
|
|
|
522 |
85ad3d82
|
Assos Assos
|
// Validation settings.
|
523 |
|
|
$form['validation'] = array(
|
524 |
|
|
'#type' => 'fieldset',
|
525 |
|
|
'#title' => t('Validation'),
|
526 |
|
|
'#collapsible' => TRUE,
|
527 |
|
|
'#collapsed' => FALSE,
|
528 |
|
|
'#weight' => 5,
|
529 |
|
|
);
|
530 |
|
|
if (webform_component_feature($component['type'], 'required')) {
|
531 |
a45e4bc1
|
Assos Assos
|
$form['validation']['required'] = array(
|
532 |
85ad3d82
|
Assos Assos
|
'#type' => 'checkbox',
|
533 |
a45e4bc1
|
Assos Assos
|
'#title' => t('Required'),
|
534 |
|
|
'#default_value' => ($component['required'] == '1' ? TRUE : FALSE),
|
535 |
85ad3d82
|
Assos Assos
|
'#description' => t('Check this option if the user must enter a value.'),
|
536 |
|
|
'#weight' => -1,
|
537 |
a45e4bc1
|
Assos Assos
|
'#parents' => array('required'),
|
538 |
85ad3d82
|
Assos Assos
|
);
|
539 |
|
|
}
|
540 |
|
|
|
541 |
|
|
// Position settings, only shown if JavaScript is disabled.
|
542 |
|
|
$form['position'] = array(
|
543 |
|
|
'#type' => 'fieldset',
|
544 |
|
|
'#title' => t('Position'),
|
545 |
|
|
'#collapsible' => TRUE,
|
546 |
|
|
'#collapsed' => TRUE,
|
547 |
|
|
'#tree' => FALSE,
|
548 |
|
|
'#weight' => 20,
|
549 |
|
|
'#attributes' => array('class' => array('webform-position')),
|
550 |
|
|
);
|
551 |
|
|
|
552 |
|
|
$options = array('0' => t('Root'));
|
553 |
|
|
foreach ($node->webform['components'] as $existing_cid => $value) {
|
554 |
|
|
if (webform_component_feature($value['type'], 'group') && (!isset($component['cid']) || $existing_cid != $component['cid'])) {
|
555 |
|
|
$options[$existing_cid] = $value['name'];
|
556 |
|
|
}
|
557 |
|
|
}
|
558 |
|
|
$form['position']['pid'] = array(
|
559 |
|
|
'#type' => 'select',
|
560 |
|
|
'#title' => t('Parent'),
|
561 |
|
|
'#default_value' => $component['pid'],
|
562 |
|
|
'#description' => t('Optional. You may organize your form by placing this component inside another fieldset.'),
|
563 |
|
|
'#options' => $options,
|
564 |
|
|
'#access' => count($options) > 1,
|
565 |
|
|
'#weight' => 3,
|
566 |
|
|
);
|
567 |
|
|
$form['position']['weight'] = array(
|
568 |
|
|
'#type' => 'textfield',
|
569 |
|
|
'#size' => 4,
|
570 |
|
|
'#title' => t('Weight'),
|
571 |
|
|
'#default_value' => $component['weight'],
|
572 |
|
|
'#description' => t('Optional. In the menu, the heavier items will sink and the lighter items will be positioned nearer the top.'),
|
573 |
|
|
'#weight' => 4,
|
574 |
|
|
);
|
575 |
|
|
|
576 |
|
|
// Add the fields specific to this component type:
|
577 |
|
|
$additional_form_elements = (array) webform_component_invoke($component['type'], 'edit', $component);
|
578 |
|
|
if (empty($additional_form_elements)) {
|
579 |
|
|
drupal_set_message(t('The webform component of type @type does not have an edit function defined.', array('@type' => $component['type'])));
|
580 |
|
|
}
|
581 |
|
|
|
582 |
|
|
// Merge the additional fields with the current fields:
|
583 |
|
|
if (isset($additional_form_elements['extra'])) {
|
584 |
|
|
$form['extra'] = array_merge($form['extra'], $additional_form_elements['extra']);
|
585 |
|
|
unset($additional_form_elements['extra']);
|
586 |
|
|
}
|
587 |
|
|
if (isset($additional_form_elements['position'])) {
|
588 |
|
|
$form['position'] = array_merge($form['position'], $additional_form_elements['position']);
|
589 |
|
|
unset($additional_form_elements['position']);
|
590 |
|
|
}
|
591 |
|
|
if (isset($additional_form_elements['display'])) {
|
592 |
|
|
$form['display'] = array_merge($form['display'], $additional_form_elements['display']);
|
593 |
|
|
unset($additional_form_elements['display']);
|
594 |
|
|
}
|
595 |
|
|
if (isset($additional_form_elements['validation'])) {
|
596 |
|
|
$form['validation'] = array_merge($form['validation'], $additional_form_elements['validation']);
|
597 |
|
|
unset($additional_form_elements['validation']);
|
598 |
|
|
}
|
599 |
|
|
elseif (count(element_children($form['validation'])) == 0) {
|
600 |
|
|
unset($form['validation']);
|
601 |
|
|
}
|
602 |
|
|
$form = array_merge($form, $additional_form_elements);
|
603 |
01d522a6
|
Assos Assos
|
// Ensure that the webform admin library is attached, possibly in addition to
|
604 |
|
|
// component-specific attachments.
|
605 |
|
|
$form['#attached']['library'][] = array('webform', 'admin');
|
606 |
85ad3d82
|
Assos Assos
|
|
607 |
|
|
// Add the submit button.
|
608 |
a45e4bc1
|
Assos Assos
|
$form['actions'] = array(
|
609 |
|
|
'#type' => 'actions',
|
610 |
|
|
'#weight' => 50,
|
611 |
|
|
);
|
612 |
3753f249
|
Assos Assos
|
$form['actions']['submit'] = array(
|
613 |
85ad3d82
|
Assos Assos
|
'#type' => 'submit',
|
614 |
|
|
'#value' => t('Save component'),
|
615 |
|
|
);
|
616 |
|
|
|
617 |
3753f249
|
Assos Assos
|
// Remove fieldsets without any child form controls.
|
618 |
a45e4bc1
|
Assos Assos
|
foreach (element_children($form) as $group_key) {
|
619 |
|
|
$group = $form[$group_key];
|
620 |
3753f249
|
Assos Assos
|
if (isset($group['#type']) && $group['#type'] === 'fieldset' && !element_children($group)) {
|
621 |
|
|
unset($form[$group_key]);
|
622 |
|
|
}
|
623 |
|
|
}
|
624 |
|
|
|
625 |
85ad3d82
|
Assos Assos
|
return $form;
|
626 |
|
|
}
|
627 |
|
|
|
628 |
|
|
/**
|
629 |
|
|
* Field name validation for the webform unique key. Must be alphanumeric.
|
630 |
|
|
*/
|
631 |
|
|
function webform_component_edit_form_validate($form, &$form_state) {
|
632 |
a45e4bc1
|
Assos Assos
|
$node = $form['#node'];;
|
633 |
85ad3d82
|
Assos Assos
|
|
634 |
|
|
if (!preg_match('/^[a-z0-9_]+$/i', $form_state['values']['form_key'])) {
|
635 |
|
|
form_set_error('form_key', t('The field key %field_key is invalid. Please include only lowercase alphanumeric characters and underscores.', array('%field_key' => $form_state['values']['form_key'])));
|
636 |
|
|
}
|
637 |
|
|
|
638 |
|
|
foreach ($node->webform['components'] as $cid => $component) {
|
639 |
|
|
if (($component['cid'] != $form_state['values']['cid'] || $form_state['values']['clone']) && ($component['pid'] == $form_state['values']['pid']) && (strcasecmp($component['form_key'], $form_state['values']['form_key']) == 0)) {
|
640 |
|
|
form_set_error('form_key', t('The field key %field_key is already in use by the field labeled %existing_field. Please use a unique key.', array('%field_key' => $form_state['values']['form_key'], '%existing_field' => $component['name'])));
|
641 |
|
|
}
|
642 |
|
|
}
|
643 |
|
|
}
|
644 |
|
|
|
645 |
|
|
/**
|
646 |
|
|
* Submit handler for webform_component_edit_form().
|
647 |
|
|
*/
|
648 |
|
|
function webform_component_edit_form_submit($form, &$form_state) {
|
649 |
|
|
// Ensure a webform record exists.
|
650 |
a45e4bc1
|
Assos Assos
|
$node = $form['#node'];
|
651 |
85ad3d82
|
Assos Assos
|
webform_ensure_record($node);
|
652 |
|
|
|
653 |
a45e4bc1
|
Assos Assos
|
// Remove extra values that match the default.
|
654 |
85ad3d82
|
Assos Assos
|
if (isset($form_state['values']['extra'])) {
|
655 |
a45e4bc1
|
Assos Assos
|
$default = array('type' => $form_state['values']['type'], 'extra' => array());
|
656 |
|
|
webform_component_defaults($default);
|
657 |
85ad3d82
|
Assos Assos
|
foreach ($form_state['values']['extra'] as $key => $value) {
|
658 |
a45e4bc1
|
Assos Assos
|
if (isset($default['extra'][$key]) && $default['extra'][$key] === $value) {
|
659 |
85ad3d82
|
Assos Assos
|
unset($form_state['values']['extra'][$key]);
|
660 |
|
|
}
|
661 |
|
|
}
|
662 |
|
|
}
|
663 |
|
|
|
664 |
|
|
// Remove empty attribute values.
|
665 |
|
|
if (isset($form_state['values']['extra']['attributes'])) {
|
666 |
|
|
foreach ($form_state['values']['extra']['attributes'] as $key => $value) {
|
667 |
|
|
if ($value === '') {
|
668 |
|
|
unset($form_state['values']['extra']['attributes'][$key]);
|
669 |
|
|
}
|
670 |
|
|
}
|
671 |
|
|
}
|
672 |
|
|
|
673 |
|
|
if ($form_state['values']['clone']) {
|
674 |
|
|
webform_component_clone($node, $form_state['values']);
|
675 |
|
|
drupal_set_message(t('Component %name cloned.', array('%name' => $form_state['values']['name'])));
|
676 |
|
|
}
|
677 |
|
|
elseif (!empty($form_state['values']['cid'])) {
|
678 |
|
|
webform_component_update($form_state['values']);
|
679 |
|
|
drupal_set_message(t('Component %name updated.', array('%name' => $form_state['values']['name'])));
|
680 |
|
|
}
|
681 |
|
|
else {
|
682 |
|
|
$cid = webform_component_insert($form_state['values']);
|
683 |
|
|
drupal_set_message(t('New component %name added.', array('%name' => $form_state['values']['name'])));
|
684 |
|
|
}
|
685 |
|
|
|
686 |
|
|
// Since Webform components have been updated but the node itself has not
|
687 |
|
|
// been saved, it is necessary to explicitly clear the cache to make sure
|
688 |
a45e4bc1
|
Assos Assos
|
// the updated webform is visible to anonymous users. This resets the page
|
689 |
|
|
// and block caches (only);
|
690 |
85ad3d82
|
Assos Assos
|
cache_clear_all();
|
691 |
|
|
|
692 |
a45e4bc1
|
Assos Assos
|
// Refresh the entity cache, should it be cached in persistent storage.
|
693 |
|
|
entity_get_controller('node')->resetCache(array($node->nid));
|
694 |
85ad3d82
|
Assos Assos
|
|
695 |
|
|
$form_state['redirect'] = array('node/' . $node->nid . '/webform/components', isset($cid) ? array('query' => array('cid' => $cid)) : array());
|
696 |
|
|
}
|
697 |
|
|
|
698 |
|
|
/**
|
699 |
|
|
* Form to confirm deletion of a component.
|
700 |
|
|
*/
|
701 |
|
|
function webform_component_delete_form($form, $form_state, $node, $component) {
|
702 |
|
|
$cid = $component['cid'];
|
703 |
|
|
|
704 |
|
|
$form = array();
|
705 |
|
|
$form['node'] = array(
|
706 |
|
|
'#type' => 'value',
|
707 |
|
|
'#value' => $node,
|
708 |
|
|
);
|
709 |
|
|
$form['component'] = array(
|
710 |
|
|
'#type' => 'value',
|
711 |
|
|
'#value' => $component,
|
712 |
|
|
);
|
713 |
|
|
|
714 |
ba09eb79
|
Assos Assos
|
$component_type = $node->webform['components'][$cid]['type'];
|
715 |
|
|
if (webform_component_feature($component_type, 'group')) {
|
716 |
85ad3d82
|
Assos Assos
|
$question = t('Delete the %name fieldset?', array('%name' => $node->webform['components'][$cid]['name']));
|
717 |
ba09eb79
|
Assos Assos
|
$description = t('This will immediately delete the %name @type component and all nested components within %name from the %webform webform. This cannot be undone.',
|
718 |
|
|
array('%name' => $node->webform['components'][$cid]['name'],
|
719 |
|
|
'@type' => webform_component_property($component_type, 'label'),
|
720 |
|
|
'%webform' => $node->title));
|
721 |
85ad3d82
|
Assos Assos
|
}
|
722 |
|
|
else {
|
723 |
|
|
$question = t('Delete the %name component?', array('%name' => $node->webform['components'][$cid]['name']));
|
724 |
|
|
$description = t('This will immediately delete the %name component from the %webform webform. This cannot be undone.', array('%name' => $node->webform['components'][$cid]['name'], '%webform' => $node->title));
|
725 |
|
|
}
|
726 |
|
|
|
727 |
|
|
return confirm_form($form, $question, 'node/' . $node->nid . '/webform/components', $description, t('Delete'));
|
728 |
|
|
}
|
729 |
|
|
|
730 |
|
|
/**
|
731 |
|
|
* Submit handler for webform_component_delete_form().
|
732 |
|
|
*/
|
733 |
|
|
function webform_component_delete_form_submit($form, &$form_state) {
|
734 |
|
|
// Delete the component.
|
735 |
|
|
$node = $form_state['values']['node'];
|
736 |
|
|
$component = $form_state['values']['component'];
|
737 |
|
|
webform_component_delete($node, $component);
|
738 |
|
|
drupal_set_message(t('Component %name deleted.', array('%name' => $component['name'])));
|
739 |
|
|
|
740 |
|
|
// Check if this webform still contains any information.
|
741 |
|
|
unset($node->webform['components'][$component['cid']]);
|
742 |
|
|
webform_check_record($node);
|
743 |
|
|
|
744 |
|
|
// Since Webform components have been updated but the node itself has not
|
745 |
|
|
// been saved, it is necessary to explicitly clear the cache to make sure
|
746 |
a45e4bc1
|
Assos Assos
|
// the updated webform is visible to anonymous users. This resets the page
|
747 |
|
|
// and block caches (only);
|
748 |
85ad3d82
|
Assos Assos
|
cache_clear_all();
|
749 |
|
|
|
750 |
a45e4bc1
|
Assos Assos
|
// Refresh the entity cache, should it be cached in persistent storage.
|
751 |
|
|
entity_get_controller('node')->resetCache(array($node->nid));
|
752 |
85ad3d82
|
Assos Assos
|
|
753 |
|
|
$form_state['redirect'] = 'node/' . $node->nid . '/webform/components';
|
754 |
|
|
}
|
755 |
|
|
|
756 |
|
|
/**
|
757 |
|
|
* Insert a new component into the database.
|
758 |
|
|
*
|
759 |
|
|
* @param $component
|
760 |
|
|
* A full component containing fields from the component form.
|
761 |
|
|
*/
|
762 |
|
|
function webform_component_insert(&$component) {
|
763 |
|
|
// Allow modules to modify the component before saving.
|
764 |
|
|
foreach (module_implements('webform_component_presave') as $module) {
|
765 |
|
|
$function = $module . '_webform_component_presave';
|
766 |
|
|
$function($component);
|
767 |
|
|
}
|
768 |
|
|
|
769 |
|
|
$component['value'] = isset($component['value']) ? $component['value'] : NULL;
|
770 |
a45e4bc1
|
Assos Assos
|
$component['required'] = isset($component['required']) ? $component['required'] : 0;
|
771 |
85ad3d82
|
Assos Assos
|
$component['extra']['private'] = isset($component['extra']['private']) ? $component['extra']['private'] : 0;
|
772 |
|
|
|
773 |
|
|
if (!isset($component['cid'])) {
|
774 |
|
|
if (lock_acquire('webform_component_insert_' . $component['nid'], 5)) {
|
775 |
|
|
$next_id_query = db_select('webform_component')->condition('nid', $component['nid']);
|
776 |
|
|
$next_id_query->addExpression('MAX(cid) + 1', 'cid');
|
777 |
|
|
$component['cid'] = $next_id_query->execute()->fetchField();
|
778 |
|
|
if ($component['cid'] == NULL) {
|
779 |
|
|
$component['cid'] = 1;
|
780 |
|
|
}
|
781 |
|
|
lock_release('webform_component_insert_' . $component['nid']);
|
782 |
|
|
}
|
783 |
|
|
else {
|
784 |
|
|
watchdog('webform', 'A Webform component could not be saved because a timeout occurred while trying to acquire a lock for the node. Details: <pre>@component</pre>', array('@component' => print_r($component, TRUE)));
|
785 |
|
|
return FALSE;
|
786 |
|
|
}
|
787 |
|
|
}
|
788 |
|
|
|
789 |
|
|
$query = db_insert('webform_component')
|
790 |
|
|
->fields(array(
|
791 |
|
|
'nid' => $component['nid'],
|
792 |
|
|
'cid' => $component['cid'],
|
793 |
|
|
'pid' => $component['pid'],
|
794 |
|
|
'form_key' => $component['form_key'],
|
795 |
|
|
'name' => $component['name'],
|
796 |
|
|
'type' => $component['type'],
|
797 |
|
|
'value' => (string) $component['value'],
|
798 |
|
|
'extra' => serialize($component['extra']),
|
799 |
a45e4bc1
|
Assos Assos
|
'required' => $component['required'],
|
800 |
85ad3d82
|
Assos Assos
|
'weight' => $component['weight'],
|
801 |
|
|
))
|
802 |
|
|
->execute();
|
803 |
|
|
|
804 |
|
|
// Post-insert actions.
|
805 |
|
|
module_invoke_all('webform_component_insert', $component);
|
806 |
|
|
|
807 |
|
|
return $component['cid'];
|
808 |
|
|
}
|
809 |
|
|
|
810 |
|
|
/**
|
811 |
|
|
* Update an existing component with new values.
|
812 |
|
|
*
|
813 |
|
|
* @param $component
|
814 |
|
|
* A full component containing a nid, cid, and all other fields from the
|
815 |
|
|
* component form. Additional properties are stored in the extra array.
|
816 |
|
|
*/
|
817 |
|
|
function webform_component_update($component) {
|
818 |
|
|
// Allow modules to modify the component before saving.
|
819 |
|
|
foreach (module_implements('webform_component_presave') as $module) {
|
820 |
|
|
$function = $module . '_webform_component_presave';
|
821 |
|
|
$function($component);
|
822 |
|
|
}
|
823 |
|
|
|
824 |
|
|
$component['value'] = isset($component['value']) ? $component['value'] : NULL;
|
825 |
a45e4bc1
|
Assos Assos
|
$component['required'] = isset($component['required']) ? $component['required'] : 0;
|
826 |
85ad3d82
|
Assos Assos
|
$component['extra']['private'] = isset($component['extra']['private']) ? $component['extra']['private'] : 0;
|
827 |
|
|
db_update('webform_component')
|
828 |
|
|
->fields(array(
|
829 |
|
|
'pid' => $component['pid'],
|
830 |
|
|
'form_key' => $component['form_key'],
|
831 |
|
|
'name' => $component['name'],
|
832 |
|
|
'type' => $component['type'],
|
833 |
|
|
'value' => isset($component['value']) ? $component['value'] : '',
|
834 |
|
|
'extra' => serialize($component['extra']),
|
835 |
a45e4bc1
|
Assos Assos
|
'required' => $component['required'],
|
836 |
85ad3d82
|
Assos Assos
|
'weight' => $component['weight']
|
837 |
|
|
))
|
838 |
|
|
->condition('nid', $component['nid'])
|
839 |
|
|
->condition('cid', $component['cid'])
|
840 |
|
|
->execute();
|
841 |
|
|
|
842 |
|
|
// Post-update actions.
|
843 |
|
|
module_invoke_all('webform_component_update', $component);
|
844 |
|
|
}
|
845 |
|
|
|
846 |
|
|
function webform_component_delete($node, $component) {
|
847 |
|
|
// Check if a delete function is available for this component. If so,
|
848 |
|
|
// load all submissions and allow the component to delete each one.
|
849 |
|
|
webform_component_include($component['type']);
|
850 |
|
|
$delete_function = '_webform_delete_' . $component['type'];
|
851 |
|
|
if (function_exists($delete_function)) {
|
852 |
|
|
module_load_include('inc', 'webform', 'includes/webform.submissions');
|
853 |
|
|
$submissions = webform_get_submissions($node->nid);
|
854 |
|
|
foreach ($submissions as $submission) {
|
855 |
|
|
if (isset($submission->data[$component['cid']])) {
|
856 |
a45e4bc1
|
Assos Assos
|
webform_component_invoke($component['type'], 'delete', $component, $submission->data[$component['cid']]);
|
857 |
85ad3d82
|
Assos Assos
|
}
|
858 |
|
|
}
|
859 |
|
|
}
|
860 |
|
|
|
861 |
|
|
// Remove database entries.
|
862 |
|
|
db_delete('webform_component')
|
863 |
|
|
->condition('nid', $node->nid)
|
864 |
|
|
->condition('cid', $component['cid'])
|
865 |
|
|
->execute();
|
866 |
|
|
db_delete('webform_submitted_data')
|
867 |
|
|
->condition('nid', $node->nid)
|
868 |
|
|
->condition('cid', $component['cid'])
|
869 |
|
|
->execute();
|
870 |
|
|
|
871 |
a45e4bc1
|
Assos Assos
|
// Delete any conditionals dependent on this component.
|
872 |
|
|
module_load_include('inc', 'webform', 'includes/webform.conditionals');
|
873 |
|
|
foreach ($node->webform['conditionals'] as $rgid => $conditional) {
|
874 |
|
|
$delete_conditional = FALSE;
|
875 |
|
|
$specs = array(
|
876 |
|
|
array(
|
877 |
|
|
'field' => 'rules',
|
878 |
|
|
'table' => 'webform_conditional_rules',
|
879 |
|
|
'component' => 'source',
|
880 |
|
|
'component_type' => 'source_type',
|
881 |
|
|
'index' => 'rid',
|
882 |
|
|
),
|
883 |
|
|
array(
|
884 |
|
|
'field' => 'actions',
|
885 |
|
|
'table' => 'webform_conditional_actions',
|
886 |
|
|
'component' => 'target',
|
887 |
|
|
'component_type' => 'target_type',
|
888 |
|
|
'index' => 'aid',
|
889 |
|
|
),
|
890 |
|
|
);
|
891 |
|
|
foreach ($specs as $spec) {
|
892 |
|
|
$count = count($conditional[$spec['field']]);
|
893 |
|
|
foreach ($conditional[$spec['field']] as $key => $thing) {
|
894 |
|
|
if ($thing[$spec['component_type']] === 'component' && $thing[$spec['component']] == $component['cid']) {
|
895 |
|
|
if ($count == 1) {
|
896 |
|
|
// Delete the conditional if this component is the only source or target.
|
897 |
|
|
webform_conditional_delete($node, $conditional);
|
898 |
|
|
break 2;
|
899 |
|
|
}
|
900 |
|
|
db_delete($spec['table'])
|
901 |
|
|
->condition('nid', $node->nid)
|
902 |
|
|
->condition('rgid', $rgid)
|
903 |
|
|
->condition($spec['index'], $key)
|
904 |
|
|
->execute();
|
905 |
|
|
$count--;
|
906 |
|
|
}
|
907 |
|
|
}
|
908 |
|
|
}
|
909 |
|
|
}
|
910 |
|
|
|
911 |
85ad3d82
|
Assos Assos
|
// Delete all elements under this element.
|
912 |
|
|
$result = db_select('webform_component', 'c')
|
913 |
|
|
->fields('c')
|
914 |
|
|
->condition('nid', $node->nid)
|
915 |
|
|
->condition('pid', $component['cid'])
|
916 |
|
|
->execute();
|
917 |
|
|
foreach ($result as $row) {
|
918 |
|
|
$child_component = $node->webform['components'][$row->cid];
|
919 |
|
|
webform_component_delete($node, $child_component);
|
920 |
|
|
}
|
921 |
|
|
|
922 |
|
|
// Post-delete actions.
|
923 |
|
|
module_invoke_all('webform_component_delete', $component);
|
924 |
|
|
}
|
925 |
|
|
|
926 |
|
|
/**
|
927 |
|
|
* Recursively insert components into the database.
|
928 |
|
|
*
|
929 |
|
|
* @param $node
|
930 |
|
|
* The node object containing the current webform.
|
931 |
|
|
* @param $component
|
932 |
|
|
* A full component containing fields from the component form.
|
933 |
|
|
*/
|
934 |
|
|
function webform_component_clone(&$node, &$component) {
|
935 |
|
|
$original_cid = $component['cid'];
|
936 |
|
|
$component['cid'] = NULL;
|
937 |
|
|
$new_cid = webform_component_insert($component);
|
938 |
|
|
$component['cid'] = $new_cid;
|
939 |
|
|
if (webform_component_feature($component['type'], 'group')) {
|
940 |
|
|
foreach ($node->webform['components'] as $cid => $child_component) {
|
941 |
|
|
if ($child_component['pid'] == $original_cid) {
|
942 |
|
|
$child_component['pid'] = $new_cid;
|
943 |
|
|
webform_component_clone($node, $child_component);
|
944 |
|
|
}
|
945 |
|
|
}
|
946 |
|
|
}
|
947 |
|
|
return $new_cid;
|
948 |
|
|
}
|
949 |
|
|
|
950 |
|
|
/**
|
951 |
|
|
* Check if a component has a particular feature.
|
952 |
|
|
*
|
953 |
|
|
* @see hook_webform_component_info()
|
954 |
|
|
*/
|
955 |
|
|
function webform_component_feature($type, $feature) {
|
956 |
|
|
$components = webform_components();
|
957 |
|
|
$defaults = array(
|
958 |
a45e4bc1
|
Assos Assos
|
'analysis' => TRUE,
|
959 |
85ad3d82
|
Assos Assos
|
'csv' => TRUE,
|
960 |
|
|
'default_value' => TRUE,
|
961 |
|
|
'description' => TRUE,
|
962 |
|
|
'email' => TRUE,
|
963 |
|
|
'email_address' => FALSE,
|
964 |
|
|
'email_name' => FALSE,
|
965 |
|
|
'required' => TRUE,
|
966 |
|
|
'title' => TRUE,
|
967 |
|
|
'title_display' => TRUE,
|
968 |
|
|
'title_inline' => TRUE,
|
969 |
|
|
'conditional' => TRUE,
|
970 |
a45e4bc1
|
Assos Assos
|
'conditional_action_set' => FALSE,
|
971 |
85ad3d82
|
Assos Assos
|
'spam_analysis' => FALSE,
|
972 |
|
|
'group' => FALSE,
|
973 |
|
|
'attachment' => FALSE,
|
974 |
|
|
'private' => TRUE,
|
975 |
a45e4bc1
|
Assos Assos
|
'placeholder' => FALSE,
|
976 |
|
|
'wrapper_classes' => TRUE,
|
977 |
|
|
'css_classes' => TRUE,
|
978 |
|
|
'views_range' => FALSE,
|
979 |
85ad3d82
|
Assos Assos
|
);
|
980 |
|
|
return isset($components[$type]['features'][$feature]) ? $components[$type]['features'][$feature] : !empty($defaults[$feature]);
|
981 |
|
|
}
|
982 |
|
|
|
983 |
a45e4bc1
|
Assos Assos
|
/**
|
984 |
|
|
* Get a component property from the component definition.
|
985 |
|
|
*
|
986 |
|
|
* @see hook_webform_component_info()
|
987 |
|
|
*/
|
988 |
|
|
function webform_component_property($type, $property) {
|
989 |
|
|
$components = webform_components();
|
990 |
|
|
$defaults = array(
|
991 |
|
|
'conditional_type' => 'string',
|
992 |
|
|
);
|
993 |
|
|
return isset($components[$type][$property]) ? $components[$type][$property] : $defaults[$property];
|
994 |
|
|
}
|
995 |
|
|
|
996 |
85ad3d82
|
Assos Assos
|
/**
|
997 |
|
|
* Create a list of components suitable for a select list.
|
998 |
|
|
*
|
999 |
|
|
* @param $node
|
1000 |
|
|
* The webform node.
|
1001 |
|
|
* @param $component_filter
|
1002 |
|
|
* Either an array of components, or a string containing a feature name (csv,
|
1003 |
|
|
* email, required, conditional) on which this list of components will be
|
1004 |
|
|
* restricted.
|
1005 |
a45e4bc1
|
Assos Assos
|
* @param $prefix_group
|
1006 |
|
|
* TRUE to indent with a hyphen, or 'path" to Prepend enclosing group (e.g.
|
1007 |
|
|
* fieldset) name(s)
|
1008 |
|
|
* @param $pagebreak_groups
|
1009 |
85ad3d82
|
Assos Assos
|
* Determine if pagebreaks should be converted to option groups in the
|
1010 |
|
|
* returned list of options.
|
1011 |
|
|
*/
|
1012 |
a45e4bc1
|
Assos Assos
|
function webform_component_list($node, $component_filter = NULL, $prepend_group = TRUE, $pagebreak_groups = FALSE) {
|
1013 |
85ad3d82
|
Assos Assos
|
$options = array();
|
1014 |
|
|
$page_names = array();
|
1015 |
a45e4bc1
|
Assos Assos
|
$parent_names = array();
|
1016 |
85ad3d82
|
Assos Assos
|
|
1017 |
|
|
$components = is_array($component_filter) ? $component_filter : $node->webform['components'];
|
1018 |
|
|
$feature = is_string($component_filter) ? $component_filter : NULL;
|
1019 |
|
|
|
1020 |
|
|
foreach ($components as $cid => $component) {
|
1021 |
a45e4bc1
|
Assos Assos
|
// If this component is a group (e.g. fieldset), then remember its name, including any parents.
|
1022 |
|
|
if ($prepend_group && webform_component_feature($component['type'], 'group')) {
|
1023 |
|
|
$parent_names[$cid] = ($component['pid'] ? $parent_names[$component['pid']] : '') .
|
1024 |
|
|
($prepend_group === 'path' ? $component['name'] . ': ' : '-');
|
1025 |
|
|
}
|
1026 |
|
|
$page_num = $component['page_num'];
|
1027 |
|
|
// If this component is a pagebreak, then generate an option group, ensuring a unique name.
|
1028 |
|
|
if ($pagebreak_groups && $component['type'] == 'pagebreak') {
|
1029 |
|
|
$page_name = $component['name'];
|
1030 |
|
|
$copy = 1;
|
1031 |
|
|
while (in_array($page_name, $page_names)) {
|
1032 |
|
|
$page_name = $component['name'] . '_' . ++$copy;
|
1033 |
85ad3d82
|
Assos Assos
|
}
|
1034 |
a45e4bc1
|
Assos Assos
|
$page_names[$page_num] = $page_name;
|
1035 |
85ad3d82
|
Assos Assos
|
}
|
1036 |
a45e4bc1
|
Assos Assos
|
// If this component should be included in the options, add it with any prefix, in a page group, as needed.
|
1037 |
|
|
if (!isset($feature) || webform_component_feature($component['type'], $feature) || $prepend_group === TRUE) {
|
1038 |
|
|
$prefix = ($prepend_group && $component['pid']) ? $parent_names[$component['pid']] : '';
|
1039 |
|
|
if ($pagebreak_groups && $page_num > 1) {
|
1040 |
|
|
$options[$page_names[$page_num]][$cid] = $prefix . $component['name'];
|
1041 |
85ad3d82
|
Assos Assos
|
}
|
1042 |
|
|
else {
|
1043 |
a45e4bc1
|
Assos Assos
|
$options[$cid] = $prefix . $component['name'];
|
1044 |
85ad3d82
|
Assos Assos
|
}
|
1045 |
|
|
}
|
1046 |
|
|
}
|
1047 |
|
|
|
1048 |
|
|
return $options;
|
1049 |
|
|
}
|
1050 |
|
|
|
1051 |
|
|
/**
|
1052 |
|
|
* A Form API process function to expand a component list into checkboxes.
|
1053 |
|
|
*/
|
1054 |
|
|
function webform_component_select($element) {
|
1055 |
|
|
// Split the select list into checkboxes.
|
1056 |
|
|
foreach ($element['#options'] as $key => $label) {
|
1057 |
|
|
$label_length = strlen($label);
|
1058 |
|
|
$label = preg_replace('/^(\-)+/', '', $label);
|
1059 |
|
|
$indents = $label_length - strlen($label);
|
1060 |
|
|
$element[$key] = array(
|
1061 |
|
|
'#title' => $label,
|
1062 |
|
|
'#type' => 'checkbox',
|
1063 |
|
|
'#default_value' => array_search($key, $element['#value']) !== FALSE,
|
1064 |
|
|
'#return_value' => $key,
|
1065 |
|
|
'#parents' => array_merge($element['#parents'], array($key)),
|
1066 |
|
|
'#indent' => $indents,
|
1067 |
|
|
);
|
1068 |
|
|
}
|
1069 |
|
|
|
1070 |
|
|
$element['#theme_wrappers'] = array();
|
1071 |
|
|
$element['#type'] = 'webform_component_select';
|
1072 |
|
|
$element['#theme'] = 'webform_component_select';
|
1073 |
|
|
$element['#attached'] = array(
|
1074 |
|
|
'library' => array(
|
1075 |
|
|
array('webform', 'admin'),
|
1076 |
a45e4bc1
|
Assos Assos
|
array('system', 'drupal.collapse'),
|
1077 |
85ad3d82
|
Assos Assos
|
),
|
1078 |
|
|
'js' => array(
|
1079 |
|
|
'misc/tableselect.js' => array(),
|
1080 |
|
|
),
|
1081 |
|
|
);
|
1082 |
|
|
|
1083 |
|
|
return $element;
|
1084 |
|
|
}
|
1085 |
|
|
|
1086 |
|
|
/**
|
1087 |
|
|
* Theme the contents of a Webform component select element.
|
1088 |
|
|
*/
|
1089 |
|
|
function theme_webform_component_select($variables) {
|
1090 |
|
|
$element = $variables['element'];
|
1091 |
|
|
|
1092 |
|
|
$rows = array();
|
1093 |
|
|
$header = array();
|
1094 |
|
|
if (!isset($element['#all_checkbox']) || $element['#all_checkbox']) {
|
1095 |
|
|
$header = array(array('class' => array('select-all'), 'data' => ' ' . t('Include all components')));
|
1096 |
|
|
}
|
1097 |
|
|
foreach (element_children($element) as $key) {
|
1098 |
a45e4bc1
|
Assos Assos
|
if ($key != 'suffix') {
|
1099 |
|
|
$rows[] = array(
|
1100 |
|
|
theme('indentation', array('size' => $element[$key]['#indent'])) . drupal_render($element[$key]),
|
1101 |
|
|
);
|
1102 |
|
|
}
|
1103 |
85ad3d82
|
Assos Assos
|
}
|
1104 |
|
|
|
1105 |
|
|
$element['#type'] = 'fieldset';
|
1106 |
|
|
$element['#value'] = NULL;
|
1107 |
|
|
$element['#attributes']['class'] = array('webform-component-select-table');
|
1108 |
|
|
if (!isset($element['#collapsible']) || $element['#collapsible']) {
|
1109 |
|
|
$element['#attributes']['class'][] = 'collapsible';
|
1110 |
|
|
}
|
1111 |
|
|
if (!isset($element['#collapsed']) || $element['#collapsed']) {
|
1112 |
|
|
$element['#attributes']['class'][] = 'collapsed';
|
1113 |
|
|
}
|
1114 |
|
|
|
1115 |
|
|
if (empty($rows)) {
|
1116 |
|
|
$element['#children'] = t('No available components.');
|
1117 |
|
|
}
|
1118 |
|
|
else {
|
1119 |
a45e4bc1
|
Assos Assos
|
$element['#children'] = '<div class="webform-component-select-wrapper">' . theme('table', array('header' => $header, 'rows' => $rows, 'sticky' => FALSE)) . '</div>';
|
1120 |
85ad3d82
|
Assos Assos
|
}
|
1121 |
|
|
|
1122 |
a45e4bc1
|
Assos Assos
|
if (isset($element['suffix'])) {
|
1123 |
|
|
$element['#children'] .= '<div class="webform-component-select-suffix">' . drupal_render($element['suffix']) . '</div>';
|
1124 |
|
|
}
|
1125 |
|
|
|
1126 |
|
|
|
1127 |
85ad3d82
|
Assos Assos
|
return theme('fieldset', array('element' => $element));
|
1128 |
|
|
}
|
1129 |
|
|
|
1130 |
|
|
/**
|
1131 |
|
|
* Find a components parents within a node.
|
1132 |
|
|
*/
|
1133 |
|
|
function webform_component_parent_keys($node, $component) {
|
1134 |
|
|
$parents = array($component['form_key']);
|
1135 |
|
|
$pid = $component['pid'];
|
1136 |
|
|
while ($pid) {
|
1137 |
|
|
$parents[] = $node->webform['components'][$pid]['form_key'];
|
1138 |
|
|
$pid = $node->webform['components'][$pid]['pid'];
|
1139 |
|
|
}
|
1140 |
|
|
return array_reverse($parents);
|
1141 |
|
|
}
|
1142 |
|
|
|
1143 |
|
|
/**
|
1144 |
|
|
* Populate a component with the defaults for that type.
|
1145 |
|
|
*/
|
1146 |
|
|
function webform_component_defaults(&$component) {
|
1147 |
3753f249
|
Assos Assos
|
$defaults = webform_component_invoke($component['type'], 'defaults');
|
1148 |
|
|
drupal_alter('webform_component_defaults', $defaults, $component['type']);
|
1149 |
|
|
if (!empty($defaults)) {
|
1150 |
85ad3d82
|
Assos Assos
|
foreach ($defaults as $key => $default) {
|
1151 |
|
|
if (!isset($component[$key])) {
|
1152 |
|
|
$component[$key] = $default;
|
1153 |
|
|
}
|
1154 |
|
|
}
|
1155 |
|
|
foreach ($defaults['extra'] as $extra => $default) {
|
1156 |
|
|
if (!isset($component['extra'][$extra])) {
|
1157 |
|
|
$component['extra'][$extra] = $default;
|
1158 |
|
|
}
|
1159 |
|
|
}
|
1160 |
|
|
}
|
1161 |
|
|
}
|
1162 |
|
|
|
1163 |
|
|
/**
|
1164 |
|
|
* Validate an element value is unique with no duplicates in the database.
|
1165 |
|
|
*/
|
1166 |
|
|
function webform_validate_unique($element, $form_state) {
|
1167 |
|
|
if ($element['#value'] !== '') {
|
1168 |
|
|
$nid = $form_state['values']['details']['nid'];
|
1169 |
|
|
$sid = $form_state['values']['details']['sid'];
|
1170 |
|
|
$query = db_select('webform_submitted_data')
|
1171 |
|
|
->fields('webform_submitted_data', array('sid'))
|
1172 |
|
|
->condition('nid', $nid)
|
1173 |
|
|
->condition('cid', $element['#webform_component']['cid'])
|
1174 |
|
|
->condition('data', $element['#value'])
|
1175 |
|
|
->range(0, 1); // More efficient than using countQuery() for data checks.
|
1176 |
|
|
if ($sid) {
|
1177 |
|
|
$query->condition('sid', $sid, '<>');
|
1178 |
|
|
}
|
1179 |
|
|
$count = $query->execute()->fetchField();
|
1180 |
|
|
if ($count) {
|
1181 |
|
|
form_error($element, t('The value %value has already been submitted once for the %title field. You may have already submitted this form, or you need to use a different value.', array('%value' => $element['#value'], '%title' => $element['#title'])));
|
1182 |
|
|
}
|
1183 |
|
|
}
|
1184 |
|
|
} |