franck@0
|
1 <?php |
franck@0
|
2 // vim: set ts=2 sw=2 expandtab syntax=php: |
franck@0
|
3 |
franck@0
|
4 /** |
franck@0
|
5 * @file |
franck@0
|
6 * Fichier principale du module noderef_view |
franck@0
|
7 * |
franck@0
|
8 * Ce module permet d'ajouter à tous les champs de type "Node Reference" |
franck@1
|
9 * pour lesquels une vue définissant les nodes autorisés a été définie |
franck@1
|
10 * un lien 'Search' affichant la vue dans une popup (via le module Popups API), |
franck@0
|
11 * permettant de choisir les nodes à mettre dans le champ en disposant de la |
franck@1
|
12 * puissance de Views pour la recherche (Exposed Filters notamment). |
franck@0
|
13 */ |
franck@0
|
14 |
franck@0
|
15 /** |
franck@0
|
16 * Implémentation de hook_view_action_info(). |
franck@0
|
17 * |
franck@0
|
18 * On crée une nouvelle action, nommée Select, et qui sera utilisée pour marquer |
franck@0
|
19 * les nodes comme données à utiliser. L'utilisation concrète qui en est faite |
franck@0
|
20 * dans ce module consiste à utiliser ces nœuds selectionés pour les ajouter |
franck@0
|
21 * dans le champ Node Reference étant à l'origine de la recherche. |
franck@0
|
22 */ |
franck@0
|
23 function noderef_view_action_info() { |
franck@0
|
24 return array( |
franck@0
|
25 'noderef_view_select' => array( |
franck@9
|
26 'description' => t('Add selected values to field'), |
franck@0
|
27 'type' => 'node', |
franck@0
|
28 'configurable' => FALSE, |
franck@0
|
29 'hooks' => array( |
franck@0
|
30 'nodeapi' => array() |
franck@0
|
31 ) |
franck@0
|
32 ) |
franck@0
|
33 ); |
franck@0
|
34 } |
franck@0
|
35 |
franck@0
|
36 /** |
franck@0
|
37 * Implémentation concrète de l'action de selection. |
franck@0
|
38 * |
franck@0
|
39 * On vide toute eventuelle selection précédente, puis on passe dans le cookie |
franck@0
|
40 * les informations sur la selection qui a été faite. |
franck@0
|
41 */ |
franck@0
|
42 function noderef_view_select($node, $context) { |
franck@0
|
43 static $count = 0; |
franck@0
|
44 if ($count == 0 && is_array($_COOKIE['noderef'])) { |
franck@0
|
45 // Reset the cookies |
franck@0
|
46 $before = time() - 300; |
franck@15
|
47 foreach ($_COOKIE['noderef'] as $id => $val) { |
franck@0
|
48 setcookie('noderef['. $id .']', 0, $before, '/'); |
franck@0
|
49 } |
franck@0
|
50 } |
franck@0
|
51 $count++; |
franck@0
|
52 $five = time() + 300; |
franck@0
|
53 setrawcookie('noderef['. $node->nid .']', rawurlencode($node->title), $five, '/'); |
franck@11
|
54 drupal_set_message(t('!title added to selection', |
franck@11
|
55 array('!title' => $node->title))); |
franck@0
|
56 } |
franck@0
|
57 |
franck@0
|
58 /** |
franck@0
|
59 * Implémentation de hook_form_alter(). |
franck@0
|
60 * |
franck@0
|
61 * On parcoure tous les formulaires à la recherche d'éventuels champs |
franck@0
|
62 * de type "Node Reference" sur lesquels appliqués nos transformations. |
franck@0
|
63 */ |
franck@0
|
64 function noderef_view_form_alter(&$form, $form_state, $form_id) { |
franck@0
|
65 if (isset($form['type']) && $form_id == $form['type']['#value'] .'_node_form') { |
franck@0
|
66 // That's a node form, get the fields and alter the form if needed |
franck@0
|
67 $fields = content_fields(); |
franck@11
|
68 $alter = _noderef_view_walk_form($form, $fields, $form); |
franck@0
|
69 if ($alter) { |
franck@0
|
70 // We've changed the form, add the JS-behavior and Views CSS |
franck@0
|
71 // (the latter to deal with exposed filters in the popup) |
franck@6
|
72 $path = drupal_get_path('module', 'noderef_view'); |
franck@6
|
73 drupal_add_js($path .'/noderef_view.js'); |
franck@6
|
74 drupal_add_css($path .'/noderef_view.css'); |
franck@0
|
75 drupal_add_css(drupal_get_path('module', 'views') .'/css/views.css'); |
franck@0
|
76 } |
franck@0
|
77 } |
franck@0
|
78 elseif ($form_id == 'views_exposed_form' && isset($_GET['destination'])) { |
franck@0
|
79 // Views "Exposed Filter" forms doesn't preserve destination by default. |
franck@0
|
80 $form['destination'] = array( |
franck@0
|
81 '#type' => 'hidden', |
franck@0
|
82 '#value' => $_GET['destination'] |
franck@0
|
83 ); |
franck@0
|
84 } |
franck@0
|
85 } |
franck@0
|
86 |
franck@0
|
87 /** |
franck@0
|
88 * Parcoure le tableau contenant le formulaire à la recherche |
franck@0
|
89 * d'élement à modifier. |
franck@0
|
90 * @return |
franck@0
|
91 * TRUE si un élement a été modifié, FALSE sinon |
franck@0
|
92 */ |
franck@11
|
93 function _noderef_view_walk_form(&$form, $fields, $items) { |
franck@0
|
94 $alter = FALSE; |
franck@15
|
95 foreach ($items as $key => $item) { |
franck@0
|
96 if (is_array($item)) { |
franck@0
|
97 if (isset($fields[$key])) { |
franck@0
|
98 $alter |= noderef_view_alter_item($form, $key, $fields[$key]); |
franck@0
|
99 } |
franck@0
|
100 else { |
franck@11
|
101 $alter |= _noderef_view_walk_form($form, $fields, $item); |
franck@0
|
102 } |
franck@0
|
103 } |
franck@0
|
104 } |
franck@0
|
105 return $alter; |
franck@0
|
106 } |
franck@0
|
107 |
franck@0
|
108 /** |
franck@0
|
109 * Modification d'un élement en particulier du formulaire. |
franck@0
|
110 * |
franck@0
|
111 * @return |
franck@0
|
112 * TRUE si l'element a été modifié, FALSE sinon. |
franck@0
|
113 */ |
franck@0
|
114 function noderef_view_alter_item(&$form, $key, $field) { |
franck@0
|
115 if (is_array($field) && $field['type'] == 'nodereference') { |
franck@2
|
116 $link = _noderef_view_get_link($field); |
franck@0
|
117 if (!empty($link)) { |
franck@0
|
118 return TRUE; |
franck@0
|
119 } |
franck@0
|
120 } |
franck@0
|
121 return FALSE; |
franck@0
|
122 } |
franck@0
|
123 |
franck@0
|
124 /** |
franck@0
|
125 * Création d'un lien vers une éventuelle vue associé au champ. |
franck@0
|
126 * |
franck@0
|
127 * @return |
franck@0
|
128 * - Un lien vers la vue si une vue est associée |
franck@0
|
129 * - Une chaine vide sinon |
franck@11
|
130 */ |
franck@0
|
131 function _noderef_view_get_link($field) { |
franck@0
|
132 $path = ''; |
franck@0
|
133 // Check if there's a view associated with this field |
franck@0
|
134 if (isset($field['advanced_view']) && $field['advanced_view'] !== '--') { |
franck@0
|
135 $view = views_get_view($field['advanced_view']); |
franck@0
|
136 // Try to find a path for this view, looking at the displays |
franck@13
|
137 if (!is_array($view->display)) { |
franck@13
|
138 return ''; |
franck@13
|
139 } |
franck@0
|
140 $path = ''; |
franck@15
|
141 foreach ($view->display as $display) { |
franck@0
|
142 if (is_array($display->display_options) |
franck@0
|
143 && isset($display->display_options['path'])) { |
franck@0
|
144 $path = $display->display_options['path']; |
franck@2
|
145 break; |
franck@0
|
146 } |
franck@0
|
147 } |
franck@0
|
148 } |
franck@0
|
149 // If we found a view with a suitable display, then link to it |
franck@0
|
150 if (!empty($path)) { |
franck@14
|
151 popups_add_popups(array('.noderef_view_link' => array( |
franck@14
|
152 'noUpdate' => FALSE, |
franck@14
|
153 'noMessage' => FALSE |
franck@14
|
154 ))); |
franck@0
|
155 $options = array( |
franck@14
|
156 'attributes' => array('class' => 'noderef_view_link'), |
franck@0
|
157 'query' => array('destination' => 'node') |
franck@0
|
158 ); |
franck@0
|
159 $path = l(t('Search'), $path, $options); |
franck@0
|
160 } |
franck@2
|
161 return $path; |
franck@0
|
162 } |
franck@0
|
163 |
franck@11
|
164 function noderef_view_theme() { |
franck@11
|
165 return array( |
franck@11
|
166 'noderef_view_autocomplete' => array( |
franck@11
|
167 'arguments' => array('element' => NULL) |
franck@11
|
168 ) |
franck@11
|
169 ); |
franck@11
|
170 } |
franck@11
|
171 |
franck@11
|
172 function noderef_view_widget_info() { |
franck@11
|
173 return array( |
franck@11
|
174 'noderef_view_autocomplete' => array( |
franck@11
|
175 'label' => t('Autocomplete text field with View'), |
franck@11
|
176 'field types' => array('nodereference'), |
franck@11
|
177 'multiple values' => CONTENT_HANDLE_CORE, |
franck@11
|
178 'callbacks' => array( |
franck@11
|
179 'default value' => CONTENT_CALLBACK_DEFAULT, |
franck@11
|
180 ), |
franck@11
|
181 ), |
franck@11
|
182 ); |
franck@11
|
183 } |
franck@11
|
184 |
franck@11
|
185 function noderef_view_elements() { |
franck@11
|
186 return array( |
franck@11
|
187 'noderef_view_autocomplete' => array( |
franck@11
|
188 '#input' => TRUE, |
franck@11
|
189 '#columns' => array('name'), '#delta' => 0, |
franck@11
|
190 '#process' => array('noderef_view_autocomplete_process'), |
franck@11
|
191 '#autocomplete_path' => FALSE, |
franck@11
|
192 ), |
franck@11
|
193 ); |
franck@11
|
194 } |
franck@11
|
195 |
franck@11
|
196 function noderef_view_widget(&$form, &$form_state, $field, $items, $delta = 0) { |
franck@11
|
197 switch ($field['widget']['type']) { |
franck@11
|
198 case 'noderef_view_autocomplete': |
franck@11
|
199 $element = array( |
franck@11
|
200 '#type' => 'noderef_view_autocomplete', |
franck@11
|
201 '#default_value' => isset($items[$delta]) ? $items[$delta] : NULL, |
franck@11
|
202 '#value_callback' => 'nodereference_autocomplete_value', |
franck@11
|
203 ); |
franck@11
|
204 break; |
franck@11
|
205 } |
franck@11
|
206 return $element; |
franck@11
|
207 } |
franck@11
|
208 |
franck@11
|
209 /** |
franck@11
|
210 * Process an individual element. |
franck@11
|
211 * |
franck@11
|
212 * Build the form element. When creating a form using FAPI #process, |
franck@11
|
213 * note that $element['#value'] is already set. |
franck@11
|
214 * |
franck@11
|
215 */ |
franck@11
|
216 function noderef_view_autocomplete_process($element, $edit, $form_state, $form) { |
franck@11
|
217 // The nodereference autocomplete widget doesn't need to create its own |
franck@11
|
218 // element, it can wrap around the text_textfield element and add an autocomplete |
franck@11
|
219 // path and some extra processing to it. |
franck@11
|
220 // Add a validation step where the value can be unwrapped. |
franck@11
|
221 $fields = content_fields(); |
franck@11
|
222 $link = _noderef_view_get_link($fields[$element['#field_name']]); |
franck@11
|
223 $field_key = $element['#columns'][0]; |
franck@11
|
224 $element[$field_key] = array( |
franck@11
|
225 '#type' => 'text_textfield', |
franck@11
|
226 '#default_value' => isset($element['#value']) ? $element['#value'] : '', |
franck@11
|
227 '#autocomplete_path' => 'nodereference/autocomplete/'. $element['#field_name'], |
franck@11
|
228 // The following values were set by the content module and need |
franck@11
|
229 // to be passed down to the nested element. |
franck@11
|
230 '#title' => $element['#title'], |
franck@11
|
231 '#required' => $element['#required'], |
franck@11
|
232 '#description' => $element['#description'], |
franck@11
|
233 '#field_name' => $element['#field_name'], |
franck@11
|
234 '#type_name' => $element['#type_name'], |
franck@11
|
235 '#delta' => $element['#delta'], |
franck@11
|
236 '#columns' => $element['#columns'], |
franck@11
|
237 ); |
franck@11
|
238 if ($link) { |
franck@11
|
239 $element[$field_key]['#noderef_view_link'] = $link; |
franck@11
|
240 $element[$field_key]['#prefix'] = "<div class='noderef-view-wrapper'>"; |
franck@11
|
241 $element[$field_key]['#suffix'] = $link ."</div>"; |
franck@11
|
242 } |
franck@11
|
243 if (empty($element[$field_key]['#element_validate'])) { |
franck@11
|
244 $element[$field_key]['#element_validate'] = array(); |
franck@11
|
245 } |
franck@11
|
246 array_unshift($element[$field_key]['#element_validate'], 'nodereference_autocomplete_validate'); |
franck@11
|
247 |
franck@11
|
248 // Used so that hook_field('validate') knows where to flag an error. |
franck@11
|
249 $element['_error_element'] = array( |
franck@11
|
250 '#type' => 'value', |
franck@11
|
251 // Wrapping the element around a text_textfield element creates a |
franck@11
|
252 // nested element, so the final id will look like 'field-name-0-nid-nid'. |
franck@11
|
253 '#value' => implode('][', array_merge($element['#parents'], array($field_key, $field_key))), |
franck@11
|
254 ); |
franck@11
|
255 return $element; |
franck@11
|
256 } |
franck@11
|
257 |
franck@11
|
258 function theme_noderef_view_autocomplete($element) { |
franck@11
|
259 return <<<EOT |
franck@11
|
260 <div class='noderef-view-wrapper'> |
franck@11
|
261 {$element['#children']} |
franck@11
|
262 {$element['#noderef_view_link']} |
franck@11
|
263 <span class='clear-block'></span> |
franck@11
|
264 </div> |
franck@11
|
265 EOT; |
franck@11
|
266 } |