field_group.api.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. <?php
  2. /**
  3. * @file
  4. * Hooks provided by the Field group module.
  5. *
  6. * Fieldgroup is a module that will wrap fields and other fieldgroups. Nothing more, nothing less.
  7. * For this there are formatters we can create on forms and view modes.
  8. *
  9. * Some of the elements defined in fieldgroup will be ported to the elements module.
  10. *
  11. * DEVELOPERS NOTES
  12. *
  13. * - Fieldgroup uses a ''#fieldgroups' property to know what fieldgroups are to be pre_rendered and
  14. * rendered by the field_group module. This means we need to be sure our groups are in #fieldgroups.
  15. * #fieldgroups is later merged with the normal #groups that can be used by any other module.
  16. * This is done to be sure fieldgroup is not taking fieldsets from profile2, commerce line items,
  17. * commerce user profiles, ... .
  18. * When trying to merge a programmatically created field wrapper (div, markup, fieldset, ...) into
  19. * groups, you might consider adding it in #field_groups as well if you want the element processed
  20. * by fieldgroup.
  21. */
  22. /**
  23. * @addtogroup hooks
  24. * @{
  25. */
  26. /**
  27. * Javascript hooks
  28. *
  29. * Drupal.FieldGroup.Effects.processHook.execute()
  30. * See field_group.js for the examples for all implemented formatters.
  31. */
  32. /**
  33. * Implements hook_field_group_formatter_info().
  34. *
  35. * Define the information on formatters. The formatters are
  36. * separated by view mode type. We have "form" for all form elements
  37. * and "display" will be the real view modes (full, teaser, sticky, ...)
  38. *
  39. * structure:
  40. * @code
  41. * array(
  42. * 'form' => array(
  43. * 'fieldset' => array(
  44. * // required, String with the name of the formatter type.
  45. * 'label' => t('Fieldset'),
  46. * // optional, String description of the formatter type.
  47. * 'description' => t('This is field group that ...'),
  48. * // required, Array of available formatter options.
  49. * 'format_types' => array('open', 'collapsible', 'collapsed'),
  50. * // required, String with default value of the style.
  51. 'default_formatter' => 'collapsible',
  52. * // optional, Array with key => default_value pairs.
  53. * 'instance_settings' => array('key' => 'value'),
  54. * ),
  55. * ),
  56. * 'display' => array(
  57. * 'fieldset' => array(
  58. * // required, String with the name of the formatter type.
  59. * 'label' => t('Fieldset'),
  60. * // optional, String description of the formatter type.
  61. * 'description' => t('This is field group that ...'),
  62. * // required, Array of available formatter options.
  63. * 'format_types' => array('open', 'collapsible', 'collapsed'),
  64. * // required, String with default value of the style.
  65. 'default_formatter' => 'collapsible',
  66. * // optional, Array with key => default_value pairs.
  67. * 'instance_settings' => array('key' => 'value'),
  68. * ),
  69. * ),
  70. * ),
  71. * @endcode
  72. *
  73. * @return $formatters
  74. * A collection of available formatting html controls for form
  75. * and display overview type.
  76. *
  77. * @see field_group_field_group_formatter_info()
  78. */
  79. function hook_field_group_formatter_info() {
  80. return array(
  81. 'form' => array(
  82. 'fieldset' => array(
  83. 'label' => t('Fieldset'),
  84. 'description' => t('This fieldgroup renders the inner content in a fieldset with the titel as legend.'),
  85. 'format_types' => array('open', 'collapsible', 'collapsed'),
  86. 'instance_settings' => array('classes' => ''),
  87. 'default_formatter' => 'collapsible',
  88. ),
  89. ),
  90. 'display' => array(
  91. 'div' => array(
  92. 'label' => t('Div'),
  93. 'description' => t('This fieldgroup renders the inner content in a simple div with the titel as legend.'),
  94. 'format_types' => array('open', 'collapsible', 'collapsed'),
  95. 'instance_settings' => array('effect' => 'none', 'speed' => 'fast', 'classes' => ''),
  96. 'default_formatter' => 'collapsible',
  97. ),
  98. ),
  99. );
  100. }
  101. /**
  102. * Implements hook_field_group_format_settings().
  103. *
  104. * Defines configuration widget for the settings on a field group
  105. * formatter. Eache formatter can have different elements and storage.
  106. *
  107. * @params Object $group The group object.
  108. * @return Array $form The form element for the format settings.
  109. */
  110. function hook_field_group_format_settings($group) {
  111. // Add a wrapper for extra settings to use by others.
  112. $form = array(
  113. 'instance_settings' => array(
  114. '#tree' => TRUE,
  115. '#weight' => 2,
  116. ),
  117. );
  118. $field_group_types = field_group_formatter_info();
  119. $mode = $group->mode == 'form' ? 'form' : 'display';
  120. $formatter = $field_group_types[$mode][$group->format_type];
  121. // Add the required formatter type selector.
  122. if (isset($formatter['format_types'])) {
  123. $form['formatter'] = array(
  124. '#title' => t('Fieldgroup settings'),
  125. '#type' => 'select',
  126. '#options' => drupal_map_assoc($formatter['format_types']),
  127. '#default_value' => isset($group->format_settings['formatter']) ? $group->format_settings['formatter'] : $formatter['default_formatter'],
  128. '#weight' => 1,
  129. );
  130. }
  131. if ($mode == 'form') {
  132. $form['instance_settings']['required_fields'] = array(
  133. '#type' => 'checkbox',
  134. '#title' => t('Mark group for required fields.'),
  135. '#default_value' => isset($group->format_settings['instance_settings']['required_fields']) ? $group->format_settings['instance_settings']['required_fields'] : (isset($formatter['instance_settings']['required_fields']) ? $formatter['instance_settings']['required_fields'] : ''),
  136. '#weight' => 2,
  137. );
  138. }
  139. $form['instance_settings']['classes'] = array(
  140. '#title' => t('Extra CSS classes'),
  141. '#type' => 'textfield',
  142. '#default_value' => isset($group->format_settings['instance_settings']['classes']) ? $group->format_settings['instance_settings']['classes'] : (isset($formatter['instance_settings']['classes']) ? $formatter['instance_settings']['classes'] : ''),
  143. '#weight' => 3,
  144. '#element_validate' => array('field_group_validate_css_class'),
  145. );
  146. $form['instance_settings']['description'] = array(
  147. '#title' => t('Description'),
  148. '#type' => 'textarea',
  149. '#default_value' => isset($group->format_settings['instance_settings']['description']) ? $group->format_settings['instance_settings']['description'] : (isset($formatter['instance_settings']['description']) ? $formatter['instance_settings']['description'] : ''),
  150. '#weight' => 0,
  151. );
  152. // Add optional instance_settings.
  153. switch ($group->format_type) {
  154. case 'div':
  155. $form['instance_settings']['effect'] = array(
  156. '#title' => t('Effect'),
  157. '#type' => 'select',
  158. '#options' => array('none' => t('None'), 'blind' => t('Blind')),
  159. '#default_value' => isset($group->format_settings['instance_settings']['effect']) ? $group->format_settings['instance_settings']['effect'] : $formatter['instance_settings']['effect'],
  160. '#weight' => 2,
  161. );
  162. $form['instance_settings']['speed'] = array(
  163. '#title' => t('Speed'),
  164. '#type' => 'select',
  165. '#options' => array('none' => t('None'), 'slow' => t('Slow'), 'fast' => t('Fast')),
  166. '#default_value' => isset($group->format_settings['instance_settings']['speed']) ? $group->format_settings['instance_settings']['speed'] : $formatter['instance_settings']['speed'],
  167. '#weight' => 3,
  168. );
  169. break;
  170. case 'fieldset':
  171. $form['instance_settings']['classes'] = array(
  172. '#title' => t('Extra CSS classes'),
  173. '#type' => 'textfield',
  174. '#default_value' => isset($group->format_settings['instance_settings']['classes']) ? $group->format_settings['instance_settings']['classes'] : $formatter['instance_settings']['classes'],
  175. '#weight' => 3,
  176. '#element_validate' => array('field_group_validate_css_class'),
  177. );
  178. break;
  179. case 'tabs':
  180. case 'htabs':
  181. case 'accordion':
  182. unset($form['instance_settings']['description']);
  183. if (isset($form['instance_settings']['required_fields'])) {
  184. unset($form['instance_settings']['required_fields']);
  185. }
  186. break;
  187. case 'tab':
  188. case 'htab':
  189. case 'accordion-item':
  190. default:
  191. }
  192. return $form;
  193. }
  194. /**
  195. * Implements hook_field_group_pre_render().
  196. *
  197. * This function gives you the oppertunity to create the given
  198. * wrapper element that can contain the fields.
  199. * In the example beneath, some variables are prepared and used when building the
  200. * actual wrapper element. All elements in drupal fapi can be used.
  201. *
  202. * Note that at this point, the field group has no notion of the fields in it.
  203. *
  204. * There is also an alternative way of handling this. The default implementation
  205. * within field_group calls "field_group_pre_render_<format_type>".
  206. * @see field_group_pre_render_fieldset.
  207. *
  208. * @param Array $elements by address.
  209. * @param Object $group The Field group info.
  210. */
  211. function hook_field_group_pre_render(& $element, $group, & $form) {
  212. // You can prepare some variables to use in the logic.
  213. $view_mode = isset($form['#view_mode']) ? $form['#view_mode'] : 'form';
  214. $id = $form['#entity_type'] . '_' . $form['#bundle'] . '_' . $view_mode . '_' . $group->group_name;
  215. // Each formatter type can have whole different set of element properties.
  216. switch ($group->format_type) {
  217. // Normal or collapsible div.
  218. case 'div':
  219. $effect = isset($group->format_settings['instance_settings']['effect']) ? $group->format_settings['instance_settings']['effect'] : 'none';
  220. $speed = isset($group->format_settings['instance_settings']['speed']) ? $group->format_settings['instance_settings']['speed'] : 'none';
  221. $add = array(
  222. '#type' => 'markup',
  223. '#weight' => $group->weight,
  224. '#id' => $id,
  225. );
  226. $classes .= " speed-$speed effect-$effect";
  227. if ($group->format_settings['formatter'] != 'open') {
  228. $add['#prefix'] = '<div class="field-group-format ' . $classes . '">
  229. <span class="field-group-format-toggler">' . check_plain(t($group->label)) . '</span>
  230. <div class="field-group-format-wrapper" style="display: none;">';
  231. $add['#suffix'] = '</div></div>';
  232. }
  233. else {
  234. $add['#prefix'] = '<div class="field-group-format ' . $group->group_name . ' ' . $classes . '">';
  235. $add['#suffix'] = '</div>';
  236. }
  237. if (!empty($description)) {
  238. $add['#prefix'] .= '<div class="description">' . $description . '</div>';
  239. }
  240. $element += $add;
  241. if ($effect == 'blind') {
  242. drupal_add_library('system', 'effects.blind');
  243. }
  244. break;
  245. break;
  246. }
  247. }
  248. /**
  249. * Implements hook_field_group_pre_render().
  250. *
  251. * Function that fungates as last resort to alter the pre_render build.
  252. */
  253. function hook_field_group_pre_render_alter(&$element, $group, & $form) {
  254. if ($group->format_type == 'htab') {
  255. $element['#theme_wrappers'] = array('my_horizontal_tab');
  256. }
  257. }
  258. /**
  259. * Implements hook_field_group_build_pre_render_alter().
  260. *
  261. * Function that fungates as last resort where you can alter things. It is
  262. * expected that when you need this function, you have most likely a very custom
  263. * case or it is a fix that can be put in field_group core.
  264. *
  265. * @param Array $elements by address.
  266. */
  267. function hook_field_group_build_pre_render_alter(& $element) {
  268. // Prepare variables.
  269. $display = isset($element['#view_mode']);
  270. $groups = array_keys($element['#groups']);
  271. // Example from field_group itself to unset empty elements.
  272. if ($display) {
  273. foreach (element_children($element) as $name) {
  274. if (in_array($name, $groups)) {
  275. if (field_group_field_group_is_empty($element[$name], $groups)) {
  276. unset($element[$name]);
  277. }
  278. }
  279. }
  280. }
  281. // You might include additional javascript files and stylesheets.
  282. $element['#attached']['js'][] = drupal_get_path('module', 'field_group') . '/field_group.js';
  283. $element['#attached']['css'][] = drupal_get_path('module', 'field_group') . '/field_group.css';
  284. }
  285. /**
  286. * Implements hook_field_group_format_summary().
  287. *
  288. * Place to override or change default summary behavior. In most
  289. * cases the implementation of field group itself will be enough.
  290. *
  291. * TODO It might be better to change this hook with already created summaries,
  292. * giving the ability to alter or add it later on.
  293. */
  294. function hook_field_group_format_summary($group) {
  295. $output = '';
  296. // Create additional summary or change the default setting.
  297. return $output;
  298. }
  299. /**
  300. * Implement hook_ctools_plugin_api().
  301. * This hook is needed to let ctools know about exportables.
  302. * If you create field groups by using hook_field_group_info, you
  303. * will need to include the ctools api hook as well.
  304. */
  305. function hook_ctools_plugin_api($module, $api) {
  306. if ($module == 'field_group' && $api == 'field_group') {
  307. return array('version' => 1);
  308. }
  309. }
  310. /**
  311. * Implements hook_field_group_info().
  312. * Don't forget to include the ctools hook to notify that
  313. * your modules has field group exports.
  314. * @see hook_ctools_plugin_api.
  315. */
  316. function hook_field_group_info() {
  317. }
  318. /**
  319. * Implements hook_field_group_update_field_group().
  320. *
  321. * This hook is invoked by ctools export API.
  322. * Note that this is used by ctools and the group could occasional be
  323. * the group ID.
  324. *
  325. * @param $object $group
  326. * The FieldGroup object.
  327. */
  328. function hook_field_group_update_field_group($group) {
  329. // Delete extra data depending on the group.
  330. }
  331. /**
  332. * Implements hook_field_group_delete_field_group().
  333. *
  334. * This hook is invoked by ctools export API.
  335. *
  336. * @param $object $group
  337. * The FieldGroup object.
  338. */
  339. function hook_field_group_delete_field_group($group) {
  340. // Delete extra data depending on the group.
  341. }
  342. /**
  343. * Implements hook_field_group_create_field_group().
  344. *
  345. * This hook is invoked by ctools export API.
  346. *
  347. * @param $object $group
  348. * The FieldGroup object.
  349. */
  350. function hook_field_group_create_field_group($group) {
  351. // Create extra data depending on the group.
  352. }
  353. /**
  354. * @} End of "addtogroup hooks".
  355. */
  356. /**
  357. * @addtogroup utility functions
  358. * @{
  359. */
  360. /**
  361. * Get the groups for a given entity type, bundle and view mode.
  362. *
  363. * @param String $entity_type
  364. * The Entity type where field groups are requested.
  365. * @param String $bundle
  366. * The entity bundle for the field groups.
  367. * @param String $view_mode
  368. * The view mode scope for the field groups.
  369. *
  370. * @see field_group_read_groups()
  371. * @see ctools_export_crud_load()
  372. * @see ctools_export_crud_load_all()
  373. * @see ctools_export_crud_delete()
  374. * @see ctools_export_crud_save()
  375. */
  376. function field_group_info_groups($entity_type = NULL, $bundle = NULL, $view_mode = NULL, $reset = FALSE) {
  377. // This function caches the result and delegates to field_group_read_groups.
  378. }
  379. /**
  380. * Get the groups for the given parameters, uncached.
  381. *
  382. * @param Array $params
  383. * The Entity type where field groups are requested.
  384. *
  385. * @see field_group_info_groups()
  386. * @see ctools_export_load_object()
  387. */
  388. function field_group_read_groups($params = array()) {
  389. // This function loads the requested groups through ctools export api.
  390. }
  391. /**
  392. * @} End of "addtogroup utility functions".
  393. */