From f02cc27014c27acaf44b27066959426db27b3493 Mon Sep 17 00:00:00 2001 From: JoshyPHP Date: Tue, 16 Jun 2015 08:16:56 +0200 Subject: [PATCH 01/10] [ticket/10620] Implemented quote improvements PHPBB3-10620 --- .../container/services_text_formatter.yml | 8 ++ phpBB/includes/ucp/ucp_pm_compose.php | 11 ++- phpBB/phpbb/textformatter/s9e/factory.php | 28 +++---- .../phpbb/textformatter/s9e/quote_helper.php | 81 +++++++++++++++++++ phpBB/phpbb/textformatter/s9e/renderer.php | 19 +++++ phpBB/phpbb/textformatter/s9e/utils.php | 1 + phpBB/posting.php | 7 +- phpBB/styles/prosilver/template/bbcode.html | 33 ++++++++ tests/functional/posting_test.php | 17 ++-- tests/functional/private_messages_test.php | 20 ++++- .../phpbb_test_case_helpers.php | 32 +++++++- .../s9e/default_formatting_test.php | 22 +++++ 12 files changed, 248 insertions(+), 31 deletions(-) create mode 100644 phpBB/phpbb/textformatter/s9e/quote_helper.php diff --git a/phpBB/config/default/container/services_text_formatter.yml b/phpBB/config/default/container/services_text_formatter.yml index 20436f0f64..ae698af9e4 100644 --- a/phpBB/config/default/container/services_text_formatter.yml +++ b/phpBB/config/default/container/services_text_formatter.yml @@ -44,6 +44,13 @@ services: - @text_formatter.s9e.factory - @dispatcher + text_formatter.s9e.quote_helper: + class: phpbb\textformatter\s9e\quote_helper + arguments: + - @user + - %core.root_path% + - %core.php_ext% + text_formatter.s9e.renderer: class: phpbb\textformatter\s9e\renderer arguments: @@ -53,6 +60,7 @@ services: - @text_formatter.s9e.factory - @dispatcher calls: + - [configure_quote_helper, [@text_formatter.s9e.quote_helper]] - [configure_smilies_path, [@config, @path_helper]] - [configure_user, [@user, @config, @auth]] diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php index 0989539a0f..c00363bee9 100644 --- a/phpBB/includes/ucp/ucp_pm_compose.php +++ b/phpBB/includes/ucp/ucp_pm_compose.php @@ -941,9 +941,18 @@ function compose_pm($id, $mode, $action, $user_folders = array()) { $message_link = ''; } + $quote_attributes = array( + 'author' => $quote_username, + 'time' => $post['message_time'], + 'user_id' => $post['author_id'], + ); + if ($action === 'quotepost') + { + $quote_attributes['post_id'] = $post['msg_id']; + } $quote_text = $phpbb_container->get('text_formatter.utils')->generate_quote( censor_text($message_parser->message), - array('author' => $quote_username) + $quote_attributes ); $message_parser->message = $message_link . $quote_text . "\n\n"; } diff --git a/phpBB/phpbb/textformatter/s9e/factory.php b/phpBB/phpbb/textformatter/s9e/factory.php index e07a1b52ca..cd4e593fb1 100644 --- a/phpBB/phpbb/textformatter/s9e/factory.php +++ b/phpBB/phpbb/textformatter/s9e/factory.php @@ -77,7 +77,12 @@ class factory implements \phpbb\textformatter\cache_interface 'quote' => "[QUOTE author={TEXT1;optional} + post_id={UINT;optional} + post_url={URL;optional;postFilter=#false} + profile_url={URL;optional;postFilter=#false} + time={UINT;optional} url={URL;optional} + user_id={UINT;optional} author={PARSE=/^\\[url=(?'url'.*?)](?'author'.*)\\[\\/url]$/i} author={PARSE=/^\\[url](?'author'(?'url'.*?))\\[\\/url]$/i} author={PARSE=/(?'url'https?:\\/\\/[^[\\]]+)/i} @@ -471,24 +476,11 @@ class factory implements \phpbb\textformatter\cache_interface $templates['li'] = $fragments['listitem'] . '' . $fragments['listitem_close']; - $fragments['quote_username_open'] = str_replace( - '{USERNAME}', - ' - ' . str_replace('{DESCRIPTION}', '{USERNAME}', $fragments['url']) . ' - {USERNAME} - ', - $fragments['quote_username_open'] - ); - - $templates['quote'] = - ' - - ' . $fragments['quote_username_open'] . '' . $fragments['quote_close'] . ' - - - ' . $fragments['quote_open'] . '' . $fragments['quote_close'] . ' - - '; + // Replace the regular quote template with the extended quote template if available + if (isset($fragments['quote_extended'])) + { + $templates['quote'] = $fragments['quote_extended']; + } // The [attachment] BBCode uses the inline_attachment template to output a comment that // is post-processed by parse_attachments() diff --git a/phpBB/phpbb/textformatter/s9e/quote_helper.php b/phpBB/phpbb/textformatter/s9e/quote_helper.php new file mode 100644 index 0000000000..24109ac8cc --- /dev/null +++ b/phpBB/phpbb/textformatter/s9e/quote_helper.php @@ -0,0 +1,81 @@ + +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\textformatter\s9e; + +class quote_helper +{ + /** + * @var string Base URL for a post link, uses {POST_ID} as placeholder + */ + protected $post_url; + + /** + * @var string Base URL for a profile link, uses {USER_ID} as placeholder + */ + protected $profile_url; + + /** + * @var \phpbb\user + */ + protected $user; + + /** + * Constructor + * + * @param \phpbb\user $user + * @param string $root_path + * @param string $php_ext + */ + public function __construct(\phpbb\user $user, $root_path, $php_ext) + { + $this->post_url = append_sid($root_path . 'viewtopic.' . $php_ext, 'p={POST_ID}#p{POST_ID}'); + $this->profile_url = append_sid($root_path . 'memberlist.' . $php_ext, 'mode=viewprofile&u={USER_ID}'); + $this->user = $user; + } + + /** + * Inject dynamic metadata into QUOTE tags in given XML + * + * @param string $xml Original XML + * @return string Modified XML + */ + public function inject_metadata($xml) + { + $post_url = $this->post_url; + $profile_url = $this->profile_url; + $user = $this->user; + + return \s9e\TextFormatter\Utils::replaceAttributes( + $xml, + 'QUOTE', + function ($attributes) use ($post_url, $profile_url, $user) + { + if (isset($attributes['post_id'])) + { + $attributes['post_url'] = str_replace('{POST_ID}', $attributes['post_id'], $post_url); + } + if (isset($attributes['time'])) + { + $attributes['date'] = $user->format_date($attributes['time']); + } + if (isset($attributes['user_id'])) + { + $attributes['profile_url'] = str_replace('{USER_ID}', $attributes['user_id'], $profile_url); + } + + return $attributes; + } + ); + } +} diff --git a/phpBB/phpbb/textformatter/s9e/renderer.php b/phpBB/phpbb/textformatter/s9e/renderer.php index 51bc44f339..2206605ba2 100644 --- a/phpBB/phpbb/textformatter/s9e/renderer.php +++ b/phpBB/phpbb/textformatter/s9e/renderer.php @@ -28,6 +28,11 @@ class renderer implements \phpbb\textformatter\renderer_interface */ protected $dispatcher; + /** + * @var quote_helper + */ + protected $quote_helper; + /** * @var \s9e\TextFormatter\Renderer */ @@ -112,6 +117,16 @@ class renderer implements \phpbb\textformatter\renderer_interface extract($dispatcher->trigger_event('core.text_formatter_s9e_renderer_setup', compact($vars))); } + /** + * Configure the quote_helper object used to display extended information in quotes + * + * @param quote_helper $quote_helper + */ + public function configure_quote_helper(quote_helper $quote_helper) + { + $this->quote_helper = $quote_helper; + } + /** * Automatically set the smilies path based on config * @@ -214,6 +229,10 @@ class renderer implements \phpbb\textformatter\renderer_interface */ public function render($xml) { + if (isset($this->quote_helper)) + { + $xml = $this->quote_helper->inject_metadata($xml); + } $renderer = $this; /** diff --git a/phpBB/phpbb/textformatter/s9e/utils.php b/phpBB/phpbb/textformatter/s9e/utils.php index 803c71a5a2..df1966fa32 100644 --- a/phpBB/phpbb/textformatter/s9e/utils.php +++ b/phpBB/phpbb/textformatter/s9e/utils.php @@ -64,6 +64,7 @@ class utils implements \phpbb\textformatter\utils_interface $quote .= '=' . $this->enquote($attributes['author']); unset($attributes['author']); } + ksort($attributes); foreach ($attributes as $name => $value) { $quote .= ' ' . $name . '=' . $this->enquote($value); diff --git a/phpBB/posting.php b/phpBB/posting.php index 2f9beefcf9..327004b1bf 100644 --- a/phpBB/posting.php +++ b/phpBB/posting.php @@ -1605,7 +1605,12 @@ if ($generate_quote) { $message_parser->message = $phpbb_container->get('text_formatter.utils')->generate_quote( censor_text($message_parser->message), - array('author' => $post_data['quote_username']) + array( + 'author' => $post_data['quote_username'], + 'post_id' => $post_data['post_id'], + 'time' => $post_data['post_time'], + 'user_id' => $post_data['poster_id'], + ) ); $message_parser->message .= "\n\n"; } diff --git a/phpBB/styles/prosilver/template/bbcode.html b/phpBB/styles/prosilver/template/bbcode.html index af8e6ae4b0..6adbdb6aba 100644 --- a/phpBB/styles/prosilver/template/bbcode.html +++ b/phpBB/styles/prosilver/template/bbcode.html @@ -11,6 +11,39 @@
{USERNAME} {L_WROTE}{L_COLON}
+ +
+ + uncited + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+

