diff options
-rw-r--r-- | CHANGELOG | 4 | ||||
-rw-r--r-- | Zotlabs/Lib/ActivityStreams.php | 43 | ||||
-rw-r--r-- | Zotlabs/Lib/LDSignatures.php | 117 | ||||
-rw-r--r-- | Zotlabs/Lib/ThreadItem.php | 6 | ||||
-rw-r--r-- | Zotlabs/Module/Acl.php | 7 | ||||
-rw-r--r-- | Zotlabs/Module/Display.php | 13 | ||||
-rw-r--r-- | Zotlabs/Module/Item.php | 11 | ||||
-rw-r--r-- | Zotlabs/Module/Oep.php | 2 | ||||
-rw-r--r-- | Zotlabs/Module/Rpost.php | 41 | ||||
-rw-r--r-- | Zotlabs/Module/Xrd.php | 2 | ||||
-rw-r--r-- | Zotlabs/Web/CheckJS.php | 6 | ||||
-rw-r--r-- | Zotlabs/Widget/Categories.php | 2 | ||||
-rwxr-xr-x | boot.php | 4 | ||||
-rw-r--r-- | include/bbcode.php | 3 | ||||
-rw-r--r-- | include/photos.php | 2 | ||||
-rw-r--r-- | include/text.php | 13 | ||||
-rw-r--r-- | view/css/conversation.css | 15 | ||||
-rw-r--r-- | view/js/main.js | 79 | ||||
-rw-r--r-- | view/js/mod_cards.js | 6 | ||||
-rw-r--r-- | view/theme/redbasic/css/style.css | 7 | ||||
-rwxr-xr-x | view/tpl/comment_item.tpl | 2 | ||||
-rwxr-xr-x | view/tpl/conv_frame.tpl | 1 | ||||
-rwxr-xr-x | view/tpl/threaded_conversation.tpl | 3 |
23 files changed, 305 insertions, 84 deletions
@@ -1,3 +1,7 @@ +Hubzilla 2.6.2 (2017-08-31) + - Fix webfinger returns invalid XML (github issue #851) + + Hubzilla 2.6.1 (2017-08-18) - Fix a regression with dav clients - Raise install requirements diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index 3bbe3b190..686f4a140 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -14,6 +14,8 @@ class ActivityStreams { public $origin = null; public $owner = null; + public $recips = null; + function __construct($string) { $this->data = json_decode($string,true); @@ -28,7 +30,7 @@ class ActivityStreams { $this->obj = $this->get_compound_property('object'); $this->tgt = $this->get_compound_property('target'); $this->origin = $this->get_compound_property('origin'); - $this->owner = $this->get_compound_property('owner','','http://purl.org/zot/protocol'); + $this->recips = $this->collect_recips(); if(($this->type === 'Note') && (! $this->obj)) { $this->obj = $this->data; @@ -41,6 +43,45 @@ class ActivityStreams { return $this->valid; } + function collect_recips($base = '',$namespace = 'https://www.w3.org/ns/activitystreams') { + $x = []; + $fields = [ 'to','cc','bto','bcc','audience']; + foreach($fields as $f) { + $y = $this->get_compound_property($f,$base,$namespace); + if($y) + $x = array_merge($x,$y); + } +// not yet ready for prime time +// $x = $this->expand($x,$base,$namespace); + return $x; + } + + function expand($arr,$base = '',$namespace = 'https://www.w3.org/ns/activitystreams') { + $ret = []; + + // right now use a hardwired recursion depth of 5 + + for($z = 0; $z < 5; $z ++) { + if(is_array($arr) && $arr) { + foreach($arr as $a) { + if(is_array($a)) { + $ret[] = $a; + } + else { + $x = $this->get_compound_property($a,$base,$namespace); + if($x) { + $ret = array_merge($ret,$x); + } + } + } + } + } + + // @fixme de-duplicate + + return $ret; + } + function get_namespace($base,$namespace) { $key = null; diff --git a/Zotlabs/Lib/LDSignatures.php b/Zotlabs/Lib/LDSignatures.php new file mode 100644 index 000000000..88dfe80c0 --- /dev/null +++ b/Zotlabs/Lib/LDSignatures.php @@ -0,0 +1,117 @@ +<?php + +namespace Zotlabs\Lib; + +require_once('library/jsonld/jsonld.php'); + +class LDSignatures { + + + static function verify($data,$pubkey) { + + $ohash = self::hash(self::signable_options($data['signature'])); + $dhash = self::hash(self::signable_data($data)); + + return rsa_verify($ohash . $dhash,base64_decode($data['signature']['signatureValue']), $pubkey); + } + + static function dopplesign(&$data,$channel) { + $data['magicEnv'] = self::salmon_sign($data,$channel); + return self::sign($data,$channel); + } + + static function sign($data,$channel) { + $options = [ + 'type' => 'RsaSignature2017', + 'nonce' => random_string(64), + 'creator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem', + 'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\Th:i:s\Z') + ]; + + $ohash = self::hash(self::signable_options($options)); + $dhash = self::hash(self::signable_data($data)); + $options['signatureValue'] = base64_encode(rsa_sign($ohash . $dhash,$channel['channel_prvkey'])); + + $signed = array_merge([ + '@context' => [ 'https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1' ], + ],$options); + + return $signed; + } + + + static function signable_data($data) { + + $newdata = []; + if($data) { + foreach($data as $k => $v) { + if(! in_array($k,[ 'signature' ])) { + $newopts[$k] = $v; + } + } + } + return json_encode($newdata,JSON_UNESCAPED_SLASHES); + } + + + static function signable_options($options) { + + $newopts = [ '@context' => 'https://w3id.org/identity/v1' ]; + if($options) { + foreach($options as $k => $v) { + if(! in_array($k,[ 'type','id','signatureValue' ])) { + $newopts[$k] = $v; + } + } + } + return json_encode($newopts,JSON_UNESCAPED_SLASHES); + } + + static function hash($obj) { + return hash('sha256',self::normalise($obj)); + } + + static function normalise($data) { + if(is_string($data)) { + $data = json_decode($data); + } + + if(! is_object($data)) + return ''; + + return jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]); + } + + static function salmon_sign($data,$channel) { + + $arr = $data; + $data = json_encode($data,JSON_UNESCAPED_SLASHES); + $data = base64url_encode($data, false); // do not strip padding + $data_type = 'application/activity+json'; + $encoding = 'base64url'; + $algorithm = 'RSA-SHA256'; + $keyhash = base64url_encode(z_root() . '/channel/' . $channel['channel_address']); + + $data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$data); + + // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods + + $precomputed = '.' . base64url_encode($data_type,false) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng=='; + + $signature = base64url_encode(rsa_sign($data . $precomputed,$channel['channel_prvkey'])); + + return ([ + 'id' => $arr['id'], + 'meData' => $data, + 'meDataType' => $data_type, + 'meEncoding' => $encoding, + 'meAlgorithm' => $algorithm, + 'meCreator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem', + 'meSignatureValue' => $signature + ]); + + } + + + +}
\ No newline at end of file diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 313001cc7..f9565d339 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -758,9 +758,9 @@ class ThreadItem { '$sourceapp' => \App::$sourcename, '$observer' => get_observer_hash(), '$anoncomments' => (($conv->get_mode() === 'channel' && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false), - '$anonname' => [ 'anonname', t('Your full name (required)'),'','','','onBlur="commentCloseUI(this,\'' . $this->get_id() . '\')"' ], - '$anonmail' => [ 'anonmail', t('Your email address (required)'),'','','','onBlur="commentCloseUI(this,\'' . $this->get_id() . '\')"' ], - '$anonurl' => [ 'anonurl', t('Your website URL (optional)'),'','','','onBlur="commentCloseUI(this,\'' . $this->get_id() . '\')"' ] + '$anonname' => [ 'anonname', t('Your full name (required)') ], + '$anonmail' => [ 'anonmail', t('Your email address (required)') ], + '$anonurl' => [ 'anonurl', t('Your website URL (optional)') ] )); return $comment_box; diff --git a/Zotlabs/Module/Acl.php b/Zotlabs/Module/Acl.php index 83fafbdff..4d7654f3d 100644 --- a/Zotlabs/Module/Acl.php +++ b/Zotlabs/Module/Acl.php @@ -324,11 +324,12 @@ class Acl extends \Zotlabs\Web\Controller { $r = array(); if($r) { - foreach($r as $g){ + foreach($r as $g) { - // remove RSS feeds from ACLs - they are inaccessible - if(strpos($g['hash'],'/') && $type != 'a') + if(($g['network'] === 'rss') && ($type != 'a')) continue; + + $g['hash'] = urlencode($g['hash']); if(in_array($g['hash'],$permitted) && $type == 'c' && (! $noforums)) { $contacts[] = array( diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php index b698513ba..66a09b983 100644 --- a/Zotlabs/Module/Display.php +++ b/Zotlabs/Module/Display.php @@ -76,7 +76,6 @@ class Display extends \Zotlabs\Web\Controller { $o = '<div id="jot-popup">'; $o .= status_editor($a,$x); $o .= '</div>'; - } // This page can be viewed by anybody so the query could be complicated @@ -181,6 +180,7 @@ class Display extends \Zotlabs\Web\Controller { 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string), 'title' => 'oembed' ]); + } $observer_hash = get_observer_hash(); @@ -190,7 +190,6 @@ class Display extends \Zotlabs\Web\Controller { if(($update && $load) || ($checkjs->disabled())) { - $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']),intval(\App::$pager['start'])); if($load || ($checkjs->disabled())) { @@ -224,7 +223,6 @@ class Display extends \Zotlabs\Web\Controller { if(! perm_is_allowed($sysid,$observer_hash,'view_stream')) $sysid = 0; - $r = q("SELECT item.id as item_id from item WHERE mid = '%s' AND (((( item.allow_cid = '' AND item.allow_gid = '' AND item.deny_cid = '' @@ -237,7 +235,6 @@ class Display extends \Zotlabs\Web\Controller { dbesc($target_item['parent_mid']), intval($sysid) ); - } } } @@ -250,6 +247,7 @@ class Display extends \Zotlabs\Web\Controller { $sysid = $sys['channel_id']; if(local_channel()) { + $r = q("SELECT item.parent AS item_id from item WHERE uid = %d and parent_mid = '%s' @@ -269,12 +267,12 @@ class Display extends \Zotlabs\Web\Controller { // make that content unsearchable by ensuring the owner_xchan can't match if(! perm_is_allowed($sysid,$observer_hash,'view_stream')) $sysid = 0; - + $r = q("SELECT item.parent AS item_id from item WHERE parent_mid = '%s' AND (((( item.allow_cid = '' AND item.allow_gid = '' AND item.deny_cid = '' AND item.deny_gid = '' AND item_private = 0 ) - and owner_xchan in ( " . stream_perms_xchans(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " )) + and uid in ( " . stream_perms_api_uids(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " )) OR uid = %d ) $sql_extra ) $item_normal @@ -292,7 +290,7 @@ class Display extends \Zotlabs\Web\Controller { } if($r) { - + $parents_str = ids_to_querystr($r,'item_id'); if($parents_str) { @@ -310,7 +308,6 @@ class Display extends \Zotlabs\Web\Controller { $items = array(); } - if ($checkjs->disabled()) { $o .= conversation($items, 'display', $update, 'traditional'); if ($items[0]['title']) diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index a86106b6a..3e023ae8b 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -659,14 +659,23 @@ class Item extends \Zotlabs\Web\Controller { // BBCODE end alert if(strlen($categories)) { + $cats = explode(',',$categories); foreach($cats as $cat) { + + if($webpage == ITEM_TYPE_CARD) { + $catlink = z_root() . '/cards/' . $channel['channel_address'] . '?f=&cat=' . urlencode(trim($cat)); + } + else { + $catlink = $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat)); + } + $post_tags[] = array( 'uid' => $profile_uid, 'ttype' => TERM_CATEGORY, 'otype' => TERM_OBJ_POST, 'term' => trim($cat), - 'url' => $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat)) + 'url' => $catlink ); } } diff --git a/Zotlabs/Module/Oep.php b/Zotlabs/Module/Oep.php index 02aa4aba9..9a1317142 100644 --- a/Zotlabs/Module/Oep.php +++ b/Zotlabs/Module/Oep.php @@ -1,6 +1,8 @@ <?php namespace Zotlabs\Module; +require_once('include/security.php'); + // oembed provider diff --git a/Zotlabs/Module/Rpost.php b/Zotlabs/Module/Rpost.php index 731eab82e..56f4f23f6 100644 --- a/Zotlabs/Module/Rpost.php +++ b/Zotlabs/Module/Rpost.php @@ -90,8 +90,6 @@ class Rpost extends \Zotlabs\Web\Controller { } $plaintext = true; - // if(feature_enabled(local_channel(),'richtext')) - // $plaintext = false; if(array_key_exists('type', $_REQUEST) && $_REQUEST['type'] === 'html') { require_once('include/html2bbcode.php'); @@ -112,26 +110,25 @@ class Rpost extends \Zotlabs\Web\Controller { } $x = array( - 'is_owner' => true, - 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''), - 'default_location' => $channel['channel_location'], - 'nickname' => $channel['channel_address'], - 'lockstate' => (($acl->is_private()) ? 'lock' : 'unlock'), - 'acl' => populate_acl($channel_acl, true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), - 'permissions' => $channel_acl, - 'bang' => '', - 'visitor' => true, - 'profile_uid' => local_channel(), - 'title' => $_REQUEST['title'], - 'body' => $_REQUEST['body'], - 'attachment' => $_REQUEST['attachment'], - 'source' => ((x($_REQUEST,'source')) ? strip_tags($_REQUEST['source']) : ''), - 'return_path' => 'rpost/return', - 'bbco_autocomplete' => 'bbcode', - 'editor_autocomplete'=> true, - 'bbcode' => true, - 'jotnets' => true - + 'is_owner' => true, + 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''), + 'default_location' => $channel['channel_location'], + 'nickname' => $channel['channel_address'], + 'lockstate' => (($acl->is_private()) ? 'lock' : 'unlock'), + 'acl' => populate_acl($channel_acl, true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), + 'permissions' => $channel_acl, + 'bang' => '', + 'visitor' => true, + 'profile_uid' => local_channel(), + 'title' => $_REQUEST['title'], + 'body' => $_REQUEST['body'], + 'attachment' => $_REQUEST['attachment'], + 'source' => ((x($_REQUEST,'source')) ? strip_tags($_REQUEST['source']) : ''), + 'return_path' => 'rpost/return', + 'bbco_autocomplete' => 'bbcode', + 'editor_autocomplete' => true, + 'bbcode' => true, + 'jotnets' => true ); $editor = status_editor($a,$x); diff --git a/Zotlabs/Module/Xrd.php b/Zotlabs/Module/Xrd.php index 64e5042cb..60a8f58fa 100644 --- a/Zotlabs/Module/Xrd.php +++ b/Zotlabs/Module/Xrd.php @@ -57,7 +57,7 @@ class Xrd extends \Zotlabs\Web\Controller { '$poco_url' => z_root() . '/poco/' . $r[0]['channel_address'], '$photo' => z_root() . '/photo/profile/l/' . $r[0]['channel_id'], '$modexp' => 'data:application/magic-public-key,' . $salmon_key, - '$subscribe' => z_root() . '/follow?f=&url={uri}', + '$subscribe' => z_root() . '/follow?f=&url={uri}', )); diff --git a/Zotlabs/Web/CheckJS.php b/Zotlabs/Web/CheckJS.php index 109790fa5..8179ceb15 100644 --- a/Zotlabs/Web/CheckJS.php +++ b/Zotlabs/Web/CheckJS.php @@ -21,9 +21,9 @@ class CheckJS { $page = urlencode(\App::$query_string); if($test) { - self::$jsdisabled = 1; + $this->jsdisabled = 1; if(array_key_exists('jsdisabled',$_COOKIE)) - self::$jsdisabled = $_COOKIE['jsdisabled']; + $this->jsdisabled = $_COOKIE['jsdisabled']; if(! array_key_exists('jsdisabled',$_COOKIE)) { \App::$page['htmlhead'] .= "\r\n" . '<script>document.cookie="jsdisabled=0; path=/"; var jsMatch = /\&jsdisabled=0/; if (!jsMatch.exec(location.href)) { location.href = "' . z_root() . '/nojs/0?f=&redir=' . $page . '" ; }</script>' . "\r\n"; @@ -41,7 +41,7 @@ class CheckJS { } function disabled() { - return self::$jsdisabled; + return $this->jsdisabled; } diff --git a/Zotlabs/Widget/Categories.php b/Zotlabs/Widget/Categories.php index 84deb03d6..305869706 100644 --- a/Zotlabs/Widget/Categories.php +++ b/Zotlabs/Widget/Categories.php @@ -19,7 +19,7 @@ class Categories { } $cat = ((x($_REQUEST,'cat')) ? htmlspecialchars($_REQUEST['cat'],ENT_COMPAT,'UTF-8') : ''); - $srchurl = \App::$query_string; + $srchurl = (($cards) ? \App::$argv[0] . '/' . \App::$argv[1] : \App::$query_string); $srchurl = rtrim(preg_replace('/cat\=[^\&].*?(\&|$)/is','',$srchurl),'&'); $srchurl = str_replace(array('?f=','&f='),array('',''),$srchurl); @@ -49,7 +49,7 @@ require_once('include/hubloc.php'); require_once('include/attach.php'); define ( 'PLATFORM_NAME', 'hubzilla' ); -define ( 'STD_VERSION', '2.7.1' ); +define ( 'STD_VERSION', '2.7.2' ); define ( 'ZOT_REVISION', '1.3' ); define ( 'DB_UPDATE_VERSION', 1193 ); @@ -64,7 +64,7 @@ define ( 'PROJECT_BASE', __DIR__ ); * This can be used in HTML and JavaScript where needed a line break. */ define ( 'EOL', '<br>' . "\r\n" ); -define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' ); +define ( 'ATOM_TIME', 'Y-m-d\\TH:i:s\\Z' ); // aka ISO 8601 "Zulu" define ( 'TEMPLATE_BUILD_PATH', 'store/[data]/smarty3' ); define ( 'DIRECTORY_MODE_NORMAL', 0x0000); // A directory client diff --git a/include/bbcode.php b/include/bbcode.php index 9f9b5c5e1..470854f06 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -1255,6 +1255,9 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) $Text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", 'bb_unspacefy_and_trim', $Text); } + // replace escaped links in code= blocks + $Text = str_replace('%eY9-!','http', $Text); + $Text = preg_replace('/\[\&\;([#a-z0-9]+)\;\]/', '&$1;', $Text); // fix any escaped ampersands that may have been converted into links diff --git a/include/photos.php b/include/photos.php index f5d5fdb48..c7c8fc0a4 100644 --- a/include/photos.php +++ b/include/photos.php @@ -595,7 +595,7 @@ function photos_album_exists($channel_id, $observer_hash, $album) { // partial backward compatibility with Hubzilla < 2.4 when we used the filename only // (ambiguous which would get chosen if you had two albums of the same name in different directories) - if(!$r) { + if(!$r && ctype_xdigit($album)) { $r = q("SELECT folder, hash, is_dir, filename, os_path, display_path FROM attach WHERE filename = '%s' AND is_dir = 1 AND uid = %d $sql_extra limit 1", dbesc(hex2bin($album)), intval($channel_id) diff --git a/include/text.php b/include/text.php index dd2dc7620..ea21e2184 100644 --- a/include/text.php +++ b/include/text.php @@ -651,7 +651,7 @@ function logger($msg, $level = LOGGER_NORMAL, $priority = LOG_INFO) { $stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); $where = basename($stack[0]['file']) . ':' . $stack[0]['line'] . ':' . $stack[1]['function'] . ': '; - $s = datetime_convert() . ':' . log_priority_str($priority) . ':' . session_id() . ':' . $where . $msg . PHP_EOL; + $s = datetime_convert('UTC','UTC', 'now', ATOM_TIME) . ':' . log_priority_str($priority) . ':' . session_id() . ':' . $where . $msg . PHP_EOL; $pluginfo = array('filename' => $logfile, 'loglevel' => $level, 'message' => $s,'priority' => $priority, 'logged' => false); if(! (App::$module == 'setup')) @@ -679,7 +679,7 @@ function btlogger($msg, $level = LOGGER_NORMAL, $priority = LOG_INFO) { if(file_exists(BTLOGGER_DEBUG_FILE) && is_writable(BTLOGGER_DEBUG_FILE)) { $stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); $where = basename($stack[0]['file']) . ':' . $stack[0]['line'] . ':' . $stack[1]['function'] . ': '; - $s = datetime_convert() . ':' . log_priority_str($priority) . ':' . session_id() . ':' . $where . $msg . PHP_EOL; + $s = datetime_convert('UTC','UTC', 'now', ATOM_TIME) . ':' . log_priority_str($priority) . ':' . session_id() . ':' . $where . $msg . PHP_EOL; @file_put_contents(BTLOGGER_DEBUG_FILE, $s, FILE_APPEND); } @@ -750,7 +750,7 @@ function dlogger($msg, $level = 0) { $where = basename($stack[0]['file']) . ':' . $stack[0]['line'] . ':' . $stack[1]['function'] . ': '; - @file_put_contents($logfile, datetime_convert() . ':' . session_id() . ' ' . $where . $msg . PHP_EOL, FILE_APPEND); + @file_put_contents($logfile, datetime_convert('UTC','UTC', 'now', ATOM_TIME) . ':' . session_id() . ' ' . $where . $msg . PHP_EOL, FILE_APPEND); } @@ -2485,7 +2485,7 @@ function handle_tag($a, &$body, &$access_tag, &$str_tags, $profile_uid, $tag, $d if(($t2) && (! $diaspora)) { //get the id - $tagcid = substr($newname,$t2 + 1); + $tagcid = urldecode(substr($newname,$t2 + 1)); if(strrpos($tagcid,' ')) $tagcid = substr($tagcid,0,strrpos($tagcid,' ')); @@ -2966,6 +2966,9 @@ function flatten_array_recursive($arr) { * @param string $s Text to highlight * @param string $lang Which language should be highlighted * @return string + * Important: The returned text has the text pattern 'http' translated to '%eY9-!' which should be converted back + * after further processing. This was done to prevent oembed links from occurring inside code blocks. + * See include/bbcode.php */ function text_highlight($s, $lang) { @@ -2986,6 +2989,8 @@ function text_highlight($s, $lang) { else $o = $s; + $o = str_replace('http','%eY9-!',$o); + return('<code>' . $o . '</code>'); } diff --git a/view/css/conversation.css b/view/css/conversation.css index d10e1e14e..dcabb5f3c 100644 --- a/view/css/conversation.css +++ b/view/css/conversation.css @@ -183,24 +183,19 @@ a.wall-item-name-link { /* comment_item */ -.comment-edit-text-empty, -.comment-edit-text-full { + +.comment-edit-text { padding: 0.5rem; width: 100%; display: inherit; -} - -.comment-edit-text-empty { - height: 2rem; line-height: 1; - overflow: hidden; + height: 2rem; resize: none; } -.comment-edit-text-full { - height: 7rem; +.comment-edit-text.expanded { line-height: 1.25; - overflow: auto; + height: 7rem; resize: vertical; } diff --git a/view/js/main.js b/view/js/main.js index 47815d2c6..41be3da59 100644 --- a/view/js/main.js +++ b/view/js/main.js @@ -1,6 +1,55 @@ function confirmDelete() { return confirm(aStr.delitem); } +function handle_comment_form(e) { + e.stopPropagation(); + + //handle eventual expanded forms + var expanded = $('.comment-edit-text.expanded'); + var i = 0; + + if(expanded.length) { + expanded.each(function() { + var ex_form = $(expanded[i].form); + var ex_fields = ex_form.find(':input[type=text], textarea'); + var ex_fields_empty = true; + + ex_fields.each(function() { + if($(this).val() != '') + ex_fields_empty = false; + }); + if(ex_fields_empty) { + ex_form.find('.comment-edit-text').removeClass('expanded').attr('placeholder', aStr.comment); + ex_form.find(':not(.comment-edit-text)').hide(); + } + i++ + }); + } + + // handle clicked form + var form = $(this); + var fields = form.find(':input[type=text], textarea'); + var fields_empty = true; + + if(form.find('.comment-edit-text').length) { + form.find('.comment-edit-text').addClass('expanded').removeAttr('placeholder'); + form.find(':not(:visible)').show(); + } + + // handle click outside of form (close empty forms) + $(document).on('click', function(e) { + fields.each(function() { + if($(this).val() != '') + fields_empty = false; + }); + if(fields_empty) { + form.find('.comment-edit-text').removeClass('expanded').attr('placeholder', aStr.comment); + form.find(':not(.comment-edit-text)').hide(); + } + }); +} + +/* function commentOpenUI(obj, id) { $(document).unbind( "click.commentOpen", handler ); @@ -44,8 +93,7 @@ function commentCloseUI(obj, id) { function commentOpen(obj, id) { if(obj.value == aStr.comment) { obj.value = ''; - $("#comment-edit-text-" + id).addClass("comment-edit-text-full"); - $("#comment-edit-text-" + id).removeClass("comment-edit-text-empty"); + $("#comment-edit-text-" + id).addClass("expanded"); $("#mod-cmnt-wrap-" + id).show(); $("#comment-tools-" + id).show(); $("#comment-edit-anon-" + id).show(); @@ -53,12 +101,11 @@ function commentOpen(obj, id) { } return false; } - +*/ function commentClose(obj, id) { if(obj.value === '') { obj.value = aStr.comment; - $("#comment-edit-text-" + id).removeClass("comment-edit-text-full"); - $("#comment-edit-text-" + id).addClass("comment-edit-text-empty"); + $("#comment-edit-text-" + id).removeClass("expanded"); $("#mod-cmnt-wrap-" + id).hide(); $("#comment-tools-" + id).hide(); $("#comment-edit-anon-" + id).hide(); @@ -67,6 +114,7 @@ function commentClose(obj, id) { return false; } + function showHideCommentBox(id) { if( $('#comment-edit-form-' + id).is(':visible')) { $('#comment-edit-form-' + id).hide(); @@ -79,8 +127,7 @@ function commentInsert(obj, id) { var tmpStr = $("#comment-edit-text-" + id).val(); if(tmpStr == '$comment') { tmpStr = ''; - $("#comment-edit-text-" + id).addClass("comment-edit-text-full"); - $("#comment-edit-text-" + id).removeClass("comment-edit-text-empty"); + $("#comment-edit-text-" + id).addClass("expanded"); openMenu("comment-tools-" + id); } var ins = $(obj).html(); @@ -101,8 +148,7 @@ function insertbbcomment(comment, BBcode, id) { var tmpStr = $("#comment-edit-text-" + id).val(); if(tmpStr == comment) { tmpStr = ""; - $("#comment-edit-text-" + id).addClass("comment-edit-text-full"); - $("#comment-edit-text-" + id).removeClass("comment-edit-text-empty"); + $("#comment-edit-text-" + id).addClass("expanded"); openMenu("comment-tools-" + id); $("#comment-edit-text-" + id).val(tmpStr); } @@ -160,8 +206,7 @@ function insertCommentURL(comment, id) { var tmpStr = $("#comment-edit-text-" + id).val(); if(tmpStr == comment) { tmpStr = ""; - $("#comment-edit-text-" + id).addClass("comment-edit-text-full"); - $("#comment-edit-text-" + id).removeClass("comment-edit-text-empty"); + $("#comment-edit-text-" + id).addClass("expanded"); openMenu("comment-tools-" + id); $("#comment-edit-text-" + id).val(tmpStr); } @@ -183,8 +228,7 @@ function qCommentInsert(obj, id) { var tmpStr = $("#comment-edit-text-" + id).val(); if(tmpStr == aStr.comment) { tmpStr = ''; - $("#comment-edit-text-" + id).addClass("comment-edit-text-full"); - $("#comment-edit-text-" + id).removeClass("comment-edit-text-empty"); + $("#comment-edit-text-" + id).addClass("expanded"); openMenu("comment-edit-submit-wrapper-" + id); } var ins = $(obj).val(); @@ -728,7 +772,7 @@ function collapseHeight() { function liveUpdate() { if(typeof profile_uid === 'undefined') profile_uid = false; /* Should probably be unified with channelId defined in head.tpl */ if((src === null) || (stopped) || (! profile_uid)) { $('.like-rotator').spin(false); return; } - if(($('.comment-edit-text-full').length) || (in_progress)) { + if(($('.comment-edit-text.expanded').length) || (in_progress)) { if(livetime) { clearTimeout(livetime); } @@ -1084,8 +1128,10 @@ function post_comment(id) { $("#comment-edit-wrapper-" + id).hide(); $("#comment-edit-text-" + id).val(''); var tarea = document.getElementById("comment-edit-text-" + id); - if(tarea) + if(tarea) { commentClose(tarea, id); + $(document).unbind( "click.commentOpen"); + } if(timer) clearTimeout(timer); timer = setTimeout(NavUpdate,1500); } @@ -1312,9 +1358,10 @@ Array.prototype.remove = function(item) { return this.push.apply(this, rest); }; - $(document).ready(function() { + $(document).on('click focus', '.comment-edit-form', handle_comment_form); + jQuery.timeago.settings.strings = { prefixAgo : aStr['t01'], prefixFromNow : aStr['t02'], diff --git a/view/js/mod_cards.js b/view/js/mod_cards.js index 78b2e1bd0..8b31c0f52 100644 --- a/view/js/mod_cards.js +++ b/view/js/mod_cards.js @@ -1,3 +1,9 @@ $(document).ready( function() { $(".autotime").timeago(); + + /* autocomplete @nicknames */ + $(".comment-edit-form textarea").editor_autocomplete(baseurl+"/acl?f=&n=1"); + /* autocomplete bbcode */ + $(".comment-edit-form textarea").bbco_autocomplete('bbcode'); + });
\ No newline at end of file diff --git a/view/theme/redbasic/css/style.css b/view/theme/redbasic/css/style.css index 37277b612..621fa2781 100644 --- a/view/theme/redbasic/css/style.css +++ b/view/theme/redbasic/css/style.css @@ -1073,16 +1073,11 @@ img.mail-conv-sender-photo { } -.comment-edit-text-empty, -.comment-edit-text-full { +.comment-edit-text { border: 1px solid #ccc; border-radius: $radius; } -.comment-edit-text-empty { - color: gray; -} - .divgrow-showmore { display: block; border-top: 1px dashed #ccc; diff --git a/view/tpl/comment_item.tpl b/view/tpl/comment_item.tpl index cba4cd3c5..62530c1de 100755 --- a/view/tpl/comment_item.tpl +++ b/view/tpl/comment_item.tpl @@ -18,7 +18,7 @@ {{$anon_extras}} </div> {{/if}} - <textarea id="comment-edit-text-{{$id}}" class="comment-edit-text-empty" name="body" onFocus="commentOpenUI(this,{{$id}});" onBlur="commentCloseUI(this,{{$id}});" ondragenter="linkdropper(event);" ondragleave="linkdropexit(event);" ondragover="linkdropper(event);" ondrop="linkdrop(event);" >{{$comment}}</textarea> + <textarea id="comment-edit-text-{{$id}}" class="comment-edit-text" placeholder="{{$comment}}" name="body" ondragenter="linkdropper(event);" ondragleave="linkdropexit(event);" ondragover="linkdropper(event);" ondrop="linkdrop(event);" ></textarea> {{if $qcomment}} <select id="qcomment-select-{{$id}}" name="qcomment-{{$id}}" class="qcomment" onchange="qCommentInsert(this,{{$id}});" > <option value=""></option> diff --git a/view/tpl/conv_frame.tpl b/view/tpl/conv_frame.tpl index aa7b55e9b..1f0e00db4 100755 --- a/view/tpl/conv_frame.tpl +++ b/view/tpl/conv_frame.tpl @@ -3,3 +3,4 @@ <div id="conversation-end"></div> <div id="page-spinner"></div> + diff --git a/view/tpl/threaded_conversation.tpl b/view/tpl/threaded_conversation.tpl index ea5c3c281..5bc7d8386 100755 --- a/view/tpl/threaded_conversation.tpl +++ b/view/tpl/threaded_conversation.tpl @@ -1,8 +1,9 @@ +<div id="threads-begin"></div> {{if $photo_item}} {{$photo_item}} {{/if}} {{foreach $threads as $thread_item}} {{include file="{{$thread_item.template}}" item=$thread_item}} {{/foreach}} - +<div id="threads-end"></div> <div id="conversation-end"></div> |