You are here

class BaseParser in Markdown 3.0.x

Same name and namespace in other branches
  1. 8.2 src/Plugin/Markdown/BaseParser.php \Drupal\markdown\Plugin\Markdown\BaseParser

Plugin annotation


@MarkdownParser(
  id = "_broken",
  label = @Translation("Missing Parser"),
)

Hierarchy

Expanded class hierarchy of BaseParser

File

src/Plugin/Markdown/BaseParser.php, line 21

Namespace

Drupal\markdown\Plugin\Markdown
View source
class BaseParser extends PluginBase implements MarkdownParserInterface, MarkdownGuidelinesInterface {

  /**
   * The allowed HTML tags, if set.
   *
   * @var array
   */
  protected $allowedTags;

  /**
   * MarkdownExtension plugins specific to a parser.
   *
   * @var array
   */
  protected static $extensions;

  /**
   * The current filter being used.
   *
   * @var \Drupal\markdown\Plugin\Filter\MarkdownFilterInterface
   */
  protected $filter;

  /**
   * The filter identifier.
   *
   * @var string
   */
  protected $filterId = '_default';

  /**
   * The parser settings.
   *
   * @var array
   */
  protected $settings = [];

  /**
   * {@inheritdoc}
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    if (isset($configuration['filter'])) {
      $this->filter = $configuration['filter'];
      $this->filterId = $this->filter
        ->getPluginId();
    }
    if (isset($configuration['settings'])) {
      $this->settings = $configuration['settings'];
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function installed() : bool {
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public static function version() {
    return NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function convertToHtml($markdown, LanguageInterface $language = NULL) {
    return $markdown;
  }

  /**
   * {@inheritdoc}
   */
  public function getFilter() {
    return $this->filter;
  }

