X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=include%2Fconversation.php;h=5d64bcef763c4bd06e9f3b158b50dc7e81814711;hb=fa11959919dcef30780f6280f1e5257c873fa8b6;hp=05c41e6d27d08a87b39a1881512cfeb0cf35fa97;hpb=0882b2df9704f9e2b32b9874dceb53a90ca72edd;p=friendica.git diff --git a/include/conversation.php b/include/conversation.php index 05c41e6d27..5d64bcef76 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -1,17 +1,20 @@ $new_body, 'images' => $saved_image); -}} +} -if (! function_exists('item_redir_and_replace_images')) { function item_redir_and_replace_images($body, $images, $cid) { $origbody = $body; @@ -95,7 +97,7 @@ function item_redir_and_replace_images($body, $images, $cid) { $cnt++; } return $newbody; -}} +} /** * Render actions localized @@ -120,7 +122,7 @@ function localize_item(&$item) { WHERE `item`.`contact-id`=`contact`.`id` AND `item`.`uri`='%s'", dbesc($item['parent-uri'])); - if (!dbm::is_result($r)) { + if (!DBM::is_result($r)) { return; } $obj = $r[0]; @@ -249,20 +251,6 @@ function localize_item(&$item) { $item['body'] = sprintf($txt, $A, $B). "\n\n\n" . $Bphoto; } - if (stristr($item['verb'], ACTIVITY_MOOD)) { - $verb = urldecode(substr($item['verb'], strpos($item['verb'], '#') + 1)); - if (! $verb) { - return; - } - - $Aname = $item['author-name']; - $Alink = $item['author-link']; - $A = '[url=' . zrl($Alink) . ']' . $Aname . '[/url]'; - - $txt = t('%1$s is currently %2$s'); - - $item['body'] = sprintf($txt, $A, t($verb)); - } if (activity_match($item['verb'], ACTIVITY_TAG)) { /// @TODO may hurt performance "joining" two tables + asterisk @@ -271,7 +259,7 @@ function localize_item(&$item) { AND `item`.`uri`='%s'", dbesc($item['parent-uri'])); - if (!dbm::is_result($r)) { + if (!DBM::is_result($r)) { return; } @@ -327,7 +315,7 @@ function localize_item(&$item) { intval($item['uid']) ); - if (dbm::is_result($r) && $r[0]['plink']) { + if (DBM::is_result($r) && $r[0]['plink']) { $target = $r[0]; $Bname = $target['author-name']; $Blink = $target['author-link']; @@ -491,7 +479,6 @@ function item_condition() { return "`item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`"; } -if (!function_exists('conversation')) { /** * "Render" a conversation or list of items for HTML display. * There are two major forms of display: @@ -505,7 +492,6 @@ if (!function_exists('conversation')) { function conversation(App $a, $items, $mode, $update, $preview = false) { require_once 'include/bbcode.php'; - require_once 'include/Contact.php'; require_once 'mod/proxy.php'; $ssl_state = ((local_user()) ? true : false); @@ -517,7 +503,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false) { $arr_blocked = null; if (local_user()) { - $str_blocked = get_pconfig(local_user(), 'system', 'blocked'); + $str_blocked = PConfig::get(local_user(), 'system', 'blocked'); if ($str_blocked) { $arr_blocked = explode(',', $str_blocked); for ($x = 0; $x < count($arr_blocked); $x ++) { @@ -726,7 +712,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false) { } if (!x($item, 'author-thumb') || ($item['author-thumb'] == "")) { - $author_contact = get_contact_details_by_url($item['author-link'], $profile_owner); + $author_contact = Contact::getDetailsByURL($item['author-link'], $profile_owner); if ($author_contact["thumb"]) { $item['author-thumb'] = $author_contact["thumb"]; } else { @@ -735,7 +721,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false) { } if (!isset($item['owner-thumb']) || ($item['owner-thumb'] == "")) { - $owner_contact = get_contact_details_by_url($item['owner-link'], $profile_owner); + $owner_contact = Contact::getDetailsByURL($item['owner-link'], $profile_owner); if ($owner_contact["thumb"]) { $item['owner-thumb'] = $owner_contact["thumb"]; } else { @@ -773,25 +759,14 @@ function conversation(App $a, $items, $mode, $update, $preview = false) { list($categories, $folders) = get_cats_and_terms($item); - if ($a->theme['template_engine'] === 'internal') { - $profile_name_e = template_escape($profile_name); - $item['title_e'] = template_escape($item['title']); - $body_e = template_escape($body); - $tags_e = template_escape($tags); - $hashtags_e = template_escape($hashtags); - $mentions_e = template_escape($mentions); - $location_e = template_escape($location); - $owner_name_e = template_escape($owner_name); - } else { - $profile_name_e = $profile_name; - $item['title_e'] = $item['title']; - $body_e = $body; - $tags_e = $tags; - $hashtags_e = $hashtags; - $mentions_e = $mentions; - $location_e = $location; - $owner_name_e = $owner_name; - } + $profile_name_e = $profile_name; + $item['title_e'] = $item['title']; + $body_e = $body; + $tags_e = $tags; + $hashtags_e = $hashtags; + $mentions_e = $mentions; + $location_e = $location; + $owner_name_e = $owner_name; if ($item['item_network'] == "") { $item['item_network'] = $item['network']; @@ -800,6 +775,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false) { $tmp_item = array( 'template' => $tpl, 'id' => (($preview) ? 'P0' : $item['item_id']), + 'guid' => (($preview) ? 'Q0' : $item['guid']), 'network' => $item['item_network'], 'network_name' => network_to_name($item['item_network'], $profile_link), 'linktitle' => sprintf( t('View %s\'s profile @ %s'), $profile_name, ((strlen($item['author-link'])) ? $item['author-link'] : $item['url'])), @@ -856,10 +832,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false) { // Normal View $page_template = get_markup_template("threaded_conversation.tpl"); - require_once 'object/Conversation.php'; - require_once 'object/Item.php'; - - $conv = new Conversation($mode, $preview); + $conv = new Thread($mode, $preview); /* * get all the topmost parents @@ -899,12 +872,12 @@ function conversation(App $a, $items, $mode, $update, $preview = false) { $item['pagedrop'] = $page_dropping; if ($item['id'] == $item['parent']) { - $item_object = new Item($item); - $conv->add_thread($item_object); + $item_object = new Post($item); + $conv->addParent($item_object); } } - $threads = $conv->get_template_data($conv_responses); + $threads = $conv->getTemplateData($conv_responses); if (!$threads) { logger('[ERROR] conversation : Failed to get template data.', LOGGER_DEBUG); @@ -921,11 +894,11 @@ function conversation(App $a, $items, $mode, $update, $preview = false) { '$mode' => $mode, '$user' => $a->user, '$threads' => $threads, - '$dropping' => ($page_dropping && feature_enabled(local_user(), 'multi_delete') ? t('Delete Selected Items') : False), + '$dropping' => ($page_dropping && Feature::isEnabled(local_user(), 'multi_delete') ? t('Delete Selected Items') : False), )); return $o; -}} +} function best_link_url($item, &$sparkle, $url = '') { @@ -938,7 +911,7 @@ function best_link_url($item, &$sparkle, $url = '') { $r = dba::select('contact', array('id'), array('network' => NETWORK_DFRN, 'uid' => local_user(), 'nurl' => normalise_link($clean_url), 'pending' => false), array('limit' => 1)); - if (dbm::is_result($r)) { + if (DBM::is_result($r)) { $best_url = 'redir/' . $r['id']; $sparkle = true; if ($url != '') { @@ -989,7 +962,7 @@ function item_photo_menu($item) { $network = ''; $rel = 0; $r = dba::select('contact', array('id', 'network', 'rel'), array('uid' => local_user(), 'nurl' => normalise_link($item['author-link'])), array('limit' => 1)); - if (dbm::is_result($r)) { + if (DBM::is_result($r)) { $cid = $r['id']; $network = $r['network']; $rel = $r['rel']; @@ -1055,7 +1028,6 @@ function item_photo_menu($item) { return $o; } -if (! function_exists('builtin_activity_puller')) { /** * @brief Checks item to see if it is one of the builtin activities (like/dislike, event attendance, consensus items, etc.) * Increments the count of each matching activity and adds a link to the author as needed. @@ -1131,9 +1103,8 @@ function builtin_activity_puller($item, &$conv_responses) { return; } } -}} +} -if (! function_exists('format_like')) { /** * Format the vote text for a profile item * @param int $cnt = number of people who vote the item @@ -1224,7 +1195,7 @@ function format_like($cnt, array $arr, $type, $id) { $o .= $expanded; return $o; -}} +} function status_editor(App $a, $x, $notes_cid = 0, $popup = false) { $o = ''; @@ -1311,7 +1282,7 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false) { '$title' => $x['title'], '$placeholdertitle' => t('Set title'), '$category' => $x['category'], - '$placeholdercategory' => (feature_enabled(local_user(), 'categories') ? t('Categories (comma-separated list)') : ''), + '$placeholdercategory' => (Feature::isEnabled(local_user(), 'categories') ? t('Categories (comma-separated list)') : ''), '$wait' => t('Please wait'), '$permset' => t('Permission settings'), '$shortpermset' => t('permissions'), @@ -1327,7 +1298,7 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false) { '$lockstate' => $x['lockstate'], '$bang' => $x['bang'], '$profile_uid' => $x['profile_uid'], - '$preview' => ((feature_enabled($x['profile_uid'],'preview')) ? t('Preview') : ''), + '$preview' => ((Feature::isEnabled($x['profile_uid'],'preview')) ? t('Preview') : ''), '$jotplugins' => $jotplugins, '$notes_cid' => $notes_cid, '$sourceapp' => t($a->sourcename), @@ -1356,13 +1327,22 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false) { return $o; } - -function get_item_children($arr, $parent) { - $children = array(); - $a = get_app(); - foreach ($arr as $item) { +/** + * Plucks the children of the given parent from a given item list. + * + * @brief Plucks all the children in the given item list of the given parent + * + * @param array $item_list + * @param array $parent + * @param bool $recursive + * @return type + */ +function get_item_children(array &$item_list, array $parent, $recursive = true) +{ + $children = []; + foreach ($item_list as $i => $item) { if ($item['id'] != $item['parent']) { - if (get_config('system', 'thread_allow') && $a->theme_thread_allow) { + if ($recursive) { // Fallback to parent-uri if thr-parent is not set $thr_parent = $item['thr-parent']; if ($thr_parent == '') { @@ -1370,65 +1350,141 @@ function get_item_children($arr, $parent) { } if ($thr_parent == $parent['uri']) { - $item['children'] = get_item_children($arr, $item); + $item['children'] = get_item_children($item_list, $item); $children[] = $item; + unset($item_list[$i]); } } elseif ($item['parent'] == $parent['id']) { $children[] = $item; + unset($item_list[$i]); } } } return $children; } -/// @TODO Add type-hint -function sort_item_children($items) { +/** + * @brief Recursively sorts a tree-like item array + * + * @param array $items + * @return array + */ +function sort_item_children(array $items) +{ $result = $items; usort($result, 'sort_thr_created_rev'); foreach ($result as $k => $i) { - if (count($result[$k]['children'])) { + if (isset($result[$k]['children'])) { $result[$k]['children'] = sort_item_children($result[$k]['children']); } } return $result; } -/// @TODO Add type-hint -function add_children_to_list($children, &$arr) { - foreach ($children as $y) { - $arr[] = $y; - if (count($y['children'])) { - add_children_to_list($y['children'], $arr); +/** + * @brief Recursively add all children items at the top level of a list + * + * @param array $children List of items to append + * @param array $item_list + */ +function add_children_to_list(array $children, array &$item_list) +{ + foreach ($children as $child) { + $item_list[] = $child; + if (isset($child['children'])) { + add_children_to_list($child['children'], $item_list); } } } -/// @TODO Add type-hint -function conv_sort($arr, $order) { - - if ((!(is_array($arr) && count($arr)))) { - return array(); +/** + * This recursive function takes the item tree structure created by conv_sort() and + * flatten the extraneous depth levels when people reply sequentially, removing the + * stairs effect in threaded conversations limiting the available content width. + * + * The basic principle is the following: if a post item has only one reply and is + * the last reply of its parent, then the reply is moved to the parent. + * + * This process is rendered somewhat more complicated because items can be either + * replies or likes, and these don't factor at all in the reply count/last reply. + * + * @brief Selectively flattens a tree-like item structure to prevent threading stairs + * + * @param array $parent A tree-like array of items + * @return array + */ +function smart_flatten_conversation(array $parent) +{ + if (! isset($parent['children']) || count($parent['children']) == 0) { + return $parent; } - $parents = array(); - $children = array(); - $newarr = array(); + // We use a for loop to ensure we process the newly-moved items + for ($i = 0; $i < count($parent['children']); $i++) { + $child = $parent['children'][$i]; - /* - * This is a preparation for having two different items with the same uri in one thread - * This will otherwise lead to an endless loop. - */ - foreach ($arr as $x) { - if (!isset($newarr[$x['uri']])) { - $newarr[$x['uri']] = $x; + if (isset($child['children']) && count($child['children'])) { + // This helps counting only the regular posts + $count_post_closure = function($var) { + return $var['verb'] === ACTIVITY_POST; + }; + + $child_post_count = count(array_filter($child['children'], $count_post_closure)); + + $remaining_post_count = count(array_filter(array_slice($parent['children'], $i), $count_post_closure)); + + // If there's only one child's children post and this is the last child post + if ($child_post_count == 1 && $remaining_post_count == 1) { + + // Searches the post item in the children + $j = 0; + while($child['children'][$j]['verb'] !== ACTIVITY_POST && $j < count($child['children'])) { + $j ++; + } + + $moved_item = $child['children'][$j]; + unset($parent['children'][$i]['children'][$j]); + $parent['children'][] = $moved_item; + } else { + $parent['children'][$i] = smart_flatten_conversation($child); + } } } - $arr = $newarr; + return $parent; +} + - foreach ($arr as $x) { - if ($x['id'] == $x['parent']) { - $parents[] = $x; +/** + * Expands a flat list of items into corresponding tree-like conversation structures, + * sort the top-level posts either on "created" or "commented", and finally + * append all the items at the top level (???) + * + * @brief Expands a flat item list into a conversation array for display + * + * @param array $item_list A list of items belonging to one or more conversations + * @param string $order Either on "created" or "commented" + * @return array + */ +function conv_sort(array $item_list, $order) +{ + $parents = []; + + if (!(is_array($item_list) && count($item_list))) { + return $parents; + } + + $item_array = []; + + // Dedupes the item list on the uri to prevent infinite loops + foreach ($item_list as $item) { + $item_array[$item['uri']] = $item; + } + + // Extract the top level items + foreach ($item_array as $item) { + if ($item['id'] == $item['parent']) { + $parents[] = $item; } } @@ -1438,73 +1494,73 @@ function conv_sort($arr, $order) { usort($parents, 'sort_thr_commented'); } - if (count($parents)) { - foreach ($parents as $i => $_x) { - $parents[$i]['children'] = get_item_children($arr, $_x); - } + /* + * Plucks children from the item_array, second pass collects eventual orphan + * items and add them as children of their top-level post. + */ + foreach ($parents as $i => $parent) { + $parents[$i]['children'] = + array_merge(get_item_children($item_array, $parent, true), + get_item_children($item_array, $parent, false)); } - /// @TODO Old-lost code? - /*foreach ($arr as $x) { - if ($x['id'] != $x['parent']) { - $p = find_thread_parent_index($parents,$x); - if ($p !== false) - $parents[$p]['children'][] = $x; - } - }*/ - if (count($parents)) { - foreach ($parents as $k => $v) { - if (count($parents[$k]['children'])) { - $parents[$k]['children'] = sort_item_children($parents[$k]['children']); - /// @TODO Old-lost code? - /*$y = $parents[$k]['children']; - usort($y,'sort_thr_created_rev'); - $parents[$k]['children'] = $y;*/ - } + foreach ($parents as $i => $parent) { + $parents[$i]['children'] = sort_item_children($parents[$i]['children']); + } + + if (PConfig::get(local_user(), 'system', 'smart_threading', 0)) { + foreach ($parents as $i => $parent) { + $parents[$i] = smart_flatten_conversation($parent); } } - $ret = array(); - if (count($parents)) { - foreach ($parents as $x) { - $ret[] = $x; - if (count($x['children'])) { - add_children_to_list($x['children'], $ret); - /// @TODO Old-lost code? - /*foreach ($x['children'] as $y) - $ret[] = $y;*/ - } + /// @TODO: Stop recusrsively adding all children back to the top level (!!!) + /// However, this apparently ensures responses (likes, attendance) display (?!) + foreach ($parents as $parent) { + if (count($parent['children'])) { + add_children_to_list($parent['children'], $parents); } } - return $ret; + return $parents; } -/// @TODO Add type-hint -function sort_thr_created($a, $b) { +/** + * @brief usort() callback to sort item arrays by the created key + * + * @param array $a + * @param array $b + * @return int + */ +function sort_thr_created(array $a, array $b) +{ return strcmp($b['created'], $a['created']); } -/// @TODO Add type-hint -function sort_thr_created_rev($a, $b) { +/** + * @brief usort() callback to reverse sort item arrays by the created key + * + * @param array $a + * @param array $b + * @return int + */ +function sort_thr_created_rev(array $a, array $b) +{ return strcmp($a['created'], $b['created']); } -/// @TODO Add type-hint -function sort_thr_commented($a, $b) { +/** + * @brief usort() callback to sort item arrays by the commented key + * + * @param array $a + * @param array $b + * @return type + */ +function sort_thr_commented(array $a, array $b) +{ return strcmp($b['commented'], $a['commented']); } -/// @TODO Add type-hint -function find_thread_parent_index($arr, $x) { - foreach ($arr as $k => $v) { - if ($v['id'] == $x['parent']) { - return $k; - } - } - return false; -} - /// @TODO Add type-hint function render_location_dummy($item) { if ($item['location'] != "") { @@ -1527,7 +1583,7 @@ function get_responses($conv_responses, $response_verbs, $ob, $item) { if (count($ret[$v]['list']) > MAX_LIKERS) { $ret[$v]['list_part'] = array_slice($ret[$v]['list'], 0, MAX_LIKERS); array_push($ret[$v]['list_part'], '' . t('View all') . ''); + . (($ob) ? $ob->getId() : $item['id']) . '">' . t('View all') . ''); } else { $ret[$v]['list_part'] = ''; }