From bb8dca03ecd7a1bd3b251f1019ef4a45047f7f8e Mon Sep 17 00:00:00 2001 From: Tananda Densmore Date: Thu, 7 Mar 2024 13:51:34 -0500 Subject: [PATCH] Added new Link target features (this is not part of the standard markdown spec so this is a bit of an extension, but I find it highly useful) --- LICENSE.txt | 4 ++++ Parsedown.php | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 28 +++++++++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/LICENSE.txt b/LICENSE.txt index 8e7c764d1..ea01bf431 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -2,6 +2,10 @@ The MIT License (MIT) Copyright (c) 2013-2018 Emanuil Rusev, erusev.com +Modified by The DigitalSorceress. www.digitalsorceress.com (added external link +target optinos) 2024 under the same license and in the same spirit as the +original. + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to diff --git a/Parsedown.php b/Parsedown.php index ae0cbdecd..3c68e68e7 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -56,6 +56,41 @@ protected function textElements($text) # Setters # + /** + * ## When enabled all parsed hyperlinks will have their target attribute set to _blank + * - This will cause all links to open in a new winwow / tab + * - If you only want links to external sites to have the target _blank then set this false + * and instead, use setExtLinksInNewWindow to true instead + * ### NOTE that this property set to true overrides setExtLinksInNewWindow + * @param bool $allLinksInNewWindow + * @return void + */ + function setAllinksInNewWindow($allLinksInNewWindow) + { + $this->allLinksInNewWindow = $allLinksInNewWindow; + } + + protected $allLinksInNewWindow; + + /** + * ## When enabled all external hyperlinks will have their target attribute set to _blank + * - This will cause links to external sites to open in a new winwow / tab + * - It uses the presense of http/https as the determining factor as to whether a link is "external" + * - This is a bit of a cheat but it works well for my purposes + * - If you only want links to all sites to have the target _blank then set this false + * and instead, use setAllinksInNewWindow to true + * ### NOTE that SetAllLinksInNewWindow true will override this behavior + * + * @param bool $extLinksInNewWindow + * @return void + */ + function setExtLinksInNewWindow($extLinksInNewWindow) + { + $this->extLinksInNewWindow = $extLinksInNewWindow; + } + + protected $extLinksInNewWindow; + function setBreaksEnabled($breaksEnabled) { $this->breaksEnabled = $breaksEnabled; @@ -1398,6 +1433,7 @@ protected function inlineLink($Excerpt) 'attributes' => array( 'href' => null, 'title' => null, + 'target' => null, ), ); @@ -1427,6 +1463,12 @@ protected function inlineLink($Excerpt) $Element['attributes']['title'] = substr($matches[2], 1, - 1); } + if ($this->allLinksInNewWindow || ($this->extLinksInNewWindow && str_starts_with($matches[1], 'http'))) { + $Element['attributes']['target'] = '_blank'; + } else { + $Element['attributes']['target'] = '_self'; + } + $extent += strlen($matches[0]); } else @@ -1452,6 +1494,12 @@ protected function inlineLink($Excerpt) $Element['attributes']['href'] = $Definition['url']; $Element['attributes']['title'] = $Definition['title']; + + if ($this->allLinksInNewWindow || ($this->extLinksInNewWindow && str_starts_with($Definition['url]'], 'http'))) { + $Element['attributes']['target'] = '_blank'; + } else { + $Element['attributes']['target'] = '_self'; + } } return array( @@ -1541,6 +1589,12 @@ protected function inlineUrl($Excerpt) ) { $url = $matches[0][0]; + if ($this->allLinksInNewWindow || ($this->extLinksInNewWindow && str_starts_with($url, 'http'))) { + $target = '_blank'; + } else { + $target = '_self'; + } + $Inline = array( 'extent' => strlen($matches[0][0]), 'position' => $matches[0][1], @@ -1549,6 +1603,7 @@ protected function inlineUrl($Excerpt) 'text' => $url, 'attributes' => array( 'href' => $url, + 'target' => $target, ), ), ); @@ -1563,6 +1618,12 @@ protected function inlineUrlTag($Excerpt) { $url = $matches[1]; + if ($this->allLinksInNewWindow || ($this->extLinksInNewWindow && str_starts_with($url, 'http'))) { + $target = '_blank'; + } else { + $target = '_self'; + } + return array( 'extent' => strlen($matches[0]), 'element' => array( @@ -1570,6 +1631,7 @@ protected function inlineUrlTag($Excerpt) 'text' => $url, 'attributes' => array( 'href' => $url, + 'target' => $target, ), ), ); diff --git a/README.md b/README.md index d366d133e..843b377c7 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,34 @@ $Parsedown->setMarkupEscaped(true); Beware that this still allows users to insert unsafe scripting vectors, ex: `[xss](javascript:alert%281%29)`. +## Link Target Features +Fork by The Digital Sorceress to add options to let one control how the target attribute is set in links + +The original parsedown did not set any link target attribute at all. This leads to the default that all links are opened in the same window. For users whow want alternate behavior, two new configuration options were added: + +### setExtLinksInNewWindow + +With this feature enabled: + +``` php +$parser->setExtLinksInNewWindow(true); +``` + +Links that start with http (so http and https) will be considered "external" and thus will use the _blank target attribute - meaning that they will open in a new window/tab instead of in the current window/tab + +When set to false, (and assuming setAllLinksInNewWindow is not set below) all links will open in _self + +When links are parsed that do not start with http/https (so relative or absolute links, they will not be targeted to _blank with this setting on (or off) + +### setAllLinksInNewWindow +Functions the same as setExtLinksInNewWindow above except that ALL links whether htey start wth http or not will be forced to target=_blank and thus open in a new tab/ window. + +``` php +$parser->setAllLinksInNewWindow(true); +``` + +This setting set to true will override the setExtLinks and force all - so if both are on then this takes prioroty. + ## Questions **How does Parsedown work?**