  /**
   * {@inheritdoc}
   */
  public function getGuidelines() {
    $base_url = Url::fromRoute('<front>', [], [
      'absolute' => TRUE,
    ])
      ->toString();
    $site_name = \Drupal::config('system.site')
      ->get('name');

    // Define default groups.
    $guides = [
      'general' => [
        'title' => $this
          ->t('General'),
        'items' => [],
      ],
      'blockquotes' => [
        'title' => $this
          ->t('Block Quotes'),
        'items' => [],
      ],
      'code' => [
        'title' => $this
          ->t('Code'),
        'items' => [],
      ],
      'headings' => [
        'title' => $this
          ->t('Headings'),
        'items' => [],
      ],
      'images' => [
        'title' => $this
          ->t('Images'),
        'items' => [],
      ],
      'links' => [
        'title' => $this
          ->t('Links'),
        'items' => [],
      ],
      'lists' => [
        'title' => $this
          ->t('Lists'),
        'items' => [],
      ],
    ];

    // @codingStandardsIgnoreStart
    // Ignore Drupal coding standards during this section of code. There are
    // multiple concatenated $this->t() strings that need to be ignored.
    // General.
    $guides['general']['items'][] = [
      'title' => $this
        ->t('Paragraphs'),
      'description' => $this
        ->t('Paragraphs are simply one or more consecutive lines of text, separated by one or more blank lines.'),
      'strip_p' => FALSE,
      'tags' => [
        'p' => [
          t('Paragraph one.') . "\n\n" . $this
            ->t('Paragraph two.'),
        ],
      ],
    ];
    $guides['general']['items'][] = [
      'title' => $this
        ->t('Line Breaks'),
      'description' => $this
        ->t('If you want to insert a <kbd>&lt;br /&gt;</kbd> break tag, end a line with two or more spaces, then type return.'),
      'strip_p' => FALSE,
      'tags' => [
        'br' => [
          t("Text with  \nline break"),
        ],
      ],
    ];
    $guides['general']['items'][] = [
      'title' => $this
        ->t('Horizontal Rule'),
      'tags' => [
        'hr' => [
          '---',
          '___',
          '***',
        ],
      ],
    ];
    $guides['general']['items'][] = [
      'title' => $this
        ->t('Deleted text'),
      'description' => $this
        ->t('The CommonMark spec does not (yet) have syntax for <kbd>&lt;del&gt;</kbd> formatting. You must manually specify them.'),
      'tags' => [
        'del' => '<del>' . $this
          ->t('Deleted') . '</del>',
      ],
    ];
    $guides['general']['items'][] = [
      'title' => $this
        ->t('Emphasized text'),
      'tags' => [
        'em' => [
          '_' . $this
            ->t('Emphasized') . '_',
          '*' . $this
            ->t('Emphasized') . '*',
        ],
      ],
    ];
    $guides['general']['items'][] = [
      'title' => $this
        ->t('Strong text'),
      'tags' => [
        'strong' => [
          '__' . $this
            ->t('Strong', [], [
            'context' => 'Font weight',
          ]) . '__',
          '**' . $this
            ->t('Strong', [], [
            'context' => 'Font weight',
          ]) . '**',
        ],
      ],
    ];

    // Blockquotes.
    $guides['blockquotes']['items'][] = [
      'tags' => [
        'blockquote' => [
          '> ' . $this
            ->t("Block quoted") . "\n\n" . $this
            ->t("Normal text"),
          '> ' . $this
            ->t("Nested block quotes\n>> Nested block quotes\n>>> Nested block quotes\n>>>> Nested block quotes") . "\n\n" . $this
            ->t("Normal text"),
          '> ' . $this
            ->t("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.") . "\n\n" . $this
            ->t("Normal text"),
        ],
      ],
    ];

    // Code.
    $guides['code']['items'][] = [
      'title' => $this
        ->t('Inline code'),
      'tags' => [
        'code' => '`' . $this
          ->t('Inline code') . '`',
      ],
    ];
    $guides['code']['items'][] = [
      'title' => $this
        ->t('Fenced code blocks'),
      'tags' => [
        'pre' => [
          "```\n" . $this
            ->t('Fenced code block') . "\n```",
          "~~~\n" . $this
            ->t('Fenced code block') . "\n~~~",
          "    " . $this
            ->t('Fenced code block - indented using 4+ spaces'),
          "\t" . $this
            ->t('Fenced code block - indented using tab'),
        ],
      ],
    ];
    $guides['code']['items'][] = [
      'title' => $this
        ->t('Fenced code blocks (using languages)'),
      'tags' => [
        'pre' => [
          "```css\n.selector {\n  color: #ff0;\n  font-size: 10px;\n  content: 'string';\n}\n```",
          "```js\nvar \$selector = \$('#id');\n\$selector.foo('bar', {\n  'baz': true,\n  'value': 1\n});\n```",
          "```php\n\$build['table'] = array(\n  '#theme' => 'table',\n  '#header' => \$header,\n  '#rows' => \$rows,\n  '#sticky' => FALSE,\n);\nprint \\Drupal::service('renderer')->renderPlain(\$build);\n```",
        ],
      ],
    ];

    // Headings.
    $guides['headings']['items'][] = [
      'tags' => [
        'h1' => '# ' . $this
          ->t('Heading 1'),
        'h2' => '## ' . $this
          ->t('Heading 2'),
        'h3' => '### ' . $this
          ->t('Heading 3'),
        'h4' => '#### ' . $this
          ->t('Heading 4'),
        'h5' => '##### ' . $this
          ->t('Heading 5'),
        'h6' => '###### ' . $this
          ->t('Heading 6'),
      ],
    ];

    // Images.
    $guides['images']['items'][] = [
      'title' => $this
        ->t('Images'),
      'tags' => [
        'img' => [
          '![' . $this
            ->t('Alt text') . '](http://lorempixel.com/400/200/ "' . $this
            ->t('Title text') . '")',
        ],
      ],
    ];
    $guides['images']['items'][] = [
      'title' => $this
        ->t('Referenced images'),
      'strip_p' => FALSE,
      'tags' => [
        'img' => [
          "Lorem ipsum dolor sit amet\n\n![" . $this
            ->t('Alt text') . "]\n\nLorem ipsum dolor sit amet\n\n[" . $this
            ->t('Alt text') . ']: http://lorempixel.com/400/200/ "' . $this
            ->t('Title text') . '"',
        ],
      ],
    ];

    // Links
    $guides['links']['items'][] = [
      'title' => $this
        ->t('Links'),
      'tags' => [
        'a' => [
          "<{$base_url}>",
          "[{$site_name}]({$base_url})",
          "<john.doe@example.com>",
          "[Email: {$site_name}](mailto:john.doe@example.com)",
        ],
      ],
    ];
    $guides['links']['items'][] = [
      'title' => $this
        ->t('Referenced links'),
      'description' => $this
        ->t('Link references are very useful if you use the same words through out a document and wish to link them all to the same link.'),
      'tags' => [
        'a' => [
          "[{$site_name}]\n\n[{$site_name}]: {$base_url} \"" . $this
            ->t('My title') . '"',
          "Lorem ipsum [dolor] sit amet, consectetur adipiscing elit.\nLorem ipsum [dolor] sit amet, consectetur adipiscing elit.\nLorem ipsum [dolor] sit amet, consectetur adipiscing elit.\n\n[dolor]: {$base_url} \"" . $this
            ->t('My title') . '"',
        ],
      ],
    ];
    $guides['links']['items'][] = [
      'title' => $this
        ->t('Fragments (anchors)'),
      'tags' => [
        'a' => [
          "[{$site_name}]({$base_url}#fragment)",
          "[{$site_name}](#element-id)",
        ],
      ],
    ];

    // Lists.
    $guides['lists']['items'][] = [
      'title' => $this
        ->t('Ordered lists'),
      'tags' => [
        'ol' => [
          "1. " . $this
            ->t('First item') . "\n2. " . $this
            ->t('Second item') . "\n3. " . $this
            ->t('Third item') . "\n4. " . $this
            ->t('Fourth item'),
          "1) " . $this
            ->t('First item') . "\n2) " . $this
            ->t('Second item') . "\n3) " . $this
            ->t('Third item') . "\n4) " . $this
            ->t('Fourth item'),
          "1. " . $this
            ->t('All start with 1') . "\n1. " . $this
            ->t('All start with 1') . "\n1. " . $this
            ->t('All start with 1') . "\n1. " . $this
            ->t('Rendered with correct numbers'),
          "1. " . $this
            ->t('First item') . "\n2. " . $this
            ->t('Second item') . "\n   1. " . $this
            ->t('First nested item') . "\n   2. " . $this
            ->t('Second nested item') . "\n      1. " . $this
            ->t('Deep nested item'),
          "5. " . $this
            ->t('Start at fifth item') . "\n6. " . $this
            ->t('Sixth item') . "\n7. " . $this
            ->t('Seventh item') . "\n8. " . $this
            ->t('Eighth item'),
        ],
      ],
    ];
    $guides['lists']['items'][] = [
      'title' => $this
        ->t('Unordered lists'),
      'tags' => [
        'ul' => [
          "- " . $this
            ->t('First item') . "\n- " . $this
            ->t('Second item'),
          "- " . $this
            ->t('First item') . "\n- " . $this
            ->t('Second item') . "\n  - " . $this
            ->t('First nested item') . "\n  - " . $this
            ->t('Second nested item') . "\n    - " . $this
            ->t('Deep nested item'),
          "* " . $this
            ->t('First item') . "\n* " . $this
            ->t('Second item'),
          "+ " . $this
            ->t('First item') . "\n+ " . $this
            ->t('Second item'),
        ],
      ],
    ];

    // @codingStandardsIgnoreEnd
    return $guides;
  }

