Skip to content

Commit

Permalink
Merge pull request #654 from UN-OCHA/RW-812
Browse files Browse the repository at this point in the history
[RW-812] Fix external links for jobs/training
  • Loading branch information
orakili authored Sep 28, 2023
2 parents d4ebaa0 + c1f160c commit f6cb1fe
Show file tree
Hide file tree
Showing 2 changed files with 230 additions and 5 deletions.
89 changes: 84 additions & 5 deletions config/filter.format.markdown_editor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ langcode: en
status: true
dependencies:
module:
- editor
- media
- reliefweb_fields
- reliefweb_guidelines
- reliefweb_utility
name: 'Markdown with Editor'
format: markdown_editor
Expand All @@ -13,7 +16,7 @@ filters:
id: filter_html
provider: filter
status: true
weight: -10
weight: -49
settings:
allowed_html: '<br> <p> <h2> <h3> <h4> <h5> <h6> <strong> <em> <a href> <ul> <ol> <li>'
filter_html_help: false
Expand All @@ -22,24 +25,100 @@ filters:
id: filter_htmlcorrector
provider: filter
status: true
weight: 10
weight: -47
settings: { }
filter_markdown:
id: filter_markdown
provider: reliefweb_utility
status: true
weight: -20
weight: -50
settings: { }
reliefweb_token_filter:
id: reliefweb_token_filter
provider: reliefweb_utility
status: false
weight: 0
weight: -37
settings:
replace_empty: '0'
reliefweb_formatted_text:
id: reliefweb_formatted_text
provider: reliefweb_fields
status: true
weight: 0
weight: -48
settings: { }
reliefweb_external_link_filter:
id: reliefweb_external_link_filter
provider: reliefweb_utility
status: true
weight: -46
settings: { }
editor_file_reference:
id: editor_file_reference
provider: editor
status: false
weight: -44
settings: { }
filter_html_escape:
id: filter_html_escape
provider: filter
status: false
weight: -45
settings: { }
filter_url:
id: filter_url
provider: filter
status: false
weight: -40
settings:
filter_url_length: 72
filter_html_image_secure:
id: filter_html_image_secure
provider: filter
status: false
weight: -36
settings: { }
filter_image_lazy_load:
id: filter_image_lazy_load
provider: filter
status: false
weight: -35
settings: { }
filter_caption:
id: filter_caption
provider: filter
status: false
weight: -41
settings: { }
filter_autop:
id: filter_autop
provider: filter
status: false
weight: -42
settings: { }
filter_align:
id: filter_align
provider: filter
status: false
weight: -43
settings: { }
media_embed:
id: media_embed
provider: media
status: false
weight: -34
settings:
default_view_mode: default
allowed_view_modes: { }
allowed_media_types: { }
filter_guideline_link:
id: filter_guideline_link
provider: reliefweb_guidelines
status: false
weight: -39
settings: { }
filter_iframe:
id: filter_iframe
provider: reliefweb_utility
status: false
weight: -38
settings: { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?php

namespace Drupal\reliefweb_utility\Plugin\Filter;

use Drupal\Component\Render\MarkupInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\filter\FilterProcessResult;
use Drupal\filter\Plugin\FilterBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;

/**
* Provides a filter to add attributes to external links to open in a new tab.
*
* @Filter(
* id = "reliefweb_external_link_filter",
* title = @Translation("Open external Links in new tab."),
* description = @Translation("Add target and rel attributes to external links so they open in a new tab."),
* type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE,
* )
*/
class ExternalLinkFilter extends FilterBase implements ContainerFactoryPluginInterface {

/**
* Current request.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;

/**
* Internal host pattern.
*
* @var string
*/
protected $internalHostPattern;

/**
* Constructs a markdown filter plugin.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, RequestStack $request_stack) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->requestStack = $request_stack;
}

/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('request_stack')
);
}

/**
* {@inheritdoc}
*/
public function process($text, $langcode) {
if (is_string($text) || $text instanceof MarkupInterface) {
$html = trim($text);
if ($html !== '') {
// Adding this meta tag is necessary to tell \DOMDocument we are dealing
// with UTF-8 encoded html.
$flags = LIBXML_NONET | LIBXML_NOBLANKS | LIBXML_NOERROR | LIBXML_NOWARNING;
$meta = '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">';
$prefix = '<!DOCTYPE html><html><head>' . $meta . '</head><body>';
$suffix = '</body></html>';
$dom = new \DOMDocument();
$dom->loadHTML($prefix . $text . $suffix, $flags);

// Process the links.
$links = $dom->getElementsByTagName('a');
foreach ($links as $link) {
$this->handleLink($link);
}

// Get the modified html.
$html = $dom->saveHTML();

// Search for the body tag and return its content.
$start = mb_strpos($html, '<body>');
$end = mb_strrpos($html, '</body>');
if ($start !== FALSE && $end !== FALSE) {
$start += 6;
$text = trim(mb_substr($html, $start, $end - $start));
}
}
}
return new FilterProcessResult($text);
}

/**
* Check if a URL is an ReliefWeb URL.
*
* @param string $url
* URL to check.
*
* @return bool
* TRUE if the URL is internal.
*/
protected function isInternalUrl($url) {
if (empty($url)) {
return TRUE;
}

if (!isset($this->internalHostPattern)) {
$internal_hosts = [
preg_quote($this->requestStack->getCurrentRequest()->getHost()),
preg_quote('reliefweb.int'),
];

$this->internalHostPattern = '#^https?://(' . implode('|', $internal_hosts) . ')(/|$)#';
}

return preg_match('#^https?://#', $url) !== 1 ||
preg_match($this->internalHostPattern, $url) === 1;
}

/**
* Add the target and rel attributes to external links to open in a new tab.
*
* @param \DOMNode $node
* Link node.
*/
protected function handleLink(\DOMNode $node) {
$url = $node->getAttribute('href');

if (!$this->isInternalUrl($url)) {
$node->setAttribute('target', '_blank');
$node->setAttribute('rel', 'noreferrer noopener');
}
}

}

0 comments on commit f6cb1fe

Please sign in to comment.