Skip to content

Commit cc01649

Browse files
authored
Wrap blocked domains and keywords in collapsible details element (#2591)
1 parent 4f8a4fa commit cc01649

File tree

5 files changed

+238
-128
lines changed

5 files changed

+238
-128
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: patch
2+
Type: changed
3+
4+
Wrap blocked domains and keywords tables in collapsible details element.

assets/css/activitypub-admin.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,25 @@ summary {
104104
color: #2271b1;
105105
}
106106

107+
.activitypub-site-block-details {
108+
margin: 10px 0;
109+
}
110+
111+
.activitypub-site-block-details summary {
112+
padding: 8px 0;
113+
color: inherit;
114+
text-decoration: none;
115+
}
116+
117+
.activitypub-site-block-details table {
118+
max-width: 500px;
119+
margin-top: 10px;
120+
}
121+
122+
.activitypub-site-block-details td:last-child {
123+
width: 80px;
124+
}
125+
107126
.activitypub-settings-accordion {
108127
border: 1px solid #c3c4c7;
109128
}

assets/js/activitypub-moderation-admin.js

Lines changed: 139 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,39 @@
22
* ActivityPub Moderation Admin JavaScript
33
*/
44

5-
(function( $ ) {
5+
/* global activitypubModerationL10n, jQuery */
6+
7+
/**
8+
* @param {Object} $ - jQuery
9+
* @param {Object} wp - WordPress global object
10+
* @param {Object} wp.i18n - Internationalization functions
11+
* @param {Object} wp.a11y - Accessibility functions
12+
* @param {Object} wp.ajax - AJAX functions
13+
*/
14+
(function( $, wp ) {
615
'use strict';
716

17+
var __ = wp.i18n.__;
18+
var _n = wp.i18n._n;
19+
var sprintf = wp.i18n.sprintf;
20+
21+
/**
22+
* Helper function to show a message using wp.a11y and alert
23+
*
24+
* @param {string} message - The message to display
25+
*/
26+
function showMessage( message ) {
27+
if ( wp.a11y && wp.a11y.speak ) {
28+
wp.a11y.speak( message, 'assertive' );
29+
}
30+
alert( message );
31+
}
32+
833
/**
934
* Helper function to validate domain format
35+
*
36+
* @param {string} domain - The domain to validate
37+
* @return {boolean} Whether the domain is valid
1038
*/
1139
function isValidDomain( domain ) {
1240
// Basic domain validation - must contain at least one dot and valid characters
@@ -16,6 +44,12 @@
1644

1745
/**
1846
* Helper function to check if a term already exists in the UI
47+
*
48+
* @param {string} type - The type of block (domain or keyword)
49+
* @param {string} value - The value to check
50+
* @param {string} context - The context (user or site)
51+
* @param {number|null} userId - The user ID (for user context)
52+
* @return {boolean} Whether the term is already blocked
1953
*/
2054
function isTermAlreadyBlocked( type, value, context, userId ) {
2155
var selector;
@@ -27,29 +61,110 @@
2761
return $( selector ).length > 0;
2862
}
2963

64+
/**
65+
* Validate a blocked term value
66+
*
67+
* @param {string} type - The type of block (domain or keyword)
68+
* @param {string} value - The value to validate
69+
* @param {string} context - The context (user or site)
70+
* @param {number|null} userId - The user ID (for user context)
71+
* @return {boolean} Whether the value is valid
72+
*/
73+
function validateBlockedTerm( type, value, context, userId ) {
74+
if ( ! value ) {
75+
showMessage( __( 'Please enter a value to block.', 'activitypub' ) );
76+
return false;
77+
}
78+
79+
if ( type === 'domain' && ! isValidDomain( value ) ) {
80+
showMessage( __( 'Please enter a valid domain (e.g., example.com).', 'activitypub' ) );
81+
return false;
82+
}
83+
84+
if ( isTermAlreadyBlocked( type, value, context, userId ) ) {
85+
showMessage( __( 'This term is already blocked.', 'activitypub' ) );
86+
return false;
87+
}
88+
89+
return true;
90+
}
91+
92+
/**
93+
* Create a table row for a blocked term.
94+
*
95+
* @param {string} type - The type of block (domain or keyword)
96+
* @param {string} value - The blocked value
97+
* @param {string} context - The context (user or site)
98+
* @return {jQuery} The constructed table row
99+
*/
100+
function createBlockedTermRow( type, value, context ) {
101+
var $button = $( '<button>', {
102+
type: 'button',
103+
'class': 'button button-small remove-' + context + '-block-btn',
104+
'data-type': type,
105+
'data-value': value,
106+
text: __( 'Remove', 'activitypub' )
107+
} );
108+
109+
return $( '<tr>' ).append( $( '<td>' ).text( value ), $( '<td>' ).append( $button ) );
110+
}
111+
30112
/**
31113
* Helper function to add a blocked term to the UI
32114
*/
33115
function addBlockedTermToUI( type, value, context, userId ) {
116+
var table;
117+
34118
if ( context === 'user' ) {
35119
// For user moderation, add to the appropriate table
36120
var container = $( '.activitypub-user-block-list[data-user-id="' + userId + '"]' );
37121

38-
var table = container.find( '.activitypub-blocked-' + type );
122+
table = container.find( '.activitypub-blocked-' + type );
39123
if ( table.length === 0 ) {
40124
table = $( '<table class="widefat striped activitypub-blocked-' + type + '" role="presentation" style="max-width: 500px; margin: 15px 0;"><tbody></tbody></table>' );
41125
container.find( '#new_user_' + type ).closest( '.add-user-block-form' ).before( table );
42126
}
43-
table.append( '<tr><td>' + value + '</td><td style="width: 80px;"><button type="button" class="button button-small remove-user-block-btn" data-type="' + type + '" data-value="' + value + '">Remove</button></td></tr>' );
127+
table.find( 'tbody' ).append( createBlockedTermRow( type, value, context ) );
44128
} else if ( context === 'site' ) {
45-
// For site moderation, add to the appropriate table
46-
var container = $( '#new_site_' + type ).closest( '.activitypub-site-block-list' );
47-
var table = container.find( '.activitypub-site-blocked-' + type );
129+
// For site moderation, add to the table inside the details element
130+
var details = $( '.activitypub-site-block-details[data-type="' + type + '"]' );
131+
table = details.find( '.activitypub-site-blocked-' + type );
132+
48133
if ( table.length === 0 ) {
49-
table = $( '<table class="widefat striped activitypub-site-blocked-' + type + '" role="presentation" style="max-width: 500px; margin: 15px 0;"><tbody></tbody></table>' );
50-
container.find( '.add-site-block-form' ).before( table );
134+
// Create table inside the details element (after summary)
135+
table = $( '<table class="widefat striped activitypub-site-blocked-' + type + '" role="presentation"><tbody></tbody></table>' );
136+
details.find( 'summary' ).after( table );
51137
}
52-
table.append( '<tr><td>' + value + '</td><td style="width: 80px;"><button type="button" class="button button-small remove-site-block-btn" data-type="' + type + '" data-value="' + value + '">Remove</button></td></tr>' );
138+
139+
table.find( 'tbody' ).append( createBlockedTermRow( type, value, context ) );
140+
141+
updateSiteBlockSummary( type );
142+
}
143+
}
144+
145+
/**
146+
* Helper function to update the site block summary count
147+
*/
148+
function updateSiteBlockSummary( type ) {
149+
var details = $( '.activitypub-site-block-details[data-type="' + type + '"]' );
150+
var table = details.find( '.activitypub-site-blocked-' + type );
151+
var count = table.find( 'tbody tr' ).length || table.find( 'tr' ).length;
152+
var summary = details.find( 'summary' );
153+
154+
if ( count === 0 ) {
155+
// Empty state
156+
var emptyText = type === 'domain'
157+
? __( 'No blocked domains', 'activitypub' )
158+
: __( 'No blocked keywords', 'activitypub' );
159+
summary.text( emptyText );
160+
details.attr( 'open', '' );
161+
table.remove();
162+
} else {
163+
// Has items - use _n for proper pluralization
164+
var text = type === 'domain'
165+
? _n( '%s blocked domain', '%s blocked domains', count, 'activitypub' )
166+
: _n( '%s blocked keyword', '%s blocked keywords', count, 'activitypub' );
167+
summary.text( sprintf( text, count ) );
53168
}
54169
}
55170

@@ -63,13 +178,11 @@
63178

64179
if ( button.length > 0 ) {
65180
// Remove the parent table row
66-
var parent = button.closest( 'tr' );
67-
var container = parent.closest( 'table' );
68-
parent.remove();
181+
button.closest( 'tr' ).remove();
69182

70-
// If the container is now empty, remove it
71-
if ( container.find( 'tr' ).length === 0 ) {
72-
container.remove();
183+
// Update the summary count for site blocks
184+
if ( context === 'site' ) {
185+
updateSiteBlockSummary( type );
73186
}
74187
}
75188
}
@@ -94,33 +207,7 @@
94207
var input = $( '#new_user_' + type );
95208
var value = input.val().trim();
96209

97-
if ( ! value ) {
98-
// Use wp.a11y.speak for better accessibility.
99-
if ( wp.a11y && wp.a11y.speak ) {
100-
wp.a11y.speak( activitypubModerationL10n.enterValue, 'assertive' );
101-
} else {
102-
alert( activitypubModerationL10n.enterValue );
103-
}
104-
return;
105-
}
106-
107-
// Validate domain format if this is a domain block
108-
if ( type === 'domain' && ! isValidDomain( value ) ) {
109-
var message = activitypubModerationL10n.invalidDomain || 'Please enter a valid domain (e.g., example.com).';
110-
if ( wp.a11y && wp.a11y.speak ) {
111-
wp.a11y.speak( message, 'assertive' );
112-
}
113-
alert( message );
114-
return;
115-
}
116-
117-
// Check if the term is already blocked
118-
if ( isTermAlreadyBlocked( type, value, 'user', userId ) ) {
119-
var message = activitypubModerationL10n.alreadyBlocked || 'This term is already blocked.';
120-
if ( wp.a11y && wp.a11y.speak ) {
121-
wp.a11y.speak( message, 'assertive' );
122-
}
123-
alert( message );
210+
if ( ! validateBlockedTerm( type, value, 'user', userId ) ) {
124211
return;
125212
}
126213

@@ -136,12 +223,8 @@
136223
input.val( '' );
137224
addBlockedTermToUI( type, value, 'user', userId );
138225
}).fail( function( response ) {
139-
var message = response && response.message ? response.message : activitypubModerationL10n.addBlockFailed;
140-
if ( wp.a11y && wp.a11y.speak ) {
141-
wp.a11y.speak( message, 'assertive' );
142-
} else {
143-
alert( message );
144-
}
226+
var message = response && response.message ? response.message : __( 'Failed to add block.', 'activitypub' );
227+
showMessage( message );
145228
});
146229
}
147230

@@ -157,12 +240,8 @@
157240
}).done( function() {
158241
removeBlockedTermFromUI( type, value, 'user' );
159242
}).fail( function( response ) {
160-
var message = response && response.message ? response.message : activitypubModerationL10n.removeBlockFailed;
161-
if ( wp.a11y && wp.a11y.speak ) {
162-
wp.a11y.speak( message, 'assertive' );
163-
} else {
164-
alert( message );
165-
}
243+
var message = response && response.message ? response.message : __( 'Failed to remove block.', 'activitypub' );
244+
showMessage( message );
166245
});
167246
}
168247

@@ -204,32 +283,7 @@
204283
var input = $( '#new_site_' + type );
205284
var value = input.val().trim();
206285

207-
if ( ! value ) {
208-
if ( wp.a11y && wp.a11y.speak ) {
209-
wp.a11y.speak( activitypubModerationL10n.enterValue, 'assertive' );
210-
} else {
211-
alert( activitypubModerationL10n.enterValue );
212-
}
213-
return;
214-
}
215-
216-
// Validate domain format if this is a domain block
217-
if ( type === 'domain' && ! isValidDomain( value ) ) {
218-
var message = activitypubModerationL10n.invalidDomain || 'Please enter a valid domain (e.g., example.com).';
219-
if ( wp.a11y && wp.a11y.speak ) {
220-
wp.a11y.speak( message, 'assertive' );
221-
}
222-
alert( message );
223-
return;
224-
}
225-
226-
// Check if the term is already blocked
227-
if ( isTermAlreadyBlocked( type, value, 'site' ) ) {
228-
var message = activitypubModerationL10n.alreadyBlocked || 'This term is already blocked.';
229-
if ( wp.a11y && wp.a11y.speak ) {
230-
wp.a11y.speak( message, 'assertive' );
231-
}
232-
alert( message );
286+
if ( ! validateBlockedTerm( type, value, 'site', null ) ) {
233287
return;
234288
}
235289

@@ -244,12 +298,8 @@
244298
input.val( '' );
245299
addBlockedTermToUI( type, value, 'site' );
246300
}).fail( function( response ) {
247-
var message = response && response.message ? response.message : activitypubModerationL10n.addBlockFailed;
248-
if ( wp.a11y && wp.a11y.speak ) {
249-
wp.a11y.speak( message, 'assertive' );
250-
} else {
251-
alert( message );
252-
}
301+
var message = response && response.message ? response.message : __( 'Failed to add block.', 'activitypub' );
302+
showMessage( message );
253303
});
254304
}
255305