  /**
   * {@inheritdoc}
   */
  public function getAllowedTags() {
    return $this->allowedTags;
  }

  /**
   * {@inheritdoc}
   */
  public function getDescription() {
    return $this->pluginDefinition['description'] ?? NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function getFilterFormat($format = NULL) {
    $default = filter_default_format();

    // Immediately return if filter is already an object.
    if ($format instanceof FilterFormatInterface) {
      return $format;
    }

    // Immediately return the default format if none was specified.
    if (!isset($format)) {
      return $default;
    }
    $formats = filter_formats();
    return isset($formats[$format]) ? $formats[$format] : $default;
  }

  /**
   * {@inheritdoc}
   */
  public function getLabel($version = TRUE) {
    if (!$version) {
      return $this->pluginDefinition['label'];
    }
    $variables['@label'] = $this->pluginDefinition['label'];
    $variables['@version'] = $this
      ->getVersion();
    return $variables['@version'] ? $this
      ->t('@label (@version)', $variables) : $variables['@label'];
  }

  /**
   * {@inheritdoc}
   */
  public function getSummary() {
    return [];
  }

  /**
   * {@inheritdoc}
   */
  public function getUrl() {
    $url = $this->pluginDefinition['url'] ?? NULL;
    if ($url && UrlHelper::isExternal($url)) {
      return Url::fromUri($url);
    }
    return $url ? Url::fromUserInput($url) : NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function getVersion() {
    return $this->pluginDefinition['version'];
  }

  /**
   * {@inheritdoc}
   */
  public function isInstalled() : bool {
    return $this->pluginDefinition['installed'];
  }

  /**
   * {@inheritdoc}
   */
  public function load($id, $markdown = NULL, LanguageInterface $language = NULL) {
    if ($parsed = ParsedMarkdown::load($id)) {
      return $parsed;
    }
    return $markdown !== NULL ? $this
      ->parse($markdown, $language)
      ->setId($id)
      ->save() : NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function loadPath($id, $path, LanguageInterface $language = NULL) {

    // Append the file modification time as a cache buster in case it changed.
    $id = "{$id}:" . filemtime($path);
    return ParsedMarkdown::load($id) ?: $this
      ->parsePath($path, $language)
      ->setId($id)
      ->save();
  }

  /**
   * {@inheritdoc}
   */
  public function loadUrl($id, $url, LanguageInterface $language = NULL) {
    return ParsedMarkdown::load($id) ?: $this
      ->parseUrl($url, $language)
      ->setId($id)
      ->save();
  }

  /**
   * {@inheritdoc}
   */
  public function parse($markdown, LanguageInterface $language = NULL) {
    return ParsedMarkdown::create($markdown, $this
      ->convertToHtml($markdown, $language), $language);
  }

  /**
   * {@inheritdoc}
   */
  public function parsePath($path, LanguageInterface $language = NULL) {
    if (!file_exists($path)) {
      throw new FileNotFoundException((string) $path);
    }
    return $this
      ->parse(file_get_contents($path) ?: '', $language);
  }

  /**
   * {@inheritdoc}
   */
  public function parseUrl($url, LanguageInterface $language = NULL) {
    if ($url instanceof Url) {
      $url = $url
        ->setAbsolute()
        ->toString();
    }
    $response = \Drupal::httpClient()
      ->get($url);
    if ($response
      ->getStatusCode() >= 200 && $response
      ->getStatusCode() < 400) {
      $contents = $response
        ->getBody()
        ->getContents();
    }
    else {
      throw new FileNotFoundException((string) $url);
    }
    return $this
      ->parse($contents, $language);
  }

  /**
   * {@inheritdoc}
   */
  public function setAllowedTags(array $tags = []) {
    $this->allowedTags = $tags;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function tips($long = FALSE) {

    // On the "short" tips, just show and render the summary, if any.
    if (!$long) {
      $summary = $this
        ->getSummary();
      if (!$summary) {
        return NULL;
      }
      return (string) \Drupal::service('renderer')
        ->render($summary);
    }

    // On the long tips, the render array must be retrieved as a "form" due to
    // the fact that vertical tabs require form processing to work properly.
    $formBuilder = \Drupal::formBuilder();
    $formState = (new FormState())
      ->addBuildInfo('args', [
      $long,
      $this,
    ]);
    $form = $formBuilder
      ->buildForm('\\Drupal\\markdown\\Form\\MarkdownFilterTipsForm', $formState);

    // Since this is essentially "hacking" the FAPI and not an actual "form",
    // just extract the relevant child elements from the "form" and render it.
    $tips = [];
    foreach ([
      'help',
      'tips',
      'guides',
      'allowed_tags',
    ] as $child) {
      if (isset($form[$child])) {
        $tips[] = $form[$child];
      }
    }
    return \Drupal::service('renderer')
      ->render($tips[1]);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
BaseParser::$allowedTags protected property The allowed HTML tags, if set.
BaseParser::$extensions protected static property MarkdownExtension plugins specific to a parser. 1
BaseParser::$filter protected property The current filter being used.
BaseParser::$filterId protected property The filter identifier.
BaseParser::$settings protected property The parser settings.
BaseParser::convertToHtml public function Converts Markdown into HTML. Overrides MarkdownParserInterface::convertToHtml 4
BaseParser::getAllowedTags public function Retrieves allowed HTML tags, if set. Overrides MarkdownParserInterface::getAllowedTags
BaseParser::getDescription public function Retrieves the description of the plugin, if set. Overrides MarkdownInstallablePluginInterface::getDescription
BaseParser::getFilter public function Retrieves the markdown filter plugin, if set. Overrides MarkdownParserInterface::getFilter
BaseParser::getFilterFormat public function Retrieves a filter format entity. Overrides MarkdownParserInterface::getFilterFormat
BaseParser::getGuidelines public function Builds a guide on how to use the Markdown Parser. Overrides MarkdownGuidelinesInterface::getGuidelines 1
BaseParser::getLabel public function Displays the human-readable label of the plugin. Overrides MarkdownInstallablePluginInterface::getLabel
BaseParser::getSummary public function Retrieves a short summary of what the MarkdownParser does. Overrides MarkdownParserInterface::getSummary
BaseParser::getUrl public function Retrieves the URL for the parser, if any. Overrides MarkdownParserInterface::getUrl
BaseParser::getVersion public function The current version of the parser. Overrides MarkdownInstallablePluginInterface::getVersion
BaseParser::installed public static function Indicates whether the parser is installed. Overrides MarkdownInstallablePluginInterface::installed 4
BaseParser::isInstalled public function Indicates whether the parser is installed. Overrides MarkdownInstallablePluginInterface::isInstalled
BaseParser::load public function Loads a cached ParsedMarkdown object. Overrides MarkdownParserInterface::load
BaseParser::loadPath public function Loads a cached ParsedMarkdown object for a local file system path. Overrides MarkdownParserInterface::loadPath
BaseParser::loadUrl public function Loads a cached ParsedMarkdown object for a URL. Overrides MarkdownParserInterface::loadUrl
BaseParser::parse public function Parses markdown into HTML. Overrides MarkdownParserInterface::parse
BaseParser::parsePath public function Parses markdown from a local file into HTML. Overrides MarkdownParserInterface::parsePath
BaseParser::parseUrl public function Parses markdown from an external URL into HTML. Overrides MarkdownParserInterface::parseUrl
BaseParser::setAllowedTags public function Sets the allowed HTML tags. Overrides MarkdownParserInterface::setAllowedTags
BaseParser::tips public function Generates a filter's tip. Overrides MarkdownParserInterface::tips
BaseParser::version public static function Retrieves the version of the installed parser. Overrides MarkdownInstallablePluginInterface::version 4
BaseParser::__construct public function Constructs a \Drupal\Component\Plugin\PluginBase object. Overrides PluginBase::__construct
DependencySerializationTrait::$_entityStorages protected property
DependencySerializationTrait::$_serviceIds protected property
DependencySerializationTrait::__sleep public function 2
DependencySerializationTrait::__wakeup public function 2
MessengerTrait::$messenger protected property The messenger. 27
MessengerTrait::messenger public function Gets the messenger. 27
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 2
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
StringTranslationTrait::$stringTranslation protected property The string translation service. 4
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.