Merge pull request #1419 from annando/1503-hashtag-handling

Improved hashtag handling
This commit is contained in:
fabrixxm 2015-03-03 19:16:43 +01:00
commit 5d9b4741a9
11 changed files with 151 additions and 132 deletions

View file

@ -18,7 +18,9 @@ function diaspora2bb($s) {
$s = html_entity_decode($s,ENT_COMPAT,'UTF-8'); $s = html_entity_decode($s,ENT_COMPAT,'UTF-8');
// Remove CR to avoid problems with following code // Remove CR to avoid problems with following code
//$s = str_replace("\r","",$s); $s = str_replace("\r","",$s);
$s = str_replace("\n"," \n",$s);
// The parser cannot handle paragraphs correctly // The parser cannot handle paragraphs correctly
$s = str_replace(array("</p>", "<p>", '<p dir="ltr">'),array("<br>", "<br>", "<br>"),$s); $s = str_replace(array("</p>", "<p>", '<p dir="ltr">'),array("<br>", "<br>", "<br>"),$s);

View file

@ -842,8 +842,10 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
// removing multiplicated newlines // removing multiplicated newlines
if (get_config("system", "remove_multiplicated_lines")) { if (get_config("system", "remove_multiplicated_lines")) {
$search = array("\n\n\n", "\n ", " \n", "[/quote]\n\n", "\n[/quote]", "[/li]\n", "\n[li]", "\n[ul]", "[/ul]\n", "\n\n[share ", "[/attachment]\n"); $search = array("\n\n\n", "\n ", " \n", "[/quote]\n\n", "\n[/quote]", "[/li]\n", "\n[li]", "\n[ul]", "[/ul]\n", "\n\n[share ", "[/attachment]\n",
$replace = array("\n\n", "\n", "\n", "[/quote]\n", "[/quote]", "[/li]", "[li]", "[ul]", "[/ul]", "\n[share ", "[/attachment]"); "\n[h1]", "[/h1]\n", "\n[h2]", "[/h2]\n", "\n[h3]", "[/h3]\n", "\n[h4]", "[/h4]\n", "\n[h5]", "[/h5]\n", "\n[h6]", "[/h6]\n");
$replace = array("\n\n", "\n", "\n", "[/quote]\n", "[/quote]", "[/li]", "[li]", "[ul]", "[/ul]", "\n[share ", "[/attachment]",
"[h1]", "[/h1]", "[h2]", "[/h2]", "[h3]", "[/h3]", "[h4]", "[/h4]", "[h5]", "[/h5]", "[h6]", "[/h6]");
do { do {
$oldtext = $Text; $oldtext = $Text;
$Text = str_replace($search, $replace, $Text); $Text = str_replace($search, $replace, $Text);
@ -923,6 +925,14 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$Text = preg_replace("/\[mail\]([$MAILSearchString]*)\[\/mail\]/", '<a href="mailto:$1">$1</a>', $Text); $Text = preg_replace("/\[mail\]([$MAILSearchString]*)\[\/mail\]/", '<a href="mailto:$1">$1</a>', $Text);
$Text = preg_replace("/\[mail\=([$MAILSearchString]*)\](.*?)\[\/mail\]/", '<a href="mailto:$1">$2</a>', $Text); $Text = preg_replace("/\[mail\=([$MAILSearchString]*)\](.*?)\[\/mail\]/", '<a href="mailto:$1">$2</a>', $Text);
// Check for headers
$Text = preg_replace("(\[h1\](.*?)\[\/h1\])ism",'<h1>$1</h1>',$Text);
$Text = preg_replace("(\[h2\](.*?)\[\/h2\])ism",'<h2>$1</h2>',$Text);
$Text = preg_replace("(\[h3\](.*?)\[\/h3\])ism",'<h3>$1</h3>',$Text);
$Text = preg_replace("(\[h4\](.*?)\[\/h4\])ism",'<h4>$1</h4>',$Text);
$Text = preg_replace("(\[h5\](.*?)\[\/h5\])ism",'<h5>$1</h5>',$Text);
$Text = preg_replace("(\[h6\](.*?)\[\/h6\])ism",'<h6>$1</h6>',$Text);
// Check for bold text // Check for bold text
$Text = preg_replace("(\[b\](.*?)\[\/b\])ism",'<strong>$1</strong>',$Text); $Text = preg_replace("(\[b\](.*?)\[\/b\])ism",'<strong>$1</strong>',$Text);

View file

@ -833,32 +833,6 @@ function diaspora_post($importer,$xml,$msg) {
$str_tags = ''; $str_tags = '';
$tags = get_tags($body);
rsort($tags);
if(count($tags)) {
foreach($tags as $tag) {
if(strpos($tag,'#') === 0) {
if(strpos($tag,'[url='))
continue;
// don't link tags that are already embedded in links
if(preg_match('/\[(\S*?)' . preg_quote($tag,'/') . '(\S*?)\]/',$body))
continue;
if(preg_match('/\[(\S*?)\]\((\S*?)' . preg_quote($tag,'/') . '(\S*?)\)/',$body))
continue;
$basetag = str_replace('_',' ',substr($tag,1));
$body = str_replace($tag,'#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]',$body);
if(strlen($str_tags))
$str_tags .= ',';
$str_tags .= '#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]';
continue;
}
}
}
$cnt = preg_match_all('/@\[url=(.*?)\[\/url\]/ism',$body,$matches,PREG_SET_ORDER); $cnt = preg_match_all('/@\[url=(.*?)\[\/url\]/ism',$body,$matches,PREG_SET_ORDER);
if($cnt) { if($cnt) {
foreach($matches as $mtch) { foreach($matches as $mtch) {
@ -1055,34 +1029,8 @@ function diaspora_fetch_message($guid, $server, $level = 0) {
return false; return false;
$item["tag"] = ''; $item["tag"] = '';
$tags = get_tags($body);
if(count($tags)) {
foreach($tags as $tag) {
if(strpos($tag,'#') === 0) {
if(strpos($tag,'[url='))
continue;
// don't link tags that are already embedded in links
if(preg_match('/\[(.*?)' . preg_quote($tag,'/') . '(.*?)\]/',$body))
continue;
if(preg_match('/\[(.*?)\]\((.*?)' . preg_quote($tag,'/') . '(.*?)\)/',$body))
continue;
$basetag = str_replace('_',' ',substr($tag,1));
$body = str_replace($tag,'#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]',$body);
if(strlen($item["tag"]))
$item["tag"] .= ',';
$item["tag"] .= '#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]';
continue;
}
}
}
$item["body"] = $body; $item["body"] = $body;
return $item; return $item;
} }
@ -1482,34 +1430,6 @@ function diaspora_comment($importer,$xml,$msg) {
$datarray = array(); $datarray = array();
$str_tags = '';
$tags = get_tags($body);
if(count($tags)) {
foreach($tags as $tag) {
if(strpos($tag,'#') === 0) {
if(strpos($tag,'[url='))
continue;
// don't link tags that are already embedded in links
if(preg_match('/\[(.*?)' . preg_quote($tag,'/') . '(.*?)\]/',$body))
continue;
if(preg_match('/\[(.*?)\]\((.*?)' . preg_quote($tag,'/') . '(.*?)\)/',$body))
continue;
$basetag = str_replace('_',' ',substr($tag,1));
$body = str_replace($tag,'#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]',$body);
if(strlen($str_tags))
$str_tags .= ',';
$str_tags .= '#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]';
continue;
}
}
}
$datarray['uid'] = $importer['uid']; $datarray['uid'] = $importer['uid'];
$datarray['contact-id'] = $contact['id']; $datarray['contact-id'] = $contact['id'];
$datarray['type'] = 'remote-comment'; $datarray['type'] = 'remote-comment';
@ -1533,7 +1453,6 @@ function diaspora_comment($importer,$xml,$msg) {
$datarray['author-link'] = $person['url']; $datarray['author-link'] = $person['url'];
$datarray['author-avatar'] = ((x($person,'thumb')) ? $person['thumb'] : $person['photo']); $datarray['author-avatar'] = ((x($person,'thumb')) ? $person['thumb'] : $person['photo']);
$datarray['body'] = $body; $datarray['body'] = $body;
$datarray['tag'] = $str_tags;
// We can't be certain what the original app is if the message is relayed. // We can't be certain what the original app is if the message is relayed.
if(($parent_item['origin']) && (! $parent_author_signature)) if(($parent_item['origin']) && (! $parent_author_signature))

View file

@ -207,12 +207,19 @@ function html2bbcode($message)
//node2bbcode($doc, 'tr', array(), "[tr]", "[/tr]"); //node2bbcode($doc, 'tr', array(), "[tr]", "[/tr]");
//node2bbcode($doc, 'td', array(), "[td]", "[/td]"); //node2bbcode($doc, 'td', array(), "[td]", "[/td]");
node2bbcode($doc, 'h1', array(), "\n\n[size=xx-large][b]", "[/b][/size]\n"); //node2bbcode($doc, 'h1', array(), "\n\n[size=xx-large][b]", "[/b][/size]\n");
node2bbcode($doc, 'h2', array(), "\n\n[size=x-large][b]", "[/b][/size]\n"); //node2bbcode($doc, 'h2', array(), "\n\n[size=x-large][b]", "[/b][/size]\n");
node2bbcode($doc, 'h3', array(), "\n\n[size=large][b]", "[/b][/size]\n"); //node2bbcode($doc, 'h3', array(), "\n\n[size=large][b]", "[/b][/size]\n");
node2bbcode($doc, 'h4', array(), "\n\n[size=medium][b]", "[/b][/size]\n"); //node2bbcode($doc, 'h4', array(), "\n\n[size=medium][b]", "[/b][/size]\n");
node2bbcode($doc, 'h5', array(), "\n\n[size=small][b]", "[/b][/size]\n"); //node2bbcode($doc, 'h5', array(), "\n\n[size=small][b]", "[/b][/size]\n");
node2bbcode($doc, 'h6', array(), "\n\n[size=x-small][b]", "[/b][/size]\n"); //node2bbcode($doc, 'h6', array(), "\n\n[size=x-small][b]", "[/b][/size]\n");
node2bbcode($doc, 'h1', array(), "\n\n[h1]", "[/h1]\n");
node2bbcode($doc, 'h2', array(), "\n\n[h2]", "[/h2]\n");
node2bbcode($doc, 'h3', array(), "\n\n[h3]", "[/h3]\n");
node2bbcode($doc, 'h4', array(), "\n\n[h4]", "[/h4]\n");
node2bbcode($doc, 'h5', array(), "\n\n[h5]", "[/h5]\n");
node2bbcode($doc, 'h6', array(), "\n\n[h6]", "[/h6]\n");
node2bbcode($doc, 'a', array('href'=>'/mailto:(.+)/'), '[mail=$1]', '[/mail]'); node2bbcode($doc, 'a', array('href'=>'/mailto:(.+)/'), '[mail=$1]', '[/mail]');
node2bbcode($doc, 'a', array('href'=>'/(.+)/'), '[url=$1]', '[/url]'); node2bbcode($doc, 'a', array('href'=>'/(.+)/'), '[url=$1]', '[/url]');

View file

@ -1239,6 +1239,9 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
logger("item_store: Set network to ".$arr["network"]." for ".$arr["uri"], LOGGER_DEBUG); logger("item_store: Set network to ".$arr["network"]." for ".$arr["uri"], LOGGER_DEBUG);
} }
// Check for hashtags in the body and repair or add hashtag links
item_body_set_hashtags($arr);
$arr['thr-parent'] = $arr['parent-uri']; $arr['thr-parent'] = $arr['parent-uri'];
if($arr['parent-uri'] === $arr['uri']) { if($arr['parent-uri'] === $arr['uri']) {
$parent_id = 0; $parent_id = 0;
@ -1556,6 +1559,73 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
return $current_post; return $current_post;
} }
function item_body_set_hashtags(&$item) {
$tags = get_tags($item["body"]);
// No hashtags?
if(!count($tags))
return(false);
// This sorting is important when there are hashtags that are part of other hashtags
// Otherwise there could be problems with hashtags like #test and #test2
rsort($tags);
$a = get_app();
$URLSearchString = "^\[\]";
// All hashtags should point to the home server
//$item["body"] = preg_replace("/#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
// "#[url=".$a->get_baseurl()."/search?tag=$2]$2[/url]", $item["body"]);
//$item["tag"] = preg_replace("/#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
// "#[url=".$a->get_baseurl()."/search?tag=$2]$2[/url]", $item["tag"]);
// mask hashtags inside of url, bookmarks and attachments to avoid urls in urls
$item["body"] = preg_replace_callback("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
function ($match){
return("[url=".$match[1]."]".str_replace("#", "&num;", $match[2])."[/url]");
},$item["body"]);
$item["body"] = preg_replace_callback("/\[bookmark\=([$URLSearchString]*)\](.*?)\[\/bookmark\]/ism",
function ($match){
return("[bookmark=".$match[1]."]".str_replace("#", "&num;", $match[2])."[/bookmark]");
},$item["body"]);
$item["body"] = preg_replace_callback("/\[attachment (.*)\](.*?)\[\/attachment\]/ism",
function ($match){
return("[attachment ".str_replace("#", "&num;", $match[1])."]".$match[2]."[/attachment]");
},$item["body"]);
// Repair recursive urls
$item["body"] = preg_replace("/&num;\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
"&num;$2", $item["body"]);
foreach($tags as $tag) {
if(strpos($tag,'#') !== 0)
continue;
if(strpos($tag,'[url='))
continue;
$basetag = str_replace('_',' ',substr($tag,1));
$newtag = '#[url='.$a->get_baseurl().'/search?tag='.rawurlencode($basetag).']'.$basetag.'[/url]';
$item["body"] = str_replace($tag, $newtag, $item["body"]);
if(!stristr($item["tag"],"/search?tag=".$basetag."]".$basetag."[/url]")) {
if(strlen($item["tag"]))
$item["tag"] = ','.$item["tag"];
$item["tag"] = $newtag.$item["tag"];
}
}
// Convert back the masked hashtags
$item["body"] = str_replace("&num;", "#", $item["body"]);
}
function get_item_guid($id) { function get_item_guid($id) {
$r = q("SELECT `guid` FROM `item` WHERE `id` = %d LIMIT 1", intval($id)); $r = q("SELECT `guid` FROM `item` WHERE `id` = %d LIMIT 1", intval($id));
if (count($r)) if (count($r))

View file

@ -163,6 +163,7 @@ function oembed_format_object($j){
// add link to source if not present in "rich" type // add link to source if not present in "rich" type
if ($j->type!='rich' || !strpos($j->html,$embedurl) ){ if ($j->type!='rich' || !strpos($j->html,$embedurl) ){
$ret .= "<h4>";
if (isset($j->title)) { if (isset($j->title)) {
if (isset($j->provider_name)) if (isset($j->provider_name))
$ret .= $j->provider_name.": "; $ret .= $j->provider_name.": ";
@ -189,11 +190,12 @@ function oembed_format_object($j){
} }
//if (isset($j->author_name)) $ret.=" by ".$j->author_name; //if (isset($j->author_name)) $ret.=" by ".$j->author_name;
//if (isset($j->provider_name)) $ret.=" on ".$j->provider_name; //if (isset($j->provider_name)) $ret.=" on ".$j->provider_name;
$ret .= "</h4>";
} else { } else {
// add <a> for html2bbcode conversion // add <a> for html2bbcode conversion
$ret .= "<a href='$embedurl' rel='oembed'>$embedurl</a>"; $ret .= "<a href='$embedurl' rel='oembed'>$embedurl</a>";
$ret.="<br style='clear:left'></span>";
} }
$ret.="<br style='clear:left'></span>";
return mb_convert_encoding($ret, 'HTML-ENTITIES', mb_detect_encoding($ret)); return mb_convert_encoding($ret, 'HTML-ENTITIES', mb_detect_encoding($ret));
} }

View file

@ -752,6 +752,9 @@ if(! function_exists('get_tags')) {
function get_tags($s) { function get_tags($s) {
$ret = array(); $ret = array();
// Convert hashtag links to hashtags
$s = preg_replace("/#\[url\=([^\[\]]*)\](.*?)\[\/url\]/ism", "#$2", $s);
// ignore anything in a code block // ignore anything in a code block
$s = preg_replace('/\[code\](.*?)\[\/code\]/sm','',$s); $s = preg_replace('/\[code\](.*?)\[\/code\]/sm','',$s);

View file

@ -23,6 +23,7 @@ require_once('include/tags.php');
require_once('include/files.php'); require_once('include/files.php');
require_once('include/threads.php'); require_once('include/threads.php');
require_once('include/text.php'); require_once('include/text.php');
require_once('include/items.php');
function item_post(&$a) { function item_post(&$a) {
@ -34,7 +35,6 @@ function item_post(&$a) {
$uid = local_user(); $uid = local_user();
if(x($_REQUEST,'dropitems')) { if(x($_REQUEST,'dropitems')) {
require_once('include/items.php');
$arr_drop = explode(',',$_REQUEST['dropitems']); $arr_drop = explode(',',$_REQUEST['dropitems']);
drop_items($arr_drop); drop_items($arr_drop);
$json = array('success' => 1); $json = array('success' => 1);
@ -569,7 +569,7 @@ function item_post(&$a) {
* and we are replying, and there isn't one already * and we are replying, and there isn't one already
*/ */
if(($parent_contact) && ($parent_contact['network'] === NETWORK_OSTATUS) if(($parent_contact) && ($parent_contact['network'] === NETWORK_OSTATUS)
&& ($parent_contact['nick']) && (! in_array('@' . $parent_contact['nick'],$tags))) { && ($parent_contact['nick']) && (! in_array('@' . $parent_contact['nick'],$tags))) {
$body = '@' . $parent_contact['nick'] . ' ' . $body; $body = '@' . $parent_contact['nick'] . ' ' . $body;
$tags[] = '@' . $parent_contact['nick']; $tags[] = '@' . $parent_contact['nick'];
@ -582,6 +582,9 @@ function item_post(&$a) {
if(count($tags)) { if(count($tags)) {
foreach($tags as $tag) { foreach($tags as $tag) {
if(strpos($tag,'#') === 0)
continue;
// If we already tagged 'Robert Johnson', don't try and tag 'Robert'. // If we already tagged 'Robert Johnson', don't try and tag 'Robert'.
// Robert Johnson should be first in the $tags array // Robert Johnson should be first in the $tags array
@ -713,6 +716,9 @@ function item_post(&$a) {
if($orig_post) if($orig_post)
$datarray['edit'] = true; $datarray['edit'] = true;
// Search for hashtags
item_body_set_hashtags($datarray);
// preview mode - prepare the body for display and send it via json // preview mode - prepare the body for display and send it via json
if($preview) { if($preview) {
@ -1035,10 +1041,9 @@ function item_content(&$a) {
$o = ''; $o = '';
if(($a->argc == 3) && ($a->argv[1] === 'drop') && intval($a->argv[2])) { if(($a->argc == 3) && ($a->argv[1] === 'drop') && intval($a->argv[2])) {
require_once('include/items.php');
$o = drop_item($a->argv[2], !is_ajax()); $o = drop_item($a->argv[2], !is_ajax());
if (is_ajax()){ if (is_ajax()){
// ajax return: [<item id>, 0 (no perm) | <owner id>] // ajax return: [<item id>, 0 (no perm) | <owner id>]
echo json_encode(array(intval($a->argv[2]), intval($o))); echo json_encode(array(intval($a->argv[2]), intval($o)));
killme(); killme();
} }
@ -1047,9 +1052,9 @@ function item_content(&$a) {
} }
/** /**
* This function removes the tag $tag from the text $body and replaces it with * This function removes the tag $tag from the text $body and replaces it with
* the appropiate link. * the appropiate link.
* *
* @param unknown_type $body the text to replace the tag in * @param unknown_type $body the text to replace the tag in
* @param unknown_type $inform a comma-seperated string containing everybody to inform * @param unknown_type $inform a comma-seperated string containing everybody to inform
* @param unknown_type $str_tags string to add the tag to * @param unknown_type $str_tags string to add the tag to
@ -1063,29 +1068,6 @@ function handle_tag($a, &$body, &$inform, &$str_tags, $profile_uid, $tag, $netwo
$replaced = false; $replaced = false;
$r = null; $r = null;
//is it a hash tag?
if(strpos($tag,'#') === 0) {
//if the tag is replaced...
if(strpos($tag,'[url='))
//...do nothing
return $replaced;
//base tag has the tags name only
$basetag = str_replace('_',' ',substr($tag,1));
//create text for link
$newtag = '#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]';
//replace tag by the link
$body = str_replace($tag, $newtag, $body);
$replaced = true;
//is the link already in str_tags?
if(! stristr($str_tags,$newtag)) {
//append or set str_tags
if(strlen($str_tags))
$str_tags .= ',';
$str_tags .= $newtag;
}
return $replaced;
}
//is it a person tag? //is it a person tag?
if(strpos($tag,'@') === 0) { if(strpos($tag,'@') === 0) {
//is it already replaced? //is it already replaced?

View file

@ -708,7 +708,7 @@ die("ss");
if (!get_config("system", "like_no_comment")) if (!get_config("system", "like_no_comment"))
$sql_extra4 = "(`item`.`deleted` = 0 OR `item`.`verb` = '".ACTIVITY_LIKE."' OR `item`.`verb` = '".ACTIVITY_DISLIKE."')"; $sql_extra4 = "(`item`.`deleted` = 0 OR `item`.`verb` = '".ACTIVITY_LIKE."' OR `item`.`verb` = '".ACTIVITY_DISLIKE."')";
else else
$sql_extra4 = "`item`.`deleted` = 0"; $sql_extra4 = "`item`.`deleted` = 0 AND `item`.`verb` = '".ACTIVITY_POST."'";
$r = q("SELECT `item`.`parent` AS `item_id`, `item`.`network` AS `item_network`, `contact`.`uid` AS `contact_uid` $r = q("SELECT `item`.`parent` AS `item_id`, `item`.`network` AS `item_network`, `contact`.`uid` AS `contact_uid`
FROM $sql_table $sql_post_table INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` FROM $sql_table $sql_post_table INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`

View file

@ -125,4 +125,36 @@ blockquote.shared_content {
.settings-heading a:after{ .settings-heading a:after{
content: ' »'; content: ' »';
} }
/* headers */
h1, h2, h3, h4, h5, h6 {
margin: 0px 0px 5px 0px;
font-weight: normal;
line-height: normal;
text-rendering: optimizelegibility;
}
h1 {
font-size: 31.5px;
}
h2 {
font-size: 24.5px;
}
h3 {
font-size: 20.5px;
}
h4 {
font-size: 18px;
}
h5 {
font-size: 16.5px;
}
h6 {
font-size: 14.95px;
}

View file

@ -283,10 +283,6 @@ body {
display: table; display: table;
} }
h4 {
font-size: 1.1em;
}
a { a {
color: #36C; color: #36C;
/* color: #3e3e8c; */ /* color: #3e3e8c; */
@ -1202,10 +1198,6 @@ section.minimal {
width: 350px; width: 350px;
float: left; float: left;
font-size: 12px; font-size: 12px;
}}
h2 {
line-height: normal;
} }
.wall-item-container .wall-item-content { .wall-item-container .wall-item-content {