root / drupal7 / sites / all / modules / ds / ds.api.php @ d719f12f
1 |
<?php
|
---|---|
2 |
|
3 |
/**
|
4 |
* @file
|
5 |
* Hooks provided by Display Suite module.
|
6 |
*/
|
7 |
|
8 |
/**
|
9 |
* @addtogroup hooks
|
10 |
* @{
|
11 |
*/
|
12 |
|
13 |
/**
|
14 |
* Implements hook_ctools_plugin_api().
|
15 |
*/
|
16 |
function hook_test_ctools_plugin_api($module, $api) { |
17 |
if (($module == 'ds' && $api == 'ds') || ($module == 'ds_extras' && $api == 'ds_extras')) { |
18 |
return array('version' => 1); |
19 |
} |
20 |
} |
21 |
|
22 |
/**
|
23 |
* Expose Display Suite field settings.
|
24 |
*
|
25 |
* This hook is called by CTools. For this hook to work, you need
|
26 |
* hook_ctools_plugin_api(). The values of this hook can be overridden
|
27 |
* and reverted through the UI.
|
28 |
*/
|
29 |
function hook_ds_field_settings_info() { |
30 |
$dsfieldsettings = array(); |
31 |
|
32 |
$dsfieldsetting = new stdClass; |
33 |
$dsfieldsetting->disabled = FALSE; /* Edit this to true to make a default dsfieldsetting disabled initially */ |
34 |
$dsfieldsetting->api_version = 1; |
35 |
$dsfieldsetting->id = 'node|article|default'; |
36 |
$dsfieldsetting->entity_type = 'node'; |
37 |
$dsfieldsetting->bundle = 'article'; |
38 |
$dsfieldsetting->view_mode = 'default'; |
39 |
$dsfieldsetting->settings = array( |
40 |
'title' => array( |
41 |
'weight' => '0', |
42 |
'label' => 'hidden', |
43 |
'format' => 'default', |
44 |
'formatter_settings' => array( |
45 |
'link' => '1', |
46 |
'wrapper' => 'h3', |
47 |
'class' => '', |
48 |
), |
49 |
), |
50 |
'node_link' => array( |
51 |
'weight' => '1', |
52 |
'label' => 'hidden', |
53 |
'format' => 'default', |
54 |
), |
55 |
); |
56 |
$dsfieldsettings['node|article|default'] = $dsfieldsetting; |
57 |
|
58 |
return $dsfieldsettings; |
59 |
} |
60 |
|
61 |
/**
|
62 |
* Expose default layout settings info.
|
63 |
*
|
64 |
* This hook is called by CTools. For this hook to work, you need
|
65 |
* hook_ctools_plugin_api(). The values of this hook can be overridden
|
66 |
* and reverted through the UI.
|
67 |
*/
|
68 |
function hook_ds_layout_settings_info() { |
69 |
$dslayouts = array(); |
70 |
|
71 |
$dslayout = new stdClass; |
72 |
$dslayout->disabled = FALSE; /* Edit this to true to make a default dslayout disabled initially */ |
73 |
$dslayout->api_version = 1; |
74 |
$dslayout->id = 'node|article|default'; |
75 |
$dslayout->entity_type = 'node'; |
76 |
$dslayout->bundle = 'article'; |
77 |
$dslayout->view_mode = 'default'; |
78 |
$dslayout->layout = 'ds_2col'; |
79 |
$dslayout->settings = array( |
80 |
'hide_empty_regions' => 0, |
81 |
'regions' => array( |
82 |
'left' => array( |
83 |
0 => 'title', |
84 |
1 => 'node_link', |
85 |
), |
86 |
'right' => array( |
87 |
0 => 'body', |
88 |
), |
89 |
), |
90 |
'fields' => array( |
91 |
'title' => 'left', |
92 |
'node_link' => 'left', |
93 |
'body' => 'right', |
94 |
), |
95 |
'classes' => array(), |
96 |
); |
97 |
$dslayouts['node|article|default'] = $dslayout; |
98 |
|
99 |
return $dslayouts; |
100 |
} |
101 |
|
102 |
/**
|
103 |
* Expose default view modes.
|
104 |
*
|
105 |
* This hook is called by CTools. For this hook to work, you need
|
106 |
* hook_ctools_plugin_api(). The values of this hook can be overridden
|
107 |
* and reverted through the UI.
|
108 |
*/
|
109 |
function hook_ds_view_modes_info() { |
110 |
$ds_view_modes = array(); |
111 |
|
112 |
$ds_view_mode = new stdClass; |
113 |
$ds_view_mode->disabled = FALSE; /* Edit this to true to make a default ds_view_mode disabled initially */ |
114 |
$ds_view_mode->api_version = 1; |
115 |
$ds_view_mode->view_mode = 'test_exportables'; |
116 |
$ds_view_mode->label = 'Test exportables'; |
117 |
$ds_view_mode->entities = array( |
118 |
'node' => 'node', |
119 |
); |
120 |
$ds_view_modes['test_exportables'] = $ds_view_mode; |
121 |
|
122 |
return $ds_view_modes; |
123 |
} |
124 |
|
125 |
/**
|
126 |
* Define fields. These fields are not overridable through the interface.
|
127 |
* If you want those, look at hook_ds_custom_fields_info().
|
128 |
*
|
129 |
* @param $entity_type
|
130 |
* The name of the entity which we are requesting fields for, e.g. 'node'.
|
131 |
*
|
132 |
* @return $fields
|
133 |
* A collection of fields which keys are the entity type name and values
|
134 |
* a collection fields.
|
135 |
*
|
136 |
* @see ds_get_fields()
|
137 |
*/
|
138 |
function hook_ds_fields_info($entity_type) { |
139 |
$fields = array(); |
140 |
|
141 |
$fields['title'] = array( |
142 |
|
143 |
// title: title of the field
|
144 |
'title' => t('Title'), |
145 |
|
146 |
// type: type of field
|
147 |
// - DS_FIELD_TYPE_THEME : calls a theming function.
|
148 |
// - DS_FIELD_TYPE_FUNCTION : calls a custom function.
|
149 |
// - DS_FIELD_TYPE_CODE : calls ds_render_code_field().
|
150 |
// - DS_FIELD_TYPE_BLOCK : calls ds_render_block_field().
|
151 |
// - DS_FIELD_TYPE_PREPROCESS : calls nothing, just takes a key from the
|
152 |
// variable field that is passed on.
|
153 |
// - DS_FIELD_TYPE_IGNORE : calls nothing, use this if you simple want
|
154 |
// to drag and drop. The field itself will have
|
155 |
// a theme function.
|
156 |
'field_type' => DS_FIELD_TYPE_FUNCTION, |
157 |
|
158 |
// ui_limit : only used for the manage display screen so
|
159 |
// you can limit fields to show based on bundles or view modes
|
160 |
// the values are always in the form of $bundle|$view_mode
|
161 |
// You may use * to select all.
|
162 |
// Make sure you use the machine name.
|
163 |
'ui_limit' => array('article|full', '*|search_index'), |
164 |
|
165 |
// file: an optional file in which the function resides.
|
166 |
// Only for DS_FIELD_TYPE_FUNCTION.
|
167 |
'file' => 'optional_filename', |
168 |
|
169 |
// function: only for DS_FIELD_TYPE_FUNCTION.
|
170 |
'function' => 'theme_ds_title_field', |
171 |
|
172 |
// properties: can have different keys.
|
173 |
'properties' => array( |
174 |
|
175 |
// formatters: optional if a function is used.
|
176 |
// In case the field_type is DS_FIELD_TYPE_THEME, you also
|
177 |
// need to register these formatters as a theming function
|
178 |
// since the key will be called with theme('function').
|
179 |
// The value is the caption used in the selection config on Field UI.
|
180 |
'formatters' => array( |
181 |
'node_title_nolink_h1' => t('H1 title'), |
182 |
'node_title_link_h1' => t('H1 title, linked to node'), |
183 |
), |
184 |
|
185 |
// settings & default: optional if you have a settings form for your field.
|
186 |
'settings' => array( |
187 |
'wrapper' => array('type' => 'textfield', 'description' => t('Eg: h1, h2, p')), |
188 |
'link' => array('type' => 'select', 'options' => array('yes', 'no')), |
189 |
), |
190 |
'default' => array('wrapper' => 'h2', 'link' => 0), |
191 |
|
192 |
// code: optional, only for code field.
|
193 |
'code' => 'my code here', |
194 |
|
195 |
// use_token: optional, only for code field.
|
196 |
'use_token' => TRUE, // or FALSE, |
197 |
|
198 |
// block: the module and delta of the block, only for block fields.
|
199 |
//
|
200 |
// @note: Display Suite uses a "|" token to split the module from
|
201 |
// the delta.
|
202 |
'block' => 'user|menu', |
203 |
|
204 |
// block_render: block render type, only for block fields.
|
205 |
// - DS_BLOCK_CONTENT : render through block template file.
|
206 |
// - DS_BLOCK_TITLE_CONTENT : render only title and content.
|
207 |
// - DS_BLOCK_CONTENT : render only content.
|
208 |
'block_render' => DS_BLOCK_CONTENT, |
209 |
) |
210 |
); |
211 |
|
212 |
return array('node' => $fields); |
213 |
|
214 |
} |
215 |
|
216 |
/**
|
217 |
* Define custom fields which can be overridden through the UI and which
|
218 |
* are exportable. The keys are almost the same as in hook_ds_fields_info()
|
219 |
* except that field_type is limited and you need an entities key.
|
220 |
*
|
221 |
* This hook is called by CTools. For this hook to work, you need
|
222 |
* hook_ctools_plugin_api(). The values of this hook can be overridden
|
223 |
* and reverted through the UI.
|
224 |
*/
|
225 |
function hook_ds_custom_fields_info() { |
226 |
$ds_fields = array(); |
227 |
|
228 |
$ds_field = new stdClass; |
229 |
$ds_field->api_version = 1; |
230 |
$ds_field->field = 'custom_field'; |
231 |
$ds_field->label = 'Custom field'; |
232 |
|
233 |
// Field type: either block or code
|
234 |
// DS_FIELD_TYPE_CODE: 5
|
235 |
// DS_FIELD_TYPE_BLOCK: 6
|
236 |
$ds_field->field_type = 5; |
237 |
|
238 |
// Collection of entities on which this custom field can work on.
|
239 |
$ds_field->entities = array( |
240 |
'node' => 'node', |
241 |
); |
242 |
$ds_field->properties = array( |
243 |
'code' => array( |
244 |
'value' => '<?php print "this is a custom field"; ?>', |
245 |
'format' => 'ds_code', |
246 |
), |
247 |
'use_token' => 0, |
248 |
); |
249 |
$ds_fields['custom_field'] = $ds_field; |
250 |
|
251 |
return $ds_fields; |
252 |
} |
253 |
|
254 |
/**
|
255 |
* Expose Views layouts definitions.
|
256 |
*
|
257 |
* This hook is called by CTools. For this hook to work, you need
|
258 |
* hook_ctools_plugin_api(). The values of this hook can be overridden
|
259 |
* and reverted through the UI.
|
260 |
*/
|
261 |
function hook_ds_vd_info() { |
262 |
$ds_vds = array(); |
263 |
|
264 |
$ds_vd = new stdClass; |
265 |
$ds_vd->api_version = 1; |
266 |
$ds_vd->vd = 'frontpage-page'; |
267 |
$ds_vd->label = 'Frontpage: Views displays'; |
268 |
$ds_vds['frontpage-page'] = $ds_vd; |
269 |
|
270 |
return $ds_vds; |
271 |
} |
272 |
|
273 |
/**
|
274 |
* Alter fields defined by Display Suite.
|
275 |
*
|
276 |
* This function is called for each entity type.
|
277 |
*
|
278 |
* @param $fields
|
279 |
* An array with fields which can be altered just before they get cached.
|
280 |
* @param $entity_type
|
281 |
* The name of the entity type.
|
282 |
*/
|
283 |
function hook_ds_fields_info_alter(&$fields, $entity_type) { |
284 |
if (isset($fields['title'])) { |
285 |
$fields['title']['title'] = t('My title'); |
286 |
} |
287 |
} |
288 |
|
289 |
/**
|
290 |
* Alter fields defined by Display Suite just before they get
|
291 |
* rendered on the Field UI. Use this hook to inject fields
|
292 |
* which you can't alter with hook_ds_fields_info_alter().
|
293 |
*
|
294 |
* Use this in edge cases, see ds_extras_ds_fields_ui_alter()
|
295 |
* which adds fields chosen in Views UI. This also runs
|
296 |
* when a layout has been chosen.
|
297 |
*
|
298 |
* @param $fields
|
299 |
* An array with fields which can be altered just before they get cached.
|
300 |
* @param $entity_type
|
301 |
* The name of the entity type.
|
302 |
*/
|
303 |
function hook_ds_fields_ui_alter(&$fields, $context) { |
304 |
$fields['title'] = t('Extra title'); |
305 |
} |
306 |
|
307 |
/**
|
308 |
* Define theme functions for fields.
|
309 |
*
|
310 |
* This only is necessary when you're using the field settings
|
311 |
* plugin which comes with the DS extras module and you want to
|
312 |
* expose a special field theming function to the interface.
|
313 |
*
|
314 |
* The theme function gets $variables as the only parameter.
|
315 |
* The optional configuration through the UI is in $variables['ds-config'].
|
316 |
*
|
317 |
* Note that 'theme_ds_field_' is always needed, so the suggestions can work.
|
318 |
*
|
319 |
* @return $field_theme_functions
|
320 |
* A collection of field theming functions.
|
321 |
*/
|
322 |
function hook_ds_field_theme_functions_info() { |
323 |
return array('theme_ds_field_mine' => t('Theme field')); |
324 |
} |
325 |
|
326 |
/**
|
327 |
* Return configuration summary for the field format.
|
328 |
*
|
329 |
* As soon as you have hook_ds_fields and one of the fields
|
330 |
* has a settings key, Display Suite will call this hook for the summary.
|
331 |
*
|
332 |
* @param $field
|
333 |
* The configuration of the field.
|
334 |
*
|
335 |
* @return $summary
|
336 |
* The summary to show on the Field UI.
|
337 |
*/
|
338 |
function hook_ds_field_format_summary($field) { |
339 |
return 'Field summary'; |
340 |
} |
341 |
|
342 |
/**
|
343 |
* Return a settings form for a Display Suite field.
|
344 |
*
|
345 |
* As soon as you have hook_ds_fields and one of the fields
|
346 |
* has a settings key, Display Suite will call this hook for field form.
|
347 |
*
|
348 |
* @param $field
|
349 |
* The configuration of the field.
|
350 |
*
|
351 |
* @return $form
|
352 |
* A form definition.
|
353 |
*/
|
354 |
function hook_ds_field_settings_form($field) { |
355 |
|
356 |
// Saved formatter settings are on $field['formatter_settings'];
|
357 |
$settings = isset($field['formatter_settings']) ? $field['formatter_settings'] : $field['properties']['default']; |
358 |
|
359 |
$form['label'] = array( |
360 |
'#type' => 'textfield', |
361 |
'#title' => t('Label'), |
362 |
'#default_value' => $settings['label'], |
363 |
); |
364 |
} |
365 |
|
366 |
/**
|
367 |
* Modify the layout settings just before they get saved.
|
368 |
*
|
369 |
* @param $record
|
370 |
* The record just before it gets saved into the database.
|
371 |
* @param $form_state
|
372 |
* The form_state values.
|
373 |
*/
|
374 |
function hook_ds_layout_settings_alter($record, $form_state) { |
375 |
$record->settings['hide_page_title'] = TRUE; |
376 |
} |
377 |
|
378 |
/**
|
379 |
* Modify the field settings before they get saved.
|
380 |
*
|
381 |
* @param $field_settings
|
382 |
* A collection of field settings which keys are fields.
|
383 |
* @param $form
|
384 |
* The current form which is submitted.
|
385 |
* @param $form_state
|
386 |
* The form state with all its values.
|
387 |
*/
|
388 |
function hook_ds_field_settings_alter(&$field_settings, $form, $form_state) { |
389 |
$field_settings['title']['region'] = 'left'; |
390 |
} |
391 |
|
392 |
/**
|
393 |
* Define layouts from code.
|
394 |
*
|
395 |
* @return $layouts
|
396 |
* A collection of layouts.
|
397 |
*/
|
398 |
function hook_ds_layout_info() { |
399 |
$path = drupal_get_path('module', 'foo'); |
400 |
|
401 |
$layouts = array( |
402 |
'foo_1col' => array( |
403 |
'label' => t('Foo one column'), |
404 |
'path' => $path . '/layouts/foo_1col', |
405 |
'regions' => array( |
406 |
'foo_content' => t('Content'), |
407 |
), |
408 |
'css' => TRUE, |
409 |
// optional, form only applies to node form at this point.
|
410 |
'form' => TRUE, |
411 |
), |
412 |
); |
413 |
|
414 |
return $layouts; |
415 |
} |
416 |
|
417 |
/**
|
418 |
* Alter the layout render array.
|
419 |
*
|
420 |
* @param $layout_render_array
|
421 |
* The render array
|
422 |
* @param $context
|
423 |
* An array with the context that is being rendered. Available keys are
|
424 |
* - entity
|
425 |
* - entity_type
|
426 |
* - bundle
|
427 |
* - view_mode
|
428 |
* @param array $vars
|
429 |
* All variables available for render. You can use this to add css classes.
|
430 |
*/
|
431 |
function hook_ds_pre_render_alter(&$layout_render_array, $context, &$vars) { |
432 |
$layout_render_array['left'][] = array('#markup' => 'cool!', '#weight' => 20); |
433 |
$vars['attributes_array']['class'][] = 'custom'; |
434 |
} |
435 |
|
436 |
/**
|
437 |
* Alter layouts found by Display Suite.
|
438 |
*
|
439 |
* @param $layouts
|
440 |
* A array of layouts which keys are the layout and which values are
|
441 |
* properties of that layout (label, path, regions and css).
|
442 |
*/
|
443 |
function hook_ds_layout_info_alter(&$layouts) { |
444 |
unset($layouts['ds_2col']); |
445 |
} |
446 |
|
447 |
/**
|
448 |
* Alter the region options in the field UI screen.
|
449 |
*
|
450 |
* This function is only called when a layout has been chosen.
|
451 |
*
|
452 |
* @param $context
|
453 |
* A collection of keys for the context. The keys are 'entity_type',
|
454 |
* 'bundle' and 'view_mode'.
|
455 |
* @param $region_info
|
456 |
* A collection of info for regions. The keys are 'region_options'
|
457 |
* and 'table_regions'.
|
458 |
*/
|
459 |
function hook_ds_layout_region_alter($context, &$region_info) { |
460 |
$region_info['region_options'][$block_key] = $block['title']; |
461 |
$region_info['table_regions'][$block_key] = array( |
462 |
'title' => check_plain($block['title']), |
463 |
'message' => t('No fields are displayed in this region'), |
464 |
); |
465 |
} |
466 |
|
467 |
/**
|
468 |
* Alter the field label options. Note that you will either
|
469 |
* update the preprocess functions or the field.tpl.php file when
|
470 |
* adding new options.
|
471 |
*
|
472 |
* @param $field_label_options
|
473 |
* A collection of field label options.
|
474 |
*/
|
475 |
function hook_ds_label_options_alter(&$field_label_options) { |
476 |
$field_label_options['label_after'] = t('Label after field'); |
477 |
} |
478 |
|
479 |
/**
|
480 |
* Themes can also define extra layouts.
|
481 |
*
|
482 |
* Create a ds_layouts folder and then a folder name that will
|
483 |
* be used as key for the layout. The folder should at least have 2 files:
|
484 |
*
|
485 |
* - key.inc
|
486 |
* - key.tpl.php
|
487 |
*
|
488 |
* The css file is optional.
|
489 |
* - key.css
|
490 |
*
|
491 |
* e.g.
|
492 |
* bartik/ds_layouts/bartik_ds/bartik_ds.inc
|
493 |
* /bartik-ds.tpl.php
|
494 |
* /bartik_ds.css
|
495 |
*
|
496 |
* bartik_ds.inc must look like this:
|
497 |
*
|
498 |
|
499 |
// Fuction name is ds_LAYOUT_KEY
|
500 |
function ds_bartik_ds() {
|
501 |
return array(
|
502 |
'label' => t('Bartik DS'),
|
503 |
'regions' => array(
|
504 |
// The key of this region name is also the variable used in
|
505 |
// the template to print the content of that region.
|
506 |
'bartik' => t('Bartik DS'),
|
507 |
),
|
508 |
// Add this if there is a default css file.
|
509 |
'css' => TRUE,
|
510 |
// Add this if there is a default preview image
|
511 |
'image' => TRUE,
|
512 |
);
|
513 |
}
|
514 |
|
515 |
*/
|
516 |
|
517 |
/**
|
518 |
* Alter the view mode just before it's rendered by the DS views entity plugin.
|
519 |
*
|
520 |
* @param $view_mode
|
521 |
* The name of the view mode.
|
522 |
* @param $context
|
523 |
* A collection of items which can be used to identify in what
|
524 |
* context an entity is being rendered. The variable contains 3 keys:
|
525 |
* - entity: The entity being rendered.
|
526 |
* - view_name: the name of the view.
|
527 |
* - display: the name of the display of the view.
|
528 |
*/
|
529 |
function hook_ds_views_view_mode_alter(&$view_mode, $context) { |
530 |
if ($context['view_name'] == 'my_view_name') { |
531 |
$view_mode = 'new_view_mode'; |
532 |
} |
533 |
} |
534 |
|
535 |
/**
|
536 |
* Theme an entity coming from the views entity plugin.
|
537 |
*
|
538 |
* @param $entity
|
539 |
* The complete entity.
|
540 |
* @param $view_mode
|
541 |
* The name of the view mode.
|
542 |
*/
|
543 |
function ds_views_row_ENTITY_NAME($entity, $view_mode) { |
544 |
$nid = $vars['row']->{$vars['field_alias']}; |
545 |
$node = node_load($nid); |
546 |
$element = node_view($node, $view_mode); |
547 |
return drupal_render($element); |
548 |
} |
549 |
|
550 |
/**
|
551 |
* Theme an entity through an advanced function coming from the views entity plugin.
|
552 |
*
|
553 |
* @param $vars
|
554 |
* An array of variables from the views preprocess functions.
|
555 |
* @param $view_mode
|
556 |
* The name of the view mode.
|
557 |
*/
|
558 |
function ds_views_row_adv_VIEWS_NAME(&$vars, $view_mode) { |
559 |
// You can do whatever you want to here.
|
560 |
$vars['object'] = 'This is what I want for christmas.'; |
561 |
} |
562 |
|
563 |
/**
|
564 |
* Modify the entity render array in the context of a view.
|
565 |
*
|
566 |
* @param array $content
|
567 |
* By reference. An entity view render array.
|
568 |
* @param array $context
|
569 |
* By reference. An associative array containing:
|
570 |
* - row: The current active row object being rendered.
|
571 |
* - view: By reference. The current view object.
|
572 |
* - view_mode: The view mode which is set in the Views' options.
|
573 |
* - load_comments: The same param passed to each row function.
|
574 |
*
|
575 |
* @see ds_views_row_render_entity()
|
576 |
*/
|
577 |
function hook_ds_views_row_render_entity_alter(&$content, &$context) { |
578 |
if ($context['view_mode'] == 'my_mode') { |
579 |
// Modify the view, or the content render array in the context of a view.
|
580 |
$view = &$context['view']; |
581 |
$element = &drupal_array_get_nested_value($content, array('field_example', 0)); |
582 |
} |
583 |
} |
584 |
|
585 |
/**
|
586 |
* Alter the strings used to separate taxonomy terms.
|
587 |
*/
|
588 |
function hook_ds_taxonomy_term_separators(&$separators) { |
589 |
// Remove the option to use a hyphen.
|
590 |
unset($separators[' - ']); |
591 |
// Add the option to use a pipe.
|
592 |
$separators[' | '] = t('pipe'); |
593 |
} |
594 |
|
595 |
/**
|
596 |
* Allow modules to provide additional classes for regions and layouts.
|
597 |
*/
|
598 |
function hook_ds_classes_alter(&$classes, $name) { |
599 |
if ('ds_classes_regions' === $name) { |
600 |
$classes['css-class-name'] = t('Custom Styling'); |
601 |
} |
602 |
} |
603 |
|
604 |
/**
|
605 |
* Alter the field template settings form
|
606 |
*
|
607 |
* @param array $form
|
608 |
* The form containing the field settings
|
609 |
* @param array $field_settings
|
610 |
* The settings of the field
|
611 |
*/
|
612 |
function hook_ds_field_theme_functions_settings_alter(&$form, $field_settings) { |
613 |
$form['something'] = array( |
614 |
'#type' => 'textfield', |
615 |
'#title' => 'test', |
616 |
); |
617 |
} |
618 |
|
619 |
/*
|
620 |
* @} End of "addtogroup hooks".
|
621 |
*/
|