type]; $form["#tree"] = TRUE; $form["instructions"] = [ '#type' => 'fieldset', '#collapsed' => TRUE, '#collapsible' => TRUE, '#title' => 'Instructions', ]; $admin_link = l( $type_info->name . " TOC administrative page", "admin/tripal/legacy/" . $type_info->module . "/" . $node->type . "toc", ['attributes' => ['target' => '_blank']] ); $form["instructions"]["main"] = [ '#markup' => '
' . t("Below is a list of the titles of content panes that can appear on this page. These titles appear in the the following order in the Table of Contents (TOC). You may rename the titles or drag and drop them to change the order. Any changes will only apply to this page. If you would like to make changes apply to multiple pages of the same type, please visit the $admin_link. ") . '
' . '' . t('The list below shows all possible content panes that can appear. However, those without content are automatically hidden and do not appear in the TOC.' . '
'), ]; $form['node'] = [ '#type' => 'value', '#value' => $node, ]; // Get the content array for this node, then pass it through the // tripal_core_node_view_alter which generates the TOC. After that // we can use the $build array to build the form. We have to add // a 'tripal_toc_mode' to the $node because we need to give the mode // to the tripal_core_node_view_build_toc function. $node->tripal_toc_mode = 'manage_node'; node_build_content($node); $build = $node->content; $build["#node"] = $node; tripal_core_node_view_alter($build); // Iterate through the built items and add form elemetns for each one. foreach (element_children($build) as $key) { $element = $build[$key]; if (array_key_exists('#tripal_toc_id', $element)) { $toc_id = $element['#tripal_toc_id']; $toc_title = $element['#tripal_toc_title']; $toc_weight = $element['#weight']; $toc_hide = $element['#hide']; // If this element is a link then we don't want to allow the user // to change the title as the link title is changed by using the // interface that created the link. $is_link = array_key_exists('#is_link', $element) ? $element['#is_link'] : FALSE; if (!$is_link) { $form['toc_items'][$toc_id]['title'] = [ '#type' => 'textfield', '#default_value' => $toc_title, ]; } else { $form['toc_items'][$toc_id]['title'] = [ '#markup' => 'link title: ' . $toc_title, '#value' => $toc_title, ]; } $form['toc_items'][$toc_id]['hide'] = [ '#type' => 'checkbox', '#default_value' => $toc_hide, ]; $form['toc_items'][$toc_id]['weight'] = [ '#type' => 'textfield', '#default_value' => $toc_weight, '#attributes' => [ 'class' => ['tripal-node-toc-items-weights'], ], '#size' => 5, ]; } } $form['toc_items']['#theme'] = 'tripal_node_toc_items_table'; $form['submit'] = [ '#type' => 'submit', '#name' => 'toc_submit', '#value' => t('Submit'), ]; $form['unset'] = [ '#type' => 'submit', '#name' => 'toc_unset', '#value' => t('Unset Node Customizations'), ]; // Check to see if this node's TOC is specifically being managed. $sql = "SELECT count(*) FROM {tripal_toc} where nid = :nid"; $managed_items = db_query($sql, [':nid' => $node->nid])->fetchField(); if ($managed_items > 0) { $form['is_managed'] = [ '#markup' => '' . t('This page currently has customiations to the TOC. This means that any customzations for the content type are overriden. Click the "Unset Node Customizations" button above to remove page-level customizations and default to the content type settings.') . '
', ]; } return $form; } /** * * @param $variables */ function theme_tripal_node_toc_items_table($variables) { $elements = $variables['element']; $toc_items = []; // Sort the toc_items using a custom sort function. But we need to include // only the items we want in the table (exclude renderable stuff). foreach (element_children($elements) as $key) { $toc_items[] = $elements[$key]; } usort($toc_items, 'theme_tripal_node_sort_toc_items'); // Build the table header. $headers = ['Content Pane Name', 'Hide', 'Weight']; // Format the form elements as rows in the table. $rows = []; foreach ($toc_items as $key => $item) { $rows[] = [ 'data' => [ drupal_render($item['title']), drupal_render($item['hide']), drupal_render($item['weight']), ], 'class' => ['draggable'], ]; } // Theme and return the table. $table = [ 'header' => $headers, 'rows' => $rows, 'attributes' => ["id" => 'tripal-node-toc-items-table'], 'sticky' => TRUE, 'caption' => t('Content Panes Available in the TOC'), 'colgroups' => [], 'empty' => t('There are no content panes for this page'), ]; drupal_add_tabledrag('tripal-node-toc-items-table', 'order', 'sibling', 'tripal-node-toc-items-weights'); return theme_table($table); } /** * * @param $a * @param $b */ function theme_tripal_node_sort_toc_items($a, $b) { if ($a['weight']['#value'] < $b['weight']['#value']) { return -1; } if ($a['weight']['#value'] > $b['weight']['#value']) { return 1; } if ($a['weight']['#value'] == $b['weight']['#value']) { return strcmp($a['title']['#value'], $b['title']['#value']); } } /** * Implements hook_validate for the tripal_core_node_toc_form. */ function tripal_core_node_toc_form_validate($form, &$form_state) { $toc_items = $form_state['values']['toc_items']; // Iterate through the TOC items and validate. foreach ($toc_items as $toc_id => $item) { if (array_key_exists('title', $item) and !$item['title']) { form_set_error('toc_items][' . $toc_id, "Please provide a valid title."); } } } /** * Implements hook_submit for the tripal_core_node_toc_form. */ function tripal_core_node_toc_form_submit($form, &$form_state) { $toc_items = $form_state['values']['toc_items']; $node = $form_state['values']['node']; if ($form_state['clicked_button']['#name'] == "toc_submit") { $transaction = db_transaction(); try { // First delete any settings for this node db_delete('tripal_toc') ->condition('nid', $node->nid) ->execute(); // Second add in any new settings for this node foreach ($toc_items as $toc_id => $item) { db_insert('tripal_toc') ->fields([ 'node_type' => $node->type, 'key' => $toc_id, 'title' => array_key_exists('title', $item) ? $item['title'] : '', 'weight' => $item['weight'], 'nid' => $node->nid, 'hide' => $item['hide'], ]) ->execute(); } drupal_set_message("TOC changes successfully applied to this node only."); } catch (Exception $e) { $transaction->rollback(); drupal_set_message("Failed to apply TOC changes.", "error"); } } if ($form_state['clicked_button']['#name'] == "toc_unset") { $transaction = db_transaction(); try { // First delete any settings for this node db_delete('tripal_toc') ->condition('nid', $node->nid) ->execute(); drupal_set_message("TOC is no longer customized specifically for this page. Now using the content type settings."); } catch (Exception $e) { $transaction->rollback(); drupal_set_message("Failed to apply TOC changes.", "error"); } } } /** * To be called by tripal_core_node_view_alter() to generate the TOC. * * @param $build * The build array passed to hook_node_view_alter() * */ function tripal_core_node_view_build_toc(&$build) { global $theme; // if this is not a full node view, we do not want to alter if ($build['#view_mode'] != 'full' OR !array_key_exists('#tripal_generic_node_template', $build)) { return; } $node_type = $build["#node"]->type; $nid = $build["#node"]->nid; // The mode alters the format of the build array. There are three types of // modes: "display", "manage_node", "manage_type". If "display" is provided // then the build array is formatted for the display of the content. // If "manage_node" is provided then the build array will contain all // content panes regardless if the pane should be hidden. This allows // the management tool to find all content panes and their settings. If // "manage_type" is provided then node-specific content panes are // excluded. Node-specific content panes are those that appear only on // specific nodes and therefore should not be used when managing the // TOC for a content type. $mode = isset($build["#node"]->tripal_toc_mode) ? $build["#node"]->tripal_toc_mode : "display"; $cache = cache_get("theme_registry:$theme", 'cache'); $node = $build['#node']; $toc = []; $toc_html = ''; // If we are looking at a Tripal node template then we want to // make some changes to each pane of content so that we can associate // a table of contents and add administrator and curator messages. if ($build['#tripal_generic_node_template'] == TRUE) { // Iterate through all the elements of the $build array and for those // that are wanting to provide content for this node. $markup = []; foreach ($build as $key => $value) { $value = $build[$key]; // Skip the body element as the Tripal node types do not use it. if ($key == 'body') { continue; } // Skip the table of contents and links as those will be placed elsewhere. if (preg_match('/^#/', $key) or $key == 'tripal_toc' or $key == 'links') { continue; } // For backwards compatibility we will handle the content type fields // named 'field_resource_blocks', 'field_resource_titles', and 'field_resource_links' // these fields can be added on the Drupal content types page and were // specifically recoginzed by Tripal v1.1. If the mode type is "manage_type" // then remove these content panes because they are node specific. if ($mode == "manage_type" and ( $key == "field_resource_links" or $key == "field_resource_titles" or $key == "field_resource_blocks")) { unset($build[$key]); continue; } if ($key == "field_resource_links") { // links should just appear on the sidebar as is and not open up a panel foreach (element_children($build[$key]) as $index) { $element = $build[$key][$index]; $weight = 0; $hide = 0; $toc_item_id = "resource-link-$index"; // Get any overrides for this key. $overrides = tripal_core_get_toc_overrides($nid, $toc_item_id, $node_type, $mode); $weight = $overrides['weight'] ? $overrides['weight'] : $weight; $hide = $overrides['hide'] ? $overrides['hide'] : $hide; // If the element should be hidden then unset this key the build // array continue to the next one if ($mode == "display" and $overrides['hide'] == 1) { continue; } // This field supports tokens, so we need to perform the substitutions // if one is needed. Get the tokens and format $base_table = preg_replace('/^chado_(.*)$/', '\1', $node_type); $tokens = chado_node_generate_tokens($base_table); $markup = $element['#markup']; // Determine which tokens were used in the format string if (preg_match_all('/\[[^]]+\]/', $markup, $used_tokens)) { // Get the value for each token used foreach ($used_tokens[0] as $token) { $token_info = $tokens[$token]; if (!empty($token_info)) { $value = chado_get_token_value($token_info, $node); $markup = str_replace($token, $value, $markup); } } $element['#markup'] = $markup; } // Add the link to the TOC $parts = explode("|", $element['#markup']); if (count($parts) == 2) { $toc[$weight][$parts[0]] = "' . t('The list below shows all possible content panes that can appear. However, those without content are automatically hidden and do not appear in the TOC.' . '
'), ]; $form['content_type'] = [ '#type' => 'value', '#value' => $content_type, ]; // Iterate through the built items and add form elemetns for each one. foreach (element_children($build) as $key) { $element = $build[$key]; if (array_key_exists('#tripal_toc_id', $element)) { $toc_id = $element['#tripal_toc_id']; $toc_title = $element['#tripal_toc_title']; $toc_weight = $element['#weight']; $toc_hide = $element['#hide']; $form['toc_items'][$toc_id]['title'] = [ '#type' => 'textfield', '#default_value' => $toc_title, ]; $form['toc_items'][$toc_id]['hide'] = [ '#type' => 'checkbox', '#default_value' => $toc_hide, ]; $form['toc_items'][$toc_id]['weight'] = [ '#type' => 'textfield', '#default_value' => $toc_weight, '#attributes' => [ 'class' => ['tripal-node-toc-items-weights'], ], '#size' => 5, ]; } } $form['toc_items']['#theme'] = 'tripal_node_toc_items_table'; $form['submit'] = [ '#type' => 'submit', '#name' => 'toc_submit', '#value' => t('Submit'), ]; $form['unset'] = [ '#type' => 'submit', '#name' => 'toc_unset', '#value' => t('Reset to Defaults'), ]; return $form; } /** * Implements hook_validate for the tripal_core_node_toc_form. */ function tripal_core_content_type_toc_form_validate($form, &$form_state) { $toc_items = $form_state['values']['toc_items']; // Iterate through the TOC items and validate. foreach ($toc_items as $toc_id => $item) { if (!$item['title']) { form_set_error('toc_items][' . $toc_id, "Please provide a valid title."); } } } /** * Implements hook_submit for the tripal_core_node_toc_form. */ function tripal_core_content_type_toc_form_submit($form, &$form_state) { $toc_items = $form_state['values']['toc_items']; $content_type = $form_state['values']['content_type']; if ($form_state['clicked_button']['#name'] == "toc_submit") { $transaction = db_transaction(); try { // First delete any settings for this content type db_delete('tripal_toc') ->condition('node_type', $content_type) ->isNull('nid') ->execute(); // Second add in any new settings for this node foreach ($toc_items as $toc_id => $item) { db_insert('tripal_toc') ->fields([ 'node_type' => $content_type, 'key' => $toc_id, 'title' => $item['title'], 'weight' => $item['weight'], 'hide' => $item['hide'], ]) ->execute(); } drupal_set_message("TOC changes successfully applied to this content type."); } catch (Exception $e) { $transaction->rollback(); drupal_set_message("Failed to apply TOC changes.", "error"); } } if ($form_state['clicked_button']['#name'] == "toc_unset") { $transaction = db_transaction(); try { // First delete any settings for this node db_delete('tripal_toc') ->condition('node_type', $content_type) ->isNull('nid') ->execute(); drupal_set_message("The TOC is reset to defaults for this content type."); } catch (Exception $e) { $transaction->rollback(); drupal_set_message("Failed to apply TOC changes.", "error"); } } }