const DIASPORA = 3;
const CONNECTORS = 4;
const TWITTER_API = 5;
+ const NPF = 6;
const OSTATUS = 7;
const TWITTER = 8;
const BACKLINK = 8;
const ACTIVITYPUB = 9;
+ const BLUESKY = 10;
- const TOP_ANCHOR = '<br class="top-anchor">';
+ const SHARED_ANCHOR = '<hr class="shared-anchor">';
+ const TOP_ANCHOR = '<br class="top-anchor">';
const BOTTOM_ANCHOR = '<br class="button-anchor">';
const PREVIEW_NONE = 0;
break;
case 'title':
- $value = self::convert(html_entity_decode($value, ENT_QUOTES, 'UTF-8'), false, true);
+ $value = self::convertForUriId(0, html_entity_decode($value, ENT_QUOTES, 'UTF-8'), BBCode::EXTERNAL);
$value = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
$value = str_replace(['[', ']'], ['[', ']'], $value);
$data['title'] = $value;
// Remove attachment
$text = self::replaceAttachment($text);
- $naked_text = HTML::toPlaintext(self::convert($text, false, 0, true), 0, !$keep_urls);
+ $naked_text = HTML::toPlaintext(self::convert($text, false, BBCode::EXTERNAL, true), 0, !$keep_urls);
DI::profiler()->stopRecording();
return $naked_text;
*/
private static function convertUrlForActivityPub(string $url): string
{
- return sprintf('<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>', $url, self::getStyledURL($url));
- }
-
- /**
- * Converts an URL in a nicer format (without the scheme and possibly shortened)
- *
- * @param string $url URL that is about to be reformatted
- * @return string reformatted link
- */
- private static function getStyledURL(string $url): string
- {
- $parts = parse_url($url);
- $scheme = $parts['scheme'] . '://';
- $styled_url = str_replace($scheme, '', $url);
-
- if (strlen($styled_url) > 30) {
- $styled_url = substr($styled_url, 0, 30) . "…";
- }
-
- return $styled_url;
+ return sprintf('<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>', $url, Strings::getStyledURL($url));
}
/*
/*
* The previously spacefied [noparse][ i ]italic[ /i ][/noparse],
- * now turns back and the [noparse] tags are trimed
+ * now turns back and the [noparse] tags are trimmed
* returning [i]italic[/i]
*
* @param array $match
$network = $contact['network'] ?? Protocol::PHANTOM;
$tpl = Renderer::getMarkupTemplate('shared_content.tpl');
- $text .= Renderer::replaceMacros($tpl, [
+ $text .= BBCode::SHARED_ANCHOR . Renderer::replaceMacros($tpl, [
'$profile' => $attributes['profile'],
'$avatar' => $attributes['avatar'],
'$author' => $attributes['author'],
/// @todo Have a closer look at the different html modes
// Handle attached links or videos
- if (in_array($simple_html, [self::MASTODON_API, self::TWITTER_API, self::ACTIVITYPUB])) {
+ if ($simple_html == self::NPF) {
+ $text = self::removeAttachment($text);
+ } elseif (in_array($simple_html, [self::MASTODON_API, self::TWITTER_API, self::ACTIVITYPUB])) {
$text = self::replaceAttachment($text);
} elseif (!in_array($simple_html, [self::INTERNAL, self::EXTERNAL, self::CONNECTORS])) {
$text = self::replaceAttachment($text, true);
}
// Check for headers
- $text = preg_replace("(\[h1\](.*?)\[\/h1\])ism", '</p><h1>$1</h1><p>', $text);
- $text = preg_replace("(\[h2\](.*?)\[\/h2\])ism", '</p><h2>$1</h2><p>', $text);
- $text = preg_replace("(\[h3\](.*?)\[\/h3\])ism", '</p><h3>$1</h3><p>', $text);
- $text = preg_replace("(\[h4\](.*?)\[\/h4\])ism", '</p><h4>$1</h4><p>', $text);
- $text = preg_replace("(\[h5\](.*?)\[\/h5\])ism", '</p><h5>$1</h5><p>', $text);
- $text = preg_replace("(\[h6\](.*?)\[\/h6\])ism", '</p><h6>$1</h6><p>', $text);
+
+ if ($simple_html == self::INTERNAL) {
+ //Ensure to always start with <h4> if possible
+ $heading_count = 0;
+ for ($level = 6; $level > 0; $level--) {
+ if (preg_match("(\[h$level\].*?\[\/h$level\])ism", $text)) {
+ $heading_count++;
+ }
+ }
+ if ($heading_count > 0) {
+ $heading = min($heading_count + 3, 6);
+ for ($level = 6; $level > 0; $level--) {
+ if (preg_match("(\[h$level\].*?\[\/h$level\])ism", $text)) {
+ $text = preg_replace("(\[h$level\](.*?)\[\/h$level\])ism", "</p><h$heading>$1</h$heading><p>", $text);
+ $heading--;
+ }
+ }
+ }
+ } else {
+ $text = preg_replace("(\[h1\](.*?)\[\/h1\])ism", '</p><h1>$1</h1><p>', $text);
+ $text = preg_replace("(\[h2\](.*?)\[\/h2\])ism", '</p><h2>$1</h2><p>', $text);
+ $text = preg_replace("(\[h3\](.*?)\[\/h3\])ism", '</p><h3>$1</h3><p>', $text);
+ $text = preg_replace("(\[h4\](.*?)\[\/h4\])ism", '</p><h4>$1</h4><p>', $text);
+ $text = preg_replace("(\[h5\](.*?)\[\/h5\])ism", '</p><h5>$1</h5><p>', $text);
+ $text = preg_replace("(\[h6\](.*?)\[\/h6\])ism", '</p><h6>$1</h6><p>', $text);
+ }
// Check for paragraph
$text = preg_replace("(\[p\](.*?)\[\/p\])ism", '<p>$1</p>', $text);
// Simplify "video" element
$text = preg_replace('(\[video[^\]]*?\ssrc\s?=\s?([^\s\]]+)[^\]]*?\].*?\[/video\])ism', '[video]$1[/video]', $text);
- if ($try_oembed) {
+ if ($simple_html == self::NPF) {
+ $text = preg_replace(
+ "/\[video\](.*?)\[\/video\]/ism",
+ '</p><video src="$1" controls width="100%" height="auto">$1</video><p>',
+ $text
+ );
+ $text = preg_replace(
+ "/\[audio\](.*?)\[\/audio\]/ism",
+ '</p><audio src="$1" controls>$1">$1</audio><p>',
+ $text
+ );
+ } elseif ($try_oembed) {
// html5 video and audio
$text = preg_replace(
"/\[video\](.*?\.(ogg|ogv|oga|ogm|webm|mp4).*?)\[\/video\]/ism",
$text = preg_replace("/\[iframe\](.*?)\[\/iframe\]/ism", '<a href="$1">$1</a>', $text);
// Youtube extensions
- if ($try_oembed) {
- $text = preg_replace_callback("/\[youtube\](https?:\/\/www.youtube.com\/watch\?v\=.*?)\[\/youtube\]/ism", $try_oembed_callback, $text);
- $text = preg_replace_callback("/\[youtube\](www.youtube.com\/watch\?v\=.*?)\[\/youtube\]/ism", $try_oembed_callback, $text);
- $text = preg_replace_callback("/\[youtube\](https?:\/\/www.youtube.com\/shorts\/.*?)\[\/youtube\]/ism", $try_oembed_callback, $text);
- $text = preg_replace_callback("/\[youtube\](https?:\/\/youtu.be\/.*?)\[\/youtube\]/ism", $try_oembed_callback, $text);
- }
-
$text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text);
$text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/embed\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text);
$text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/shorts\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text);
);
}
- if ($try_oembed) {
- $text = preg_replace_callback("/\[vimeo\](https?:\/\/player.vimeo.com\/video\/[0-9]+).*?\[\/vimeo\]/ism", $try_oembed_callback, $text);
- $text = preg_replace_callback("/\[vimeo\](https?:\/\/vimeo.com\/[0-9]+).*?\[\/vimeo\]/ism", $try_oembed_callback, $text);
- }
-
$text = preg_replace("/\[vimeo\]https?:\/\/player.vimeo.com\/video\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $text);
$text = preg_replace("/\[vimeo\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $text);
$text
);
- if (in_array($simple_html, [self::OSTATUS, self::TWITTER])) {
+ if (in_array($simple_html, [self::OSTATUS, self::TWITTER, self::BLUESKY])) {
$text = preg_replace_callback("/([^#@!])\[url\=([^\]]*)\](.*?)\[\/url\]/ism", [self::class, 'expandLinksCallback'], $text);
//$text = preg_replace("/[^#@!]\[url\=([^\]]*)\](.*?)\[\/url\]/ism", ' $2 [url]$1[/url]', $text);
$text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", ' $2 [url]$1[/url]', $text);
// Convert it to HTML - don't try oembed
if ($for_diaspora) {
- $text = self::convert($text, false, self::DIASPORA);
+ $text = self::convertForUriId(0, $text, self::DIASPORA);
// Add all tags that maybe were removed
if (preg_match_all("/#\[url\=([$url_search_string]*)\](.*?)\[\/url\]/ism", $original_text, $tags)) {
$text = $text . ' ' . $tagline;
}
} else {
- $text = self::convert($text, false, self::CONNECTORS);
+ $text = self::convertForUriId(0, $text, self::CONNECTORS);
}
// If a link is followed by a quote then there should be a newline before it