From 24c3bc3f1f566ffa1b78885defae3e274b59c64c Mon Sep 17 00:00:00 2001 From: rxu Date: Tue, 24 Mar 2020 23:17:04 +0700 Subject: [PATCH 1/9] [ticket/16413] Add an option to define CPF FontAwesome contact icon PHPBB3-16413 --- phpBB/adm/style/acp_profile.html | 2 + phpBB/adm/style/ajax.js | 11 +++++ phpBB/includes/acp/acp_profile.php | 6 ++- phpBB/language/en/acp/profile.php | 2 + .../custom_profile_field_contact_icon.php | 49 +++++++++++++++++++ phpBB/phpbb/profilefields/manager.php | 3 ++ .../prosilver/template/viewtopic_body.html | 4 +- phpBB/viewtopic.php | 1 + 8 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 phpBB/phpbb/db/migration/data/v330/custom_profile_field_contact_icon.php diff --git a/phpBB/adm/style/acp_profile.html b/phpBB/adm/style/acp_profile.html index 7a0ecce14e..bef10f8284 100644 --- a/phpBB/adm/style/acp_profile.html +++ b/phpBB/adm/style/acp_profile.html @@ -91,6 +91,8 @@
checked="checked" />
+

{{ lang('FIELD_ICON_EXPLAIN') }}
+
{% EVENT acp_profile_contact_after %} diff --git a/phpBB/adm/style/ajax.js b/phpBB/adm/style/ajax.js index 2c364bcd86..38738d787e 100644 --- a/phpBB/adm/style/ajax.js +++ b/phpBB/adm/style/ajax.js @@ -420,5 +420,16 @@ $(function() { } }); +/** +* Automatically display custom profile fields FontAwesome icon +*/ +$(function() { + $('#field_icon').on('keyup blur', function() { + var input = $(this).val(); + var $icon = $(this).next('i'); + $icon.attr('class', 'icon fa-' + input + ' fa-fw'); + }); + +}); })(jQuery); // Avoid conflicts with other libraries diff --git a/phpBB/includes/acp/acp_profile.php b/phpBB/includes/acp/acp_profile.php index 8cf60c2e7d..4f7b34cfde 100644 --- a/phpBB/includes/acp/acp_profile.php +++ b/phpBB/includes/acp/acp_profile.php @@ -360,6 +360,7 @@ class acp_profile $field_row = array_merge($profile_field->get_default_option_values(), array( 'field_ident' => str_replace(' ', '_', utf8_clean_string($request->variable('field_ident', '', true))), 'field_required' => 0, + 'field_icon' => '', 'field_show_novalue'=> 0, 'field_hide' => 0, 'field_show_profile'=> 0, @@ -381,7 +382,7 @@ class acp_profile // $exclude contains the data we gather in each step $exclude = array( - 1 => array('field_ident', 'lang_name', 'lang_explain', 'field_option_none', 'field_show_on_reg', 'field_show_on_pm', 'field_show_on_vt', 'field_show_on_ml', 'field_required', 'field_show_novalue', 'field_hide', 'field_show_profile', 'field_no_view', 'field_is_contact', 'field_contact_desc', 'field_contact_url'), + 1 => array('field_ident', 'field_icon', 'lang_name', 'lang_explain', 'field_option_none', 'field_show_on_reg', 'field_show_on_pm', 'field_show_on_vt', 'field_show_on_ml', 'field_required', 'field_show_novalue', 'field_hide', 'field_show_profile', 'field_no_view', 'field_is_contact', 'field_contact_desc', 'field_contact_url'), 2 => array('field_length', 'field_maxlen', 'field_minlen', 'field_validation', 'field_novalue', 'field_default_value'), 3 => array('l_lang_name', 'l_lang_explain', 'l_lang_default_value', 'l_lang_options') ); @@ -428,6 +429,7 @@ class acp_profile $options = $profile_field->prepare_options_form($exclude, $visibility_ary); $cp->vars['field_ident'] = ($action == 'create' && $step == 1) ? utf8_clean_string($request->variable('field_ident', $field_row['field_ident'], true)) : $request->variable('field_ident', $field_row['field_ident']); + $cp->vars['field_icon'] = $request->variable('field_icon', $field_row['field_icon']); $cp->vars['lang_name'] = $request->variable('lang_name', $field_row['lang_name'], true); $cp->vars['lang_explain'] = $request->variable('lang_explain', $field_row['lang_explain'], true); $cp->vars['lang_default_value'] = $request->variable('lang_default_value', $field_row['lang_default_value'], true); @@ -648,6 +650,7 @@ class acp_profile 'L_LANG_SPECIFIC' => sprintf($user->lang['LANG_SPECIFIC_OPTIONS'], $config['default_lang']), 'FIELD_TYPE' => $profile_field->get_name(), 'FIELD_IDENT' => $cp->vars['field_ident'], + 'FIELD_ICON' => $cp->vars['field_icon'], 'LANG_NAME' => $cp->vars['lang_name'], 'LANG_EXPLAIN' => $cp->vars['lang_explain'], ); @@ -984,6 +987,7 @@ class acp_profile 'field_is_contact' => $cp->vars['field_is_contact'], 'field_contact_desc' => $cp->vars['field_contact_desc'], 'field_contact_url' => $cp->vars['field_contact_url'], + 'field_icon' => $cp->vars['field_icon'], ); $field_data = $cp->vars; diff --git a/phpBB/language/en/acp/profile.php b/phpBB/language/en/acp/profile.php index 579235c912..f924a97e0d 100644 --- a/phpBB/language/en/acp/profile.php +++ b/phpBB/language/en/acp/profile.php @@ -93,6 +93,8 @@ $lang = array_merge($lang, array( 'FIELD_DESCRIPTION' => 'Field description', 'FIELD_DESCRIPTION_EXPLAIN' => 'The explanation for this field presented to the user.', 'FIELD_DROPDOWN' => 'Dropdown box', + 'FIELD_ICON' => 'Field icon', + 'FIELD_ICON_EXPLAIN' => 'Enter the name of a Font Awesome icon to use with the field while displaying in the mini-profile on the topic screen. Leave this field blank to use phpBB default contact image icon.', 'FIELD_IDENT' => 'Field identification', 'FIELD_IDENT_ALREADY_EXIST' => 'The chosen field identification already exist. Please choose another name.', 'FIELD_IDENT_EXPLAIN' => 'The field identification is a name to identify the profile field within the database and the templates.', diff --git a/phpBB/phpbb/db/migration/data/v330/custom_profile_field_contact_icon.php b/phpBB/phpbb/db/migration/data/v330/custom_profile_field_contact_icon.php new file mode 100644 index 0000000000..6376f6cd4c --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v330/custom_profile_field_contact_icon.php @@ -0,0 +1,49 @@ + +* @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\db\migration\data\v330; + +class custom_profile_field_contact_icon extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return $this->db_tools->sql_column_exists($this->table_prefix . 'profile_fields', 'field_icon'); + } + + public static function depends_on() + { + return ['\phpbb\db\migration\data\v330\v330',]; + } + + public function update_schema() + { + return array( + 'add_columns' => [ + $this->table_prefix . 'profile_fields' => [ + 'field_icon' => array('VCHAR:255', ''), + ], + ], + ); + } + + public function revert_schema() + { + return array( + 'drop_columns' => array( + $this->table_prefix . 'profile_fields' => array( + 'field_icon', + ), + ), + ); + } +} diff --git a/phpBB/phpbb/profilefields/manager.php b/phpBB/phpbb/profilefields/manager.php index 7cc37e12ce..8ed6870576 100644 --- a/phpBB/phpbb/profilefields/manager.php +++ b/phpBB/phpbb/profilefields/manager.php @@ -332,6 +332,7 @@ class manager $tpl_fields[] = [ 'PROFILE_FIELD_IDENT' => $field_ident, + 'PROFILE_FIELD_ICON' => $field_data['field_icon'], 'PROFILE_FIELD_TYPE' => $field_data['field_type'], 'PROFILE_FIELD_NAME' => $profile_field->get_field_name($field_data['lang_name']), 'PROFILE_FIELD_EXPLAIN' => $this->language->lang($field_data['lang_explain']), @@ -484,6 +485,7 @@ class manager $tpl_fields['row'] += [ "PROFILE_{$ident_upper}_IDENT" => $ident, + "PROFILE_{$ident_upper}_ICON" => $ident_ary['data']['field_icon'], "PROFILE_{$ident_upper}_VALUE" => $value, "PROFILE_{$ident_upper}_VALUE_RAW" => $value_raw, "PROFILE_{$ident_upper}_CONTACT" => $contact_url, @@ -498,6 +500,7 @@ class manager $tpl_fields['blockrow'][] = [ 'PROFILE_FIELD_IDENT' => $ident, + 'PROFILE_FIELD_ICON' => $ident_ary['data']['field_icon'], 'PROFILE_FIELD_VALUE' => $value, 'PROFILE_FIELD_VALUE_RAW' => $value_raw, 'PROFILE_FIELD_CONTACT' => $contact_url, diff --git a/phpBB/styles/prosilver/template/viewtopic_body.html b/phpBB/styles/prosilver/template/viewtopic_body.html index febc2d35d4..15bd6abb72 100644 --- a/phpBB/styles/prosilver/template/viewtopic_body.html +++ b/phpBB/styles/prosilver/template/viewtopic_body.html @@ -193,7 +193,9 @@ class="last-cell"> {% EVENT viewtopic_body_contact_icon_prepend %} - {% if postrow.contact.ID == 'pm' %} + {% if postrow.contact.ICON %} + {{ Icon('font', contact.ICON, '', true, '') }} + {% elseif postrow.contact.ID == 'pm' %} {{ Icon('font', 'message', '', true, 'far contact-icon') }} {% elseif postrow.contact.ID == 'email' %} {{ Icon('font', 'at', '', true, 'fas contact-icon') }} diff --git a/phpBB/viewtopic.php b/phpBB/viewtopic.php index 3181204292..6bb4450b16 100644 --- a/phpBB/viewtopic.php +++ b/phpBB/viewtopic.php @@ -2195,6 +2195,7 @@ for ($i = 0, $end = count($post_list); $i < $end; ++$i) { $template->assign_block_vars('postrow.contact', array( 'ID' => $field_data['PROFILE_FIELD_IDENT'], + 'ICON' => $field_data['PROFILE_FIELD_ICON'], 'NAME' => $field_data['PROFILE_FIELD_NAME'], 'U_CONTACT' => $field_data['PROFILE_FIELD_CONTACT'], )); From 95da75d82ca22cee9b3770c92898cf5ab5034a14 Mon Sep 17 00:00:00 2001 From: rxu Date: Mon, 12 May 2025 14:47:55 +0700 Subject: [PATCH 2/9] [ticket/16413] Add icon background color option PHPBB3-16413 --- phpBB/adm/style/acp_profile.html | 2 +- phpBB/includes/acp/acp_profile.php | 12 ++++++-- .../custom_profile_field_contact_icon.php | 28 ++++++++++--------- .../prosilver/template/viewtopic_body.html | 3 +- phpBB/viewtopic.php | 4 ++- 5 files changed, 30 insertions(+), 19 deletions(-) rename phpBB/phpbb/db/migration/data/{v330 => v400}/custom_profile_field_contact_icon.php (56%) diff --git a/phpBB/adm/style/acp_profile.html b/phpBB/adm/style/acp_profile.html index bef10f8284..6a0b3ae11d 100644 --- a/phpBB/adm/style/acp_profile.html +++ b/phpBB/adm/style/acp_profile.html @@ -92,7 +92,7 @@

