tripal_core.toc.inc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. <?php
  2. /**
  3. *
  4. */
  5. function tripal_core_node_toc_form($form, &$form_state, $node) {
  6. $form["#tree"] = TRUE;
  7. $form["instructions"] = array(
  8. '#markup' => '</p>' . t('Below is a list of the titles of
  9. content panes that can appear on this page. These titles appear in the
  10. the following order in the Table of Contents (TOC). You may rename
  11. the titles or drag and drop them to change the order. <b>Any changes will
  12. only apply to this page</b>. If you would like to make changes apply to multiple
  13. pages of the same tpye, please visit the TOC administrative page.') . '<p>' .
  14. '<p>' . t('The list below shows all possible content panes that can appear.
  15. However, those without content are hidden and do not appear in the TOC.' . '</p>'),
  16. );
  17. $form['node'] = array(
  18. '#type' => 'value',
  19. '#value' => $node,
  20. );
  21. // Get the content array for this node, then pass it through the
  22. // tripal_core_node_view_alter which generates the TOC. After that
  23. // we can use the $build array to build the form.
  24. node_build_content($node);
  25. $build = $node->content;
  26. $build["#node"] = $node;
  27. tripal_core_node_view_alter($build);
  28. // Iterate through the built items and add form elemetns for each one.
  29. foreach(element_children($build) as $key) {
  30. $element = $build[$key];
  31. if (array_key_exists('#tripal_toc_id', $element)) {
  32. $toc_id = $element['#tripal_toc_id'];
  33. $toc_title = $element['#tripal_toc_title'];
  34. $toc_weight = $element['#weight'];
  35. $form['toc_items'][$toc_id]['title'] = array(
  36. '#type' => 'textfield',
  37. '#default_value' => $toc_title,
  38. );
  39. $form['toc_items'][$toc_id]['weight'] = array(
  40. '#type' => 'textfield',
  41. '#default_value' => $toc_weight,
  42. '#attributes' => array(
  43. 'class' => array('tripal-node-toc-items-weights'),
  44. ),
  45. '#size' => 5,
  46. );
  47. }
  48. }
  49. $form['toc_items']['#theme'] = 'tripal_node_toc_items_table';
  50. $form['submit'] = array(
  51. '#type' => 'submit',
  52. '#name' => 'toc_submit',
  53. '#value' => t('Submit'),
  54. );
  55. return $form;
  56. }
  57. /**
  58. *
  59. * @param $variables
  60. */
  61. function theme_tripal_node_toc_items_table($variables) {
  62. $elements = $variables['element'];
  63. $toc_items = array();
  64. // Sort the toc_items using a custom sort function. But we need to include
  65. // only the items we want in the table (exclude renderable stuff).
  66. foreach(element_children($elements) as $key) {
  67. $toc_items[] = $elements[$key];
  68. }
  69. usort($toc_items, 'theme_tripal_node_sort_toc_items');
  70. // Build the table header.
  71. $headers = array('Content Pane Name', 'Weight');
  72. // Format the form elements as rows in the table.
  73. $rows = array();
  74. foreach ($toc_items as $key => $item) {
  75. $rows[] = array(
  76. 'data' => array(
  77. drupal_render($item['title']),
  78. drupal_render($item['weight']),
  79. ),
  80. 'class' => array('draggable'),
  81. );
  82. }
  83. // Theme and return the table.
  84. $table = array(
  85. 'header' => $headers,
  86. 'rows' => $rows,
  87. 'attributes' => array("id" => 'tripal-node-toc-items-table'),
  88. 'sticky' => TRUE,
  89. 'caption' => t('Content Panes Available in the TOC'),
  90. 'colgroups' => array(),
  91. 'empty' => t('There are no content panes for this page'),
  92. );
  93. drupal_add_tabledrag('tripal-node-toc-items-table', 'order', 'sibling', 'tripal-node-toc-items-weights');
  94. return theme_table($table);
  95. }
  96. /**
  97. *
  98. * @param $a
  99. * @param $b
  100. */
  101. function theme_tripal_node_sort_toc_items($a, $b) {
  102. if ($a['weight']['#value'] < $b['weight']['#value']) {
  103. return -1;
  104. }
  105. if ($a['weight']['#value'] > $b['weight']['#value']) {
  106. return 1;
  107. }
  108. if ($a['weight']['#value'] == $b['weight']['#value']) {
  109. return strcmp($a['title']['#value'], $b['title']['#value']);
  110. }
  111. }
  112. /**
  113. * Implements hook_validate for the tripal_core_node_toc_form.
  114. */
  115. function tripal_core_node_toc_form_validate($form, &$form_state) {
  116. $toc_items = $form_state['values']['toc_items'];
  117. // Iterate through the TOC items and validate.
  118. foreach ($toc_items as $toc_id => $item) {
  119. if (!$item['title']) {
  120. form_set_error('toc_items][' . $toc_id, "Please provide a valid title.");
  121. }
  122. }
  123. }
  124. /**
  125. * Implements hook_submit for the tripal_core_node_toc_form.
  126. */
  127. function tripal_core_node_toc_form_submit($form, &$form_state) {
  128. $toc_items = $form_state['values']['toc_items'];
  129. $node = $form_state['values']['node'];
  130. $transaction = db_transaction();
  131. try {
  132. // First delete any settings for this node
  133. db_delete('tripal_toc')
  134. ->condition('nid', $node->nid)
  135. ->execute();
  136. // Second add in any new settings for this node
  137. foreach ($toc_items as $toc_id => $item) {
  138. db_insert('tripal_toc')
  139. ->fields(array(
  140. 'node_type' => $node->type,
  141. 'key' => $toc_id,
  142. 'title' => $item['title'],
  143. 'weight' => $item['weight'],
  144. 'nid' => $node->nid,
  145. ))
  146. ->execute();
  147. }
  148. drupal_set_message("TOC changes successfully applied to this node only.");
  149. }
  150. catch (Exception $e) {
  151. $transaction->rollback();
  152. drupal_set_message("Failed to apply TOC changes.", "error");
  153. }
  154. }
  155. /**
  156. * To be called by tripal_core_node_view_alter() to generate the TOC.
  157. *
  158. * @param $build
  159. * The build array passed to hook_node_view_alter()
  160. */
  161. function tripal_core_node_view_add_toc(&$build) {
  162. global $theme;
  163. // if this is not a full node view, we do not want to alter
  164. if ($build['#view_mode'] != 'full' OR !array_key_exists('#tripal_generic_node_template', $build)) {
  165. return;
  166. }
  167. $node_type = $build["#node"]->type;
  168. $nid = $build["#node"]->nid;
  169. $cache = cache_get("theme_registry:$theme", 'cache');
  170. $node = $build['#node'];
  171. $toc = array();
  172. $toc_html = '';
  173. // If we are looking at a Tripal node template then we want to
  174. // make some changes to each pane of content so that we can associate
  175. // a table of contents and add administrator and curator messages.
  176. if ($build['#tripal_generic_node_template'] == TRUE) {
  177. // Iterate through all the elements of the $build array and for those
  178. // that are wanting to provide content for this node.
  179. $markup = array();
  180. foreach ($build as $key => $value) {
  181. $value = $build[$key];
  182. // Skip the body element as the Tripal node types do not use it.
  183. if ($key == 'body') {
  184. continue;
  185. }
  186. // Skip the table of contents and links as those will be placed elsewhere.
  187. if (preg_match('/^#/', $key) or $key == 'tripal_toc' or $key == 'links') {
  188. continue;
  189. }
  190. // For backwards compatibility we will handle the content type fields
  191. // named 'field_resource_blocks', 'field_resource_titles', and 'field_resource_links'
  192. // these fields can be added on the Drupal content types page and were
  193. // specifically recoginzed by Tripal v1.1.
  194. if ($key == "field_resource_links") {
  195. // links should just appear on the sidebar as is and not open up a panel
  196. foreach (element_children($build[$key]) as $index) {
  197. $element = $build[$key][$index];
  198. $weight = 0;
  199. $parts = explode("|", $element['#markup']);
  200. if (count($parts) == 2) {
  201. $toc[$weight][$parts[0]] = "<div class=\"tripal_toc_list_item\">" . l($parts[0], $parts[1], array('attributes' => array('target' => '_blank'))) . "</div>";
  202. }
  203. else {
  204. $toc[$weight][$parts[0]] = "<div class=\"tripal_toc_list_item\">" . $element['#markup'] . "</div>";
  205. }
  206. // remove this link from the build array as we've moved it to appear in the TOC
  207. unset($build[$key]);
  208. }
  209. continue;
  210. }
  211. if ($key == "field_resource_titles") {
  212. // ignore these, we will use them in the field_resource_blocks if
  213. // statement below
  214. continue;
  215. }
  216. if ($key == "field_resource_blocks") {
  217. foreach (element_children($build[$key]) as $index) {
  218. // get the details and the title
  219. $weight = 0;
  220. $markup = $build[$key][$index]["#markup"];
  221. $toc_item_id = "resource-$index";
  222. // Get any overrides for this key.
  223. $overrides = tripal_core_get_toc_overrides($nid, $toc_item_id, $node_type);
  224. // If the element should be hidden then unset this key the build
  225. // array continue to the next one
  226. if ($overrides['hide'] == 1) {
  227. unset($build[$key]);
  228. continue;
  229. }
  230. $toc_item_title = $build["field_resource_titles"][$index]["#markup"];
  231. $toc_item_title = $overrides['title'] ? $overrides['title'] : $toc_item_title;
  232. $weight = $overrides['weight'] ? $overrides['weight'] : $weight;
  233. $updated_markup = "
  234. <div id=\"$toc_item_id-tripal-data-pane\" class=\"tripal-data-pane\">
  235. <div class=\"$toc_item_id-tripal-data-pane-title tripal-data-pane-title\">$toc_item_title</div>
  236. $markup
  237. </div>
  238. </div>
  239. ";
  240. $build[$toc_item_id]['#markup'] = $updated_markup;
  241. $build[$toc_item_id]['#toc_handled'] = TRUE;
  242. $build[$toc_item_id]['#tripal_toc_id'] = $toc_item_id;
  243. $build[$toc_item_id]['#tripal_toc_title'] = $toc_item_title;
  244. $build[$toc_item_id]['#weight'] = $weight;
  245. // add the entry to the TOC
  246. $toc_item_link = "<div class=\"tripal_toc_list_item\"><a id=\"$toc_item_id\" class=\"tripal_toc_list_item_link\" href=\"?pane=$toc_item_id\">$toc_item_title</a></div>";
  247. $toc[$weight][$toc_item_title] = $toc_item_link;
  248. }
  249. // Remove the key from the build array. We have have replaced it
  250. unset($build[$key]);
  251. unset($build["field_resource_titles"]);
  252. continue;
  253. }
  254. // Skip any keys we may have already handled. This is the case for
  255. // the field_resource_blocks where we removed the old CCK fields
  256. // and added new ones. We don't want these new ones to be processed
  257. // again by the code below.
  258. if (array_key_exists('#toc_handled', $build[$key]) and $build[$key]['#toc_handled'] == TRUE) {
  259. continue;
  260. }
  261. // For all other fields we will handle in the following way.
  262. //-----------------------
  263. // INITIALIZE THE CONTENT VARIABLES
  264. //-----------------------
  265. $toc_item_title = $key;
  266. $toc_item_id = $key;
  267. $toc_item_link = '';
  268. $weight = 0;
  269. // get the title for the table of contents. Tripal templates should
  270. // have a '#tripal_toc_title' element in the build array
  271. if (array_key_exists('#tripal_toc_title', $build[$key])) {
  272. $toc_item_title = $build[$key]['#tripal_toc_title'];
  273. }
  274. // other elements in the $build array may just have a '#title' element,
  275. if (array_key_exists('#title', $build[$key])) {
  276. $toc_item_title = $build[$key]['#title'];
  277. }
  278. $toc_item_title = ucwords($toc_item_title);
  279. if (array_key_exists('#weight', $build[$key])) {
  280. $weight = $build[$key]['#weight'];
  281. }
  282. // Get any overrides for this key.
  283. $overrides = tripal_core_get_toc_overrides($nid, $toc_item_id, $node_type);
  284. // If the element should be hidden then unset this key the build
  285. // array continue to the next one
  286. if ($overrides['hide'] == 1) {
  287. unset($build[$key]);
  288. continue;
  289. }
  290. // now override the title if a value is set in the tripal_toc table
  291. $toc_item_title = $overrides['title'] ? $overrides['title'] : $toc_item_title;
  292. $weight = $overrides['weight'] ? $overrides['weight'] : $weight;
  293. if (array_key_exists('#tripal_toc_id', $build[$key])) {
  294. $toc_item_id = $build[$key]['#tripal_toc_id'];
  295. }
  296. $toc_item_link = "<div class=\"tripal_toc_list_item\"><a id=\"$toc_item_id\" class=\"tripal_toc_list_item_link\" href=\"?pane=$toc_item_id\">$toc_item_title</a></div>";
  297. //-----------------------
  298. // GET THE MARKUP FOR EACH ELEMENT
  299. //-----------------------
  300. $markup = '';
  301. // find the markup. Some fields will have a '#markup' and others, such
  302. // as CCK elements may have a set of '#markup' elements organized by
  303. // numerical keys.
  304. if (array_key_exists('#markup', $build[$key]) and trim($build[$key]['#markup'])) {
  305. $markup = $build[$key]['#markup'];
  306. }
  307. // For backwards copmatibility we should support the '#value' element as well.
  308. elseif (array_key_exists('#value', $build[$key]) and trim($build[$key]['#value'])) {
  309. $markup = $build[$key]['#markup'];
  310. }
  311. // if we have no '#markup' field then this element has not yet
  312. // been rendered. Let's render it and substitute that for markup
  313. if (!$markup) {
  314. $markup = trim(render($build[$key]));
  315. $build[$key] = array(
  316. '#markup' => $markup,
  317. '#tripal_toc_id' => $toc_item_id,
  318. '#tripal_toc_title' => $toc_item_title,
  319. '#weight' => $weight,
  320. );
  321. }
  322. // if we still don't have markup then skip this one
  323. if (!$markup) {
  324. continue;
  325. }
  326. //-----------------------
  327. // FIND THE TEMPLATE PATH
  328. //-----------------------
  329. // get the template path so we can put it in an admin message box
  330. $path = '';
  331. if (!array_key_exists('#tripal_template_show', $build[$key]) or
  332. $build[$key]['#tripal_template_show'] == TRUE) {
  333. if ($cache and array_key_exists($key, $cache->data) and array_key_exists('path', $cache->data[$key])) {
  334. $path = $cache->data[$key]['path'] . '/' . $key . '.tpl.php';
  335. $path = tripal_set_message("Administrators, you can
  336. customize the way the content above is presented. Tripal provides a template
  337. file for each pane of content. To customize, copy the template file to your
  338. site's default theme, edit then " .
  339. l('clear the Drupal cache', 'admin/config/development/performance', array('attributes' => array('target' => '_blank'))) . ".
  340. Currently, the content above is provided by this template: <br><br>$path",
  341. TRIPAL_INFO,
  342. array('return_html' => 1)
  343. );
  344. }
  345. }
  346. //-----------------------
  347. // SET THE WEIGHTS FOR THE TOC ELEMENTS
  348. //-----------------------
  349. // set the weight of the TOC item and add it to our $toc array
  350. // for building of the TOC below
  351. $weight = 0;
  352. if (array_key_exists('#weight', $build[$key])) {
  353. $weight = $build[$key]['#weight'];
  354. }
  355. // override the weight if it's set in the tripal_toc table
  356. $weight = $overrides['weight'] ? $overrides['weight'] : $weight;
  357. $toc[$weight][$toc_item_title] = $toc_item_link;
  358. //-----------------------
  359. // CREATE THE DATA BLOCK
  360. //-----------------------
  361. // add a surrounding <div> box around the content
  362. $updated_markup = "
  363. <div id=\"$toc_item_id-tripal-data-pane\" class=\"tripal-data-pane\">
  364. <div class=\"$toc_item_id-tripal-data-pane-title tripal-data-pane-title\">$toc_item_title</div>
  365. $markup
  366. $path
  367. </div>
  368. </div>
  369. ";
  370. $build[$key]['#markup'] = $updated_markup;
  371. $build[$key]['#weight'] = $weight;
  372. } // end foreach ($build as $key => $value) {
  373. } // end if ($build['#tripal_generic_node_template'] == TRUE) {
  374. //-----------------------
  375. // BUILD THE TABLE OF CONTENTS LINKS
  376. //-----------------------
  377. // first sort the links numerically by their weight
  378. ksort($toc, SORT_NUMERIC);
  379. $toc_html = '';
  380. foreach ($toc as $weight => $links) {
  381. // for links in the same weight, sort them alphabetically
  382. ksort($links);
  383. foreach ($links as $toc_item_title => $toc_item_link) {
  384. $toc_html .= $toc_item_link;
  385. }
  386. }
  387. $build['tripal_toc']['#markup'] = "<div id=\"$node->type-tripal-toc-pane\" class=\"tripal-toc-pane\">$toc_html</div>";
  388. }
  389. /**
  390. *
  391. * @param $build
  392. */
  393. function tripal_core_get_toc_overrides($nid, $key, $node_type) {
  394. // Set override defaults
  395. $override_title = '';
  396. $override_weight = '';
  397. $override_hide = 0;
  398. // First look to see if the node has customizations for this item.
  399. $toc_item_overrides = db_select('tripal_toc', 'tc')
  400. ->fields('tc', array('title', 'weight', 'hide'))
  401. ->condition('key', $key)
  402. ->condition('nid', $nid)
  403. ->execute()
  404. ->fetchObject();
  405. if ($toc_item_overrides) {
  406. $override_title = $toc_item_overrides->title;
  407. $override_weight = $toc_item_overrides->weight;
  408. $override_hide = $toc_item_overrides->hide;
  409. }
  410. // If there are no specific node customizations then look to see if there
  411. // are customizations for this content type.
  412. else {
  413. $toc_item_overrides = db_select('tripal_toc', 'tc')
  414. ->fields('tc', array('title', 'weight', 'hide'))
  415. ->condition('node_type', $node_type)
  416. ->condition('key', $key)
  417. ->isNull('nid')
  418. ->execute()
  419. ->fetchObject();
  420. if ($toc_item_overrides) {
  421. $override_title = $toc_item_overrides->title;
  422. $override_weight = $toc_item_overrides->weight;
  423. $override_hide = $toc_item_overrides->hide;
  424. }
  425. }
  426. return array(
  427. 'title' => $override_title,
  428. 'weight' => $override_weight,
  429. 'hide' => $override_hide,
  430. );
  431. }