You are here

function tableofcontents_filter in Table of Contents 5.2

Same name and namespace in other branches
  1. 5 tableofcontents.module \tableofcontents_filter()
  2. 6.3 tableofcontents.module \tableofcontents_filter()
  3. 6.2 tableofcontents.module \tableofcontents_filter()

Implementation of hook_filter().

File

./tableofcontents.module, line 74
This is a filter module to generate a collapsible jquery enabled mediawiki style table of contents based on <h[1-6]> tags. Transforms header tags into named anchors.

Code

function tableofcontents_filter($op, $delta = 0, $format = -1, $text = '') {
  if ($op == 'list') {
    return array(
      0 => t('Table of Contents'),
    );
  }
  global $toc_options;
  switch ($op) {
    case 'description':
      return t('Inserts a table of contents in the place of &lt;!--tableofcontents--&gt; tags.');
    case 'no cache':
      return FALSE;
    case 'settings':
      return _tableofcontents_settings($format);
    case 'prepare':

      // get all toc markers and options
      preg_match_all('!<\\!-- ?tableofcontents(.*)-->!', $text, $options_str, PREG_PATTERN_ORDER);

      // to optimize performance enclose preparation in conditional that tests for presence of ToC marker
      if (!empty($options_str[0]) && $options_str[0][0] != "") {

        // Set defaults.
        $toc_options = array();

        // We save a translate call and only translate this when we process the options.
        $toc_options["title"] = variable_get('tableofcontents_title_' . $format, 'Table of Contents');
        $toc_options["list"] = variable_get('tableofcontents_list_type_' . $format, 'ol');
        $toc_options["minlevel"] = variable_get('tableofcontents_minlevel_' . $format, 2);
        $toc_options["maxlevel"] = variable_get('tableofcontents_maxlevel_' . $format, 3);
        $toc_options["attachments"] = variable_get('tableofcontents_attachments_' . $format, FALSE);

        // Only process options if user arguments were specified and are allowed.
        if (variable_get('tableofcontents_allow_override_' . $format, TRUE) && count($options_str, 1) > 2) {

          // parse separate options
          preg_match_all('/([A-z]+): ?([A-z0-9 ]+);/', $options_str[1][0], $options, PREG_PATTERN_ORDER);

          // make sure arguments contain valid option identifiers
          $allowed_options = array_keys($toc_options);
          for ($i = 0; $i < sizeof($options[1]); $i++) {
            if (!in_array($options[1][$i], $allowed_options)) {
              form_set_error("Table of Contents", t("Table of Contents Error: " . $options[1][$i] . " is an invalid option."));
            }
            else {
              $toc_options[$options[1][$i]] = $options[2][$i];
            }
          }

          // validate option values, use defaults for invalid values, build & display error message
          $error_status = false;
          if ($toc_options["list"] != "ol" && $toc_options["list"] != "ul") {
            $error_message[] = $toc_options["list"] . " is an invalid list type. The only valid values for list are 'ol' or 'ul'. Using default value of ol.\n";
            $error_status = true;
            $toc_options["list"] = "ol";
          }
          if (!($toc_options["minlevel"] >= 1 && $toc_options["minlevel"] < 6)) {
            $error_message[] = $toc_options["minlevel"] . " is an invalid minimum level option. You must use a number between 1 and 4. Using default value of 1.\n";
            $error_status = true;
            $toc_options["minlevel"] = 1;
          }
          if (!($toc_options["maxlevel"] >= $toc_options["minlevel"] && $toc_options["maxlevel"] <= 6)) {
            $error_message[] = $toc_options["maxlevel"] . " is an invalid maximum depth option. You must use a number between " . $toc_options["minlevel"] . " and 5. Using default value of 3.";
            $error_status = true;
            $toc_options["maxlevel"] = 3;
          }
          if (!($toc_options["attachments"] == 1 || $toc_options["attachments"] == 0)) {
            $error_message[] = t("!attachments is an invalid attachments option. Attachments option must be set to '1' to display or '0' to hide.", array(
              '!attachments' => $toc_options["attachments"],
            ));
            $error_status = true;
          }
          if ($error_status) {

            // According to IRC, there can be issues with translations when you use dynamic variables
            // As well, t() should only be on single paragraphs with no newlines.
            // within t().
            foreach ($error_message as $message) {
              form_set_error("Table of Contents", t('%error', array(
                '%error' => $message,
              )));
            }
          }
        }

        // Translate title.
        $toc_options["title"] = t($toc_options["title"]);
      }
      return $text;
    case 'process':

      // to optimize performance enclose processing in conditional that tests for the presence of the toc marker options
      if (isset($toc_options)) {

        //build the toc

        // toc(array('level' => 1, 'heading' => $text))
        $toc = array();

        // $i = index of header level being processed
        // $matches[0][$i] -> Whole string matched
        // $matches[1][$i] -> First heading level
        // $matches[2][$i] -> Whole string of attributes
        // $matches[3][$i] -> id attibute, used for anchor
        // $matches[4][$i] -> Text of id attribute
        // $matches[5][$i] -> Text inside of h tag
        // $matches[6][$i] -> Close heading level, should be equal to open level
        $matches = array();

        //get all headers of current level, case insensitive
        $pattern = '/<h([' . $toc_options["minlevel"] . '-' . $toc_options["maxlevel"] . '])( .*?(id="([^"]+)" ?.*?))?>(.*?)<\\/h([' . $toc_options["minlevel"] . '-' . $toc_options["maxlevel"] . '])>/is';
        preg_match('!<\\!-- ?tableofcontents(.*)-->!', $text, $matches, PREG_OFFSET_CAPTURE);
        $heading_search_text = substr($text, $matches[0][1]);
        $matches = array();
        preg_match_all($pattern, $heading_search_text, $matches, PREG_PATTERN_ORDER);
        $anchors = array();
        for ($i = 0; $i < sizeof($matches[0]); $i++) {

          // Strip HTML and non alphanumerics
          $level = $matches[1][$i];
          $heading = strip_tags($matches[5][$i]);
          $anchor = $matches[4][$i];
          array_push($toc, array(
            'level' => $level,
            'heading' => $heading,
            'anchor' => $anchor,
          ));
        }

        // If attachments are enabled, prepare the $files variable
        if ($toc_options["attachments"]) {
          $nid = explode('/', $_GET['q']);
          if (isset($nid[0]) && $nid[0] == 'node' && isset($nid[1]) && is_numeric($nid[1])) {
            $nid = $nid[1];
            $node = node_load($nid);
          }
          if (!empty($node->files)) {
            $files = $node->files;
          }
        }

        // Build HTML for the Table of Contents.
        $toc_html = theme('tableofcontents_toc', $toc, $toc_options, $files);

        // replace all tableofcontents markers with generated ToC html
        return preg_replace('!<\\!-- ?tableofcontents(.*)-->!', $toc_html, $text);
      }
      else {
        return $text;
      }
  }
}