diff --git a/.github/changelog/2591-from-description b/.github/changelog/2591-from-description new file mode 100644 index 0000000000..92e4481c15 --- /dev/null +++ b/.github/changelog/2591-from-description @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Wrap blocked domains and keywords tables in collapsible details element. diff --git a/assets/css/activitypub-admin.css b/assets/css/activitypub-admin.css index ae415dbc66..5b3254654c 100644 --- a/assets/css/activitypub-admin.css +++ b/assets/css/activitypub-admin.css @@ -104,6 +104,25 @@ summary { color: #2271b1; } +.activitypub-site-block-details { + margin: 10px 0; +} + +.activitypub-site-block-details summary { + padding: 8px 0; + color: inherit; + text-decoration: none; +} + +.activitypub-site-block-details table { + max-width: 500px; + margin-top: 10px; +} + +.activitypub-site-block-details td:last-child { + width: 80px; +} + .activitypub-settings-accordion { border: 1px solid #c3c4c7; } diff --git a/assets/js/activitypub-moderation-admin.js b/assets/js/activitypub-moderation-admin.js index 95cef0f7b3..207d41c16a 100644 --- a/assets/js/activitypub-moderation-admin.js +++ b/assets/js/activitypub-moderation-admin.js @@ -2,11 +2,39 @@ * ActivityPub Moderation Admin JavaScript */ -(function( $ ) { +/* global activitypubModerationL10n, jQuery */ + +/** + * @param {Object} $ - jQuery + * @param {Object} wp - WordPress global object + * @param {Object} wp.i18n - Internationalization functions + * @param {Object} wp.a11y - Accessibility functions + * @param {Object} wp.ajax - AJAX functions + */ +(function( $, wp ) { 'use strict'; + var __ = wp.i18n.__; + var _n = wp.i18n._n; + var sprintf = wp.i18n.sprintf; + + /** + * Helper function to show a message using wp.a11y and alert + * + * @param {string} message - The message to display + */ + function showMessage( message ) { + if ( wp.a11y && wp.a11y.speak ) { + wp.a11y.speak( message, 'assertive' ); + } + alert( message ); + } + /** * Helper function to validate domain format + * + * @param {string} domain - The domain to validate + * @return {boolean} Whether the domain is valid */ function isValidDomain( domain ) { // Basic domain validation - must contain at least one dot and valid characters @@ -16,6 +44,12 @@ /** * Helper function to check if a term already exists in the UI + * + * @param {string} type - The type of block (domain or keyword) + * @param {string} value - The value to check + * @param {string} context - The context (user or site) + * @param {number|null} userId - The user ID (for user context) + * @return {boolean} Whether the term is already blocked */ function isTermAlreadyBlocked( type, value, context, userId ) { var selector; @@ -27,29 +61,110 @@ return $( selector ).length > 0; } + /** + * Validate a blocked term value + * + * @param {string} type - The type of block (domain or keyword) + * @param {string} value - The value to validate + * @param {string} context - The context (user or site) + * @param {number|null} userId - The user ID (for user context) + * @return {boolean} Whether the value is valid + */ + function validateBlockedTerm( type, value, context, userId ) { + if ( ! value ) { + showMessage( __( 'Please enter a value to block.', 'activitypub' ) ); + return false; + } + + if ( type === 'domain' && ! isValidDomain( value ) ) { + showMessage( __( 'Please enter a valid domain (e.g., example.com).', 'activitypub' ) ); + return false; + } + + if ( isTermAlreadyBlocked( type, value, context, userId ) ) { + showMessage( __( 'This term is already blocked.', 'activitypub' ) ); + return false; + } + + return true; + } + + /** + * Create a table row for a blocked term. + * + * @param {string} type - The type of block (domain or keyword) + * @param {string} value - The blocked value + * @param {string} context - The context (user or site) + * @return {jQuery} The constructed table row + */ + function createBlockedTermRow( type, value, context ) { + var $button = $( '' ); + table.find( 'tbody' ).append( createBlockedTermRow( type, value, context ) ); } else if ( context === 'site' ) { - // For site moderation, add to the appropriate table - var container = $( '#new_site_' + type ).closest( '.activitypub-site-block-list' ); - var table = container.find( '.activitypub-site-blocked-' + type ); + // For site moderation, add to the table inside the details element + var details = $( '.activitypub-site-block-details[data-type="' + type + '"]' ); + table = details.find( '.activitypub-site-blocked-' + type ); + if ( table.length === 0 ) { - table = $( '' ); - container.find( '.add-site-block-form' ).before( table ); + // Create table inside the details element (after summary) + table = $( '' ); + details.find( 'summary' ).after( table ); } - table.append( '' + value + '' ); + + table.find( 'tbody' ).append( createBlockedTermRow( type, value, context ) ); + + updateSiteBlockSummary( type ); + } + } + + /** + * Helper function to update the site block summary count + */ + function updateSiteBlockSummary( type ) { + var details = $( '.activitypub-site-block-details[data-type="' + type + '"]' ); + var table = details.find( '.activitypub-site-blocked-' + type ); + var count = table.find( 'tbody tr' ).length || table.find( 'tr' ).length; + var summary = details.find( 'summary' ); + + if ( count === 0 ) { + // Empty state + var emptyText = type === 'domain' + ? __( 'No blocked domains', 'activitypub' ) + : __( 'No blocked keywords', 'activitypub' ); + summary.text( emptyText ); + details.attr( 'open', '' ); + table.remove(); + } else { + // Has items - use _n for proper pluralization + var text = type === 'domain' + ? _n( '%s blocked domain', '%s blocked domains', count, 'activitypub' ) + : _n( '%s blocked keyword', '%s blocked keywords', count, 'activitypub' ); + summary.text( sprintf( text, count ) ); } } @@ -63,13 +178,11 @@ if ( button.length > 0 ) { // Remove the parent table row - var parent = button.closest( 'tr' ); - var container = parent.closest( 'table' ); - parent.remove(); + button.closest( 'tr' ).remove(); - // If the container is now empty, remove it - if ( container.find( 'tr' ).length === 0 ) { - container.remove(); + // Update the summary count for site blocks + if ( context === 'site' ) { + updateSiteBlockSummary( type ); } } } @@ -94,33 +207,7 @@ var input = $( '#new_user_' + type ); var value = input.val().trim(); - if ( ! value ) { - // Use wp.a11y.speak for better accessibility. - if ( wp.a11y && wp.a11y.speak ) { - wp.a11y.speak( activitypubModerationL10n.enterValue, 'assertive' ); - } else { - alert( activitypubModerationL10n.enterValue ); - } - return; - } - - // Validate domain format if this is a domain block - if ( type === 'domain' && ! isValidDomain( value ) ) { - var message = activitypubModerationL10n.invalidDomain || 'Please enter a valid domain (e.g., example.com).'; - if ( wp.a11y && wp.a11y.speak ) { - wp.a11y.speak( message, 'assertive' ); - } - alert( message ); - return; - } - - // Check if the term is already blocked - if ( isTermAlreadyBlocked( type, value, 'user', userId ) ) { - var message = activitypubModerationL10n.alreadyBlocked || 'This term is already blocked.'; - if ( wp.a11y && wp.a11y.speak ) { - wp.a11y.speak( message, 'assertive' ); - } - alert( message ); + if ( ! validateBlockedTerm( type, value, 'user', userId ) ) { return; } @@ -136,12 +223,8 @@ input.val( '' ); addBlockedTermToUI( type, value, 'user', userId ); }).fail( function( response ) { - var message = response && response.message ? response.message : activitypubModerationL10n.addBlockFailed; - if ( wp.a11y && wp.a11y.speak ) { - wp.a11y.speak( message, 'assertive' ); - } else { - alert( message ); - } + var message = response && response.message ? response.message : __( 'Failed to add block.', 'activitypub' ); + showMessage( message ); }); } @@ -157,12 +240,8 @@ }).done( function() { removeBlockedTermFromUI( type, value, 'user' ); }).fail( function( response ) { - var message = response && response.message ? response.message : activitypubModerationL10n.removeBlockFailed; - if ( wp.a11y && wp.a11y.speak ) { - wp.a11y.speak( message, 'assertive' ); - } else { - alert( message ); - } + var message = response && response.message ? response.message : __( 'Failed to remove block.', 'activitypub' ); + showMessage( message ); }); } @@ -204,32 +283,7 @@ var input = $( '#new_site_' + type ); var value = input.val().trim(); - if ( ! value ) { - if ( wp.a11y && wp.a11y.speak ) { - wp.a11y.speak( activitypubModerationL10n.enterValue, 'assertive' ); - } else { - alert( activitypubModerationL10n.enterValue ); - } - return; - } - - // Validate domain format if this is a domain block - if ( type === 'domain' && ! isValidDomain( value ) ) { - var message = activitypubModerationL10n.invalidDomain || 'Please enter a valid domain (e.g., example.com).'; - if ( wp.a11y && wp.a11y.speak ) { - wp.a11y.speak( message, 'assertive' ); - } - alert( message ); - return; - } - - // Check if the term is already blocked - if ( isTermAlreadyBlocked( type, value, 'site' ) ) { - var message = activitypubModerationL10n.alreadyBlocked || 'This term is already blocked.'; - if ( wp.a11y && wp.a11y.speak ) { - wp.a11y.speak( message, 'assertive' ); - } - alert( message ); + if ( ! validateBlockedTerm( type, value, 'site', null ) ) { return; } @@ -244,12 +298,8 @@ input.val( '' ); addBlockedTermToUI( type, value, 'site' ); }).fail( function( response ) { - var message = response && response.message ? response.message : activitypubModerationL10n.addBlockFailed; - if ( wp.a11y && wp.a11y.speak ) { - wp.a11y.speak( message, 'assertive' ); - } else { - alert( message ); - } + var message = response && response.message ? response.message : __( 'Failed to add block.', 'activitypub' ); + showMessage( message ); }); } @@ -264,12 +314,8 @@ }).done( function() { removeBlockedTermFromUI( type, value, 'site' ); }).fail( function( response ) { - var message = response && response.message ? response.message : activitypubModerationL10n.removeBlockFailed; - if ( wp.a11y && wp.a11y.speak ) { - wp.a11y.speak( message, 'assertive' ); - } else { - alert( message ); - } + var message = response && response.message ? response.message : __( 'Failed to remove block.', 'activitypub' ); + showMessage( message ); }); } @@ -302,4 +348,4 @@ // Initialize when document is ready. $( document ).ready( init ); -})( jQuery ); +})( jQuery, wp ); diff --git a/includes/wp-admin/class-admin.php b/includes/wp-admin/class-admin.php index e3b4ca4cfd..af99fc2032 100644 --- a/includes/wp-admin/class-admin.php +++ b/includes/wp-admin/class-admin.php @@ -342,22 +342,23 @@ public static function enqueue_moderation_scripts() { \wp_enqueue_script( 'activitypub-moderation-admin', ACTIVITYPUB_PLUGIN_URL . 'assets/js/activitypub-moderation-admin.js', - array( 'jquery', 'wp-util', 'wp-a11y' ), + array( 'jquery', 'wp-util', 'wp-a11y', 'wp-i18n' ), ACTIVITYPUB_PLUGIN_VERSION, true ); + \wp_set_script_translations( + 'activitypub-moderation-admin', + 'activitypub', + ACTIVITYPUB_PLUGIN_DIR . 'languages' + ); + // Localize script with translations and nonces. \wp_localize_script( 'activitypub-moderation-admin', 'activitypubModerationL10n', array( - 'enterValue' => \__( 'Please enter a value to block.', 'activitypub' ), - 'addBlockFailed' => \__( 'Failed to add block.', 'activitypub' ), - 'removeBlockFailed' => \__( 'Failed to remove block.', 'activitypub' ), - 'alreadyBlocked' => \__( 'This term is already blocked.', 'activitypub' ), - 'invalidDomain' => \__( 'Please enter a valid domain (e.g., example.com).', 'activitypub' ), - 'nonce' => \wp_create_nonce( 'activitypub_moderation_settings' ), + 'nonce' => \wp_create_nonce( 'activitypub_moderation_settings' ), ) ); } diff --git a/includes/wp-admin/class-settings-fields.php b/includes/wp-admin/class-settings-fields.php index 1886e36bb0..090a9586a1 100644 --- a/includes/wp-admin/class-settings-fields.php +++ b/includes/wp-admin/class-settings-fields.php @@ -433,24 +433,44 @@ public static function render_moderation_section_description() { */ public static function render_site_blocked_domains_field() { $blocked_domains = Moderation::get_site_blocks()['domains']; + $count = \count( $blocked_domains ); ?>

- - - - - - - - - - +
> + + 0 ) : ?> + + + + + + + + + + + + + + + + + +
@@ -467,24 +487,44 @@ public static function render_site_blocked_domains_field() { */ public static function render_site_blocked_keywords_field() { $blocked_keywords = Moderation::get_site_blocks()['keywords']; + $count = \count( $blocked_keywords ); ?>

- - - - - - - - - - +
> + + 0 ) : ?> + + + + + + + + + + + + + + + + + +