diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php deleted file mode 100644 index bea15e3d4c..0000000000 --- a/include/bb2diaspora.php +++ /dev/null @@ -1,264 +0,0 @@ -', '

', '

'], ['
', '
', '
'], $s); - - // Escaping the hash tags - $s = preg_replace('/\#([^\s\#])/', '#$1', $s); - - $s = Markdown::convert($s); - - $regexp = "/@\{(?:([^\}]+?); )?([^\} ]+)\}/"; - $s = preg_replace_callback($regexp, 'diaspora_mention2bb', $s); - - $s = str_replace('#', '#', $s); - - $s = html2bbcode($s); - - // protect the recycle symbol from turning into a tag, but without unescaping angles and naked ampersands - $s = str_replace('♲', html_entity_decode('♲', ENT_QUOTES, 'UTF-8'), $s); - - // Convert everything that looks like a link to a link - $s = preg_replace('/([^\]=]|^)(https?\:\/\/)([a-zA-Z0-9:\/\-?&;.=_~#%$!+,@]+(?

"], ["
"], $Text); - - $stamp1 = microtime(true); - - // Now convert HTML to Markdown - $converter = new HtmlConverter(); - $Text = $converter->convert($Text); - - // unmask the special chars back to HTML - $Text = str_replace(['&\_lt\_;', '&\_gt\_;', '&\_amp\_;'], ['<', '>', '&'], $Text); - - $a->save_timestamp($stamp1, "parser"); - - // Libertree has a problem with escaped hashtags. - $Text = str_replace(['\#'], ['#'], $Text); - - // Remove any leading or trailing whitespace, as this will mess up - // the Diaspora signature verification and cause the item to disappear - $Text = trim($Text); - - if ($fordiaspora) { - $URLSearchString = "^\[\]"; - $Text = preg_replace_callback("/([@]\[(.*?)\])\(([$URLSearchString]*?)\)/ism", 'diaspora_mentions', $Text); - } - - // Restore code blocks - $Text = preg_replace_callback('/#codeblock-([0-9]+)#/iU', - function ($matches) use ($codeblocks) { - $return = ''; - if (isset($codeblocks[intval($matches[1])])) { - $return = $codeblocks[$matches[1]]; - } - return $return; - } - , $Text); - - Addon::callHooks('bb2diaspora',$Text); - - return $Text; -} - -function unescape_underscores_in_links($m) { - $y = str_replace('\\_', '_', $m[2]); - return('[' . $m[1] . '](' . $y . ')'); -} - -function format_event_diaspora($ev) { - if (! ((is_array($ev)) && count($ev))) { - return ''; - } - - $bd_format = L10n::t('l F d, Y \@ g:i A') ; // Friday January 18, 2011 @ 8 AM - - $o = 'Friendica event notification:' . "\n"; - - $o .= '**' . (($ev['summary']) ? bb2diaspora($ev['summary']) : bb2diaspora($ev['desc'])) . '**' . "\n"; - - // @todo What. Is. Going. On. With. This. Useless. Ternary. Operator? - mrpetovan - $o .= L10n::t('Starts:') . ' ' . '[' . day_translate( - $ev['adjust'] ? DateTimeFormat::utc($ev['start'], $bd_format) : DateTimeFormat::utc($ev['start'], $bd_format) - ) - . '](' . System::baseUrl() . '/localtime/?f=&time=' . urlencode(DateTimeFormat::utc($ev['start'])) . ")\n"; - - if (! $ev['nofinish']) { - $o .= L10n::t('Finishes:') . ' ' . '[' . day_translate( - $ev['adjust'] ? DateTimeFormat::utc($ev['finish'], $bd_format) : DateTimeFormat::utc($ev['finish'], $bd_format) - ) - . '](' . System::baseUrl() . '/localtime/?f=&time=' . urlencode(DateTimeFormat::utc($ev['finish'])) . ")\n"; - } - - if (strlen($ev['location'])) { - $o .= L10n::t('Location:') . bb2diaspora($ev['location']) - . "\n"; - } - - $o .= "\n"; - return $o; -} diff --git a/mod/babel.php b/mod/babel.php index 43b5c4e807..99e6f4078d 100644 --- a/mod/babel.php +++ b/mod/babel.php @@ -7,7 +7,6 @@ use Friendica\Content\Text\BBCode; use Friendica\Content\Text\Markdown; use Friendica\Core\L10n; -require_once 'include/bb2diaspora.php'; require_once 'include/html2bbcode.php'; function visible_lf($s) @@ -49,16 +48,16 @@ function babel_content() $o .= '

' . L10n::t('bbcode => html2bbcode: ') . '

