View source
<?php
namespace Drupal\markdown\Plugin\Markdown\CommonMark;
use Composer\Semver\Semver;
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\markdown\Form\SubformState;
use Drupal\markdown\Plugin\Markdown\AllowedHtmlInterface;
use Drupal\markdown\Plugin\Markdown\BaseExtensibleParser;
use Drupal\markdown\Plugin\Markdown\SettingsInterface;
use Drupal\markdown\Traits\ParserAllowedHtmlTrait;
use Drupal\markdown\Util\Composer;
use Drupal\markdown\Util\KeyValuePipeConverter;
class CommonMark extends BaseExtensibleParser implements AllowedHtmlInterface {
use ParserAllowedHtmlTrait;
protected static $converterClass;
protected static $environmentClass;
protected static $version;
protected $converter;
protected $environment;
public function __sleep() {
unset($this->converter);
unset($this->environment);
return parent::__sleep();
}
public static function defaultSettings($pluginDefinition) {
if (!$pluginDefinition->version || Semver::satisfies($pluginDefinition->version, '<0.6.0')) {
return [];
}
return [
'allow_unsafe_links' => TRUE,
'enable_em' => TRUE,
'enable_strong' => TRUE,
'html_input' => 'escape',
'max_nesting_level' => 0,
'renderer' => [
'block_separator' => "\n",
'inner_separator' => "\n",
'soft_break' => "\n",
],
'use_asterisk' => TRUE,
'use_underscore' => TRUE,
'unordered_list_markers' => [
'-',
'*',
'+',
],
] + parent::defaultSettings($pluginDefinition);
}
public static function converterClass() {
if (!isset(static::$converterClass)) {
$classes = [
'\\League\\CommonMark\\CommonMarkConverter',
'\\ColinODell\\CommonMark\\CommonMarkConverter',
];
foreach ($classes as $class) {
if (class_exists($class)) {
static::$converterClass = $class;
}
}
}
return static::$converterClass;
}
public static function environmentClass() {
if (!isset(static::$environmentClass)) {
$classes = [
'\\League\\CommonMark\\Environment\\Environment',
'\\League\\CommonMark\\Environment',
];
foreach ($classes as $class) {
if (class_exists($class)) {
static::$environmentClass = $class;
}
}
}
return static::$environmentClass;
}
protected function convertToHtml($markdown, LanguageInterface $language = NULL) {
return $this
->converter()
->convertToHtml($markdown);
}
public function buildConfigurationForm(array $element, FormStateInterface $form_state) {
$element = parent::buildConfigurationForm($element, $form_state);
$element += $this
->createSettingElement('allow_unsafe_links', [
'#type' => 'checkbox',
'#title' => $this
->t('Allow Unsafe Links'),
'#description' => $this
->t('Allows potentially risky links and image URLs to remain in the document.'),
], $form_state);
$this
->renderStrategyDisabledSettingState($form_state, $element['allow_unsafe_links']);
$element += $this
->createSettingElement('enable_em', [
'#type' => 'checkbox',
'#title' => $this
->t('Enable Emphasis'),
'#description' => $this
->t('Enables <code><em></code> parsing.'),
], $form_state);
$element += $this
->createSettingElement('enable_strong', [
'#type' => 'checkbox',
'#title' => $this
->t('Enable Strong'),
'#description' => $this
->t('Enables <code><strong></code> parsing.'),
], $form_state);
$element += $this
->createSettingElement('html_input', [
'#weight' => -1,
'#type' => 'select',
'#title' => $this
->t('HTML Input'),
'#description' => $this
->t('Strategy to use when handling raw HTML input.'),
'#options' => [
'allow' => $this
->t('Allow'),
'escape' => $this
->t('Escape'),
'strip' => $this
->t('Strip'),
],
], $form_state);
$this
->renderStrategyDisabledSettingState($form_state, $element['html_input']);
if ($this
->getRenderStrategy() !== static::NONE) {
$element['html_input']['#value'] = 'allow';
}
$element += $this
->createSettingElement('max_nesting_level', [
'#type' => 'number',
'#title' => $this
->t('Maximum Nesting Level'),
'#description' => $this
->t('The maximum nesting level for blocks. Setting this to a positive integer can help protect against long parse times and/or segfaults if blocks are too deeply-nested.'),
'#min' => 0,
'#max' => 100000,
], $form_state, 'intval');
$element['renderer'] = [
'#type' => 'container',
];
$rendererSubformState = SubformState::createForSubform($element['renderer'], $element, $form_state);
$element['renderer'] += $this
->createSettingElement('renderer.block_separator', [
'#type' => 'textfield',
'#title' => $this
->t('Block Separator'),
'#description' => $this
->t('String to use for separating renderer block elements.'),
], $rendererSubformState, '\\Drupal\\markdown\\Plugin\\Markdown\\CommonMark\\CommonMark::addcslashes');
$element['renderer'] += $this
->createSettingElement('renderer.inner_separator', [
'#type' => 'textfield',
'#title' => $this
->t('Inner Separator'),
'#description' => $this
->t('String to use for separating inner block contents.'),
], $rendererSubformState, '\\Drupal\\markdown\\Plugin\\Markdown\\CommonMark\\CommonMark::addcslashes');
$element['renderer'] += $this
->createSettingElement('renderer.soft_break', [
'#type' => 'textfield',
'#title' => $this
->t('Soft Break'),
'#description' => $this
->t('String to use for rendering soft breaks.'),
], $rendererSubformState, '\\Drupal\\markdown\\Plugin\\Markdown\\CommonMark\\CommonMark::addcslashes');
$element['renderer']['#access'] = $element['renderer']['block_separator']['#access'];
$element += $this
->createSettingElement('use_asterisk', [
'#type' => 'checkbox',
'#title' => $this
->t('Use Asterisk'),
'#description' => $this
->t('Enables parsing of <code>*</code> for emphasis.'),
], $form_state);
$element += $this
->createSettingElement('use_underscore', [
'#type' => 'checkbox',
'#title' => $this
->t('Use Underscore'),
'#description' => $this
->t('Enables parsing of <code>_</code> for emphasis.'),
], $form_state);
$element += $this
->createSettingElement('unordered_list_markers', [
'#type' => 'textarea',
'#title' => $this
->t('Unordered List Markers'),
'#description' => $this
->t('Characters that are used to indicated a bulleted list; only one character per line.'),
], $form_state, '\\Drupal\\markdown\\Util\\KeyValuePipeConverter::denormalizeNoKeys');
return $element;
}
public static function addcslashes($string, $charlist = "\n\r\t") {
return \addcslashes($string, $charlist);
}
public function converter() {
if (!$this->converter) {
$version = $this
->getVersion();
if (Semver::satisfies($version, '>=0.13.0')) {
$this->converter = $this
->getObject($this
->getSettings(TRUE), $this
->getEnvironment());
}
elseif (Semver::satisfies($version, '>=0.6.0 <0.13.0')) {
$this->converter = $this
->getObject($this
->getSettings(TRUE));
}
else {
$this->converter = $this
->getObject();
}
}
return $this->converter;
}
protected function createEnvironment() {
$environment = static::environmentClass();
return $environment::createCommonMarkEnvironment();
}
public function extensionInterfaces() {
if (!interface_exists('\\League\\CommonMark\\Extension\\ExtensionInterface')) {
return [];
}
return parent::extensionInterfaces();
}
public function getConfiguration() {
$configuration = parent::getConfiguration();
if ($this
->getRenderStrategy() !== static::NONE) {
$configuration['settings']['allow_unsafe_links'] = TRUE;
$configuration['settings']['html_input'] = 'allow';
}
if (isset($configuration['settings']['renderer']) && is_array($configuration['settings']['renderer'])) {
foreach ($configuration['settings']['renderer'] as &$setting) {
$setting = addcslashes($setting, "\n\r\t");
}
}
if (isset($configuration['settings']['max_nesting_level']) && $configuration['settings']['max_nesting_level'] === INF) {
$configuration['settings']['max_nesting_level'] = 0;
}
foreach ([
'unordered_list_markers',
] as $name) {
if (isset($configuration['settings'][$name])) {
$configuration['settings'][$name] = KeyValuePipeConverter::normalize($configuration['settings'][$name]);
}
}
return $configuration;
}
protected function getEnvironment() {
if (!$this->environment) {
$environment = $this
->createEnvironment();
$settings = $this
->getSettings(TRUE);
if ($this
->getRenderStrategy() !== static::NONE) {
$settings['allow_unsafe_links'] = TRUE;
$settings['html_input'] = 'allow';
}
$extensions = $this
->extensions();
foreach ($extensions as $extension) {
if (!$extension
->isEnabled()) {
continue;
}
if ($extension instanceof SettingsInterface) {
$settingsKey = $extension
->settingsKey();
if ($settingsKey === NULL || $settingsKey === TRUE) {
throw new InvalidPluginDefinitionException($extension
->getPluginId(), sprintf('The "%s" markdown extension must also supply a value in %s. This is a requirement of the parser so it knows how extension settings should be merged.', $extension
->getPluginId(), '\\Drupal\\markdown\\Plugin\\Markdown\\SettingsInterface::settingsKey'));
}
if ($settingsKey !== FALSE) {
$extensionSettings = $extension
->getSettings(TRUE);
if ($settingsKey) {
$extensionSettings = [
$settingsKey => $extensionSettings,
];
}
$settings = NestedArray::mergeDeep($settings, $extensionSettings);
}
}
$extension
->register($environment);
}
$environment
->setConfig(NestedArray::mergeDeep($environment
->getConfig(), $settings));
$this->environment = $environment;
}
return $this->environment;
}
public function setConfiguration(array $configuration) {
if (isset($configuration['settings']['renderer'])) {
foreach ($configuration['settings']['renderer'] as &$setting) {
$setting = stripcslashes($setting);
}
}
if (isset($configuration['settings']['max_nesting_level']) && $configuration['settings']['max_nesting_level'] <= 0) {
$configuration['settings']['max_nesting_level'] = INF;
}
foreach ([
'unordered_list_markers',
] as $name) {
if (isset($configuration['settings'][$name])) {
$configuration['settings'][$name] = KeyValuePipeConverter::normalize($configuration['settings'][$name]);
}
}
return parent::setConfiguration($configuration);
}
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::validateConfigurationForm($form, $form_state);
if ($unorderedListMarkers = $form_state
->getValue('unordered_list_markers')) {
$unorderedListMarkers = KeyValuePipeConverter::normalize($unorderedListMarkers);
foreach ($unorderedListMarkers as $marker) {
if (strlen($marker) > 1) {
$form_state
->setError($form['unordered_list_markers'], $this
->t('The Unordered List Markers must be only one character per line.'));
}
}
}
}
}