{{ lang('FIELD_ICON_EXPLAIN') }}
-
+
{{ Icon('font', FIELD_ICON, '', true, {'style': 'color: #' ~ FIELD_ICON_COLOR}) }}
{% EVENT acp_profile_contact_after %} diff --git a/phpBB/includes/acp/acp_profile.php b/phpBB/includes/acp/acp_profile.php index 4f7b34cfde..9dc95ece36 100644 --- a/phpBB/includes/acp/acp_profile.php +++ b/phpBB/includes/acp/acp_profile.php @@ -360,7 +360,7 @@ class acp_profile $field_row = array_merge($profile_field->get_default_option_values(), array( 'field_ident' => str_replace(' ', '_', utf8_clean_string($request->variable('field_ident', '', true))), 'field_required' => 0, - 'field_icon' => '', + 'field_icon' => json_encode(['name' => '', 'color' => '']), 'field_show_novalue'=> 0, 'field_hide' => 0, 'field_show_profile'=> 0, @@ -428,8 +428,12 @@ class acp_profile $options = $profile_field->prepare_options_form($exclude, $visibility_ary); + $field_icon_data = json_decode($field_row['field_icon'], true); + $cp->vars['field_icon'] = json_encode([ + 'name' => $request->variable('field_icon', $field_icon_data['name'] ?: ''), + 'color' => $request->variable('field_icon_color', $field_icon_data['color'] ?: ''), + ]); $cp->vars['field_ident'] = ($action == 'create' && $step == 1) ? utf8_clean_string($request->variable('field_ident', $field_row['field_ident'], true)) : $request->variable('field_ident', $field_row['field_ident']); - $cp->vars['field_icon'] = $request->variable('field_icon', $field_row['field_icon']); $cp->vars['lang_name'] = $request->variable('lang_name', $field_row['lang_name'], true); $cp->vars['lang_explain'] = $request->variable('lang_explain', $field_row['lang_explain'], true); $cp->vars['lang_default_value'] = $request->variable('lang_default_value', $field_row['lang_default_value'], true); @@ -632,6 +636,7 @@ class acp_profile { // Create basic options - only small differences between field types case 1: + $field_icon_data = json_decode($cp->vars['field_icon'], true); $template_vars = array( 'S_STEP_ONE' => true, 'S_FIELD_REQUIRED' => ($cp->vars['field_required']) ? true : false, @@ -650,7 +655,8 @@ class acp_profile 'L_LANG_SPECIFIC' => sprintf($user->lang['LANG_SPECIFIC_OPTIONS'], $config['default_lang']), 'FIELD_TYPE' => $profile_field->get_name(), 'FIELD_IDENT' => $cp->vars['field_ident'], - 'FIELD_ICON' => $cp->vars['field_icon'], + 'FIELD_ICON' => $field_icon_data['name'], + 'FIELD_ICON_COLOR' => $field_icon_data['color'], 'LANG_NAME' => $cp->vars['lang_name'], 'LANG_EXPLAIN' => $cp->vars['lang_explain'], ); diff --git a/phpBB/phpbb/db/migration/data/v330/custom_profile_field_contact_icon.php b/phpBB/phpbb/db/migration/data/v400/custom_profile_field_contact_icon.php similarity index 56% rename from phpBB/phpbb/db/migration/data/v330/custom_profile_field_contact_icon.php rename to phpBB/phpbb/db/migration/data/v400/custom_profile_field_contact_icon.php index 6376f6cd4c..9df240f495 100644 --- a/phpBB/phpbb/db/migration/data/v330/custom_profile_field_contact_icon.php +++ b/phpBB/phpbb/db/migration/data/v400/custom_profile_field_contact_icon.php @@ -1,17 +1,17 @@ -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited + * @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\db\migration\data\v330; +namespace phpbb\db\migration\data\v400; class custom_profile_field_contact_icon extends \phpbb\db\migration\migration { @@ -22,7 +22,9 @@ class custom_profile_field_contact_icon extends \phpbb\db\migration\migration public static function depends_on() { - return ['\phpbb\db\migration\data\v330\v330',]; + return [ + '\phpbb\db\migration\data\v400\dev', + ]; } public function update_schema() @@ -30,7 +32,7 @@ class custom_profile_field_contact_icon extends \phpbb\db\migration\migration return array( 'add_columns' => [ $this->table_prefix . 'profile_fields' => [ - 'field_icon' => array('VCHAR:255', ''), + 'field_icon' => array('VCHAR:255', json_encode(['name' => '', 'color' => ''])), ], ], ); diff --git a/phpBB/styles/prosilver/template/viewtopic_body.html b/phpBB/styles/prosilver/template/viewtopic_body.html index 15bd6abb72..778830429a 100644 --- a/phpBB/styles/prosilver/template/viewtopic_body.html +++ b/phpBB/styles/prosilver/template/viewtopic_body.html @@ -194,7 +194,8 @@
class="last-cell"> {% EVENT viewtopic_body_contact_icon_prepend %} {% if postrow.contact.ICON %} - {{ Icon('font', contact.ICON, '', true, '') }} + {% set color = postrow.contact.ICON_COLOR ? ('color: #' ~ contact.ICON_COLOR) : '' %} + {{ Icon('font', contact.ICON, '', true, '', '', {'style': color}) }} {% elseif postrow.contact.ID == 'pm' %} {{ Icon('font', 'message', '', true, 'far contact-icon') }} {% elseif postrow.contact.ID == 'email' %} diff --git a/phpBB/viewtopic.php b/phpBB/viewtopic.php index 6bb4450b16..7f2ce77eb8 100644 --- a/phpBB/viewtopic.php +++ b/phpBB/viewtopic.php @@ -2193,9 +2193,11 @@ for ($i = 0, $end = count($post_list); $i < $end; ++$i) if ($field_data['S_PROFILE_CONTACT']) { + $icon_data = json_decode($field_data['PROFILE_FIELD_ICON'], true); $template->assign_block_vars('postrow.contact', array( 'ID' => $field_data['PROFILE_FIELD_IDENT'], - 'ICON' => $field_data['PROFILE_FIELD_ICON'], + 'ICON' => $icon_data['name'], + 'ICON_COLOR'=> $icon_data['color'], 'NAME' => $field_data['PROFILE_FIELD_NAME'], 'U_CONTACT' => $field_data['PROFILE_FIELD_CONTACT'], )); From 9fad2359177c56d7a89c24cc1461b7f628cfca5d Mon Sep 17 00:00:00 2001 From: rxu Date: Mon, 12 May 2025 17:28:32 +0700 Subject: [PATCH 3/9] [ticket/16413] Add icon background color option PHPBB3-16413 --- phpBB/adm/style/acp_profile.html | 3 ++- phpBB/adm/style/ajax.js | 7 ++++++- phpBB/language/en/acp/profile.php | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/phpBB/adm/style/acp_profile.html b/phpBB/adm/style/acp_profile.html index 6a0b3ae11d..982bd5c4f5 100644 --- a/phpBB/adm/style/acp_profile.html +++ b/phpBB/adm/style/acp_profile.html @@ -92,7 +92,8 @@

{{ lang('FIELD_ICON_EXPLAIN') }}
-
{{ Icon('font', FIELD_ICON, '', true, {'style': 'color: #' ~ FIELD_ICON_COLOR}) }}
+
{{ Icon('font', FIELD_ICON, '', true, '', {'style': 'font-size: 16px; margin:0 6px; vertical-align: middle;' ~ (FIELD_ICON_COLOR ? (' color: #' ~ FIELD_ICON_COLOR ~ ';') : '')}) }}
+
{% EVENT acp_profile_contact_after %} diff --git a/phpBB/adm/style/ajax.js b/phpBB/adm/style/ajax.js index 38738d787e..a68301ea68 100644 --- a/phpBB/adm/style/ajax.js +++ b/phpBB/adm/style/ajax.js @@ -424,10 +424,15 @@ $(function() { * Automatically display custom profile fields FontAwesome icon */ $(function() { + var $field_icon = $('#field_icon'); + if (!$field_icon.next('i').length) { + $field_icon.after(''); + } + $('#field_icon').on('keyup blur', function() { var input = $(this).val(); var $icon = $(this).next('i'); - $icon.attr('class', 'icon fa-' + input + ' fa-fw'); + $icon.attr('class', 'o-icon o-icon-font fa-fw fa-' + input + ' fas'); }); }); diff --git a/phpBB/language/en/acp/profile.php b/phpBB/language/en/acp/profile.php index f924a97e0d..bc22b833ce 100644 --- a/phpBB/language/en/acp/profile.php +++ b/phpBB/language/en/acp/profile.php @@ -94,6 +94,7 @@ $lang = array_merge($lang, array( 'FIELD_DESCRIPTION_EXPLAIN' => 'The explanation for this field presented to the user.', 'FIELD_DROPDOWN' => 'Dropdown box', 'FIELD_ICON' => 'Field icon', + 'FIELD_ICON_COLOR' => 'Icon color', 'FIELD_ICON_EXPLAIN' => 'Enter the name of a Font Awesome icon to use with the field while displaying in the mini-profile on the topic screen. Leave this field blank to use phpBB default contact image icon.', 'FIELD_IDENT' => 'Field identification', 'FIELD_IDENT_ALREADY_EXIST' => 'The chosen field identification already exist. Please choose another name.', From dbe91cac884dea4dfc901c53093cb032065252c9 Mon Sep 17 00:00:00 2001 From: rxu Date: Mon, 19 May 2025 17:37:52 +0700 Subject: [PATCH 4/9] [ticket/16413] Add icon color picker PHPBB3-16413 --- phpBB/adm/style/acp_profile.html | 7 +++- phpBB/adm/style/admin.css | 26 ++++++++++++ phpBB/adm/style/ajax.js | 41 ++++++++++++++++++- .../prosilver/template/viewtopic_body.html | 4 +- 4 files changed, 72 insertions(+), 6 deletions(-) diff --git a/phpBB/adm/style/acp_profile.html b/phpBB/adm/style/acp_profile.html index 982bd5c4f5..40e5b28bca 100644 --- a/phpBB/adm/style/acp_profile.html +++ b/phpBB/adm/style/acp_profile.html @@ -92,8 +92,11 @@

{{ lang('FIELD_ICON_EXPLAIN') }}
-
{{ Icon('font', FIELD_ICON, '', true, '', {'style': 'font-size: 16px; margin:0 6px; vertical-align: middle;' ~ (FIELD_ICON_COLOR ? (' color: #' ~ FIELD_ICON_COLOR ~ ';') : '')}) }}
-
+
{{ Icon('font', FIELD_ICON, '', true, 'acp-icon', {'style': 'margin:0 6px;' ~ (FIELD_ICON_COLOR ? (' color: #' ~ FIELD_ICON_COLOR ~ ';') : '')}) }}
+
+ + +
{% EVENT acp_profile_contact_after %} diff --git a/phpBB/adm/style/admin.css b/phpBB/adm/style/admin.css index 290eaffcf8..78e380da9f 100644 --- a/phpBB/adm/style/admin.css +++ b/phpBB/adm/style/admin.css @@ -3152,3 +3152,29 @@ span + .o-icon { .acp-icon-disabled { color: #d0d0d0; } + + +input[type="color"] { + background-color: transparent; + border: solid 1px #d3d3d3; + border-radius: 50%; + width: 24px; + height: 24px; + padding: 2px; + cursor: pointer; + -webkit-appearance: none; +} + +input[type="color"]::-webkit-color-swatch-wrapper { + padding: 0; +} + +input[type="color"]::-webkit-color-swatch { + border: 0; + border-radius: 50%; +} + +input[type="color"]::-moz-color-swatch { + border: 0; + border-radius: 50%; +} diff --git a/phpBB/adm/style/ajax.js b/phpBB/adm/style/ajax.js index a68301ea68..18ed04d9ef 100644 --- a/phpBB/adm/style/ajax.js +++ b/phpBB/adm/style/ajax.js @@ -429,12 +429,49 @@ $(function() { $field_icon.after(''); } - $('#field_icon').on('keyup blur', function() { + $field_icon.on('keyup blur', function() { var input = $(this).val(); var $icon = $(this).next('i'); - $icon.attr('class', 'o-icon o-icon-font fa-fw fa-' + input + ' fas'); + $icon.attr('class', 'o-icon o-icon-font fa-fw fa-' + input + ' fas acp-icon'); }); + const DEFAULT_COLOR = '#000000'; + const HEX_REGEX = /^#[A-Fa-f0-9]{6}$/; + const colorPicker = document.getElementById('field_icon_color_picker'); + + if (!colorPicker) { + return; + } + + const colorText = colorPicker.previousElementSibling; + + if (!colorText || colorText.type !== 'text') { + return; + } + + const syncColors = (source, target) => { + const value = '#' + source.value.trim(); + target.value = HEX_REGEX.test(value) ? value : DEFAULT_COLOR; + }; + + const handleInput = ({ target }) => { + if (target === colorPicker) { + colorText.value = target.value.substring(1); + } else { + syncColors(colorText, colorPicker); + } + var icon = $field_icon.next('i'); + icon.css('color', colorPicker.value); + }; + + colorPicker.addEventListener("input", handleInput); + colorText.addEventListener("input", handleInput); + colorText.addEventListener('blur', () => { + if (!colorText.value.trim()) { + colorPicker.value = DEFAULT_COLOR; + } + }); + syncColors(colorText, colorPicker); }); })(jQuery); // Avoid conflicts with other libraries diff --git a/phpBB/styles/prosilver/template/viewtopic_body.html b/phpBB/styles/prosilver/template/viewtopic_body.html index 778830429a..97ada402f7 100644 --- a/phpBB/styles/prosilver/template/viewtopic_body.html +++ b/phpBB/styles/prosilver/template/viewtopic_body.html @@ -194,8 +194,8 @@
class="last-cell"> {% EVENT viewtopic_body_contact_icon_prepend %} {% if postrow.contact.ICON %} - {% set color = postrow.contact.ICON_COLOR ? ('color: #' ~ contact.ICON_COLOR) : '' %} - {{ Icon('font', contact.ICON, '', true, '', '', {'style': color}) }} + {% set color = postrow.contact.ICON_COLOR ? ({style: 'color: #' ~ contact.ICON_COLOR}) : [] %} + {{ Icon('font', contact.ICON, '', true, '', color) }} {% elseif postrow.contact.ID == 'pm' %} {{ Icon('font', 'message', '', true, 'far contact-icon') }} {% elseif postrow.contact.ID == 'email' %} From 80af2dc25e721193de2f76208bf273f3ec75d866 Mon Sep 17 00:00:00 2001 From: rxu Date: Mon, 19 May 2025 22:23:06 +0700 Subject: [PATCH 5/9] [ticket/16413] refactor JQuery to pure Javascript PHPBB3-16413 --- phpBB/adm/style/admin.js | 61 ++++++++++++++++++++++++++++++++++++++++ phpBB/adm/style/ajax.js | 53 ---------------------------------- 2 files changed, 61 insertions(+), 53 deletions(-) diff --git a/phpBB/adm/style/admin.js b/phpBB/adm/style/admin.js index ff89458ca8..38a90592c6 100644 --- a/phpBB/adm/style/admin.js +++ b/phpBB/adm/style/admin.js @@ -244,6 +244,67 @@ function parse_document(container) }); } +/** +* Automatically display custom profile fields FontAwesome icon +*/ +const DEFAULT_COLOR = '#000000'; +const HEX_REGEX = /^#[A-Fa-f0-9]{6}$/; +const colorPicker = document.getElementById('field_icon_color_picker'); +const colorText = colorPicker.previousElementSibling; + +const syncColors = (source, target) => { + const value = '#' + source.value.trim(); + target.value = HEX_REGEX.test(value) ? value : DEFAULT_COLOR; +}; + +const handleInput = ({ target }) => { + if (target === colorPicker) { + colorText.value = target.value.substring(1); + } else { + syncColors(colorText, colorPicker); + } + const icon = field_icon?.nextElementSibling; + if (icon && icon.tagName.toLowerCase() === 'i') { + icon.style.color = colorPicker.value; + } +}; + +colorPicker.addEventListener('input', handleInput); +colorText.addEventListener('input', handleInput); +colorText.addEventListener('blur', () => { + if (!colorText.value.trim()) { + colorPicker.value = DEFAULT_COLOR; + } +}); +syncColors(colorText, colorPicker); + +var field_icon = document.getElementById('field_icon'); +if (!field_icon.nextElementSibling) { + icon_demo = document.createElement('i'); + icon_demo.setAttribute('style', `margin:0 6px; color: ${colorPicker.value}`); + icon_demo.setAttribute('class', `o-icon o-icon-font fa-fw fas acp-icon`); + field_icon.after(icon_demo); +} + +const updateIconClass = (element, newClass) => { + + element.classList.forEach(className => { + if (className.startsWith('fa-') && className !== 'fa-fw') { + element.classList.remove(className); + } + }); + + element.classList.add(`fa-${newClass}`); +}; + +field_icon.addEventListener('keyup', function() { + updateIconClass(this.nextElementSibling, this.value); +}); + +field_icon.addEventListener('blur', function() { + updateIconClass(this.nextElementSibling, this.value); +}); + /** * Run onload functions */ diff --git a/phpBB/adm/style/ajax.js b/phpBB/adm/style/ajax.js index 18ed04d9ef..2c364bcd86 100644 --- a/phpBB/adm/style/ajax.js +++ b/phpBB/adm/style/ajax.js @@ -420,58 +420,5 @@ $(function() { } }); -/** -* Automatically display custom profile fields FontAwesome icon -*/ -$(function() { - var $field_icon = $('#field_icon'); - if (!$field_icon.next('i').length) { - $field_icon.after(''); - } - - $field_icon.on('keyup blur', function() { - var input = $(this).val(); - var $icon = $(this).next('i'); - $icon.attr('class', 'o-icon o-icon-font fa-fw fa-' + input + ' fas acp-icon'); - }); - - const DEFAULT_COLOR = '#000000'; - const HEX_REGEX = /^#[A-Fa-f0-9]{6}$/; - const colorPicker = document.getElementById('field_icon_color_picker'); - - if (!colorPicker) { - return; - } - - const colorText = colorPicker.previousElementSibling; - - if (!colorText || colorText.type !== 'text') { - return; - } - - const syncColors = (source, target) => { - const value = '#' + source.value.trim(); - target.value = HEX_REGEX.test(value) ? value : DEFAULT_COLOR; - }; - - const handleInput = ({ target }) => { - if (target === colorPicker) { - colorText.value = target.value.substring(1); - } else { - syncColors(colorText, colorPicker); - } - var icon = $field_icon.next('i'); - icon.css('color', colorPicker.value); - }; - - colorPicker.addEventListener("input", handleInput); - colorText.addEventListener("input", handleInput); - colorText.addEventListener('blur', () => { - if (!colorText.value.trim()) { - colorPicker.value = DEFAULT_COLOR; - } - }); - syncColors(colorText, colorPicker); -}); })(jQuery); // Avoid conflicts with other libraries From b84bc9adfcb9a9e8dd644968d6100d9486a54435 Mon Sep 17 00:00:00 2001 From: rxu Date: Mon, 19 May 2025 23:22:16 +0700 Subject: [PATCH 6/9] [ticket/16413] Handle displaying icon on PM screen Also, save empty color if custom icon name is empty. PHPBB3-16413 --- phpBB/includes/acp/acp_profile.php | 6 ++++-- phpBB/includes/ucp/ucp_pm_viewmessage.php | 3 +++ phpBB/styles/prosilver/template/ucp_pm_viewmessage.html | 5 ++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/phpBB/includes/acp/acp_profile.php b/phpBB/includes/acp/acp_profile.php index 9dc95ece36..fbc8f87750 100644 --- a/phpBB/includes/acp/acp_profile.php +++ b/phpBB/includes/acp/acp_profile.php @@ -429,9 +429,11 @@ class acp_profile $options = $profile_field->prepare_options_form($exclude, $visibility_ary); $field_icon_data = json_decode($field_row['field_icon'], true); + $field_icon_name = $request->variable('field_icon', $field_icon_data['name'] ?: ''); + $field_icon_color = $field_icon_name ? $request->variable('field_icon_color', $field_icon_data['color'] ?: '') : ''; $cp->vars['field_icon'] = json_encode([ - 'name' => $request->variable('field_icon', $field_icon_data['name'] ?: ''), - 'color' => $request->variable('field_icon_color', $field_icon_data['color'] ?: ''), + 'name' => $field_icon_name, + 'color' => $field_icon_color, ]); $cp->vars['field_ident'] = ($action == 'create' && $step == 1) ? utf8_clean_string($request->variable('field_ident', $field_row['field_ident'], true)) : $request->variable('field_ident', $field_row['field_ident']); $cp->vars['lang_name'] = $request->variable('lang_name', $field_row['lang_name'], true); diff --git a/phpBB/includes/ucp/ucp_pm_viewmessage.php b/phpBB/includes/ucp/ucp_pm_viewmessage.php index d418e49887..e4e179c82a 100644 --- a/phpBB/includes/ucp/ucp_pm_viewmessage.php +++ b/phpBB/includes/ucp/ucp_pm_viewmessage.php @@ -373,8 +373,11 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) if ($cp_block_row['S_PROFILE_CONTACT']) { + $icon_data = json_decode($cp_block_row['PROFILE_FIELD_ICON'], true); $template->assign_block_vars('contact', array( 'ID' => $cp_block_row['PROFILE_FIELD_IDENT'], + 'ICON' => $icon_data['name'], + 'ICON_COLOR'=> $icon_data['color'], 'NAME' => $cp_block_row['PROFILE_FIELD_NAME'], 'U_CONTACT' => $cp_block_row['PROFILE_FIELD_CONTACT'], )); diff --git a/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html b/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html index 6572d965b8..2f5ca3d5ae 100644 --- a/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html +++ b/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html @@ -71,7 +71,10 @@
class="last-cell"> - {% if contact.ID == 'pm' %} + {% if contact.ICON %} + {% set color = contact.ICON_COLOR ? ({style: 'color: #' ~ contact.ICON_COLOR}) : [] %} + {{ Icon('font', contact.ICON, '', true, '', color) }} + {% elseif contact.ID == 'pm' %} {{ Icon('font', 'message', '', true, 'far contact-icon') }} {% elseif contact.ID == 'email' %} {{ Icon('font', 'at', '', true, 'fas contact-icon') }} From 299d6a0030113529351a86b712cb53171669dd70 Mon Sep 17 00:00:00 2001 From: rxu Date: Mon, 19 May 2025 23:41:07 +0700 Subject: [PATCH 7/9] [ticket/16413] Adjust language entries PHPBB3-16413 --- phpBB/language/en/acp/profile.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpBB/language/en/acp/profile.php b/phpBB/language/en/acp/profile.php index bc22b833ce..c5290c8313 100644 --- a/phpBB/language/en/acp/profile.php +++ b/phpBB/language/en/acp/profile.php @@ -94,8 +94,8 @@ $lang = array_merge($lang, array( 'FIELD_DESCRIPTION_EXPLAIN' => 'The explanation for this field presented to the user.', 'FIELD_DROPDOWN' => 'Dropdown box', 'FIELD_ICON' => 'Field icon', - 'FIELD_ICON_COLOR' => 'Icon color', - 'FIELD_ICON_EXPLAIN' => 'Enter the name of a Font Awesome icon to use with the field while displaying in the mini-profile on the topic screen. Leave this field blank to use phpBB default contact image icon.', + 'FIELD_ICON_COLOR' => 'Icon colour', + 'FIELD_ICON_EXPLAIN' => 'Enter the name of a Font Awesome icon to use if displaying as a contact field option above is set. Optionally, set the icon colour in 6-value hexadecimal format or choose it using the colour picker next to the icon colour field (only effective when Font Awesome icon name is set). Leave Font Awesome icon field blank to use phpBB default contact field icon if any (this will also empty the icon colour field).', 'FIELD_IDENT' => 'Field identification', 'FIELD_IDENT_ALREADY_EXIST' => 'The chosen field identification already exist. Please choose another name.', 'FIELD_IDENT_EXPLAIN' => 'The field identification is a name to identify the profile field within the database and the templates.', From 71f0a3cb62006628c8c07d0be6a2aebd6373ef4c Mon Sep 17 00:00:00 2001 From: rxu Date: Tue, 20 May 2025 12:02:54 +0700 Subject: [PATCH 8/9] [ticket/16413] Adjust code and language entry, add test PHPBB3-16413 --- phpBB/adm/style/acp_profile.html | 4 +- phpBB/includes/acp/acp_profile.php | 2 +- phpBB/language/en/acp/profile.php | 2 +- .../profile_field_contact_icon_test.php | 66 +++++++++++++++++++ 4 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 tests/functional/profile_field_contact_icon_test.php diff --git a/phpBB/adm/style/acp_profile.html b/phpBB/adm/style/acp_profile.html index 40e5b28bca..4df30408e7 100644 --- a/phpBB/adm/style/acp_profile.html +++ b/phpBB/adm/style/acp_profile.html @@ -92,9 +92,9 @@

{{ lang('FIELD_ICON_EXPLAIN') }}
-
{{ Icon('font', FIELD_ICON, '', true, 'acp-icon', {'style': 'margin:0 6px;' ~ (FIELD_ICON_COLOR ? (' color: #' ~ FIELD_ICON_COLOR ~ ';') : '')}) }}
+
{{ Icon('font', FIELD_ICON, '', true, 'acp-icon', {'style': 'margin:0 6px;' ~ (FIELD_ICON_COLOR ? (' color: #' ~ FIELD_ICON_COLOR ~ ';') : '')}) }}
- +
diff --git a/phpBB/includes/acp/acp_profile.php b/phpBB/includes/acp/acp_profile.php index fbc8f87750..edbd691c2c 100644 --- a/phpBB/includes/acp/acp_profile.php +++ b/phpBB/includes/acp/acp_profile.php @@ -382,7 +382,7 @@ class acp_profile // $exclude contains the data we gather in each step $exclude = array( - 1 => array('field_ident', 'field_icon', 'lang_name', 'lang_explain', 'field_option_none', 'field_show_on_reg', 'field_show_on_pm', 'field_show_on_vt', 'field_show_on_ml', 'field_required', 'field_show_novalue', 'field_hide', 'field_show_profile', 'field_no_view', 'field_is_contact', 'field_contact_desc', 'field_contact_url'), + 1 => array('field_ident', 'field_icon', 'field_icon_color', 'lang_name', 'lang_explain', 'field_option_none', 'field_show_on_reg', 'field_show_on_pm', 'field_show_on_vt', 'field_show_on_ml', 'field_required', 'field_show_novalue', 'field_hide', 'field_show_profile', 'field_no_view', 'field_is_contact', 'field_contact_desc', 'field_contact_url'), 2 => array('field_length', 'field_maxlen', 'field_minlen', 'field_validation', 'field_novalue', 'field_default_value'), 3 => array('l_lang_name', 'l_lang_explain', 'l_lang_default_value', 'l_lang_options') ); diff --git a/phpBB/language/en/acp/profile.php b/phpBB/language/en/acp/profile.php index c5290c8313..ff97c32071 100644 --- a/phpBB/language/en/acp/profile.php +++ b/phpBB/language/en/acp/profile.php @@ -95,7 +95,7 @@ $lang = array_merge($lang, array( 'FIELD_DROPDOWN' => 'Dropdown box', 'FIELD_ICON' => 'Field icon', 'FIELD_ICON_COLOR' => 'Icon colour', - 'FIELD_ICON_EXPLAIN' => 'Enter the name of a Font Awesome icon to use if displaying as a contact field option above is set. Optionally, set the icon colour in 6-value hexadecimal format or choose it using the colour picker next to the icon colour field (only effective when Font Awesome icon name is set). Leave Font Awesome icon field blank to use phpBB default contact field icon if any (this will also empty the icon colour field).', + 'FIELD_ICON_EXPLAIN' => 'Enter a Font Awesome icon name to display with this contact field. Optionally, set its colour using a 6-digit hex code or the colour picker. Leave blank to use phpBB’s default icon and clear the colour.', 'FIELD_IDENT' => 'Field identification', 'FIELD_IDENT_ALREADY_EXIST' => 'The chosen field identification already exist. Please choose another name.', 'FIELD_IDENT_EXPLAIN' => 'The field identification is a name to identify the profile field within the database and the templates.', diff --git a/tests/functional/profile_field_contact_icon_test.php b/tests/functional/profile_field_contact_icon_test.php new file mode 100644 index 0000000000..4b8a128b35 --- /dev/null +++ b/tests/functional/profile_field_contact_icon_test.php @@ -0,0 +1,66 @@ + +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +/** +* @group functional +*/ +class phpbb_functional_profile_field_contact_icon_test extends phpbb_functional_test_case +{ + protected function setUp(): void + { + parent::setUp(); + + $this->login(); + $this->admin_login(); + $this->add_lang('acp/profile'); + } + + public function test_add_contact_field_icon() + { + // Custom profile fields page + $crawler = self::request('GET', 'adm/index.php?i=acp_profile&mode=profile&sid=' . $this->sid); + + // Get any contact profile field, f.e. phpbb_twitter + $twitter_field = $crawler->filter('tbody tr') + ->reduce( + function ($node, $i) { + $text = $node->text(); + return ((bool) strpos($text, 'phpbb_twitter')); + }); + + $twitter_edit_url = $twitter_field->filter('.actions a')->eq(2)->attr('href'); + + $crawler = self::request('GET', 'adm/' . $twitter_edit_url . '&sid=' . $this->sid); + + $this->assertStringContainsString('phpbb_twitter', $crawler->text()); + + $form = $crawler->selectButton('Profile type specific options')->form([ + 'field_icon' => 'twitter', + 'field_icon_color' => '1da1f2', + ]); + $crawler= self::submit($form); + + $this->assertStringContainsString('Profile type specific options', $crawler->text()); + + $form = $crawler->selectButton('Save')->form(); + $crawler= self::submit($form); + $this->assertContainsLang('CHANGED_PROFILE_FIELD', $crawler->text()); + + // Ensure contact filed icon was saved correctly + $crawler = self::request('GET', 'adm/' . $twitter_edit_url . '&sid=' . $this->sid); + $this->assertEquals('twitter', $crawler->filter('#field_icon')->attr('value')); + $this->assertEquals('1da1f2', $crawler->filter('#contact_field_icon_bgcolor')->attr('value')); + $this->assertEquals(1, $crawler->filter('i.fa-twitter')->count()); + $this->assertStringContainsString('#1da1f2;', $crawler->filter('i.fa-twitter')->attr('style')); + } +} From 599cb06107931f6c5b9e8c15871b9b60b18a99ad Mon Sep 17 00:00:00 2001 From: rxu Date: Tue, 20 May 2025 13:14:54 +0700 Subject: [PATCH 9/9] [ticket/16413] Add icon displaying test PHPBB3-16413 --- .../profile_field_contact_icon_test.php | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tests/functional/profile_field_contact_icon_test.php b/tests/functional/profile_field_contact_icon_test.php index 4b8a128b35..a19ac46e44 100644 --- a/tests/functional/profile_field_contact_icon_test.php +++ b/tests/functional/profile_field_contact_icon_test.php @@ -35,7 +35,7 @@ class phpbb_functional_profile_field_contact_icon_test extends phpbb_functional_ ->reduce( function ($node, $i) { $text = $node->text(); - return ((bool) strpos($text, 'phpbb_twitter')); + return (strpos($text, 'phpbb_twitter') !== false); }); $twitter_edit_url = $twitter_field->filter('.actions a')->eq(2)->attr('href'); @@ -63,4 +63,33 @@ class phpbb_functional_profile_field_contact_icon_test extends phpbb_functional_ $this->assertEquals(1, $crawler->filter('i.fa-twitter')->count()); $this->assertStringContainsString('#1da1f2;', $crawler->filter('i.fa-twitter')->attr('style')); } + + /** + * @depends test_add_contact_field_icon + */ + public function test_display_field_icon() + { + $this->add_lang('ucp'); + + // Set Twitter profile field + $crawler = self::request('GET', 'ucp.php?i=ucp_profile&mode=profile_info'); + $this->assertContainsLang('UCP_PROFILE_PROFILE_INFO', $crawler->filter('#cp-main h2')->text()); + + $form = $crawler->selectButton('Submit')->form([ + 'pf_phpbb_twitter' => 'phpbb_twitter', + ]); + $crawler = self::submit($form); + $this->assertContainsLang('PROFILE_UPDATED', $crawler->filter('#message')->text()); + + // Ensure Twitter icon displays in topic + $crawler = self::request('GET', 'viewtopic.php?t=1'); + $this->assertEquals('Twitter', $crawler->filter('#profile1 a[title="Twitter"]')->attr('title')); + $this->assertStringContainsString('#1da1f2', $crawler->filter('#profile1 a[title="Twitter"] > i.fa-twitter')->attr('style')); + + // Ensure Twitter icon displays on view private message screen + $message_id = $this->create_private_message('Self PM', 'Self PM', [2]); + $crawler = self::request('GET', 'ucp.php?i=pm&mode=view&p=' . $message_id . '&sid=' . $this->sid); + $this->assertEquals('Twitter', $crawler->filter('.profile-contact a[title="Twitter"]')->attr('title')); + $this->assertStringContainsString('#1da1f2', $crawler->filter('.profile-contact a[title="Twitter"] > i.fa-twitter')->attr('style')); + } }