' . EOL . EOL; $o .= visible_lf($bbcode) . EOL . EOL; - $diaspora = bb2diaspora($text); - $o .= '

' . L10n::t('bb2diaspora: ') . '

' . EOL . EOL; + $diaspora = BBCode::toMarkdown($text); + $o .= '

' . L10n::t('BBCode::toMarkdown: ') . '

' . EOL . EOL; $o .= visible_lf($diaspora) . EOL . EOL; $html = Markdown::convert($diaspora); - $o .= '

' . L10n::t('bb2diaspora => Markdown: ') . '

' . EOL . EOL; + $o .= '

' . L10n::t('BBCode::toMarkdown => Markdown::convert: ') . '

' . EOL . EOL; $o .= $html . EOL . EOL; - $bbcode = diaspora2bb($diaspora); - $o .= '

' . L10n::t('bb2diaspora => diaspora2bb: ') . '

' . EOL . EOL; + $bbcode = Markdown::toBBCode($diaspora); + $o .= '

' . L10n::t('BBCode::toMarkdown => Markdown::toBBCode: ') . '

' . EOL . EOL; $o .= visible_lf($bbcode) . EOL . EOL; $bbcode = html2bbcode($html); @@ -71,7 +70,7 @@ function babel_content() $o .= '

' . L10n::t("Source input \x28Diaspora format\x29: ") . '

' . EOL . EOL; $o .= '
' . $d2bbtext . '
' . EOL . EOL; - $bb = diaspora2bb($d2bbtext); + $bb = Markdown::toBBCode($d2bbtext); $o .= '

' . L10n::t('diaspora2bb: ') . '

