This repository was archived by the owner on May 9, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathajax.inc
More file actions
220 lines (197 loc) · 7.21 KB
/
ajax.inc
File metadata and controls
220 lines (197 loc) · 7.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
<?php
/**
* @file
* Helpers for the Drupal Ajax framework. When in a form context you probably
* want to include this file as follows:
*
* cm_tools_form_include($form_state, 'ajax');
*/
/**
* Create a Drupal Ajax command which removes any messages on the page already.
*
* @return An array suitable for use with the ajax_render() function.
*/
function ajax_command_remove_messages() {
// If you want to add anything to the page which gets removed at the same
// time that messages are removed, give it the 'remove-with-messages' class.
return ajax_command_remove('.messages, .remove-with-messages');
}
/**
* Create a Drupal Ajax command which renders messages at the top.
*
* @return An array suitable for use with the ajax_render() function.
*/
function ajax_command_prepend_messages() {
return ajax_command_prepend(NULL, theme('status_messages'));
}
/**
* A re-usable #ajax callback which allows the triggering element to specify
* which ajax_commands to run, saving the need for lots and lots of callbacks.
*
* If an '#ajax_command' parameter is an array with first element '/' then it is
* regarded as an #array_parents-esque array indicating part of the form. As
* such, that part of the rebuilt form will be passed to the ajax_command
* callback in its place. See example below.
*
* The return value of each ajax command callback will be ignored if does not
* conform to the syntax of a drupal ajax command (i.e. a non-empty array). This
* allows arbitrary other callbacks to be used also. For example the following
* entry will silently bin all drupal messages:
*
* 'theme' => array('status_messages'),
*
* @code
* <?php
* cm_tools_form_include($form_state, 'ajax');
*
* $form['myelement'] = array(
* '#type' => 'submit',
* '#value' => t('Hello'),
* '#ajax' => array(
* 'wrapper' => $myuniquewrapperhtmlid,
* 'callback' => 'cm_tools_ajax_callback_commands',
* ),
* '#executes_submit_callback' => TRUE|FALSE,
* '#limit_validation_errors' => array(),
*
* // AJAX commands to return to the browser when this button is clicked
* // (These are *not* used when form validation failed - something only
* // relevant when '#executes_submit_callback' is TRUE, see below):
*
* '#ajax_commands' => array(
*
* // Replace our ['#ajax']['wrapper'] div with part of the form:
* 'ajax_command_insert' => array(NULL, array('/', 'path', 'to', 'el')),
*
* // Refresh any drupal messages on the page:
* 'ajax_command_remove_messages' => array(),
* 'ajax_command_prepend_messages' => array(),
*
* // OR perhaps we want to just silently bin all drupal messages so they
* // do not show here, nor on any subsequent page load:
* 'theme' => array('status_messages'),
* ),
*
* // AJAX commands to return instead of the above when validation failed
* // (Only relevant where '#executes_submit_callback' is TRUE):
* '#ajax_invalid_commands' => array(
* ),
* );
*/
function cm_tools_ajax_callback_commands(&$form, &$form_state) {
$commands = array();
// Support arbitrary ajax commands.
$triggering_element_commands = NULL;
if (isset($form_state['triggering_element']['#ajax_commands'])) {
$triggering_element_commands = $form_state['triggering_element']['#ajax_commands'];
}
// If there were errors (in cases where validation occured), then we take our
// ajax commands from a different place - #ajax_invalid_commands.
if (form_get_errors()) {
$triggering_element_commands = NULL;
if (isset($form_state['triggering_element']['#ajax_invalid_commands'])) {
$triggering_element_commands = $form_state['triggering_element']['#ajax_invalid_commands'];
}
}
// If no ajax commands are specified, default to at least printing messages.
if (!isset($triggering_element_commands)) {
$triggering_element_commands['ajax_command_remove_messages'] = array();
$triggering_element_commands['ajax_command_prepend_messages'] = array();
}
if (!empty($triggering_element_commands)) {
foreach ($triggering_element_commands as $function => $parameters) {
// This line allows people to call the same callback twice in the same
// array by affixing spaces. A drawback of using array keys to indicate
// function names.
$function = trim($function);
if (is_callable($function)) {
// Support #array_parents-esque args, these are indicated by an array
// value with '/' as the first value.
foreach ($parameters as $k => $p) {
if (is_array($p) && $p[0] === '/') {
$single = FALSE;
if (!is_array($p[1])) {
$single = TRUE;
$parameters[$k] = array('/', array_slice($parameters[$k], 1));
}
array_shift($parameters[$k]);
foreach ($parameters[$k] as $pk => $array_parents) {
$parameters[$k][$pk] = cm_tools_form_get_relative_element($array_parents, $form, $form_state['triggering_element'], TRUE);
if (empty($parameters[$k][$pk])) {
$parameters[$k][$pk] = NULL;
}
else {
$parameters[$k][$pk] = drupal_render($parameters[$k][$pk]);
}
}
if ($single) {
$parameters[$k] = reset($parameters[$k]);
}
}
}
$command = call_user_func_array($function, $parameters);
if (!empty($command) && is_array($command)) {
$commands[] = $command;
}
}
}
}
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
/**
* Filters a given FAPI 'parents' property, allowing it to specify
* it's parents relatively using '.' and '..' prefixes.
*
* @param $parents array of the format:
* array('path', 'to', 'another_element')
* OR array('..', '..', 'relative', 'path')
*
* @param $form
* The whole form in which the relative element could reside
*
* @param $root_element
* The root element from which relative paths should be resolved.
*
* @param $return_element
* (Optional) If TRUE then the actual form element will be returned
* and not just the #parents array describing its location.
*
* Note. This function will only work once all elements have had their #parents
* set. This is after the #process callbacks have been executed.
*
* @return The #parents of the element being referenced.
*/
function cm_tools_form_get_relative_element($parents, $form, $root_element, $return_element = FALSE) {
if (isset($parents)) {
reset($parents);
$root = NULL;
while (!empty($parents) && ($parent = reset($parents)) && substr($parent, 0, 1) == '.') {
array_shift($parents);
if (!isset($root)) {
$root = $root_element['#parents'];
}
switch ($parent) {
case '..':
if (!empty($root)) {
array_pop($root);
}
break;
}
}
// This means that the path was never relative
// Just return the $parents directly
if (empty($root)) {
$root = array();
}
if ($return_element) {
return drupal_array_get_nested_value($form, array_merge($root, $parents));
}
else {
return array_merge($root, $parents);
}
}
return $parents;
}