You are here

function footnotes_filter in Footnotes 5.2

Same name and namespace in other branches
  1. 5 footnotes.module \footnotes_filter()
  2. 6.2 footnotes.module \footnotes_filter()
  3. 6 footnotes.module \footnotes_filter()

Implementation of hook_filter().

The bulk of filtering work is done here. This hook is quite complicated, so we'll discuss each operation it defines.

File

./footnotes.module, line 72
The Footnotes module is a filter that can be used to insert automatically numbered footnotes into Drupal texts.

Code

function footnotes_filter($op, $delta = 0, $format = -1, $text = '') {

  // The "list" operation provides the module an opportunity to declare both how
  // many filters it defines and a human-readable name for each filter. Note that
  // the returned name should be passed through t() for translation.
  if ($op == 'list') {
    return array(
      0 => t('Footnotes [fn]...[/fn]'),
      1 => t('Footnotes Textile style'),
      99 => t('Better URL filter (fork from core)'),
    );
  }

  // All operations besides "list" provide a $delta argument so we know which
  // filter they refer to. We'll switch on that argument now so that we can
  // discuss each filter in turn.
  switch ($delta) {

    // First is the html footnotes filter
    case 0:
      switch ($op) {

        // This description is shown in the administrative interface, unlike the
        // filter tips which are shown in the content editing interface.
        case 'description':
          return t('Use [fn]...[/fn] (or <fn>...</fn>) to insert automatically numbered footnotes.');

        // We don't need the "prepare" operation for this filter, but it's required
        // to at least return the input text as-is.
        case 'prepare':
          return $text;

        // The actual filtering is performed here. The supplied text should be
        // returned, once any necessary substitutions have taken place.
        case 'process':

          // Supporting both [fn] and <fn> now. Thanks to fletchgqc http://drupal.org/node/268026
          // Convert all square brackets to angle brackets. This way all further code just
          // manipulates angle brackets. (Angle brackets are preferred here for the simple reason
          // that square brackets are more tedious to use in regexps.)
          $text = preg_replace('|\\[fn([^\\]]*)\\]|', '<fn$1>', $text);
          $text = preg_replace('|\\[/fn\\]|', '</fn>', $text);
          $text = preg_replace('|\\[footnotes([^\\]]*)\\]|', '<footnotes$1>', $text);

          // Check that there are an even number of open and closing tags.
          // If there is one closing tag missing, append this to the end.
          // If there is more disparity, throw a warning and continue.
          // A closing tag may sometimes be missing when we are processing a teaser
          // and it has been cut in the middle of the footnote. http://drupal.org/node/253326
          $foo = array();
          $open_tags = preg_match_all("|<fn([^>]*)>|", $text, $foo);
          $close_tags = preg_match_all("|</fn>|", $text, $foo);
          if ($open_tags == $close_tags + 1) {
            $text = $text . '</fn>';
          }
          elseif ($open_tags > $close_tags + 1) {
            trigger_error(t("You have unclosed fn tags. This is invalid and will produce unpredictable results."));
          }
          $pattern = '|<fn([^>]*)>(.*?)</fn>|s';
          $text = preg_replace_callback($pattern, '_footnotes_replace_callback', $text);

          // Replace tag <footnotes> with the list of footnotes.
          // If tag is not present, by default add the footnotes at the end.
          // Thanks to acp on drupal.org for this idea. see http://drupal.org/node/87226
          $footer = '';
          $footer = _footnotes_replace_callback(NULL, 'output footer');
          $pattern = '|(<footnotes([^\\]]*)>)|';
          if (preg_match($pattern, $text) > 0) {
            $text = preg_replace($pattern, $footer, $text, 1);
            return $text;
          }
          else {
            return $text . "\n\n" . $footer;
          }
      }
      break;

    // Textile version.
    case 1:
      switch ($op) {

        // This description is shown in the administrative interface, unlike the
        // filter tips which are shown in the content editing interface.
        case 'description':
          return t('Use [# ...] to insert automatically numbered footnotes in Textile markup.');

        // We don't need the "prepare" operation for this filter, but it's required
        // to at least return the input text as-is.
        case 'prepare':
          return $text;

        // The actual filtering is performed here. The supplied text should be
        // returned, once any necessary substitutions have taken place.
        case 'process':
          $text = preg_replace_callback('|\\[# (.*?)\\]|s', '_footnotes_replace_callback_textile', $text);

          //Replace Textile tag "footnotes." with the list of footnotes.

          //If tag is not present, by default add the footnotes at the end.

          //Thanks to acp on drupal.org for this idea. see http://drupal.org/node/87226
          $footer = '';
          $footer = _footnotes_replace_callback_textile(NULL, 'output footer');
          if (preg_match('/\\n *footnotes\\. *(\\n|$)/', $text) > 0) {
            $text = preg_replace('/\\n *footnotes\\. *(\\n|$)/', "\n{$footer}\n", $text, 1);
            return $text;
          }
          else {
            return $text . "\n\n" . $footer;
          }
      }
      break;
    case 99:
      switch ($op) {
        case 'description':
          return t('Better URL filter: Turns web and e-mail addresses into clickable links. NOTE: This filter is an enhancement to the Drupal core URL filter and will be deprecated if the enhancements are ever committed to Drupal core. <a href="http://drupal.org/node/161217">#161217</a>');

        // We don't need the "prepare" operation for this filter, but it's required
        // to at least return the input text as-is.
        case 'prepare':
          return $text;
        case 'process':
          return _footnotes_filter_url($text, $format);
        case 'settings':
          return _footnotes_filter_url_settings($format);
      }
      break;
  }
}