diff --git a/mod/item.php b/mod/item.php index f3bdc30ecb..651c2224cb 100644 --- a/mod/item.php +++ b/mod/item.php @@ -29,6 +29,7 @@ */ use Friendica\App; +use Friendica\Content\Item as ItemHelper; use Friendica\Content\Text\BBCode; use Friendica\Core\Hook; use Friendica\Core\Logger; @@ -395,7 +396,7 @@ function item_post(App $a) { } } - $success = handle_tag($body, $inform, local_user() ? local_user() : $profile_uid, $tag, $network); + $success = ItemHelper::replaceTag($body, $inform, local_user() ? local_user() : $profile_uid, $tag, $network); if ($success['replaced']) { $tagged[] = $tag; } @@ -867,123 +868,3 @@ function item_content(App $a) return $o; } - -/** - * This function removes the tag $tag from the text $body and replaces it with - * the appropriate link. - * - * @param App $a - * @param string $body the text to replace the tag in - * @param string $inform a comma-seperated string containing everybody to inform - * @param integer $profile_uid - * @param string $tag the tag to replace - * @param string $network The network of the post - * - * @return array|bool ['replaced' => $replaced, 'contact' => $contact]; - * @throws ImagickException - * @throws HTTPException\InternalServerErrorException - */ -function handle_tag(&$body, &$inform, $profile_uid, $tag, $network = "") -{ - $replaced = false; - - //is it a person tag? - if (Tag::isType($tag, Tag::MENTION, Tag::IMPLICIT_MENTION, Tag::EXCLUSIVE_MENTION)) { - $tag_type = substr($tag, 0, 1); - //is it already replaced? - if (strpos($tag, '[url=')) { - // Checking for the alias that is used for OStatus - $pattern = "/[@!]\[url\=(.*?)\](.*?)\[\/url\]/ism"; - if (preg_match($pattern, $tag, $matches)) { - $data = Contact::getDetailsByURL($matches[1]); - - if ($data["alias"] != "") { - $newtag = '@[url=' . $data["alias"] . ']' . $data["nick"] . '[/url]'; - } - } - - return $replaced; - } - - //get the person's name - $name = substr($tag, 1); - - // Sometimes the tag detection doesn't seem to work right - // This is some workaround - $nameparts = explode(" ", $name); - $name = $nameparts[0]; - - // Try to detect the contact in various ways - if (strpos($name, 'http://')) { - // At first we have to ensure that the contact exists - Contact::getIdForURL($name); - - // Now we should have something - $contact = Contact::getDetailsByURL($name); - } elseif (strpos($name, '@')) { - // This function automatically probes when no entry was found - $contact = Contact::getDetailsByAddr($name); - } else { - $contact = false; - $fields = ['id', 'url', 'nick', 'name', 'alias', 'network', 'forum', 'prv']; - - if (strrpos($name, '+')) { - // Is it in format @nick+number? - $tagcid = intval(substr($name, strrpos($name, '+') + 1)); - $contact = DBA::selectFirst('contact', $fields, ['id' => $tagcid, 'uid' => $profile_uid]); - } - - // select someone by nick or attag in the current network - if (!DBA::isResult($contact) && ($network != "")) { - $condition = ["(`nick` = ? OR `attag` = ?) AND `network` = ? AND `uid` = ?", - $name, $name, $network, $profile_uid]; - $contact = DBA::selectFirst('contact', $fields, $condition); - } - - //select someone by name in the current network - if (!DBA::isResult($contact) && ($network != "")) { - $condition = ['name' => $name, 'network' => $network, 'uid' => $profile_uid]; - $contact = DBA::selectFirst('contact', $fields, $condition); - } - - // select someone by nick or attag in any network - if (!DBA::isResult($contact)) { - $condition = ["(`nick` = ? OR `attag` = ?) AND `uid` = ?", $name, $name, $profile_uid]; - $contact = DBA::selectFirst('contact', $fields, $condition); - } - - // select someone by name in any network - if (!DBA::isResult($contact)) { - $condition = ['name' => $name, 'uid' => $profile_uid]; - $contact = DBA::selectFirst('contact', $fields, $condition); - } - } - - // Check if $contact has been successfully loaded - if (DBA::isResult($contact)) { - if (strlen($inform) && (isset($contact["notify"]) || isset($contact["id"]))) { - $inform .= ','; - } - - if (isset($contact["id"])) { - $inform .= 'cid:' . $contact["id"]; - } elseif (isset($contact["notify"])) { - $inform .= $contact["notify"]; - } - - $profile = $contact["url"]; - $newname = ($contact["name"] ?? '') ?: $contact["nick"]; - } - - //if there is an url for this persons profile - if (isset($profile) && ($newname != "")) { - $replaced = true; - // create profile link - $profile = str_replace(',', '%2c', $profile); - $newtag = $tag_type.'[url=' . $profile . ']' . $newname . '[/url]'; - $body = str_replace($tag_type . $name, $newtag, $body); - } - } - - return ['replaced' => $replaced, 'contact' => $contact]; -} diff --git a/src/Content/Item.php b/src/Content/Item.php index 51a14435ef..40deb976c7 100644 --- a/src/Content/Item.php +++ b/src/Content/Item.php @@ -21,7 +21,10 @@ namespace Friendica\Content; +use Friendica\Database\DBA; +use Friendica\Model\Contact; use Friendica\Model\FileTag; +use Friendica\Model\Tag; /** * A content helper class for displaying items @@ -100,4 +103,123 @@ class Item return [$categories, $folders]; } + + /** + * This function removes the tag $tag from the text $body and replaces it with + * the appropriate link. + * + * @param string $body the text to replace the tag in + * @param string $inform a comma-seperated string containing everybody to inform + * @param integer $profile_uid the user id to replace the tag for (0 = anyone) + * @param string $tag the tag to replace + * @param string $network The network of the post + * + * @return array|bool ['replaced' => $replaced, 'contact' => $contact]; + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException + */ + public static function replaceTag(&$body, &$inform, $profile_uid, $tag, $network = '') + { + $replaced = false; + + //is it a person tag? + if (Tag::isType($tag, Tag::MENTION, Tag::IMPLICIT_MENTION, Tag::EXCLUSIVE_MENTION)) { + $tag_type = substr($tag, 0, 1); + //is it already replaced? + if (strpos($tag, '[url=')) { + // Checking for the alias that is used for OStatus + $pattern = '/[@!]\[url\=(.*?)\](.*?)\[\/url\]/ism'; + if (preg_match($pattern, $tag, $matches)) { + $data = Contact::getDetailsByURL($matches[1]); + + if ($data['alias'] != '') { + $newtag = '@[url=' . $data['alias'] . ']' . $data['nick'] . '[/url]'; + } + } + + return $replaced; + } + + //get the person's name + $name = substr($tag, 1); + + // Sometimes the tag detection doesn't seem to work right + // This is some workaround + $nameparts = explode(' ', $name); + $name = $nameparts[0]; + + // Try to detect the contact in various ways + if (strpos($name, 'http://')) { + // At first we have to ensure that the contact exists + Contact::getIdForURL($name); + + // Now we should have something + $contact = Contact::getDetailsByURL($name, $profile_uid); + } elseif (strpos($name, '@')) { + // This function automatically probes when no entry was found + $contact = Contact::getDetailsByAddr($name, $profile_uid); + } else { + $contact = false; + $fields = ['id', 'url', 'nick', 'name', 'alias', 'network', 'forum', 'prv']; + + if (strrpos($name, '+')) { + // Is it in format @nick+number? + $tagcid = intval(substr($name, strrpos($name, '+') + 1)); + $contact = DBA::selectFirst('contact', $fields, ['id' => $tagcid, 'uid' => $profile_uid]); + } + + // select someone by nick or attag in the current network + if (!DBA::isResult($contact) && ($network != '')) { + $condition = ["(`nick` = ? OR `attag` = ?) AND `network` = ? AND `uid` = ?", + $name, $name, $network, $profile_uid]; + $contact = DBA::selectFirst('contact', $fields, $condition); + } + + //select someone by name in the current network + if (!DBA::isResult($contact) && ($network != '')) { + $condition = ['name' => $name, 'network' => $network, 'uid' => $profile_uid]; + $contact = DBA::selectFirst('contact', $fields, $condition); + } + + // select someone by nick or attag in any network + if (!DBA::isResult($contact)) { + $condition = ["(`nick` = ? OR `attag` = ?) AND `uid` = ?", $name, $name, $profile_uid]; + $contact = DBA::selectFirst('contact', $fields, $condition); + } + + // select someone by name in any network + if (!DBA::isResult($contact)) { + $condition = ['name' => $name, 'uid' => $profile_uid]; + $contact = DBA::selectFirst('contact', $fields, $condition); + } + } + + // Check if $contact has been successfully loaded + if (DBA::isResult($contact)) { + if (strlen($inform) && (isset($contact['notify']) || isset($contact['id']))) { + $inform .= ','; + } + + if (isset($contact['id'])) { + $inform .= 'cid:' . $contact['id']; + } elseif (isset($contact['notify'])) { + $inform .= $contact['notify']; + } + + $profile = $contact['url']; + $newname = ($contact['name'] ?? '') ?: $contact['nick']; + } + + //if there is an url for this persons profile + if (isset($profile) && ($newname != '')) { + $replaced = true; + // create profile link + $profile = str_replace(',', '%2c', $profile); + $newtag = $tag_type.'[url=' . $profile . ']' . $newname . '[/url]'; + $body = str_replace($tag_type . $name, $newtag, $body); + } + } + + return ['replaced' => $replaced, 'contact' => $contact]; + } } diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 0f3c4ad529..d7fda23aeb 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -24,6 +24,8 @@ namespace Friendica\Content\Text; use DOMDocument; use DOMXPath; use Exception; +use Friendica\Content\ContactSelector; +use Friendica\Content\Item; use Friendica\Content\OEmbed; use Friendica\Content\Smilies; use Friendica\Core\Hook; @@ -35,6 +37,7 @@ use Friendica\DI; use Friendica\Model\Contact; use Friendica\Model\Event; use Friendica\Model\Photo; +use Friendica\Model\Tag; use Friendica\Network\Probe; use Friendica\Object\Image; use Friendica\Protocol\Activity; @@ -1073,14 +1076,21 @@ class BBCode default: $text = ($is_quote_share? "\n" : ''); + $authorId = Contact::getIdForURL($attributes['profile']); + + $contact = Contact::getById($authorId, ['network']); + $tpl = Renderer::getMarkupTemplate('shared_content.tpl'); $text .= Renderer::replaceMacros($tpl, [ - '$profile' => $attributes['profile'], - '$avatar' => $attributes['avatar'], - '$author' => $attributes['author'], - '$link' => $attributes['link'], - '$posted' => $attributes['posted'], - '$content' => trim($content) + '$profile' => $attributes['profile'], + '$avatar' => $attributes['avatar'], + '$author' => $attributes['author'], + '$link' => $attributes['link'], + '$link_title' => DI::l10n()->t('link to source'), + '$posted' => $attributes['posted'], + '$network_name' => ContactSelector::networkToName($contact['network'], $attributes['profile']), + '$network_icon' => ContactSelector::networkToIcon($contact['network'], $attributes['profile']), + '$content' => self::setMentions(trim($content), 0, $contact['network']), ]); break; } @@ -2165,4 +2175,52 @@ class BBCode return Strings::performWithEscapedBlocks($text, '#\[(?:' . implode('|', $tagList) . ').*?\[/(?:' . implode('|', $tagList) . ')]#ism', $callback); } + + /** + * Replaces mentions in the provided message body for the provided user and network if any + * + * @param $body + * @param $profile_uid + * @param $network + * @return string + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException + */ + public static function setMentions($body, $profile_uid = 0, $network = '') + { + BBCode::performWithEscapedTags($body, ['noparse', 'pre', 'code'], function ($body) use ($profile_uid, $network) { + $tags = BBCode::getTags($body); + + $tagged = []; + $inform = ''; + + foreach ($tags as $tag) { + $tag_type = substr($tag, 0, 1); + + if ($tag_type == Tag::TAG_CHARACTER[Tag::HASHTAG]) { + continue; + } + + /* + * If we already tagged 'Robert Johnson', don't try and tag 'Robert'. + * Robert Johnson should be first in the $tags array + */ + foreach ($tagged as $nextTag) { + if (stristr($nextTag, $tag . ' ')) { + continue 2; + } + } + + $success = Item::replaceTag($body, $inform, $profile_uid, $tag, $network); + + if ($success['replaced']) { + $tagged[] = $tag; + } + } + + return $body; + }); + + return $body; + } } diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 02f9e829f2..470bff1077 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -1168,7 +1168,7 @@ class Contact if (!DBA::isResult($r)) { $data = Probe::uri($addr); - $profile = self::getDetailsByURL($data['url'], $uid); + $profile = self::getDetailsByURL($data['url'], $uid, $data); } else { $profile = $r[0]; } diff --git a/src/Network/Probe.php b/src/Network/Probe.php index 71d676236d..dcb0bf192f 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -441,7 +441,7 @@ class Probe } } - if (!empty(self::$baseurl)) { + if (empty($data['baseurl']) && !empty(self::$baseurl)) { $data['baseurl'] = self::$baseurl; } @@ -736,13 +736,6 @@ class Probe Logger::log($uri." is ".$result["network"], Logger::DEBUG); - if (empty($result["baseurl"]) && ($result["network"] != Protocol::PHANTOM)) { - $pos = strpos($result["url"], $host); - if ($pos) { - $result["baseurl"] = substr($result["url"], 0, $pos).$host; - } - } - return $result; } diff --git a/view/global.css b/view/global.css index cd0253ac66..874b1d6e98 100644 --- a/view/global.css +++ b/view/global.css @@ -180,11 +180,6 @@ span.connector { margin-right: 9px; } -.shared_header span { - display: table-cell; - float: none; -} - blockquote.shared_content { margin-left: 32px; color: #000; diff --git a/view/theme/frio/css/style.css b/view/theme/frio/css/style.css index 014b3daaa3..e9b42ff409 100644 --- a/view/theme/frio/css/style.css +++ b/view/theme/frio/css/style.css @@ -1747,19 +1747,24 @@ aside .panel-body { } /* wall-item content elements */ -.shared-wrapper, +.shared-wrapper { + position: relative; + margin-top: 10px; + margin-bottom: 0; +} .vevent { padding: 10px; box-shadow: 0 0 0 1.5px rgba(0, 0, 0, .1) inset, 0 1px 1px rgba(0, 0, 0, .05); } @media screen and (max-width: 767px) { - .shared-wrapper, .vevent { - margin-left: 0px; - margin-right: 0px; + margin-left: 0px; + margin-right: 0px; } + .shared-wrapper { + margin: 5px -10px 0; + } } -.shared-wrapper:hover, .vevent:hover { box-shadow: 0 0 0 1.5px rgba(0, 0, 0, .15) inset, 0 1px 1px rgba(0, 0, 0, .05); } @@ -1915,7 +1920,7 @@ code > .hl-main { /* * Comments */ -.well { +wall-item-comment-wrapper.well { border: none; box-shadow: none; /*background-color: #ededed;*/ @@ -1923,14 +1928,14 @@ code > .hl-main { background-image: none; margin-bottom: 1px; } -.well-small { +wall-item-comment-wrapper.well-small { padding: 10px; border-radius: 3px; } -.well hr { +wall-item-comment-wrapper.well hr { border-top: 1px solid #d9d9d9; } -.wall-entry .well { +.wall-entry wall-item-comment-wrapper.well { margin-bottom: 0; } .comment-container { diff --git a/view/theme/frio/templates/search_item.tpl b/view/theme/frio/templates/search_item.tpl index ce5497dda5..a5b6d52d6d 100644 --- a/view/theme/frio/templates/search_item.tpl +++ b/view/theme/frio/templates/search_item.tpl @@ -92,11 +92,6 @@ {{* item content *}}
- {{* insert some space if it's an top-level post *}} - {{if $item.thread_level==1}} -
 
- {{/if}} - {{if $item.title}}

{{$item.title}}


{{/if}} diff --git a/view/theme/frio/templates/shared_content.tpl b/view/theme/frio/templates/shared_content.tpl new file mode 100644 index 0000000000..a4f47e6184 --- /dev/null +++ b/view/theme/frio/templates/shared_content.tpl @@ -0,0 +1,24 @@ +
+
+ {{if $avatar}} + + + + {{/if}} +
{{$author}}
+
+ {{if $network_icon}} + + {{else}} + {{$network_name}} + {{/if}} + {{if $link}} + + + + {{/if}} +
+
{{$posted}}
+
+
{{$content nofilter}}
+