{L_CODE}{L_COLON} {L_SELECT_ALL_CODE}


 
diff --git a/tests/functional/posting_test.php b/tests/functional/posting_test.php index ccfeb10deb..d9e6cc5ab3 100644 --- a/tests/functional/posting_test.php +++ b/tests/functional/posting_test.php @@ -75,7 +75,7 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case public function test_quote() { $text = 'Test post "\' &&'; - $expected = '[quote="admin"]' . $text . '[/quote]'; + $expected = '([quote="admin"[^]]*\\]' . preg_quote($text) . '\\[/quote\\])'; $this->login(); $topic = $this->create_topic(2, 'Test Topic 1', 'Test topic'); @@ -83,7 +83,7 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case $crawler = self::request('GET', "posting.php?mode=quote&f=2&t={$post['topic_id']}&p={$post['post_id']}&sid={$this->sid}"); - $this->assertContains($expected, $crawler->filter('textarea#message')->text()); + $this->assertRegexp($expected, $crawler->filter('textarea#message')->text()); } /** @@ -93,10 +93,10 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case { $text = '0[quote]1[quote]2[/quote]1[/quote]0'; $expected = array( - 0 => '[quote="admin"]0[quote]1[quote]2[/quote]1[/quote]0[/quote]', - 1 => '[quote="admin"]00[/quote]', - 2 => '[quote="admin"]0[quote]11[/quote]0[/quote]', - 3 => '[quote="admin"]0[quote]1[quote]2[/quote]1[/quote]0[/quote]', + 0 => '0[quote]1[quote]2[/quote]1[/quote]0', + 1 => '00', + 2 => '0[quote]11[/quote]0', + 3 => '0[quote]1[quote]2[/quote]1[/quote]0', ); $this->login(); @@ -109,7 +109,10 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case { $this->set_quote_depth($quote_depth); $crawler = self::request('GET', $quote_url); - $this->assertContains($expected_text, $crawler->filter('textarea#message')->text()); + $this->assertRegexp( + '(\\[quote="admin"[^]]*\\]' . preg_quote($expected_text) . '\\[/quote\\])', + $crawler->filter('textarea#message')->text() + ); } } diff --git a/tests/functional/private_messages_test.php b/tests/functional/private_messages_test.php index be584c20c1..9bfb5bc7ad 100644 --- a/tests/functional/private_messages_test.php +++ b/tests/functional/private_messages_test.php @@ -69,16 +69,30 @@ class phpbb_functional_private_messages_test extends phpbb_functional_test_case public function test_quote_post() { - $text = 'Test post'; - $expected = '[quote="admin"]' . $text . '[/quote]'; + $text = 'Test post'; $this->login(); $topic = $this->create_topic(2, 'Test Topic 1', 'Test topic'); $post = $this->create_post(2, $topic['topic_id'], 'Re: Test Topic 1', $text); + $expected = '(\\[quote="admin" post_id="' . $post['post_id'] . '" time="\\d+" user_id="2"\\]' . $text . '\\[/quote\\])'; + $crawler = self::request('GET', 'ucp.php?i=pm&mode=compose&action=quotepost&p=' . $post['post_id'] . '&sid=' . $this->sid); - $this->assertContains($expected, $crawler->filter('textarea#message')->text()); + $this->assertRegexp($expected, $crawler->filter('textarea#message')->text()); + } + + public function test_quote_pm() + { + $text = 'This is a test private message sent by the testing framework.'; + $expected = '(\\[quote="admin" time="\\d+" user_id="2"\\]' . $text . '\\[/quote\\])'; + + $this->login(); + $message_id = $this->create_private_message('Test', $text, array(2)); + + $crawler = self::request('GET', 'ucp.php?i=pm&mode=compose&action=quote&p=' . $message_id . '&sid=' . $this->sid); + + $this->assertRegexp($expected, $crawler->filter('textarea#message')->text()); } public function test_quote_forward() diff --git a/tests/test_framework/phpbb_test_case_helpers.php b/tests/test_framework/phpbb_test_case_helpers.php index cf530cc5be..62a56ed693 100644 --- a/tests/test_framework/phpbb_test_case_helpers.php +++ b/tests/test_framework/phpbb_test_case_helpers.php @@ -476,11 +476,21 @@ class phpbb_test_case_helpers { $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); $lang = new \phpbb\language\language($lang_loader); - $user = new \phpbb\user($lang, '\phpbb\datetime'); + + $user = $this->test_case->getMockBuilder('\phpbb\user') + ->setConstructorArgs(array($lang, '\phpbb\datetime')) + ->setMethods(array('format_date')) + ->getMock(); + $user->expects($this->test_case->any()) + ->method('format_date') + ->will($this->test_case->returnCallback(__CLASS__ . '::format_date')); + + $user->date_format = 'Y-m-d H:i:s'; $user->optionset('viewcensors', true); $user->optionset('viewflash', true); $user->optionset('viewimg', true); $user->optionset('viewsmilies', true); + $user->timezone = new \DateTimeZone('UTC'); $container->set('user', $user); } $user->add_lang('common'); @@ -490,6 +500,14 @@ class phpbb_test_case_helpers $user->style = array('style_id' => 1); } + // Create and register a quote_helper + $quote_helper = new \phpbb\textformatter\s9e\quote_helper( + $container->get('user'), + $phpbb_root_path, + $phpEx + ); + $container->set('text_formatter.s9e.quote_helper', $quote_helper); + // Create and register the text_formatter.s9e.parser service and its alias $parser = new \phpbb\textformatter\s9e\parser( $cache, @@ -515,6 +533,7 @@ class phpbb_test_case_helpers $auth = ($container->has('auth')) ? $container->get('auth') : new \phpbb\auth\auth; // Calls configured in services.yml + $renderer->configure_quote_helper($quote_helper); $renderer->configure_smilies_path($config, $container->get('path_helper')); $renderer->configure_user($user, $config, $auth); @@ -528,4 +547,15 @@ class phpbb_test_case_helpers return $container; } + + /** + * Mocked replacement for \phpbb\user::format_date() + * + * @param integer $gmepoch unix timestamp + * @return string + */ + static public function format_date($gmepoch) + { + return gmdate('Y-m-d H:i:s', $gmepoch); + } } diff --git a/tests/text_formatter/s9e/default_formatting_test.php b/tests/text_formatter/s9e/default_formatting_test.php index 67921d5b1e..3f8e375ad1 100644 --- a/tests/text_formatter/s9e/default_formatting_test.php +++ b/tests/text_formatter/s9e/default_formatting_test.php @@ -225,6 +225,28 @@ class phpbb_textformatter_s9e_default_formatting_test extends phpbb_test_case "[quote]\nThis is a long quote that is definitely going to exceed 80 characters\n[/quote]\n\nFollowed by a reply", "
\nThis is a long quote that is definitely going to exceed 80 characters\n
\n\nFollowed by a reply" ), + array( + '[quote="Username" post_id="123"]...[/quote]', + '
Username wrote: ...
' + ), + array( + // Users are not allowed to submit their own URL for the post + '[quote="Username" post_url="http://fake.example.org"]...[/quote]', + '
Username wrote:...
' + ), + array( + '[quote="Username" time="58705871"]...[/quote]', + '
1971-11-11 11:11:11 Username wrote:...
' + ), + array( + '[quote="Username" user_id="123"]...[/quote]', + '
Username wrote:...
' + ), + array( + // Users are not allowed to submit their own URL for the profile + '[quote="Username" profile_url="http://fake.example.org"]...[/quote]', + '
Username wrote:...
' + ), ); } } From c934b8f150c81115062687e59988ca0f78b35c37 Mon Sep 17 00:00:00 2001 From: JoshyPHP Date: Sat, 20 Jun 2015 17:18:46 +0200 Subject: [PATCH 02/10] [ticket/10620] Updated docblock PHPBB3-10620 --- phpBB/phpbb/textformatter/utils_interface.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/phpBB/phpbb/textformatter/utils_interface.php b/phpBB/phpbb/textformatter/utils_interface.php index 41a6ba2345..4810453cd1 100644 --- a/phpBB/phpbb/textformatter/utils_interface.php +++ b/phpBB/phpbb/textformatter/utils_interface.php @@ -32,7 +32,10 @@ interface utils_interface * Create a quote block for given text * * Possible attributes: - * - author + * - author: author's name (usually a username) + * - post_id: post_id of the post being quoted + * - user_id: user_id of the user being quoted + * - time: timestamp of the original message * * @param string $text Quote's text * @param array $attributes Quote's attributes From 06936bda05a48e5b6e20d7c0b0979cf7fc1a29ae Mon Sep 17 00:00:00 2001 From: JoshyPHP Date: Mon, 22 Jun 2015 04:00:55 +0200 Subject: [PATCH 03/10] [ticket/10620] Added enhanced quotes in topic review Added support for enhanced quotes in topic_review's quote button. NOTE: the UI doesn't appear to be testable via PhantomJS. PHPBB3-10620 --- phpBB/assets/javascript/editor.js | 58 ++++++++++++++++++- phpBB/includes/functions_posting.php | 2 + .../template/posting_topic_review.html | 2 +- 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/phpBB/assets/javascript/editor.js b/phpBB/assets/javascript/editor.js index 298526ab1f..d0d849330a 100644 --- a/phpBB/assets/javascript/editor.js +++ b/phpBB/assets/javascript/editor.js @@ -167,7 +167,7 @@ function attachInline(index, filename) { /** * Add quote text to message */ -function addquote(post_id, username, l_wrote) { +function addquote(post_id, username, l_wrote, attributes) { var message_name = 'message_' + post_id; var theSelection = ''; var divarea = false; @@ -213,7 +213,12 @@ function addquote(post_id, username, l_wrote) { if (theSelection) { if (bbcodeEnabled) { - insert_text('[quote="' + username + '"]' + theSelection + '[/quote]'); + if (typeof attributes === 'undefined') + { + attributes = {}; + } + attributes.author = username; + insert_text(generate_quote(theSelection, attributes)); } else { insert_text(username + ' ' + l_wrote + ':' + '\n'); var lines = split_lines(theSelection); @@ -226,6 +231,55 @@ function addquote(post_id, username, l_wrote) { return; } +/** +* Create a quote block for given text +* +* Possible attributes: +* - author: author's name (usually a username) +* - post_id: post_id of the post being quoted +* - user_id: user_id of the user being quoted +* - time: timestamp of the original message +* +* @param {!string} text Quote's text +* @param {!Object} attributes Quote's attributes +* @return {!string} Quote block to be used in a new post/text +*/ +function generate_quote(text, attributes) +{ + var quote = '[quote'; + if ('author' in attributes) + { + // Add the author as the BBCode's default attribute + quote += '=' + enquote(attributes.author); + delete attributes.author; + } + for (var name in attributes) + { + var value = attributes[name]; + quote += ' ' + name + '=' + enquote(String(value)); + } + quote += ']' + text + '[/quote]'; + + return quote; +} + +/** +* Return given string between quotes +* +* Will use either single- or double- quotes depending on whichever requires less escaping. +* Quotes and backslashes are escaped with backslashes where necessary +* +* @param {!string} str Original string +* @return {!string} Escaped string within quotes +*/ +function enquote(str) +{ + var singleQuoted = "'" + str.replace(/[\\']/g, '\\$&') + "'", + doubleQuoted = '"' + str.replace(/[\\"]/g, '\\$&') + '"'; + + return (singleQuoted.length < doubleQuoted.length) ? singleQuoted : doubleQuoted; +} + function split_lines(text) { var lines = text.split('\n'); var splitLines = new Array(); diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index a1ace42c32..9109c48ab6 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -1193,6 +1193,8 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id 'MESSAGE' => $message, 'DECODED_MESSAGE' => $decoded_message, 'POST_ID' => $row['post_id'], + 'POST_TIME' => $row['post_time'], + 'USER_ID' => $row['user_id'], 'U_MINI_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['post_id']) . '#p' . $row['post_id'], 'U_MCP_DETAILS' => ($auth->acl_get('m_info', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main&mode=post_details&f=' . $forum_id . '&p=' . $row['post_id'], true, $user->session_id) : '', 'POSTER_QUOTE' => ($show_quote_button && $auth->acl_get('f_reply', $forum_id)) ? addslashes(get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username'])) : '', diff --git a/phpBB/styles/prosilver/template/posting_topic_review.html b/phpBB/styles/prosilver/template/posting_topic_review.html index 6909877196..fc7d0a2c63 100644 --- a/phpBB/styles/prosilver/template/posting_topic_review.html +++ b/phpBB/styles/prosilver/template/posting_topic_review.html @@ -35,7 +35,7 @@
  • - + {L_QUOTE} {topic_review_row.POST_AUTHOR}
  • From 129b3375ae873b3e6e947e3c5f47897bc4f9c572 Mon Sep 17 00:00:00 2001 From: JoshyPHP Date: Mon, 22 Jun 2015 18:25:20 +0200 Subject: [PATCH 04/10] [ticket/10620] Added enhanced quotes in pm history PHPBB3-10620 --- phpBB/includes/functions_privmsgs.php | 2 ++ phpBB/styles/prosilver/template/ucp_pm_history.html | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/phpBB/includes/functions_privmsgs.php b/phpBB/includes/functions_privmsgs.php index 245b1c0d1a..26df5b9954 100644 --- a/phpBB/includes/functions_privmsgs.php +++ b/phpBB/includes/functions_privmsgs.php @@ -2100,6 +2100,8 @@ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode 'S_IN_POST_MODE' => $in_post_mode, 'MSG_ID' => $row['msg_id'], + 'MESSAGE_TIME' => $row['message_time'], + 'USER_ID' => $row['user_id'], 'U_VIEW_MESSAGE' => "$url&f=$folder_id&p=" . $row['msg_id'], 'U_QUOTE' => (!$in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) ? "$url&mode=compose&action=quote&f=" . $folder_id . "&p=" . $row['msg_id'] : '', 'U_POST_REPLY_PM' => ($author_id != $user->data['user_id'] && $author_id != ANONYMOUS && $auth->acl_get('u_sendpm')) ? "$url&mode=compose&action=reply&f=$folder_id&p=" . $row['msg_id'] : '') diff --git a/phpBB/styles/prosilver/template/ucp_pm_history.html b/phpBB/styles/prosilver/template/ucp_pm_history.html index 0e9c3844cc..8f7b4fdb3e 100644 --- a/phpBB/styles/prosilver/template/ucp_pm_history.html +++ b/phpBB/styles/prosilver/template/ucp_pm_history.html @@ -20,7 +20,7 @@
    • - href="{history_row.U_QUOTE}"href="#postingbox" onclick="addquote({history_row.MSG_ID}, '{history_row.MESSAGE_AUTHOR_QUOTE}', '{LA_WROTE}');" title="{L_QUOTE} {history_row.MESSAGE_AUTHOR}" class="button icon-button quote-icon"> + href="{history_row.U_QUOTE}"href="#postingbox" onclick="addquote({history_row.MSG_ID}, '{history_row.MESSAGE_AUTHOR_QUOTE}', '{LA_WROTE}', {time:{history_row.MESSAGE_TIME},user_id:{history_row.USER_ID}});" title="{L_QUOTE} {history_row.MESSAGE_AUTHOR}" class="button icon-button quote-icon"> {L_QUOTE} {history_row.MESSAGE_AUTHOR}
    • From 4f1b25706f6a1ae6eb1c6c60ef27b42bb7ac4b40 Mon Sep 17 00:00:00 2001 From: JoshyPHP Date: Wed, 24 Jun 2015 22:20:39 +0200 Subject: [PATCH 05/10] [ticket/10620] Removed extraneous quotes from attribute values PHPBB3-10620 --- phpBB/assets/javascript/editor.js | 18 ++++++++++++------ phpBB/phpbb/textformatter/s9e/utils.php | 18 ++++++++++++------ tests/functional/posting_test.php | 4 ++-- tests/functional/private_messages_test.php | 6 +++--- .../s9e/default_formatting_test.php | 10 +++++----- tests/text_formatter/s9e/utils_test.php | 10 +++++++--- 6 files changed, 41 insertions(+), 25 deletions(-) diff --git a/phpBB/assets/javascript/editor.js b/phpBB/assets/javascript/editor.js index d0d849330a..878a5cab86 100644 --- a/phpBB/assets/javascript/editor.js +++ b/phpBB/assets/javascript/editor.js @@ -250,13 +250,13 @@ function generate_quote(text, attributes) if ('author' in attributes) { // Add the author as the BBCode's default attribute - quote += '=' + enquote(attributes.author); + quote += '=' + format_attribute_value(attributes.author); delete attributes.author; } for (var name in attributes) { var value = attributes[name]; - quote += ' ' + name + '=' + enquote(String(value)); + quote += ' ' + name + '=' + format_attribute_value(String(value)); } quote += ']' + text + '[/quote]'; @@ -264,16 +264,22 @@ function generate_quote(text, attributes) } /** -* Return given string between quotes +* Format given string to be used as an attribute value * -* Will use either single- or double- quotes depending on whichever requires less escaping. +* Will return the string as-is if it can be used in a BBCode without quotes. Otherwise, +* it will use either single- or double- quotes depending on whichever requires less escaping. * Quotes and backslashes are escaped with backslashes where necessary * * @param {!string} str Original string -* @return {!string} Escaped string within quotes +* @return {!string} Same string if possible, escaped string within quotes otherwise */ -function enquote(str) +function format_attribute_value(str) { + if (!/[ "'\\\]]/.test(str)) + { + // Return as-is if it contains none of: space, ' " \ or ] + return str; + } var singleQuoted = "'" + str.replace(/[\\']/g, '\\$&') + "'", doubleQuoted = '"' + str.replace(/[\\"]/g, '\\$&') + '"'; diff --git a/phpBB/phpbb/textformatter/s9e/utils.php b/phpBB/phpbb/textformatter/s9e/utils.php index df1966fa32..40479b3423 100644 --- a/phpBB/phpbb/textformatter/s9e/utils.php +++ b/phpBB/phpbb/textformatter/s9e/utils.php @@ -35,16 +35,22 @@ class utils implements \phpbb\textformatter\utils_interface } /** - * Return given string between quotes + * Format given string to be used as an attribute value * - * Will use either single- or double- quotes depending on whichever requires less escaping. + * Will return the string as-is if it can be used in a BBCode without quotes. Otherwise, + * it will use either single- or double- quotes depending on whichever requires less escaping. * Quotes and backslashes are escaped with backslashes where necessary * * @param string $str Original string - * @return string Escaped string within quotes + * @return string Same string if possible, escaped string within quotes otherwise */ - protected function enquote($str) + protected function format_attribute_value($str) { + if (!preg_match('/[ "\'\\\\\\]]/', $str)) + { + // Return as-is if it contains none of: space, ' " \ or ] + return $str; + } $singleQuoted = "'" . addcslashes($str, "\\'") . "'"; $doubleQuoted = '"' . addcslashes($str, '\\"') . '"'; @@ -61,13 +67,13 @@ class utils implements \phpbb\textformatter\utils_interface if (isset($attributes['author'])) { // Add the author as the BBCode's default attribute - $quote .= '=' . $this->enquote($attributes['author']); + $quote .= '=' . $this->format_attribute_value($attributes['author']); unset($attributes['author']); } ksort($attributes); foreach ($attributes as $name => $value) { - $quote .= ' ' . $name . '=' . $this->enquote($value); + $quote .= ' ' . $name . '=' . $this->format_attribute_value($value); } $quote .= ']'; $newline = (strlen($quote . $text . '[/quote]') > 80 || strpos($text, "\n") !== false) ? "\n" : ''; diff --git a/tests/functional/posting_test.php b/tests/functional/posting_test.php index d9e6cc5ab3..4f4ecfef45 100644 --- a/tests/functional/posting_test.php +++ b/tests/functional/posting_test.php @@ -75,7 +75,7 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case public function test_quote() { $text = 'Test post "\' &&amp;'; - $expected = '([quote="admin"[^]]*\\]' . preg_quote($text) . '\\[/quote\\])'; + $expected = '([quote=admin[^]]*\\]' . preg_quote($text) . '\\[/quote\\])'; $this->login(); $topic = $this->create_topic(2, 'Test Topic 1', 'Test topic'); @@ -110,7 +110,7 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case $this->set_quote_depth($quote_depth); $crawler = self::request('GET', $quote_url); $this->assertRegexp( - '(\\[quote="admin"[^]]*\\]' . preg_quote($expected_text) . '\\[/quote\\])', + '(\\[quote=admin[^]]*\\]' . preg_quote($expected_text) . '\\[/quote\\])', $crawler->filter('textarea#message')->text() ); } diff --git a/tests/functional/private_messages_test.php b/tests/functional/private_messages_test.php index 9bfb5bc7ad..a7d1a29e80 100644 --- a/tests/functional/private_messages_test.php +++ b/tests/functional/private_messages_test.php @@ -75,7 +75,7 @@ class phpbb_functional_private_messages_test extends phpbb_functional_test_case $topic = $this->create_topic(2, 'Test Topic 1', 'Test topic'); $post = $this->create_post(2, $topic['topic_id'], 'Re: Test Topic 1', $text); - $expected = '(\\[quote="admin" post_id="' . $post['post_id'] . '" time="\\d+" user_id="2"\\]' . $text . '\\[/quote\\])'; + $expected = '(\\[quote=admin post_id=' . $post['post_id'] . ' time=\\d+ user_id=2\\]' . $text . '\\[/quote\\])'; $crawler = self::request('GET', 'ucp.php?i=pm&mode=compose&action=quotepost&p=' . $post['post_id'] . '&sid=' . $this->sid); @@ -85,7 +85,7 @@ class phpbb_functional_private_messages_test extends phpbb_functional_test_case public function test_quote_pm() { $text = 'This is a test private message sent by the testing framework.'; - $expected = '(\\[quote="admin" time="\\d+" user_id="2"\\]' . $text . '\\[/quote\\])'; + $expected = '(\\[quote=admin time=\\d+ user_id=2\\]' . $text . '\\[/quote\\])'; $this->login(); $message_id = $this->create_private_message('Test', $text, array(2)); @@ -98,7 +98,7 @@ class phpbb_functional_private_messages_test extends phpbb_functional_test_case public function test_quote_forward() { $text = 'This is a test private message sent by the testing framework.'; - $expected = "[quote=\"admin\"]\n" . $text . "\n[/quote]"; + $expected = '[quote=admin]' . $text . '[/quote]'; $this->login(); $message_id = $this->create_private_message('Test', $text, array(2)); diff --git a/tests/text_formatter/s9e/default_formatting_test.php b/tests/text_formatter/s9e/default_formatting_test.php index 3f8e375ad1..38604b49a0 100644 --- a/tests/text_formatter/s9e/default_formatting_test.php +++ b/tests/text_formatter/s9e/default_formatting_test.php @@ -218,7 +218,7 @@ class phpbb_textformatter_s9e_default_formatting_test extends phpbb_test_case '
      ' ), array( - '[quote="http://example.org"]...[/quote]', + '[quote=http://example.org]...[/quote]', '
      ' ), array( @@ -226,7 +226,7 @@ class phpbb_textformatter_s9e_default_formatting_test extends phpbb_test_case "
      \nThis is a long quote that is definitely going to exceed 80 characters\n
      \n\nFollowed by a reply" ), array( - '[quote="Username" post_id="123"]...[/quote]', + '[quote=Username post_id=123]...[/quote]', '
      Username wrote: ...
      ' ), array( @@ -235,16 +235,16 @@ class phpbb_textformatter_s9e_default_formatting_test extends phpbb_test_case '
      Username wrote:...
      ' ), array( - '[quote="Username" time="58705871"]...[/quote]', + '[quote=Username time=58705871]...[/quote]', '
      1971-11-11 11:11:11 Username wrote:...
      ' ), array( - '[quote="Username" user_id="123"]...[/quote]', + '[quote=Username user_id=123]...[/quote]', '
      Username wrote:...
      ' ), array( // Users are not allowed to submit their own URL for the profile - '[quote="Username" profile_url="http://fake.example.org"]...[/quote]', + '[quote=Username profile_url=http://fake.example.org]...[/quote]', '
      Username wrote:...
      ' ), ); diff --git a/tests/text_formatter/s9e/utils_test.php b/tests/text_formatter/s9e/utils_test.php index 152c316b2e..f2b480facb 100644 --- a/tests/text_formatter/s9e/utils_test.php +++ b/tests/text_formatter/s9e/utils_test.php @@ -98,11 +98,15 @@ class phpbb_textformatter_s9e_utils_test extends phpbb_test_case array('foo') ), array( - '[quote="foo"]..[/quote] [quote="bar"]..[/quote]', + '[quote=foo]..[/quote] [quote]..[/quote]', + array('foo') + ), + array( + '[quote=foo]..[/quote] [quote=bar]..[/quote]', array('foo', 'bar') ), array( - '[quote="foo"].[quote="baz"]..[/quote].[/quote] [quote="bar"]..[/quote]', + '[quote=foo].[quote=baz]..[/quote].[/quote] [quote=bar]..[/quote]', array('foo', 'bar') ), ); @@ -169,7 +173,7 @@ class phpbb_textformatter_s9e_utils_test extends phpbb_test_case 'post_id' => 123, 'url' => 'http://example.org' ), - '[quote="user" post_id="123" url="http://example.org"]...[/quote]', + '[quote=user post_id=123 url=http://example.org]...[/quote]', ), array( 'This is a long quote that is definitely going to exceed 80 characters', From 7ce2d996a82b5a2f68560a4136c1f3938a1955d4 Mon Sep 17 00:00:00 2001 From: JoshyPHP Date: Wed, 24 Jun 2015 22:36:38 +0200 Subject: [PATCH 06/10] [ticket/10620] Added tests PHPBB3-10620 --- .../s9e/default_formatting_test.php | 5 ++++ tests/text_formatter/s9e/utils_test.php | 30 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/tests/text_formatter/s9e/default_formatting_test.php b/tests/text_formatter/s9e/default_formatting_test.php index 38604b49a0..ed75555b42 100644 --- a/tests/text_formatter/s9e/default_formatting_test.php +++ b/tests/text_formatter/s9e/default_formatting_test.php @@ -247,6 +247,11 @@ class phpbb_textformatter_s9e_default_formatting_test extends phpbb_test_case '[quote=Username profile_url=http://fake.example.org]...[/quote]', '
      Username wrote:...
      ' ), + array( + // From phpbb_textformatter_s9e_utils_test::test_generate_quote() + '[quote=\'[quote="foo"]\']...[/quote]', + '
      [quote="foo"] wrote:...
      ' + ), ); } } diff --git a/tests/text_formatter/s9e/utils_test.php b/tests/text_formatter/s9e/utils_test.php index f2b480facb..1c03783792 100644 --- a/tests/text_formatter/s9e/utils_test.php +++ b/tests/text_formatter/s9e/utils_test.php @@ -175,6 +175,36 @@ class phpbb_textformatter_s9e_utils_test extends phpbb_test_case ), '[quote=user post_id=123 url=http://example.org]...[/quote]', ), + array( + '...', + array('author' => ' '), + '[quote=" "]...[/quote]', + ), + array( + '...', + array('author' => 'foo bar'), + '[quote="foo bar"]...[/quote]', + ), + array( + '...', + array('author' => '\\'), + '[quote="\\\\"]...[/quote]', + ), + array( + '...', + array('author' => '[quote="foo"]'), + '[quote=\'[quote="foo"]\']...[/quote]', + ), + array( + '...', + array('author' => '""'), + '[quote=\'""\']...[/quote]', + ), + array( + '...', + array('author' => "''"), + '[quote="\'\'"]...[/quote]', + ), array( 'This is a long quote that is definitely going to exceed 80 characters', array(), From 4c9507e20ad4e3de291143c8a40d5c977388f5a5 Mon Sep 17 00:00:00 2001 From: JoshyPHP Date: Wed, 24 Jun 2015 22:36:44 +0200 Subject: [PATCH 07/10] [ticket/10620] Fixed some stylistic issues in JS PHPBB3-10620 --- phpBB/assets/javascript/editor.js | 35 +++++++++++++------------------ 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/phpBB/assets/javascript/editor.js b/phpBB/assets/javascript/editor.js index 878a5cab86..f0fa064ec5 100644 --- a/phpBB/assets/javascript/editor.js +++ b/phpBB/assets/javascript/editor.js @@ -111,7 +111,6 @@ function bbfontstyle(bbopen, bbclose) { } textarea.focus(); - return; } /** @@ -177,6 +176,9 @@ function addquote(post_id, username, l_wrote, attributes) { // Backwards compatibility l_wrote = 'wrote'; } + if (typeof attributes !== 'object') { + attributes = {}; + } if (document.all) { divarea = document.all[message_name]; @@ -213,12 +215,8 @@ function addquote(post_id, username, l_wrote, attributes) { if (theSelection) { if (bbcodeEnabled) { - if (typeof attributes === 'undefined') - { - attributes = {}; - } attributes.author = username; - insert_text(generate_quote(theSelection, attributes)); + insert_text(generateQuote(theSelection, attributes)); } else { insert_text(username + ' ' + l_wrote + ':' + '\n'); var lines = split_lines(theSelection); @@ -227,8 +225,6 @@ function addquote(post_id, username, l_wrote, attributes) { } } } - - return; } /** @@ -244,19 +240,18 @@ function addquote(post_id, username, l_wrote, attributes) { * @param {!Object} attributes Quote's attributes * @return {!string} Quote block to be used in a new post/text */ -function generate_quote(text, attributes) -{ +function generateQuote(text, attributes) { var quote = '[quote'; - if ('author' in attributes) - { + if (attributes.author) { // Add the author as the BBCode's default attribute - quote += '=' + format_attribute_value(attributes.author); + quote += '=' + formatAttributeValue(attributes.author); delete attributes.author; } - for (var name in attributes) - { - var value = attributes[name]; - quote += ' ' + name + '=' + format_attribute_value(String(value)); + for (var name in attributes) { + if (attributes.hasOwnProperty(name)) { + var value = attributes[name]; + quote += ' ' + name + '=' + formatAttributeValue(value.toString()); + } } quote += ']' + text + '[/quote]'; @@ -273,10 +268,8 @@ function generate_quote(text, attributes) * @param {!string} str Original string * @return {!string} Same string if possible, escaped string within quotes otherwise */ -function format_attribute_value(str) -{ - if (!/[ "'\\\]]/.test(str)) - { +function formatAttributeValue(str) { + if (!/[ "'\\\]]/.test(str)) { // Return as-is if it contains none of: space, ' " \ or ] return str; } From 5a55ce3f6832677e2c0a244d3a5c0b4c2587b8c5 Mon Sep 17 00:00:00 2001 From: JoshyPHP Date: Wed, 24 Jun 2015 22:41:58 +0200 Subject: [PATCH 08/10] [ticket/10620] Add more whitespace to long quotes in JS PHPBB3-10620 --- phpBB/assets/javascript/editor.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/phpBB/assets/javascript/editor.js b/phpBB/assets/javascript/editor.js index f0fa064ec5..df353bc29d 100644 --- a/phpBB/assets/javascript/editor.js +++ b/phpBB/assets/javascript/editor.js @@ -241,6 +241,7 @@ function addquote(post_id, username, l_wrote, attributes) { * @return {!string} Quote block to be used in a new post/text */ function generateQuote(text, attributes) { + text = text.replace(/^\s+/, '').replace(/\s+$/, ''); var quote = '[quote'; if (attributes.author) { // Add the author as the BBCode's default attribute @@ -253,7 +254,9 @@ function generateQuote(text, attributes) { quote += ' ' + name + '=' + formatAttributeValue(value.toString()); } } - quote += ']' + text + '[/quote]'; + quote += ']'; + var newline = ((quote + text + '[/quote]').length > 80 || text.indexOf('\n') > -1) ? '\n' : ''; + quote += newline + text + newline + '[/quote]'; return quote; } From 1f6b9bc0487ba43a614b05528dcd9ae830cc3b0f Mon Sep 17 00:00:00 2001 From: JoshyPHP Date: Wed, 24 Jun 2015 23:42:36 +0200 Subject: [PATCH 09/10] [ticket/10620] Fixed functional tests to account for newlines PHPBB3-10620 --- tests/functional/posting_test.php | 4 ++-- tests/functional/private_messages_test.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/functional/posting_test.php b/tests/functional/posting_test.php index 4f4ecfef45..e9b62c0b6c 100644 --- a/tests/functional/posting_test.php +++ b/tests/functional/posting_test.php @@ -75,7 +75,7 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case public function test_quote() { $text = 'Test post "\' &&amp;'; - $expected = '([quote=admin[^]]*\\]' . preg_quote($text) . '\\[/quote\\])'; + $expected = "(\\[quote=admin[^\\]]*\\]\n" . preg_quote($text) . "\n\\[/quote\\])"; $this->login(); $topic = $this->create_topic(2, 'Test Topic 1', 'Test topic'); @@ -110,7 +110,7 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case $this->set_quote_depth($quote_depth); $crawler = self::request('GET', $quote_url); $this->assertRegexp( - '(\\[quote=admin[^]]*\\]' . preg_quote($expected_text) . '\\[/quote\\])', + "(\\[quote=admin[^\\]]*\\]\n?" . preg_quote($expected_text) . "\n?\\[/quote\\])", $crawler->filter('textarea#message')->text() ); } diff --git a/tests/functional/private_messages_test.php b/tests/functional/private_messages_test.php index a7d1a29e80..7fda26fb49 100644 --- a/tests/functional/private_messages_test.php +++ b/tests/functional/private_messages_test.php @@ -85,7 +85,7 @@ class phpbb_functional_private_messages_test extends phpbb_functional_test_case public function test_quote_pm() { $text = 'This is a test private message sent by the testing framework.'; - $expected = '(\\[quote=admin time=\\d+ user_id=2\\]' . $text . '\\[/quote\\])'; + $expected = "(\\[quote=admin time=\\d+ user_id=2\\]\n" . $text . "\n\\[/quote\\])"; $this->login(); $message_id = $this->create_private_message('Test', $text, array(2)); @@ -98,7 +98,7 @@ class phpbb_functional_private_messages_test extends phpbb_functional_test_case public function test_quote_forward() { $text = 'This is a test private message sent by the testing framework.'; - $expected = '[quote=admin]' . $text . '[/quote]'; + $expected = "[quote=admin]\n" . $text . "\n[/quote]"; $this->login(); $message_id = $this->create_private_message('Test', $text, array(2)); From 9d364aee4a739d0a8c8b745449940a37d81c9abf Mon Sep 17 00:00:00 2001 From: JoshyPHP Date: Thu, 25 Jun 2015 02:23:00 +0200 Subject: [PATCH 10/10] [ticket/10620] Moved quote's date to the upper corner PHPBB3-10620 --- phpBB/styles/prosilver/template/bbcode.html | 4 +++- phpBB/styles/prosilver/theme/content.css | 5 +++++ tests/text_formatter/s9e/default_formatting_test.php | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/phpBB/styles/prosilver/template/bbcode.html b/phpBB/styles/prosilver/template/bbcode.html index 6adbdb6aba..8c4e941092 100644 --- a/phpBB/styles/prosilver/template/bbcode.html +++ b/phpBB/styles/prosilver/template/bbcode.html @@ -19,7 +19,6 @@
      - @@ -38,6 +37,9 @@ + +
      +
      diff --git a/phpBB/styles/prosilver/theme/content.css b/phpBB/styles/prosilver/theme/content.css index 3d2e445c37..e20aaef7d4 100644 --- a/phpBB/styles/prosilver/theme/content.css +++ b/phpBB/styles/prosilver/theme/content.css @@ -486,6 +486,11 @@ blockquote.uncited { padding-top: 25px; } +blockquote cite > div { + float: right; + font-weight: normal; +} + /* Code block */ .codebox { padding: 3px; diff --git a/tests/text_formatter/s9e/default_formatting_test.php b/tests/text_formatter/s9e/default_formatting_test.php index ed75555b42..40bec9ceee 100644 --- a/tests/text_formatter/s9e/default_formatting_test.php +++ b/tests/text_formatter/s9e/default_formatting_test.php @@ -236,7 +236,7 @@ class phpbb_textformatter_s9e_default_formatting_test extends phpbb_test_case ), array( '[quote=Username time=58705871]...[/quote]', - '
      1971-11-11 11:11:11 Username wrote:...
      ' + '
      Username wrote:
      1971-11-11 11:11:11
      ...
      ' ), array( '[quote=Username user_id=123]...[/quote]',