class HashAutolinker in Markdown 3.0.x
Plugin annotation
@MarkdownExtension(
id = "hash_autolinker",
label = @Translation("# Autolinker"),
installed = TRUE,
description = @Translation("Automatically link commonly used references that come after a hash character (#) without having to use the link syntax."),
parsers = {"thephpleague/commonmark", "thephpleague/commonmark-gfm"},
)
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements DerivativeInspectionInterface, PluginInspectionInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
- class \Drupal\markdown\Plugin\Markdown\Extension\BaseExtension implements MarkdownExtensionInterface uses MarkdownStatesTrait
- class \Drupal\markdown\Plugin\Markdown\Extension\CommonMarkExtension implements CommonMarkExtensionInterface
- class \Drupal\markdown\Plugin\Markdown\Extension\HashAutolinker implements \League\CommonMark\Inline\Parser\InlineParserInterface, MarkdownGuidelinesAlterInterface
- class \Drupal\markdown\Plugin\Markdown\Extension\CommonMarkExtension implements CommonMarkExtensionInterface
- class \Drupal\markdown\Plugin\Markdown\Extension\BaseExtension implements MarkdownExtensionInterface uses MarkdownStatesTrait
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
Expanded class hierarchy of HashAutolinker
File
- src/
Plugin/ Markdown/ Extension/ HashAutolinker.php, line 23
Namespace
Drupal\markdown\Plugin\Markdown\ExtensionView source
class HashAutolinker extends CommonMarkExtension implements InlineParserInterface, MarkdownGuidelinesAlterInterface {
/**
* {@inheritdoc}
*/
public function alterGuidelines(array &$guides = []) {
if ($this
->getSetting('type') === 'node') {
$description = [
t('Text that starts with hash symbol (#) followed by numbers will be automatically be linked to a node on this site.'),
];
if ($this
->getSetting('node_title')) {
$description[] = t('The node title will be used in place the text.');
}
$description[] = t('If the node does not exist, it will not automatically link.');
$guides['links']['items'][] = [
'title' => t('# Autolinker'),
'description' => $description,
];
}
elseif ($this
->getSetting('type') === 'url') {
$description = [
t('Text that starts with a hash symbol (#) followed by any character other than a space will automatically be linked to the following URL: <code>@url</code>', [
'@url' => $this
->getSetting('url'),
]),
];
if ($this
->getSetting('url_title')) {
$description[] = t('The URL title will be used in place of the original text.');
}
$guides['links']['items'][] = [
'title' => t('@ Autolinker'),
'description' => $description,
'tags' => [
'a' => [
'#3060',
'#2562913',
'#259843',
],
],
];
}
}
/**
* {@inheritdoc}
*/
public function defaultSettings() {
return [
'type' => 'node',
'node_title' => TRUE,
'url' => 'https://www.drupal.org/node/[text]',
'url_title' => TRUE,
];
}
/**
* {@inheritdoc}
*/
public function getCharacters() : array {
return [
'#',
];
}
/**
* {@inheritdoc}
*/
public function parse(InlineParserContext $inline_context) : bool {
$cursor = $inline_context
->getCursor();
// The # symbol must not have any other characters immediately prior.
$previous_char = $cursor
->peek(-1);
if ($previous_char !== NULL && $previous_char !== ' ' && $previous_char !== '[') {
// peek() doesn't modify the cursor, so no need to restore state first.
return FALSE;
}
// Save the cursor state in case we need to rewind and bail.
$previous_state = $cursor
->saveState();
// Advance past the # symbol to keep parsing simpler.
$cursor
->advance();
// Parse the handle.
$text = $cursor
->match('/^[^\\s\\]]+/');
$url = FALSE;
$title = FALSE;
$type = $this
->getSetting('type');
// @todo Make entity type abstract and comment aware.
if ($type === 'node' && is_numeric($text) && ($node = \Drupal::entityTypeManager()
->getStorage('node')
->load($text))) {
$url = $node
->toUrl('canonical', [
'absolute' => TRUE,
])
->toString();
if ($this
->getSetting('node_title') && ($title = $node
->label())) {
$text = $title;
}
else {
$text = "#{$text}";
}
}
elseif ($type === 'url' && ($url = $this
->getSetting('url')) && strpos($url, '[text]') !== FALSE) {
$url = str_replace('[text]', $text, $url);
if ($this
->getSetting('url_title') && ($title = $this
->getUrlTitle($url))) {
$text = $title;
$title = FALSE;
}
}
else {
$text = FALSE;
}
// Regex failed to match; this isn't a valid @ handle.
if (empty($text) || empty($url)) {
$cursor
->restoreState($previous_state);
return FALSE;
}
$inline_context
->getContainer()
->appendChild(new Link($url, $text, $title));
return TRUE;
}
/**
* Retrieves a URL page title.
*
* @param string $url
* The URL to retrieve the title from.
*
* @return string|false
* The URL title or FALSE if it could not be retrieved.
*/
protected function getUrlTitle($url) {
$response = \Drupal::httpClient()
->get($url);
if ($response
->getStatusCode() >= 200 && $response
->getStatusCode() < 400) {
$dom = new \DOMDocument();
@$dom
->loadHTML($response
->getBody()
->getContents());
if (($title = $dom
->getElementsByTagName('title')) && $title->length) {
return Html::escape(trim(preg_replace('/\\s+/', ' ', $title
->item(0)->textContent)));
}
}
return FALSE;
}
/**
* Retrieves an Entity object for the current route.
*
* @return \Drupal\Core\Entity\EntityInterface|null
* An Entity object or NULL if none could be found.
*/
protected function currentRouteEntity() {
$route_match = \Drupal::routeMatch();
foreach ($route_match
->getParameters()
->all() as $item) {
if ($item instanceof EntityInterface) {
return $item;
}
}
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $element, FormStateInterface $formState, MarkdownFilterInterface $filter) {
$element = parent::settingsForm($element, $formState, $filter);
$selector = $this
->getSatesSelector($this
->getElementParents($element, [
$this
->getPluginId(),
]), 'type');
$element['type'] = [
'#type' => 'select',
'#title' => $this
->t('Map text to'),
'#default_value' => $this
->getSetting('type'),
'#options' => [
'node' => $this
->t('Node'),
'url' => $this
->t('URL'),
],
];
$element['node_title'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Replace text with title of node'),
'#description' => $this
->t('If enabled, it will replace the matched text with the title of the node.'),
'#default_value' => $this
->getSetting('node_title'),
'#states' => [
'visible' => [
$selector => [
'value' => 'node',
],
],
],
];
$element['url'] = [
'#type' => 'textfield',
'#title' => $this
->t('URL'),
'#description' => $this
->t('A URL to format text with. Use the token "[text]" where it is needed. If you need to include the #, use the URL encoded equivalent: <code>%23</code>. Example: <code>https://twitter.com/search?q=%23[text]</code>.'),
'#default_value' => $this
->getSetting('url'),
'#states' => [
'visible' => [
$selector => [
'value' => 'url',
],
],
],
];
$element['url_title'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Replace text with title of URL'),
'#description' => $this
->t('If enabled, it will replace the matched text with the title of the URL.'),
'#default_value' => $this
->getSetting('url_title'),
'#states' => [
'visible' => [
$selector => [
'value' => 'url',
],
],
],
];
return $element;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
BaseExtension:: |
protected | function | Returns generic default configuration for markdown extension plugins. | |
BaseExtension:: |
public | function | ||
BaseExtension:: |
public | function | ||
BaseExtension:: |
public | function | ||
BaseExtension:: |
public | function |
Retrieves the description of the plugin, if set. Overrides MarkdownInstallablePluginInterface:: |
|
BaseExtension:: |
public | function |
Displays the human-readable label of the plugin. Overrides MarkdownInstallablePluginInterface:: |
|
BaseExtension:: |
public | function |
Retrieves a setting. Overrides MarkdownExtensionInterface:: |
|
BaseExtension:: |
public | function |
Retrieves the current settings. Overrides MarkdownExtensionInterface:: |
|
BaseExtension:: |
public | function |
Retrieves the URL of the plugin, if set. Overrides MarkdownInstallablePluginInterface:: |
|
BaseExtension:: |
public | function |
The current version of the parser. Overrides MarkdownInstallablePluginInterface:: |
|
BaseExtension:: |
public static | function |
Indicates whether the parser is installed. Overrides MarkdownInstallablePluginInterface:: |
|
BaseExtension:: |
public | function |
Indicates whether the extension is being used. Overrides MarkdownExtensionInterface:: |
|
BaseExtension:: |
public | function |
Indicates whether the parser is installed. Overrides MarkdownInstallablePluginInterface:: |
|
BaseExtension:: |
public | function | ||
BaseExtension:: |
public | function | ||
BaseExtension:: |
public | function |
Sets a specific setting. Overrides MarkdownExtensionInterface:: |
|
BaseExtension:: |
public | function |
Provides settings to an extension. Overrides MarkdownExtensionInterface:: |
|
BaseExtension:: |
public static | function |
Retrieves the version of the installed parser. Overrides MarkdownInstallablePluginInterface:: |
|
BaseExtension:: |
public | function |
Constructs a \Drupal\Component\Plugin\PluginBase object. Overrides PluginBase:: |
|
CommonMarkExtension:: |
public | function |
Retrieves the name of the extension. Overrides CommonMarkExtensionInterface:: |
|
DependencySerializationTrait:: |
protected | property | ||
DependencySerializationTrait:: |
protected | property | ||
DependencySerializationTrait:: |
public | function | 2 | |
DependencySerializationTrait:: |
public | function | 2 | |
HashAutolinker:: |
public | function |
Alters existing guides on how to use the Markdown Parser. Overrides MarkdownGuidelinesAlterInterface:: |
|
HashAutolinker:: |
protected | function | Retrieves an Entity object for the current route. | |
HashAutolinker:: |
public | function |
Retrieves the default settings. Overrides BaseExtension:: |
|
HashAutolinker:: |
public | function | ||
HashAutolinker:: |
protected | function | Retrieves a URL page title. | |
HashAutolinker:: |
public | function | ||
HashAutolinker:: |
public | function |
Returns the configuration form elements specific to this plugin. Overrides BaseExtension:: |
|
MarkdownStatesTrait:: |
protected static | function | Retrieves the ancestry of the extension in a form/render array. | |
MarkdownStatesTrait:: |
protected static | function | Retrieves a states selector to use based on the form/render array parents. | |
MessengerTrait:: |
protected | property | The messenger. | 27 |
MessengerTrait:: |
public | function | Gets the messenger. | 27 |
MessengerTrait:: |
public | function | Sets the messenger. | |
PluginBase:: |
protected | property | Configuration information passed into the plugin. | 1 |
PluginBase:: |
protected | property | The plugin implementation definition. | 1 |
PluginBase:: |
protected | property | The plugin_id. | |
PluginBase:: |
constant | A string which is used to separate base plugin IDs from the derivative ID. | ||
PluginBase:: |
public | function |
Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the definition of the plugin implementation. Overrides PluginInspectionInterface:: |
2 |
PluginBase:: |
public | function |
Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface:: |
|
PluginBase:: |
public | function | Determines if the plugin is configurable. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 4 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. |