tripal_fields_layout.module 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. <?php
  2. /**
  3. *
  4. * Implements hook_form_FORM_ID_alter().
  5. *
  6. * The field_ui_field_edit_form is used for customizing the settings of
  7. * a field attached to an entity.
  8. */
  9. function tripal_fields_layout_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
  10. // For entity fields added by Tripal Entities we don't want the
  11. // the end-user to change the cardinality and the required fields
  12. // such that record can't be saved in Chado.
  13. $dbs = tripal_fields_layout_get_db_names_for_published_vocabularies();
  14. if (in_array($form['#instance']['entity_type'], $dbs)) {
  15. $form['field']['cardinality']['#access'] = FALSE;
  16. $form['instance']['required']['#access'] = FALSE;
  17. }
  18. // TODO: don't the the maximum length be larger than the field size.
  19. }
  20. /**
  21. * Implements hook_form_FORM_ID_alter().
  22. *
  23. * The field_ui_display_overview_form is used for formatting the display
  24. * or layout of fields attached to an entity.
  25. */
  26. function tripal_fields_layout_form_field_ui_display_overview_form_alter(&$form, &$form_state, $form_id) {
  27. $entity_type = $form['#entity_type'];
  28. $bundle_name = $form['#bundle'];
  29. // Get the bundle record.
  30. $bundle = db_select('tripal_bundle', 'tb')
  31. ->fields('tb')
  32. ->condition('bundle', $bundle_name)
  33. ->execute()
  34. ->fetchObject();
  35. if (module_exists('ds')) {
  36. drupal_set_message('Tripal is not compatible with the Display Suite (ds)
  37. module. If you would like to use Tripal-style panels for the layout
  38. of your pages please disable the Display Suite module. If you
  39. prefer to use the Display Suite module then disable the Tripal
  40. Fields Layout (tripal_fields_layout) module.', 'warning');
  41. }
  42. // Add a vertical tab fieldset at the bottom of the
  43. $form['overview_vert_tabs'] = array(
  44. '#type' => 'vertical_tabs'
  45. );
  46. $form['modes']['#group'] = 'overview_vert_tabs';
  47. $form['modes']['#weight'] = 1000;
  48. $form['te_add_panels'] = array(
  49. '#type' => 'fieldset',
  50. '#title' => 'Add a Panel',
  51. '#collapsible' => TRUE,
  52. '#collapsed' => TRUE,
  53. '#group' => 'overview_vert_tabs'
  54. );
  55. $form['te_add_panels']['instructions'] = array(
  56. '#type' => 'item',
  57. '#markup' => t('You may add as many panels to your page layout as
  58. desired. Panels can be used to organize fields into categories....')
  59. );
  60. $form['te_add_panels']['panel_name'] = array(
  61. '#type' => 'textfield',
  62. '#title' => 'Panel Name',
  63. '#description' => t('Please provide a computer readable name for this
  64. panel. The name should only contain alphanumeric values and
  65. underscores. It must not begin with a number.')
  66. );
  67. $form['te_add_panels']['panel_label'] = array(
  68. '#type' => 'textfield',
  69. '#title' => 'Panel Label',
  70. '#description' => t('Please provide a human readable label for this
  71. panel. This is the name that will appear to site visitors.')
  72. );
  73. $form['te_add_panels']['add_button'] = array(
  74. '#type' => 'submit',
  75. '#value' => 'Add Panel',
  76. '#name' => 'add-panel-submit'
  77. );
  78. // Layout Panels
  79. $form['te_layout_panels'] = array(
  80. '#type' => 'fieldset',
  81. '#title' => 'Arrange Panels',
  82. '#collapsible' => TRUE,
  83. '#collapsed' => TRUE,
  84. '#group' => 'overview_vert_tabs'
  85. );
  86. $form['te_layout_panels']['instructions'] = array(
  87. '#type' => 'item',
  88. '#markup' => t('Drag and drop the panel to change its order.')
  89. );
  90. $form['te_layout_panels']['panel_items']['#tree'] = TRUE;
  91. // Get available panels
  92. $result = db_select('tripal_panels', 'tp')
  93. ->fields('tp', array('panel_id', 'name', 'label', 'weight'))
  94. ->condition('name', 'te_base', '<>')
  95. ->condition('name', 'te_disabled', '<>')
  96. ->orderby('weight', 'asc')
  97. ->execute();
  98. $has_panel = FALSE;
  99. foreach ($result as $item) {
  100. $form['te_layout_panels']['panel_items'][$item->panel_id] = array(
  101. 'label' => array(
  102. '#markup' => check_plain($item->label),
  103. ),
  104. 'weight' => array(
  105. '#type' => 'weight',
  106. '#title' => t('Weight'),
  107. '#default_value' => $item->weight,
  108. '#delta' => 50,
  109. '#title_display' => 'invisible',
  110. ),
  111. 'remove' => array(
  112. '#type' => 'button',
  113. '#value' => 'Remove',
  114. '#name' => "arrange-panel-remove-$item->panel_id",
  115. )
  116. );
  117. $has_panel = TRUE;
  118. }
  119. if ($has_panel) {
  120. $form['te_layout_panels']['panel_items']['#theme_wrappers'] = array('tripal_fields_layout_form_draggable_panel_table');
  121. // Now we add our submit button, for submitting the form results.
  122. //
  123. // The 'actions' wrapper used here isn't strictly necessary for tabledrag,
  124. // but is included as a Form API recommended practice.
  125. $form['te_layout_panels']['add_button'] = array(
  126. '#type' => 'submit',
  127. '#value' => 'Save Panel Order',
  128. '#name' => 'order-panel-submit'
  129. );
  130. }
  131. else {
  132. $form['te_layout_panels']['instructions']['#markup'] = t('You need to add some panel first.');
  133. }
  134. // Configure Panels
  135. $form['te_configure_panels'] = array(
  136. '#type' => 'fieldset',
  137. '#title' => 'Configure Panels',
  138. '#collapsible' => TRUE,
  139. '#collapsed' => TRUE,
  140. '#group' => 'overview_vert_tabs'
  141. );
  142. // Make sure our default panels are in the database.
  143. _tripal_fields_layout_check_default_field_panels($bundle);
  144. // Now add each panel as a region.
  145. $form['fields']['#regions'] = array();
  146. $panels = db_select('tripal_panels', 'tp')
  147. ->fields('tp')
  148. ->condition('bundle_id', $bundle->id)
  149. ->orderBy('weight', 'ASC')
  150. ->orderBy('label', 'ASC')
  151. ->execute();
  152. $panel_options = array();
  153. while ($panel = $panels->fetchObject()) {
  154. $settings = unserialize($panel->settings);
  155. $form['fields']['#regions'][$panel->name] = array(
  156. 'title' => t($panel->label),
  157. 'message' => t($settings['message']),
  158. );
  159. $panel_options[$panel->name] = $panel->label;
  160. }
  161. // Set the table headers to add a new 'region' column.
  162. $form['fields']['#header'] = array(
  163. t('Field'),
  164. t('Weight'),
  165. t('Parent'),
  166. t('Label'),
  167. array('data' => t('Format'), 'colspan' => 3),
  168. t('Region'),
  169. );
  170. // Change the region callback for each field to place each field in the
  171. // proper "panel" region. Also, set the default region to be the base region.
  172. $fields = $form['fields'];
  173. $default_panel = 'te_base';
  174. foreach (element_children($fields) as $field_name) {
  175. $field_instance = field_info_instance($entity_type, $field_name, $bundle_name);
  176. $panel_id = db_select('tripal_panel_fields', 'tpf')
  177. ->fields('tpf', array('panel_id'))
  178. ->condition('field_id', $field_instance['id'])
  179. ->execute()
  180. ->fetchField();
  181. if ($panel_id) {
  182. $default_panel = db_select('tripal_panels', 'tp')
  183. ->fields('tp', array('name'))
  184. ->condition('panel_id', $panel_id)
  185. ->execute()
  186. ->fetchField();
  187. }
  188. $form['fields'][$field_name]['#region_callback'] = 'tripal_fields_layout_field_ui_row_region';
  189. $form['fields'][$field_name]['region'] = array(
  190. '#type' => 'select',
  191. '#options' => $panel_options,
  192. '#default_value' => $default_panel,
  193. '#attributes' => array(
  194. 'class' => array('te-field-region'),
  195. )
  196. );
  197. $form['fields'][$field_name]['#field_instance_id'] = array(
  198. '#type' => 'value',
  199. '#value' => $field_instance['id']
  200. );
  201. }
  202. // Add validate and submit handlers. Rearrange the submit callbacks
  203. // so ours is first.
  204. $form['#validate'][] = 'tripal_fields_layout_field_ui_validate';
  205. $submit = $form['#submit'];
  206. $form['#submit'] = array('tripal_fields_layout_field_ui_submit');
  207. $form['#submit'] = array_merge($form['#submit'], $submit);
  208. }
  209. /**
  210. * A helper function for checking if the default panels are in the database.
  211. */
  212. function _tripal_fields_layout_check_default_field_panels($bundle) {
  213. // Make sure we have records for our default regions: te_base and te_hidden.
  214. // First check if the base region is in the database. If not, add it.
  215. $te_base = db_select('tripal_panels', 'tp')
  216. ->fields('tp')
  217. ->condition('name', 'te_base')
  218. ->condition('bundle_id', $bundle->id)
  219. ->execute()
  220. ->fetchObject();
  221. if (!$te_base) {
  222. $settings = array(
  223. 'message' => 'Fields that should appear at the top of each page should be placed in the base panel. These fields are always present and help orient the user by at least indicating the necessary information to uniquely identiy the content.',
  224. );
  225. db_insert('tripal_panels')
  226. ->fields(array(
  227. 'bundle_id' => $bundle->id,
  228. 'name' => 'te_base',
  229. 'label' => 'Base Content',
  230. 'settings' => serialize($settings),
  231. 'weight' => -9999999
  232. ))
  233. ->execute();
  234. }
  235. // Next check if the hidden region is in the database. If not, add it.
  236. $te_base = db_select('tripal_panels', 'tp')
  237. ->fields('tp')
  238. ->condition('name', 'te_disabled')
  239. ->condition('bundle_id', $bundle->id)
  240. ->execute()
  241. ->fetchObject();
  242. if (!$te_base) {
  243. $settings = array(
  244. 'message' => 'Place field here to hide them from display.',
  245. );
  246. db_insert('tripal_panels')
  247. ->fields(array(
  248. 'bundle_id' => $bundle->id,
  249. 'name' => 'te_disabled',
  250. 'label' => 'Disabled',
  251. 'settings' => serialize($settings),
  252. 'weight' => 9999999
  253. ))
  254. ->execute();
  255. }
  256. }
  257. /**
  258. * Returns the region to which a row on the Field UI page belongs.
  259. *
  260. * @param $row
  261. * The current row that is being rendered in the Field UI page.
  262. */
  263. function tripal_fields_layout_field_ui_row_region($row) {
  264. $default_panel = 'te_base';
  265. $panel = '';
  266. $field_instance_id = $row['#field_instance_id']['#value'];
  267. // Get panel_id
  268. $panel_id = db_select('tripal_panel_fields', 'tpf')
  269. ->fields('tpf', array('panel_id'))
  270. ->condition('field_id', $field_instance_id)
  271. ->execute()
  272. ->fetchField();
  273. // Get panel name
  274. if ($panel_id) {
  275. $panel = db_select('tripal_panels', 'tp')
  276. ->fields('tp', array('name'))
  277. ->condition('panel_id', $panel_id)
  278. ->execute()
  279. ->fetchField();
  280. }
  281. // First get the panel
  282. if (!$panel) {
  283. $panel = $default_panel;
  284. }
  285. dpm(array($row['human_name']['#markup'] => $row,$panel => 'panel'));
  286. return $panel;
  287. }
  288. /**
  289. * Validates the field UI form to ensure proper panel assignments.
  290. *
  291. * @param $form
  292. * @param $form_state
  293. */
  294. function tripal_fields_layout_field_ui_validate($form, &$form_state) {
  295. if ($form_state ['clicked_button'] ['#name'] == 'add-panel-submit') {
  296. // Check if a valide panel name is provided
  297. $name = $form_state ['values'] ['panel_name'];
  298. if (! $name) {
  299. form_set_error ( 'panel_name', t ( "Please provide a name for the new panel." ) );
  300. }
  301. else if (preg_match ( '/^\d+/', $name )) {
  302. form_set_error ( 'panel_name', t ( "Panel name must not begin with a number." ) );
  303. }
  304. else if (preg_match ( '/\s+/', $name )) {
  305. form_set_error ( 'panel_name', t ( "Panel name should only contain alphanumeric values and underscores." ) );
  306. }
  307. // Check if a panel label is provided
  308. $label = $form_state ['values'] ['panel_label'];
  309. if (! $label) {
  310. form_set_error ( 'panel_label', t ( "Please provide a label for the new panel." ) );
  311. }
  312. }
  313. else if ($form_state ['clicked_button'] ['#name'] == 'order-panel-submit') {
  314. }
  315. else if ($form_state ['clicked_button'] ['#name'] == 'op') {
  316. }
  317. else if (preg_match('/^arrange-panel-remove-/', $form_state ['clicked_button'] ['#name'])) {
  318. $table = $form['te_layout_panels']['panel_items'];
  319. $button = $form_state ['triggering_element'] ['#name'];
  320. $panel_id = str_replace ('arrange-panel-remove-', '', $button);
  321. db_delete('tripal_panels')
  322. ->condition ('panel_id', $panel_id)
  323. ->execute();
  324. db_delete('tripal_panel_fields')
  325. ->condition ('panel_id', $panel_id)
  326. ->execute();
  327. }
  328. }
  329. /**
  330. * Responds to a submit from the field UI form for saving panel assignments.
  331. *
  332. * @param $form
  333. * @param $form_state
  334. */
  335. function tripal_fields_layout_field_ui_submit($form, &$form_state) {
  336. // Add a new panel
  337. if ($form_state ['clicked_button'] ['#name'] == 'add-panel-submit') {
  338. $bundle_id = $form_state['build_info']['args'][1]->id;
  339. $name = $form_state['values']['panel_name'];
  340. $label = $form_state['values']['panel_label'];
  341. $settings = array(
  342. 'message' => 'Place field in this panel.',
  343. );
  344. db_insert('tripal_panels')
  345. ->fields(array(
  346. 'bundle_id' => $bundle_id,
  347. 'name' => $name,
  348. 'label' => $label,
  349. 'settings' => serialize($settings),
  350. 'weight' => 0
  351. ))
  352. ->execute();
  353. }
  354. // Order panel
  355. else if ($form_state ['clicked_button'] ['#name'] == 'order-panel-submit') {
  356. $panels = $form_state['values']['panel_items'];
  357. foreach ($panels AS $id => $panel) {
  358. db_query(
  359. 'UPDATE {tripal_panels} SET weight = :weight WHERE panel_id = :id',
  360. array(
  361. ':weight' => $panel['weight'],
  362. ':id' => $id
  363. )
  364. );
  365. }
  366. }
  367. // Save field regions
  368. else if ($form_state ['clicked_button'] ['#name'] == 'op') {
  369. $fields = $form_state['values']['fields'];
  370. foreach($fields AS $field_name => $field_data){
  371. // Get field instance id
  372. $field_instance_id = $form['fields'][$field_name]['#field_instance_id']['#value'];
  373. // Get region panel_id
  374. $region = $field_data['region'];
  375. $panel_id = db_select('tripal_panels', 'tp')
  376. ->fields('tp', array('panel_id'))
  377. ->condition('name', $region)
  378. ->execute()
  379. ->fetchField();
  380. // Save
  381. $penal_field_id = db_select('tripal_panel_fields', 'tpf')
  382. ->fields('tpf', array('panel_field_id'))
  383. ->condition('field_id', $field_instance_id)
  384. ->execute()
  385. ->fetchField();
  386. if ($penal_field_id) {
  387. db_update('tripal_panel_fields')
  388. ->fields(array(
  389. 'panel_id' => $panel_id,
  390. ))
  391. ->condition('panel_field_id', $penal_field_id)
  392. ->execute();
  393. }
  394. else {
  395. db_insert('tripal_panel_fields')
  396. ->fields(array(
  397. 'panel_id' => $panel_id,
  398. 'field_id' => $field_instance_id
  399. ))
  400. ->execute();
  401. }
  402. }
  403. }
  404. }
  405. /**
  406. * Theme the Panel Order Table as a draggable table
  407. *
  408. * @param unknown $variables
  409. * @return unknown
  410. */
  411. function theme_tripal_fields_layout_form_draggable_panel_table ($variables) {
  412. $element = $variables['element'];
  413. $rows = array();
  414. foreach (element_children($element) as $id) {
  415. // Before we add our 'weight' column to the row, we need to give the
  416. // element a custom class so that it can be identified in the
  417. // drupal_add_tabledrag call.
  418. //
  419. // This could also have been done during the form declaration by adding
  420. // '#attributes' => array('class' => 'example-item-weight'),
  421. // directy to the 'weight' element in tabledrag_example_simple_form().
  422. $element[$id]['weight']['#attributes']['class'] = array('tripal_panel-item-weight');
  423. $element[$id]['label']['#printed'] = FALSE;
  424. $element[$id]['weight']['#printed'] = FALSE;
  425. $element[$id]['remove']['#printed'] = FALSE;
  426. // We are now ready to add each element of our $form data to the $rows
  427. // array, so that they end up as individual table cells when rendered
  428. // in the final table. We run each element through the drupal_render()
  429. // function to generate the final html markup for that element.
  430. $rows[] = array(
  431. 'data' => array(
  432. // Add our 'description' column.
  433. drupal_render($element[$id]['label']),
  434. // Add our 'weight' column.
  435. drupal_render($element[$id]['weight']),
  436. // Add remove column
  437. drupal_render($element[$id]['remove'])
  438. ),
  439. // To support the tabledrag behaviour, we need to assign each row of the
  440. // table a class attribute of 'draggable'. This will add the 'draggable'
  441. // class to the <tr> element for that row when the final table is
  442. // rendered.
  443. 'class' => array('draggable'),
  444. );
  445. }
  446. // We now define the table header values. Ensure that the 'header' count
  447. // matches the final column count for your table.
  448. $header = array(t('Label'), t('Weight'), t('Action'));
  449. // We also need to pass the drupal_add_tabledrag() function an id which will
  450. // be used to identify the <table> element containing our tabledrag form.
  451. // Because an element's 'id' should be unique on a page, make sure the value
  452. // you select is NOT the same as the form ID used in your form declaration.
  453. $table_id = 'tripal_panel-arrange_panel_table';
  454. // We can render our tabledrag table for output.
  455. $output = '';
  456. if (count($rows) > 0) {
  457. $output = theme('table', array(
  458. 'header' => $header,
  459. 'rows' => $rows,
  460. 'attributes' => array('id' => $table_id),
  461. ));
  462. }
  463. // And then render any remaining form elements (such as our submit button).
  464. //$output .= drupal_render_children($element);
  465. // We now call the drupal_add_tabledrag() function in order to add the
  466. // tabledrag.js goodness onto our page.
  467. //
  468. // For a basic sortable table, we need to pass it:
  469. // - the $table_id of our <table> element,
  470. // - the $action to be performed on our form items ('order'),
  471. // - a string describing where $action should be applied ('siblings'),
  472. // - and the class of the element containing our 'weight' element.
  473. drupal_add_tabledrag($table_id, 'order', 'sibling', 'tripal_panel-item-weight');
  474. return $output;
  475. }
  476. /**
  477. * Implements hook_theme().
  478. */
  479. function tripal_fields_layout_theme($existing, $type, $theme, $path) {
  480. return array(
  481. 'tripal_fields_layout_form_draggable_panel_table' => array(
  482. 'render element' => 'element',
  483. ),
  484. );
  485. }