@@ -264,12 +314,8 @@
264314
}).done( function() {
265315
removeBlockedTermFromUI( type, value, 'site' );
266316
}).fail( function( response ) {
267-
var message = response && response.message ? response.message : activitypubModerationL10n.removeBlockFailed;
268-
if ( wp.a11y && wp.a11y.speak ) {
269-
wp.a11y.speak( message, 'assertive' );
270-
} else {
271-
alert( message );
272-
}
317+
var message = response && response.message ? response.message : __( 'Failed to remove block.', 'activitypub' );
318+
showMessage( message );
273319
});
274320
}
275321

@@ -302,4 +348,4 @@
302348
// Initialize when document is ready.
303349
$( document ).ready( init );
304350

305-
})( jQuery );
351+
})( jQuery, wp );

includes/wp-admin/class-admin.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -342,22 +342,23 @@ public static function enqueue_moderation_scripts() {
342342
\wp_enqueue_script(
343343
'activitypub-moderation-admin',
344344
ACTIVITYPUB_PLUGIN_URL . 'assets/js/activitypub-moderation-admin.js',
345-
array( 'jquery', 'wp-util', 'wp-a11y' ),
345+
array( 'jquery', 'wp-util', 'wp-a11y', 'wp-i18n' ),
346346
ACTIVITYPUB_PLUGIN_VERSION,
347347
true
348348
);
349349

350+
\wp_set_script_translations(
351+
'activitypub-moderation-admin',
352+
'activitypub',
353+
ACTIVITYPUB_PLUGIN_DIR . 'languages'
354+
);
355+
350356
// Localize script with translations and nonces.
351357
\wp_localize_script(
352358
'activitypub-moderation-admin',
353359
'activitypubModerationL10n',
354360
array(
355-
'enterValue' => \__( 'Please enter a value to block.', 'activitypub' ),
356-
'addBlockFailed' => \__( 'Failed to add block.', 'activitypub' ),
357-
'removeBlockFailed' => \__( 'Failed to remove block.', 'activitypub' ),
358-
'alreadyBlocked' => \__( 'This term is already blocked.', 'activitypub' ),
359-
'invalidDomain' => \__( 'Please enter a valid domain (e.g., example.com).', 'activitypub' ),
360-
'nonce' => \wp_create_nonce( 'activitypub_moderation_settings' ),
361+
'nonce' => \wp_create_nonce( 'activitypub_moderation_settings' ),
361362
)
362363
);
363364
}

0 commit comments

Comments
 (0)