1 | <?php |
---|
2 | |
---|
3 | /** |
---|
4 | * @file |
---|
5 | * Create fields' form for a content type. |
---|
6 | * |
---|
7 | * Each field defines its own component of the content entry form, via its |
---|
8 | * chosen widget. |
---|
9 | */ |
---|
10 | function content_form(&$form, &$form_state) { |
---|
11 | $type = content_types($form['type']['#value']); |
---|
12 | foreach ($type['fields'] as $field_name => $field) { |
---|
13 | $form['#field_info'][$field['field_name']] = $field; |
---|
14 | $form += (array) content_field_form($form, $form_state, $field); |
---|
15 | } |
---|
16 | return $form; |
---|
17 | } |
---|
18 | |
---|
19 | /** |
---|
20 | * Create a separate form element for each field. |
---|
21 | * |
---|
22 | * // TODO: $count param ? not used anymore ? |
---|
23 | * Hook_widget() picks up two new values, $count and $delta, to help |
---|
24 | * widgets know what information to return since multiple values are |
---|
25 | * sometimes controlled by the content module. |
---|
26 | * |
---|
27 | * @param $form |
---|
28 | * the form to add this field element to |
---|
29 | * @param $form_state |
---|
30 | * the form_state for the above form |
---|
31 | * @param $field |
---|
32 | * the field array to use to create the form element |
---|
33 | * @param $get_delta |
---|
34 | * use to get only a specific delta value of a multiple value field, otherwise |
---|
35 | * function will return the entire $field form element. |
---|
36 | */ |
---|
37 | function content_field_form(&$form, &$form_state, $field, $get_delta = NULL) { |
---|
38 | $form['#cache'] = FALSE; |
---|
39 | $node = $form['#node']; |
---|
40 | $addition = array(); |
---|
41 | $form_element = array(); |
---|
42 | $field_name = $field['field_name']; |
---|
43 | |
---|
44 | $items = array(); |
---|
45 | |
---|
46 | // TODO: is the "if (function_exists($function)) {" needed ? |
---|
47 | // defining the $function here makes it unclear where it is actually called |
---|
48 | $function = $field['widget']['module'] .'_widget'; |
---|
49 | if (function_exists($function)) { |
---|
50 | // Prepare the values to be filled in the widget. |
---|
51 | // We look in the following places: |
---|
52 | // - Form submitted values |
---|
53 | // - Node values (when editing an existing node), or pre-filled values (when |
---|
54 | // creating a new node translation) |
---|
55 | // - Default values set for the field (when creating a new node). |
---|
56 | if (!empty($form_state['values'][$field['field_name']])) { |
---|
57 | $items = $form_state['values'][$field['field_name']]; |
---|
58 | // If there was an AHAH add more button in this field, don't save it. |
---|
59 | unset($items[$field['field_name'] .'_add_more']); |
---|
60 | } |
---|
61 | elseif (!empty($node->$field['field_name'])) { |
---|
62 | $items = $node->$field['field_name']; |
---|
63 | } |
---|
64 | elseif (empty($node->nid)) { |
---|
65 | if (content_callback('widget', 'default value', $field) != CONTENT_CALLBACK_NONE) { |
---|
66 | // If a module wants to insert custom default values here, |
---|
67 | // it should provide a hook_default_value() function to call, |
---|
68 | // otherwise the content module's content_default_value() function |
---|
69 | // will be used. |
---|
70 | $callback = content_callback('widget', 'default value', $field) == CONTENT_CALLBACK_CUSTOM ? $field['widget']['module'] .'_default_value' : 'content_default_value'; |
---|
71 | if (function_exists($callback)) { |
---|
72 | $items = $callback($form, $form_state, $field, 0); |
---|
73 | } |
---|
74 | } |
---|
75 | } |
---|
76 | |
---|
77 | // See if access to this form element is restricted, |
---|
78 | // if so, skip widget processing and just set the value. |
---|
79 | $access = content_access('edit', $field, NULL, $node); |
---|
80 | if (!$access) { |
---|
81 | $addition[$field_name] = array( |
---|
82 | '#access' => $access, |
---|
83 | '#type' => 'value', |
---|
84 | '#value' => $items, |
---|
85 | ); |
---|
86 | return $addition; |
---|
87 | } |
---|
88 | |
---|
89 | // If content module handles multiple values for this form element, |
---|
90 | // and not selecting an individual $delta, process the multiple value form. |
---|
91 | if (!isset($get_delta) && content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_CORE) { |
---|
92 | $form_element = content_multiple_value_form($form, $form_state, $field, $items); |
---|
93 | } |
---|
94 | // If the widget is handling multiple values (e.g optionwidgets), |
---|
95 | // or selecting an individual element, just get a single form |
---|
96 | // element and make it the $delta value. |
---|
97 | else { |
---|
98 | $delta = isset($get_delta) ? $get_delta : 0; |
---|
99 | if ($element = $function($form, $form_state, $field, $items, $delta)) { |
---|
100 | $title = check_plain(t($field['widget']['label'])); |
---|
101 | $description = content_filter_xss(t($field['widget']['description'])); |
---|
102 | $defaults = array( |
---|
103 | '#required' => $get_delta > 0 ? FALSE : $field['required'], |
---|
104 | '#columns' => array_keys($field['columns']), |
---|
105 | '#title' => $title, |
---|
106 | '#description' => $description, |
---|
107 | '#delta' => $delta, |
---|
108 | '#field_name' => $field['field_name'], |
---|
109 | '#type_name' => $field['type_name'], |
---|
110 | ); |
---|
111 | // If we're processing a specific delta value for a field where the |
---|
112 | // content module handles multiples, set the delta in the result. |
---|
113 | // For fields that handle their own processing, we can't make assumptions |
---|
114 | // about how the field is structured, just merge in the returned value. |
---|
115 | if (content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_CORE) { |
---|
116 | $form_element[$delta] = array_merge($element, $defaults); |
---|
117 | } |
---|
118 | else { |
---|
119 | $form_element = array_merge($element, $defaults); |
---|
120 | } |
---|
121 | } |
---|
122 | } |
---|
123 | |
---|
124 | // Field name is needed at top level as well as the individual elements |
---|
125 | // so the multiple values or other field level theme or processing can find it. |
---|
126 | if ($form_element) { |
---|
127 | $defaults = array( |
---|
128 | '#field_name' => $field['field_name'], |
---|
129 | '#tree' => TRUE, |
---|
130 | '#weight' => $field['widget']['weight'], |
---|
131 | '#access' => $access, |
---|
132 | // TODO: what's the need for #count ? does not seem to be used anywhere ? |
---|
133 | '#count' => count($form_element), |
---|
134 | ); |
---|
135 | $addition[$field['field_name']] = array_merge($form_element, $defaults); |
---|
136 | } |
---|
137 | } |
---|
138 | return $addition; |
---|
139 | } |
---|
140 | |
---|
141 | /** |
---|
142 | * Special handling to create form elements for multiple values. |
---|
143 | * |
---|
144 | * Handles generic features for multiple fields: |
---|
145 | * - number of widgets |
---|
146 | * - AHAH-'add more' button |
---|
147 | * - drag-n-drop value reordering |
---|
148 | */ |
---|
149 | function content_multiple_value_form(&$form, &$form_state, $field, $items) { |
---|
150 | $field_name = $field['field_name']; |
---|
151 | |
---|
152 | switch ($field['multiple']) { |
---|
153 | case 0: |
---|
154 | $deltas = array(0); |
---|
155 | $max = 0; |
---|
156 | break; |
---|
157 | |
---|
158 | case 1: |
---|
159 | $deltas = array_keys($items); |
---|
160 | $current_item_count = max(1, (isset($form_state['item_count'][$field_name]) ? $form_state['item_count'][$field_name] : count($deltas))); |
---|
161 | $max = (!empty($deltas) ? max($deltas) : -1); |
---|
162 | while (count($deltas) < $current_item_count) { |
---|
163 | $max++; |
---|
164 | $deltas[] = $max; |
---|
165 | } |
---|
166 | break; |
---|
167 | |
---|
168 | default: |
---|
169 | $max = $field['multiple'] - 1; |
---|
170 | $deltas = range(0, $max); |
---|
171 | break; |
---|
172 | } |
---|
173 | |
---|
174 | $title = check_plain(t($field['widget']['label'])); |
---|
175 | $description = content_filter_xss(t($field['widget']['description'])); |
---|
176 | |
---|
177 | $form_element = array( |
---|
178 | '#theme' => 'content_multiple_values', |
---|
179 | '#title' => $title, |
---|
180 | '#required' => $field['required'], |
---|
181 | '#description' => $description, |
---|
182 | ); |
---|
183 | $function = $field['widget']['module'] .'_widget'; |
---|
184 | |
---|
185 | foreach ($deltas as $delta) { |
---|
186 | if ($element = $function($form, $form_state, $field, $items, $delta)) { |
---|
187 | $defaults = array( |
---|
188 | '#title' => ($field['multiple'] >= 1) ? '' : $title, |
---|
189 | '#description' => ($field['multiple'] >= 1) ? '' : $description, |
---|
190 | '#required' => ($field['multiple'] == 0 ? $field['required'] : FALSE), |
---|
191 | '#weight' => $delta, |
---|
192 | '#delta' => $delta, |
---|
193 | '#columns' => array_keys($field['columns']), |
---|
194 | '#field_name' => $field_name, |
---|
195 | '#type_name' => $field['type_name'], |
---|
196 | ); |
---|
197 | |
---|
198 | // Add an input field for the delta (drag-n-drop reordering), which will |
---|
199 | // be hidden by tabledrag js behavior. |
---|
200 | if ($field['multiple'] >= 1) { |
---|
201 | // We name the element '_weight' to avoid clashing with column names |
---|
202 | // defined by field modules. |
---|
203 | $element['_weight'] = array( |
---|
204 | '#type' => 'weight', |
---|
205 | '#delta' => $max, // this 'delta' is the 'weight' element's property |
---|
206 | '#default_value' => isset($items[$delta]['_weight']) ? $items[$delta]['_weight'] : $delta, |
---|
207 | '#weight' => 100, |
---|
208 | ); |
---|
209 | } |
---|
210 | |
---|
211 | // Add a checkbox to allow users remove a single delta item. |
---|
212 | // See content_set_empty() and theme_content_multiple_values(). |
---|
213 | if ($field['multiple'] == 1) { |
---|
214 | // We name the element '_remove' to avoid clashing with column names |
---|
215 | // defined by field modules. |
---|
216 | $element['_remove'] = array( |
---|
217 | '#type' => 'checkbox', |
---|
218 | '#attributes' => array('class' => 'content-multiple-remove-checkbox'), |
---|
219 | '#default_value' => isset($items[$delta]['_remove']) ? $items[$delta]['_remove'] : 0, |
---|
220 | ); |
---|
221 | } |
---|
222 | |
---|
223 | $form_element[$delta] = array_merge($element, $defaults); |
---|
224 | } |
---|
225 | } |
---|
226 | |
---|
227 | // Add an #after_build callback to prevent validation of fields that are |
---|
228 | // flagged for removal and enforce field requirement settings. |
---|
229 | if ($field['multiple'] >= 1) { |
---|
230 | $form_element['#after_build'] = array('content_multiple_value_after_build_proxy'); |
---|
231 | } |
---|
232 | |
---|
233 | // Add AHAH add more button, if not working with a programmed form. |
---|
234 | if ($field['multiple'] == 1 && empty($form['#programmed'])) { |
---|
235 | // Make sure the form is cached so ahah can work. |
---|
236 | $form['#cache'] = TRUE; |
---|
237 | $content_type = content_types($field['type_name']); |
---|
238 | $field_name_css = str_replace('_', '-', $field_name); |
---|
239 | |
---|
240 | $form_element[$field_name .'_add_more'] = array( |
---|
241 | '#type' => 'submit', |
---|
242 | '#name' => $field_name .'_add_more', |
---|
243 | '#value' => t('Add another item'), |
---|
244 | '#weight' => $field['widget']['weight'] + $max + 1, |
---|
245 | // Submit callback for disabled JavaScript. drupal_get_form() might get |
---|
246 | // the form from the cache, so we can't rely on content_form_alter() |
---|
247 | // including this file. Therefore, call a proxy function to do this. |
---|
248 | '#submit' => array('content_add_more_submit_proxy'), |
---|
249 | '#ahah' => array( |
---|
250 | 'path' => 'content/js_add_more/'. $content_type['url_str'] .'/'. $field_name, |
---|
251 | 'wrapper' => $field_name_css .'-items', |
---|
252 | 'method' => 'replace', |
---|
253 | 'effect' => 'fade', |
---|
254 | ), |
---|
255 | // When JS is disabled, the content_add_more_submit handler will find |
---|
256 | // the relevant field using these entries. |
---|
257 | '#field_name' => $field_name, |
---|
258 | '#type_name' => $field['type_name'], |
---|
259 | ); |
---|
260 | |
---|
261 | // Add wrappers for the fields and 'more' button. |
---|
262 | $form_element['#prefix'] = '<div id="'. $field_name_css .'-items">'; |
---|
263 | $form_element['#suffix'] = '</div>'; |
---|
264 | $form_element[$field_name .'_add_more']['#prefix'] = '<div class="content-add-more clear-block">'; |
---|
265 | $form_element[$field_name .'_add_more']['#suffix'] = '</div>'; |
---|
266 | } |
---|
267 | |
---|
268 | return $form_element; |
---|
269 | } |
---|
270 | |
---|
271 | /** |
---|
272 | * After build callback for multiple value fields. |
---|
273 | */ |
---|
274 | function content_multiple_value_after_build($elements, &$form_state) { |
---|
275 | $items_map = array(); |
---|
276 | |
---|
277 | foreach (element_children($elements) as $delta) { |
---|
278 | // Find delta items for this field when the form if being processed for validation. |
---|
279 | if (isset($elements[$delta]) && $elements[$delta] && is_numeric($delta) && !empty($elements[$delta]['#needs_validation'])) { |
---|
280 | |
---|
281 | // Find items that have been flagged for removal. |
---|
282 | if (isset($elements[$delta]['_remove']) && !empty($elements[$delta]['_remove']['#value'])) { |
---|
283 | |
---|
284 | // Update the value in the #post attribute of the elements. |
---|
285 | $post = &$elements[$delta]['#post']; |
---|
286 | foreach ($elements[$delta]['#parents'] as $name) { |
---|
287 | $post = &$post[$name]; |
---|
288 | } |
---|
289 | $post = array('_weight' => $elements[$delta]['_weight']['#value'], '_remove' => 1); |
---|
290 | |
---|
291 | // Alter the value of this element and children recursively. |
---|
292 | content_multiple_value_after_build_recursive($elements[$delta], $elements[$delta]['#post']); |
---|
293 | |
---|
294 | $items_map[$delta] = TRUE; |
---|
295 | } |
---|
296 | else { |
---|
297 | $items_map[$delta] = FALSE; |
---|
298 | } |
---|
299 | } |
---|
300 | } |
---|
301 | |
---|
302 | // If the multiple values field is required, then make sure there's at |
---|
303 | // least one item not flagged for removal. This is necessary to point |
---|
304 | // the user to the correct form element when the validation error is |
---|
305 | // issued from content_multiple_value_nodeapi_validate(). |
---|
306 | $items_count = count($items_map); |
---|
307 | if (!empty($elements['#required']) && $items_count > 0) { |
---|
308 | // If the number of removed items is equal to the total number of |
---|
309 | // items, then we'll reset the '_remove' flag of the first item, and |
---|
310 | // that will be used to point the user when the required field error |
---|
311 | // is issued by content_multiple_value_nodeapi_validate(). |
---|
312 | if ($items_count == count(array_filter($items_map))) { |
---|
313 | $delta = key($items_map); |
---|
314 | if (isset($elements[$delta]['_remove'])) { |
---|
315 | $elements[$delta]['_remove']['#value'] = 0; |
---|
316 | } |
---|
317 | } |
---|
318 | } |
---|
319 | |
---|
320 | return $elements; |
---|
321 | } |
---|
322 | |
---|
323 | /** |
---|
324 | * Helper function to deal with items flagged for removal recursively. |
---|
325 | */ |
---|
326 | function content_multiple_value_after_build_recursive(&$elements, $post) { |
---|
327 | foreach (element_children($elements) as $key) { |
---|
328 | if (isset($elements[$key]) && $elements[$key] && !in_array($key, array('_weight', '_remove', '_error_element'))) { |
---|
329 | // Recurse through all children elements. |
---|
330 | content_multiple_value_after_build_recursive($elements[$key], $post); |
---|
331 | } |
---|
332 | } |
---|
333 | |
---|
334 | // Remove values for items flagged for removal. |
---|
335 | if (isset($elements['#value'])) { |
---|
336 | $elements['#value'] = NULL; |
---|
337 | form_set_value($elements, NULL, $form_state); |
---|
338 | $elements['#post'] = $post; |
---|
339 | } |
---|
340 | } |
---|
341 | |
---|
342 | /** |
---|
343 | * Implementation of nodeapi('validate') for multiple value fields |
---|
344 | * managed by content module itself. |
---|
345 | */ |
---|
346 | function content_multiple_value_nodeapi_validate(&$node, $field, &$items, $form) { |
---|
347 | $field_name = $field['field_name']; |
---|
348 | |
---|
349 | // Getting the field structure from the form allows other modules alter |
---|
350 | // field properties such as the required attribute. |
---|
351 | $field = $form['#field_info'][$field_name]; |
---|
352 | |
---|
353 | // Get rid of the add more items element. |
---|
354 | unset($items[$field_name .'_add_more']); |
---|
355 | |
---|
356 | // Reorder items to account for drag-n-drop reordering. |
---|
357 | $items = _content_sort_items($field, $items); |
---|
358 | |
---|
359 | // Create a copy of the items before filtering those that are flagged |
---|
360 | // for removal. We need this copy later to obtain the error element. |
---|
361 | $items_copy = $items; |
---|
362 | |
---|
363 | // Filter out items flagged for removal. |
---|
364 | $items = content_set_empty($field, $items); |
---|
365 | |
---|
366 | // Enforce field requirement settings. |
---|
367 | if ($field['required'] && empty($node->_content_ignore_required_fields[$field_name]) && content_access('edit', $field, NULL, $node)) { |
---|
368 | // Count non-empty items. |
---|
369 | $count = 0; |
---|
370 | $function = $field['module'] .'_content_is_empty'; |
---|
371 | foreach ($items as $item) { |
---|
372 | if (!$function($item, $field)) { |
---|
373 | $count++; |
---|
374 | } |
---|
375 | } |
---|
376 | // The field is required so we expect at least one non-empty item. |
---|
377 | if ($count == 0) { |
---|
378 | // Try to guess the element path in the form from the first item that |
---|
379 | // is not flagged for removal. Defaults to first item. |
---|
380 | $error_element_index = 0; |
---|
381 | foreach ($items_copy as $index => $item) { |
---|
382 | if (empty($item['_remove'])) { |
---|
383 | $error_element_index = $index; |
---|
384 | break; |
---|
385 | } |
---|
386 | } |
---|
387 | $error_element = isset($items_copy[$error_element_index]) && is_array($items_copy[$error_element_index]) && isset($items_copy[$error_element_index]['_error_element']) ? $items_copy[$error_element_index]['_error_element'] : ''; |
---|
388 | form_set_error($error_element, t('%name field is required.', array('%name' => t($field['widget']['label'])))); |
---|
389 | } |
---|
390 | } |
---|
391 | } |
---|
392 | |
---|
393 | /** |
---|
394 | * Submit handler to add more choices to a content form. This handler is used when |
---|
395 | * JavaScript is not available. It makes changes to the form state and the |
---|
396 | * entire form is rebuilt during the page reload. |
---|
397 | */ |
---|
398 | function content_add_more_submit($form, &$form_state) { |
---|
399 | // Set the form to rebuild and run submit handlers. |
---|
400 | node_form_submit_build_node($form, $form_state); |
---|
401 | $field_name = $form_state['clicked_button']['#field_name']; |
---|
402 | $type_name = $form_state['clicked_button']['#type_name']; |
---|
403 | |
---|
404 | // Make the changes we want to the form state. |
---|
405 | if ($form_state['values'][$field_name][$field_name .'_add_more']) { |
---|
406 | $form_state['item_count'][$field_name] = count($form_state['values'][$field_name]); |
---|
407 | } |
---|
408 | } |
---|
409 | |
---|
410 | /** |
---|
411 | * Menu callback for AHAH addition of new empty widgets. |
---|
412 | */ |
---|
413 | function content_add_more_js($type_name_url, $field_name) { |
---|
414 | $content_type = content_types($type_name_url); |
---|
415 | $type = content_types($type_name_url); |
---|
416 | $field = content_fields($field_name, $type['type']); |
---|
417 | |
---|
418 | if (($field['multiple'] != 1) || empty($_POST['form_build_id'])) { |
---|
419 | // Invalid request. |
---|
420 | drupal_json(array('data' => '')); |
---|
421 | exit; |
---|
422 | } |
---|
423 | |
---|
424 | // Retrieve the cached form. |
---|
425 | $form_state = array('submitted' => FALSE); |
---|
426 | $form_build_id = $_POST['form_build_id']; |
---|
427 | $form = form_get_cache($form_build_id, $form_state); |
---|
428 | if (!$form) { |
---|
429 | // Invalid form_build_id. |
---|
430 | drupal_json(array('data' => '')); |
---|
431 | exit; |
---|
432 | } |
---|
433 | |
---|
434 | // We don't simply return a new empty widget to append to existing ones, because |
---|
435 | // - ahah.js won't simply let us add a new row to a table |
---|
436 | // - attaching the 'draggable' behavior won't be easy |
---|
437 | // So we resort to rebuilding the whole table of widgets including the existing ones, |
---|
438 | // which makes us jump through a few hoops. |
---|
439 | |
---|
440 | // The form that we get from the cache is unbuilt. We need to build it so that |
---|
441 | // _value callbacks can be executed and $form_state['values'] populated. |
---|
442 | // We only want to affect $form_state['values'], not the $form itself |
---|
443 | // (built forms aren't supposed to enter the cache) nor the rest of $form_data, |
---|
444 | // so we use copies of $form and $form_data. |
---|
445 | $form_copy = $form; |
---|
446 | $form_state_copy = $form_state; |
---|
447 | $form_copy['#post'] = array(); |
---|
448 | form_builder($_POST['form_id'], $form_copy, $form_state_copy); |
---|
449 | // Just grab the data we need. |
---|
450 | $form_state['values'] = $form_state_copy['values']; |
---|
451 | // Reset cached ids, so that they don't affect the actual form we output. |
---|
452 | form_clean_id(NULL, TRUE); |
---|
453 | |
---|
454 | // Sort the $form_state['values'] we just built *and* the incoming $_POST data |
---|
455 | // according to d-n-d reordering. |
---|
456 | unset($form_state['values'][$field_name][$field['field_name'] .'_add_more']); |
---|
457 | foreach ($_POST[$field_name] as $delta => $item) { |
---|
458 | $form_state['values'][$field_name][$delta]['_weight'] = $item['_weight']; |
---|
459 | $form_state['values'][$field_name][$delta]['_remove'] = isset($item['_remove']) ? $item['_remove'] : 0; |
---|
460 | } |
---|
461 | $form_state['values'][$field_name] = _content_sort_items($field, $form_state['values'][$field_name]); |
---|
462 | $_POST[$field_name] = _content_sort_items($field, $_POST[$field_name]); |
---|
463 | |
---|
464 | // Build our new form element for the whole field, asking for one more element. |
---|
465 | $delta = max(array_keys($_POST[$field_name])) + 1; |
---|
466 | $form_state['item_count'] = array($field_name => count($_POST[$field_name]) + 1); |
---|
467 | $form_element = content_field_form($form, $form_state, $field); |
---|
468 | // Let other modules alter it. |
---|
469 | // We pass an empty array as hook_form_alter's usual 'form_state' parameter, |
---|
470 | // instead of $form_atate (for reasons we may never remember). |
---|
471 | // However, this argument is still expected to be passed by-reference |
---|
472 | // (and PHP5.3 will throw an error if it isn't.) This leads to: |
---|
473 | $data = &$form_element; |
---|
474 | $empty_form_state = array(); |
---|
475 | $data['__drupal_alter_by_ref'] = array(&$empty_form_state); |
---|
476 | drupal_alter('form', $data, 'content_add_more_js'); |
---|
477 | |
---|
478 | // Add the new element at the right place in the (original, unbuilt) form. |
---|
479 | $success = content_set_nested_elements($form, $field_name, $form_element[$field_name]); |
---|
480 | |
---|
481 | // Save the new definition of the form. |
---|
482 | $form_state['values'] = array(); |
---|
483 | form_set_cache($form_build_id, $form, $form_state); |
---|
484 | |
---|
485 | // Build the new form against the incoming $_POST values so that we can |
---|
486 | // render the new element. |
---|
487 | $_POST[$field_name][$delta]['_weight'] = $delta; |
---|
488 | $form_state = array('submitted' => FALSE); |
---|
489 | $form += array( |
---|
490 | '#post' => $_POST, |
---|
491 | '#programmed' => FALSE, |
---|
492 | ); |
---|
493 | $form = form_builder($_POST['form_id'], $form, $form_state); |
---|
494 | |
---|
495 | // Render the new output. |
---|
496 | $field_form = array_shift(content_get_nested_elements($form, $field_name)); |
---|
497 | |
---|
498 | // We add a div around the new content to receive the ahah effect. |
---|
499 | $field_form[$delta]['#prefix'] = '<div class="ahah-new-content">'. (isset($field_form[$delta]['#prefix']) ? $field_form[$delta]['#prefix'] : ''); |
---|
500 | $field_form[$delta]['#suffix'] = (isset($field_form[$delta]['#suffix']) ? $field_form[$delta]['#suffix'] : '') .'</div>'; |
---|
501 | // Prevent duplicate wrapper. |
---|
502 | unset($field_form['#prefix'], $field_form['#suffix']); |
---|
503 | |
---|
504 | // If a newly inserted widget contains AHAH behaviors, they normally won't |
---|
505 | // work because AHAH doesn't know about those - it just attaches to the exact |
---|
506 | // form elements that were initially specified in the Drupal.settings object. |
---|
507 | // The new ones didn't exist then, so we need to update Drupal.settings |
---|
508 | // by ourselves in order to let AHAH know about those new form elements. |
---|
509 | $javascript = drupal_add_js(NULL, NULL); |
---|
510 | $output_js = isset($javascript['setting']) ? '<script type="text/javascript">jQuery.extend(Drupal.settings, '. drupal_to_js(call_user_func_array('array_merge_recursive', $javascript['setting'])) .');</script>' : ''; |
---|
511 | |
---|
512 | $output = theme('status_messages') . drupal_render($field_form) . $output_js; |
---|
513 | |
---|
514 | // Using drupal_json() breaks filefield's file upload, because the jQuery |
---|
515 | // Form plugin handles file uploads in a way that is not compatible with |
---|
516 | // 'text/javascript' response type. |
---|
517 | $GLOBALS['devel_shutdown'] = FALSE; |
---|
518 | print drupal_to_js(array('status' => TRUE, 'data' => $output)); |
---|
519 | exit; |
---|
520 | } |
---|