use DOMDocument;
use DOMXPath;
-use Friendica\Core\Addon;
+use Friendica\Content\Widget\ContactBlock;
+use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\Config;
-use Friendica\Core\PConfig;
-use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
-use Friendica\Database\DBA;
use Friendica\Model\Contact;
use Friendica\Util\Network;
use Friendica\Util\Proxy as ProxyUtils;
+use Friendica\Util\Strings;
use Friendica\Util\XML;
use League\HTMLToMarkdown\HtmlConverter;
-use Friendica\Content\Feature;
class HTML
{
$xpath = new DOMXPath($doc);
+ /** @var \DOMNode[] $list */
$list = $xpath->query("//" . $tag);
foreach ($list as $node) {
$attr = [];
$node->parentNode->insertBefore($StartCode, $node);
if ($node->hasChildNodes()) {
+ /** @var \DOMNode $child */
foreach ($node->childNodes as $child) {
- $newNode = $child->cloneNode(true);
- $node->parentNode->insertBefore($newNode, $node);
+ if (trim($child->nodeValue)) {
+ $newNode = $child->cloneNode(true);
+ $node->parentNode->insertBefore($newNode, $node);
+ }
}
}
/**
* Made by: ike@piratenpartei.de
* Originally made for the syncom project: http://wiki.piratenpartei.de/Syncom
- * https://github.com/annando/Syncom
+ * https://github.com/annando/Syncom
*
* @brief Converter for HTML to BBCode
* @param string $message
* @param string $basepath
* @return string
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function toBBCode($message, $basepath = '')
{
$xpath = new DomXPath($doc);
$list = $xpath->query("//pre");
foreach ($list as $node) {
- $node->nodeValue = str_replace("\n", "\r", $node->nodeValue);
+ // Ensure to escape unescaped & - they will otherwise raise a warning
+ $safe_value = preg_replace('/&(?!\w+;)/', '&', $node->nodeValue);
+ $node->nodeValue = str_replace("\n", "\r", $safe_value);
}
$message = $doc->saveHTML();
self::tagToBBCode($doc, 'a', ['href' => '/mailto:(.+)/'], '[mail=$1]', '[/mail]');
self::tagToBBCode($doc, 'a', ['href' => '/(.+)/'], '[url=$1]', '[/url]');
+ self::tagToBBCode($doc, 'img', ['src' => '/(.+)/', 'alt' => '/(.+)/'], '[img=$1]$2', '[/img]');
self::tagToBBCode($doc, 'img', ['src' => '/(.+)/', 'width' => '/(\d+)/', 'height' => '/(\d+)/'], '[img=$2x$3]$1', '[/img]');
self::tagToBBCode($doc, 'img', ['src' => '/(.+)/'], '[img]$1', '[/img]');
$message = preg_replace('=\r *\r=i', "\n", $message);
$message = str_replace("\r", "\n", $message);
- Addon::callHooks('html2bbcode', $message);
+ Hook::callAll('html2bbcode', $message);
$message = strip_tags($message);
$ignore = false;
}
+ $ignore = $ignore || strpos($treffer[1], '#') === 0;
+
if (!$ignore) {
$urls[$treffer[1]] = $treffer[1];
}
return $urls;
}
- public static function toPlaintext($html, $wraplength = 75, $compact = false)
+ /**
+ * @param string $html
+ * @param int $wraplength Ensures individual lines aren't longer than this many characters. Doesn't break words.
+ * @param bool $compact True: Completely strips image tags; False: Keeps image URLs
+ * @return string
+ */
+ public static function toPlaintext(string $html, $wraplength = 75, $compact = false)
{
$message = str_replace("\r", "", $html);
$message = mb_convert_encoding($message, 'HTML-ENTITIES', "UTF-8");
- @$doc->loadHTML($message);
-
- $xpath = new DOMXPath($doc);
- $list = $xpath->query("//pre");
- foreach ($list as $node) {
- $node->nodeValue = str_replace("\n", "\r", $node->nodeValue);
- }
+ @$doc->loadHTML($message, LIBXML_HTML_NODEFDTD);
$message = $doc->saveHTML();
- $message = str_replace(["\n<", ">\n", "\r", "\n", "\xC3\x82\xC2\xA0"], ["<", ">", "<br>", " ", ""], $message);
- $message = preg_replace('= [\s]*=i', " ", $message);
+ // Remove eventual UTF-8 BOM
+ $message = str_replace("\xC3\x82\xC2\xA0", "", $message);
// Collecting all links
$urls = self::collectURLs($message);
- @$doc->loadHTML($message);
+ @$doc->loadHTML($message, LIBXML_HTML_NODEFDTD);
self::tagToBBCode($doc, 'html', [], '', '');
self::tagToBBCode($doc, 'body', [], '', '');
- // MyBB-Auszeichnungen
- /*
- self::node2BBCode($doc, 'span', array('style'=>'text-decoration: underline;'), '_', '_');
- self::node2BBCode($doc, 'span', array('style'=>'font-style: italic;'), '/', '/');
- self::node2BBCode($doc, 'span', array('style'=>'font-weight: bold;'), '*', '*');
-
- self::node2BBCode($doc, 'strong', array(), '*', '*');
- self::node2BBCode($doc, 'b', array(), '*', '*');
- self::node2BBCode($doc, 'i', array(), '/', '/');
- self::node2BBCode($doc, 'u', array(), '_', '_');
- */
-
if ($compact) {
self::tagToBBCode($doc, 'blockquote', [], "»", "«");
} else {
self::tagToBBCode($doc, 'div', [], "\r", "\r");
self::tagToBBCode($doc, 'p', [], "\n", "\n");
- //self::node2BBCode($doc, 'ul', array(), "\n[list]", "[/list]\n");
- //self::node2BBCode($doc, 'ol', array(), "\n[list=1]", "[/list]\n");
self::tagToBBCode($doc, 'li', [], "\n* ", "\n");
self::tagToBBCode($doc, 'hr', [], "\n" . str_repeat("-", 70) . "\n", "");
self::tagToBBCode($doc, 'h5', [], "\n\n*", "*\n");
self::tagToBBCode($doc, 'h6', [], "\n\n*", "*\n");
- // Problem: there is no reliable way to detect if it is a link to a tag or profile
- //self::node2BBCode($doc, 'a', array('href'=>'/(.+)/'), ' $1 ', ' ', true);
- //self::node2BBCode($doc, 'a', array('href'=>'/(.+)/', 'rel'=>'oembed'), ' $1 ', '', true);
- //self::node2BBCode($doc, 'img', array('alt'=>'/(.+)/'), '$1', '');
- //self::node2BBCode($doc, 'img', array('title'=>'/(.+)/'), '$1', '');
- //self::node2BBCode($doc, 'img', array(), '', '');
if (!$compact) {
self::tagToBBCode($doc, 'img', ['src' => '/(.+)/'], ' [img]$1', '[/img] ');
} else {
* @brief Convert video HTML to BBCode tags
*
* @param string $s
+ * @return string
*/
public static function toBBCodeVideo($s)
{
/**
* Loader for infinite scrolling
+ *
* @return string html for loader
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function scrollLoader()
{
/**
* Get html for contact block.
*
- * @template contact_block.tpl
- * @hook contact_block_end (contacts=>array, output=>string)
+ * @deprecated since version 2019.03
+ * @see ContactBlock::getHTML()
* @return string
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+ * @throws \ImagickException
*/
public static function contactBlock()
{
- $o = '';
- $a = get_app();
-
- $shown = PConfig::get($a->profile['uid'], 'system', 'display_friend_count', 24);
- if ($shown == 0) {
- return;
- }
-
- if (!is_array($a->profile) || $a->profile['hide-friends']) {
- return $o;
- }
-
- $r = q("SELECT COUNT(*) AS `total` FROM `contact`
- WHERE `uid` = %d AND NOT `self` AND NOT `blocked`
- AND NOT `pending` AND NOT `hidden` AND NOT `archive`
- AND `network` IN ('%s', '%s', '%s')",
- intval($a->profile['uid']),
- DBA::escape(Protocol::DFRN),
- DBA::escape(Protocol::OSTATUS),
- DBA::escape(Protocol::DIASPORA)
- );
-
- if (DBA::isResult($r)) {
- $total = intval($r[0]['total']);
- }
-
- if (!$total) {
- $contacts = L10n::t('No contacts');
- $micropro = null;
- } else {
- // Splitting the query in two parts makes it much faster
- $r = q("SELECT `id` FROM `contact`
- WHERE `uid` = %d AND NOT `self` AND NOT `blocked`
- AND NOT `pending` AND NOT `hidden` AND NOT `archive`
- AND `network` IN ('%s', '%s', '%s')
- ORDER BY RAND() LIMIT %d",
- intval($a->profile['uid']),
- DBA::escape(Protocol::DFRN),
- DBA::escape(Protocol::OSTATUS),
- DBA::escape(Protocol::DIASPORA),
- intval($shown)
- );
-
- if (DBA::isResult($r)) {
- $contacts = [];
- foreach ($r as $contact) {
- $contacts[] = $contact["id"];
- }
-
- $r = q("SELECT `id`, `uid`, `addr`, `url`, `name`, `thumb`, `network` FROM `contact` WHERE `id` IN (%s)",
- DBA::escape(implode(",", $contacts))
- );
+ $a = \get_app();
- if (DBA::isResult($r)) {
- $contacts = L10n::tt('%d Contact', '%d Contacts', $total);
- $micropro = [];
- foreach ($r as $rr) {
- $micropro[] = self::micropro($rr, true, 'mpfriend');
- }
- }
- }
- }
-
- $tpl = Renderer::getMarkupTemplate('contact_block.tpl');
- $o = Renderer::replaceMacros($tpl, [
- '$contacts' => $contacts,
- '$nickname' => $a->profile['nickname'],
- '$viewcontacts' => L10n::t('View Contacts'),
- '$micropro' => $micropro,
- ]);
-
- $arr = ['contacts' => $r, 'output' => $o];
-
- Addon::callHooks('contact_block_end', $arr);
-
- return $o;
+ return ContactBlock::getHTML($a->profile);
}
/**
- * @brief Format contacts as picture links or as texxt links
+ * @brief Format contacts as picture links or as text links
*
- * @param array $contact Array with contacts which contains an array with
- * int 'id' => The ID of the contact
- * int 'uid' => The user ID of the user who owns this data
- * string 'name' => The name of the contact
- * string 'url' => The url to the profile page of the contact
- * string 'addr' => The webbie of the contact (e.g.) username@friendica.com
- * string 'network' => The network to which the contact belongs to
- * string 'thumb' => The contact picture
- * string 'click' => js code which is performed when clicking on the contact
- * @param boolean $redirect If true try to use the redir url if it's possible
- * @param string $class CSS class for the
- * @param boolean $textmode If true display the contacts as text links
- * if false display the contacts as picture links
-
- * @return string Formatted html
- */
+ * @param array $contact Array with contacts which contains an array with
+ * int 'id' => The ID of the contact
+ * int 'uid' => The user ID of the user who owns this data
+ * string 'name' => The name of the contact
+ * string 'url' => The url to the profile page of the contact
+ * string 'addr' => The webbie of the contact (e.g.) username@friendica.com
+ * string 'network' => The network to which the contact belongs to
+ * string 'thumb' => The contact picture
+ * string 'click' => js code which is performed when clicking on the contact
+ * @param boolean $redirect If true try to use the redir url if it's possible
+ * @param string $class CSS class for the
+ * @param boolean $textmode If true display the contacts as text links
+ * if false display the contacts as picture links
+ * @return string Formatted html
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+ * @throws \ImagickException
+ */
public static function micropro($contact, $redirect = false, $class = '', $textmode = false)
{
// Use the contact URL if no address is available
- if (!x($contact, "addr")) {
+ if (empty($contact['addr'])) {
$contact["addr"] = $contact["url"];
}
}
// If there is some js available we don't need the url
- if (x($contact, 'click')) {
+ if (!empty($contact['click'])) {
$url = '';
}
* @param string $s Search query.
* @param string $id HTML id
* @param string $url Search url.
- * @param bool $save Show save search button.
* @param bool $aside Display the search widgit aside.
*
* @return string Formatted HTML.
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- public static function search($s, $id = 'search-box', $url = 'search', $save = false, $aside = true)
+ public static function search($s, $id = 'search-box', $url = 'search', $aside = true)
{
$mode = 'text';
$save_label = $mode === 'text' ? L10n::t('Save') : L10n::t('Follow');
$values = [
- '$s' => htmlspecialchars($s),
+ '$s' => $s,
'$id' => $id,
'$action_url' => $url,
'$search_label' => L10n::t('Search'),
'$save_label' => $save_label,
- '$savedsearch' => local_user() && Feature::isEnabled(local_user(), 'savedsearch'),
+ '$savedsearch' => 'savedsearch',
'$search_hint' => L10n::t('@name, !forum, #tags, content'),
'$mode' => $mode
];
* Replace naked text hyperlink with HTML formatted hyperlink
*
* @param string $s
+ * @return string
*/
public static function toLink($s)
{
* @param string $html
* @param array $reasons
* @return string
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function applyContentFilter($html, array $reasons)
{
$tpl = Renderer::getMarkupTemplate('wall/content_filter.tpl');
$html = Renderer::replaceMacros($tpl, [
'$reasons' => $reasons,
- '$rnd' => random_string(8),
+ '$rnd' => Strings::getRandomHex(8),
'$openclose' => L10n::t('Click to open/close'),
'$html' => $html
]);