You are here

readmore.module in Readmore 8

Same filename and directory in other branches
  1. 7 readmore.module
  2. 2.x readmore.module

Contains readmore module.

File

readmore.module
View source
<?php

/**
 * @file
 * Contains readmore module.
 */
use Drupal\Component\Utility\Unicode;

/**
 * Implements hook_theme().
 */
function readmore_theme() {
  return [
    'readmore' => [
      'variables' => [
        'summary' => NULL,
        'text' => NULL,
      ],
    ],
  ];
}

/**
 * Truncate string by a number of characters.
 *
 * @param string $text
 *   The string to truncate.
 * @param string $format
 *   The format of the content.
 * @param int $size
 *   An upper limit on the returned string length.
 * @param bool $wordsafe
 *   If TRUE, attempt to truncate on a word boundary.
 *
 * @return string
 *   Return truncated string.
 */
function readmore_truncate_string($text, $format = NULL, $size = NULL, $wordsafe = FALSE, $use_break = TRUE) {
  if (!isset($size)) {

    // If size is not set then use default.
    $size = 500;
  }
  if ($use_break) {

    // Find where the delimiter is in the body.
    $delimiter = Unicode::strpos($text, '<!--break-->');
    if ($delimiter) {

      // Set new size.
      $size = $delimiter;
    }
  }

  // We check for the presence of the PHP evaluator filter in the current
  // format. If the body contains PHP code just return as is.
  $filters = [];
  if (isset($format)) {
    $filter_entities = \Drupal::entityTypeManager()
      ->getStorage('filter_format')
      ->loadByProperties([
      'status' => TRUE,
    ]);
    foreach ($filter_entities as $filter) {
      $filters[] = $filter
        ->id();
      if ($filter
        ->id() == 'php_code' && strpos($text, '<?') !== FALSE) {
        return $text;
      }
    }
  }

  // The summary may not be longer than maximum length specified. Initial slice.
  $summary = Unicode::truncate($text, $size, $wordsafe, FALSE);
  if ($wordsafe) {

    // Store the actual length of the truncated string.
    $max_rpos = Unicode::strlen($summary);

    // How much to cut off the end of the summary so that it doesn't end in the
    // middle of a paragraph, sentence, or word.
    // Initialize it to maximum in order to find the minimum.
    $min_rpos = $max_rpos;

    // Store the reverse of the summary.
    $reversed = strrev($summary);

    // Build an array of arrays of break points grouped by preference.
    $break_points = [];

    // A paragraph near the end of sliced summary is most preferable.
    $break_points[] = [
      '</p>' => 0,
    ];

    // If no complete paragraph then treat line breaks as paragraphs.
    $line_breaks = [
      '<br />' => 6,
      '<br>' => 4,
    ];

    // Newline only indicates a line break if line break converter
    // filter is present.
    if (isset($filters['filter_autop'])) {
      $line_breaks["\n"] = 1;
    }
    $break_points[] = $line_breaks;

    // If the first paragraph is too long, split at the end of a sentence.
    $break_points[] = [
      '. ' => 1,
      '! ' => 1,
      '? ' => 1,
      '。' => 0,
      '؟ ' => 1,
    ];

    // Iterate over the groups of break points until a break point is found.
    foreach ($break_points as $points) {

      // Look for each break point, starting at the end of the summary.
      foreach ($points as $point => $offset) {

        // The summary is already reversed, but the break point isn't.
        $rpos = Unicode::strpos($reversed, strrev($point));
        if ($rpos !== FALSE) {
          $min_rpos = min($rpos + $offset, $min_rpos);
        }
      }

      // If a break point was found in this group, slice and stop searching.
      if ($min_rpos !== $max_rpos) {

        // Don't slice with length 0. Length must be <0 to slice from RHS.
        $summary = $min_rpos === 0 ? $summary : Unicode::substr($summary, 0, 0 - $min_rpos);
        break;
      }
    }
  }
  return $summary;
}

Functions

Namesort descending Description
readmore_theme Implements hook_theme().
readmore_truncate_string Truncate string by a number of characters.