' . EOL . EOL; $o .= '
' . $bb . '
' . EOL . EOL; } diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 8dd9305ca3..9c7dac2605 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -1,33 +1,37 @@ %s
', trim(BBCode::convert($data["description"]))); + $return .= sprintf('
%s
', trim(self::convert($data["description"]))); } if ($data["type"] == "link") { @@ -1202,7 +1206,7 @@ class BBCode $text = Cache::get($match[1]); if (is_null($text)) { - $a = get_app(); + $a = self::getApp(); $stamp1 = microtime(true); @@ -1261,7 +1265,7 @@ class BBCode $text = Cache::get($match[1]); if (is_null($text)) { - $a = get_app(); + $a = self::getApp(); $stamp1 = microtime(true); @@ -1285,7 +1289,7 @@ class BBCode $doc = new DOMDocument(); @$doc->loadHTML($body); - $xpath = new DomXPath($doc); + $xpath = new DOMXPath($doc); $list = $xpath->query("//meta[@name]"); foreach ($list as $node) { $attr = []; @@ -1348,7 +1352,7 @@ class BBCode */ public static function convert($text, $try_oembed = true, $simple_html = false, $for_plaintext = false) { - $a = get_app(); + $a = self::getApp(); /* * preg_match_callback function to replace potential Oembed tags with Oembed content @@ -1978,4 +1982,148 @@ class BBCode return $abstract; } + + /** + * @brief Callback function to replace a Friendica style mention in a mention for Diaspora + * + * @param array $match Matching values for the callback + * @return string Replaced mention + */ + private static function bbCodeMention2DiasporaCallback($match) + { + $contact = Contact::getDetailsByURL($match[3]); + + if (empty($contact['addr'])) { + $contact = Probe::uri($match[3]); + } + + if (empty($contact['addr'])) { + return $match[0]; + } + + $mention = '@{' . $match[2] . '; ' . $contact['addr'] . '}'; + return $mention; + } + + /** + * @brief Converts a BBCode text into Markdown + * + * This function converts a BBCode item body to be sent to Markdown-enabled + * systems like Diaspora and Libertree + * + * @param string $text + * @param bool $for_diaspora Diaspora requires more changes than Libertree + * @return string + */ + public static function toMarkdown($text, $for_diaspora = true) + { + $a = self::getApp(); + + $original_text = $text; + + // Since Diaspora is creating a summary for links, this function removes them before posting + if ($for_diaspora) { + $text = self::removeShareInformation($text); + } + + /** + * Transform #tags, strip off the [url] and replace spaces with underscore + */ + $url_search_string = "^\[\]"; + $text = preg_replace_callback("/#\[url\=([$url_search_string]*)\](.*?)\[\/url\]/i", + function ($matches) { + return '#' . str_replace(' ', '_', $matches[2]); + }, + $text + ); + + // Converting images with size parameters to simple images. Markdown doesn't know it. + $text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $text); + + // Extracting multi-line code blocks before the whitespace processing/code highlighter in self::convert() + $codeblocks = []; + + $text = preg_replace_callback("#\[code(?:=([^\]]*))?\](.*?)\[\/code\]#is", + function ($matches) use (&$codeblocks) { + $return = $matches[0]; + if (strpos($matches[2], "\n") !== false) { + $return = '#codeblock-' . count($codeblocks) . '#'; + + $prefix = '````' . $matches[1] . PHP_EOL; + $codeblocks[] = $prefix . trim($matches[2]) . PHP_EOL . '````'; + } + return $return; + }, + $text + ); + + // Convert it to HTML - don't try oembed + if ($for_diaspora) { + $text = self::convert($text, false, 3); + + // Add all tags that maybe were removed + if (preg_match_all("/#\[url\=([$url_search_string]*)\](.*?)\[\/url\]/ism", $original_text, $tags)) { + $tagline = ""; + foreach ($tags[2] as $tag) { + $tag = html_entity_decode($tag, ENT_QUOTES, 'UTF-8'); + if (!strpos(html_entity_decode($text, ENT_QUOTES, 'UTF-8'), '#' . $tag)) { + $tagline .= '#' . $tag . ' '; + } + } + $text = $text . " " . $tagline; + } + } else { + $text = self::convert($text, false, 4); + } + + // mask some special HTML chars from conversation to markdown + $text = str_replace(['<', '>', '&'], ['&_lt_;', '&_gt_;', '&_amp_;'], $text); + + // If a link is followed by a quote then there should be a newline before it + // Maybe we should make this newline at every time before a quote. + $text = str_replace(["
"], ["
"], $text); + + $stamp1 = microtime(true); + + // Now convert HTML to Markdown + $converter = new HtmlConverter(); + $text = $converter->convert($text); + + // unmask the special chars back to HTML + $text = str_replace(['&\_lt\_;', '&\_gt\_;', '&\_amp\_;'], ['<', '>', '&'], $text); + + $a->save_timestamp($stamp1, "parser"); + + // Libertree has a problem with escaped hashtags. + $text = str_replace(['\#'], ['#'], $text); + + // Remove any leading or trailing whitespace, as this will mess up + // the Diaspora signature verification and cause the item to disappear + $text = trim($text); + + if ($for_diaspora) { + $url_search_string = "^\[\]"; + $text = preg_replace_callback( + "/([@]\[(.*?)\])\(([$url_search_string]*?)\)/ism", + ['self', 'bbCodeMention2DiasporaCallback'], + $text + ); + } + + // Restore code blocks + $text = preg_replace_callback('/#codeblock-([0-9]+)#/iU', + function ($matches) use ($codeblocks) { + $return = ''; + if (isset($codeblocks[intval($matches[1])])) { + $return = $codeblocks[$matches[1]]; + } + return $return; + }, + $text + ); + + Addon::callHooks('bb2diaspora', $text); + + return $text; + } } diff --git a/src/Content/Text/Markdown.php b/src/Content/Text/Markdown.php index 1d2f68bc7c..e7383a3fd7 100644 --- a/src/Content/Text/Markdown.php +++ b/src/Content/Text/Markdown.php @@ -7,8 +7,11 @@ namespace Friendica\Content\Text; use Friendica\BaseObject; +use Friendica\Model\Contact; use Michelf\MarkdownExtra; +require_once 'include/html2bbcode.php'; + /** * Friendica-specific usage of Markdown * @@ -36,4 +39,81 @@ class Markdown extends BaseObject return $html; } + + /** + * @brief Callback function to replace a Diaspora style mention in a mention for Friendica + * + * @param array $match Matching values for the callback + * @return string Replaced mention + */ + private static function diasporaMention2BBCodeCallback($match) + { + if ($match[2] == '') { + return; + } + + $data = Contact::getDetailsByAddr($match[2]); + + $name = $match[1]; + + if ($name == '') { + $name = $data['name']; + } + + return '@[url=' . $data['url'] . ']' . $name . '[/url]'; + } + + /* + * we don't want to support a bbcode specific markdown interpreter + * and the markdown library we have is pretty good, but provides HTML output. + * So we'll use that to convert to HTML, then convert the HTML back to bbcode, + * and then clean up a few Diaspora specific constructs. + */ + public static function toBBCode($s) + { + $s = html_entity_decode($s, ENT_COMPAT, 'UTF-8'); + + // Handles single newlines + $s = str_replace("\r\n", "\n", $s); + $s = str_replace("\n", " \n", $s); + $s = str_replace("\r", " \n", $s); + + // Replace lonely stars in lines not starting with it with literal stars + $s = preg_replace('/^([^\*]+)\*([^\*]*)$/im', '$1\*$2', $s); + + // The parser cannot handle paragraphs correctly + $s = str_replace(['

', '

', '

'], ['
', '
', '
'], $s); + + // Escaping the hash tags + $s = preg_replace('/\#([^\s\#])/', '#$1', $s); + + $s = self::convert($s); + + $regexp = "/@\{(?:([^\}]+?); )?([^\} ]+)\}/"; + $s = preg_replace_callback($regexp, ['self', 'diasporaMention2BBCodeCallback'], $s); + + $s = str_replace('#', '#', $s); + + $s = html2bbcode($s); + + // protect the recycle symbol from turning into a tag, but without unescaping angles and naked ampersands + $s = str_replace('♲', html_entity_decode('♲', ENT_QUOTES, 'UTF-8'), $s); + + // Convert everything that looks like a link to a link + $s = preg_replace('/([^\]=]|^)(https?\:\/\/)([a-zA-Z0-9:\/\-?&;.=_~#%$!+,@]+(?image_url); $birthday = unxmlify($data->birthday); $gender = unxmlify($data->gender); - $about = diaspora2bb(unxmlify($data->bio)); - $location = diaspora2bb(unxmlify($data->location)); + $about = Markdown::toBBCode(unxmlify($data->bio)); + $location = Markdown::toBBCode(unxmlify($data->location)); $searchable = (unxmlify($data->searchable) == "true"); $nsfw = (unxmlify($data->nsfw) == "true"); $tags = unxmlify($data->tag_string); @@ -2660,7 +2661,7 @@ class Diaspora if (self::isReshare($r[0]["body"], true)) { $r = []; } elseif (self::isReshare($r[0]["body"], false) || strstr($r[0]["body"], "[share")) { - $r[0]["body"] = diaspora2bb(bb2diaspora($r[0]["body"])); + $r[0]["body"] = Markdown::toBBCode(BBCode::toMarkdown($r[0]["body"])); $r[0]["body"] = self::replacePeopleGuid($r[0]["body"], $r[0]["author-link"]); @@ -2695,7 +2696,7 @@ class Diaspora if (DBM::is_result($r)) { // If it is a reshared post from another network then reformat to avoid display problems with two share elements if (self::isReshare($r[0]["body"], false)) { - $r[0]["body"] = diaspora2bb(bb2diaspora($r[0]["body"])); + $r[0]["body"] = Markdown::toBBCode(BBCode::toMarkdown($r[0]["body"])); $r[0]["body"] = self::replacePeopleGuid($r[0]["body"], $r[0]["author-link"]); } @@ -2939,7 +2940,7 @@ class Diaspora } } - $body = diaspora2bb($text); + $body = Markdown::toBBCode($text); $datarray = []; @@ -3590,14 +3591,14 @@ class Diaspora $eventdata['end'] = DateTimeFormat::convert($event['finish'], "UTC", $eventdata['timezone'], $mask); } if ($event['summary']) { - $eventdata['summary'] = html_entity_decode(bb2diaspora($event['summary'])); + $eventdata['summary'] = html_entity_decode(BBCode::toMarkdown($event['summary'])); } if ($event['desc']) { - $eventdata['description'] = html_entity_decode(bb2diaspora($event['desc'])); + $eventdata['description'] = html_entity_decode(BBCode::toMarkdown($event['desc'])); } if ($event['location']) { $location = []; - $location["address"] = html_entity_decode(bb2diaspora($event['location'])); + $location["address"] = html_entity_decode(BBCode::toMarkdown($event['location'])); $location["lat"] = 0; $location["lng"] = 0; $eventdata['location'] = $location; @@ -3647,7 +3648,7 @@ class Diaspora $body = $item["body"]; // convert to markdown - $body = html_entity_decode(bb2diaspora($body)); + $body = html_entity_decode(BBCode::toMarkdown($body)); // Adding the title if (strlen($title)) { @@ -3832,7 +3833,7 @@ class Diaspora $parent = $p[0]; - $text = html_entity_decode(bb2diaspora($item["body"])); + $text = html_entity_decode(BBCode::toMarkdown($item["body"])); $created = DateTimeFormat::utc($item["created"], DateTimeFormat::ATOM); $comment = ["author" => self::myHandle($owner), @@ -4068,7 +4069,7 @@ class Diaspora "participants" => $cnv["recips"] ]; - $body = bb2diaspora($item["body"]); + $body = BBCode::toMarkdown($item["body"]); $created = DateTimeFormat::utc($item["created"], DateTimeFormat::ATOM); $msg = [