/** * Content Blocker – admin.js * Color-picker init + service repeater (add / remove rows). */ ( function ( $ ) { 'use strict'; /* ── Color pickers ── */ function initColorPickers( ctx ) { $( '.cb-color-picker', ctx ).wpColorPicker(); } /* ── Live header update: "interner-name — Anbietername" ── */ function syncTitle( box ) { const id = ( $( '.cb-input-id', box ).val() || '' ).trim(); const name = ( $( '.cb-input-name', box ).val() || '' ).trim(); const head = ( id || ( cbAdmin.newServiceLbl || 'neu' ) ) + ( name ? ' — ' + name : '' ); $( '.cb-service-title', box ).first().text( head ); } function bindNameSync( box ) { $( '.cb-input-name, .cb-input-id', box ).on( 'input', function () { syncTitle( box ); } ); } /* ── Expand / collapse a service box ── */ function setExpanded( box, open ) { $( '.cb-service-grid', box ).toggle( open ); const $btn = $( '.cb-service-toggle', box ); $btn.attr( 'aria-expanded', open ? 'true' : 'false' ).text( open ? '▾' : '▸' ); } /* Delegated once on document → works for existing AND dynamically added rows, * and is resilient to load-order issues. */ $( document ).on( 'click', '.cb-service-toggle, .cb-service-title', function () { const box = $( this ).closest( '.cb-service-box' ); const open = $( '.cb-service-toggle', box ).attr( 'aria-expanded' ) !== 'true'; setExpanded( box, open ); } ); function bindToggle( box ) { // No-op kept for call sites; toggling is handled by delegation above. } /* ── Re-index a row's field names after a remove ── */ function reindexRows() { $( '#cb-services-list .cb-service-box' ).each( function ( i ) { $( this ).attr( 'data-cb-index', i ); $( this ).find( '[name]' ).each( function () { const n = $( this ).attr( 'name' ); $( this ).attr( 'name', n.replace( /cb_services\[\d+\]/, 'cb_services[' + i + ']' ) ); } ); } ); } /* ── Add a new (optionally prefilled) service row ── */ function addServiceRow( preset ) { const index = $( '#cb-services-list .cb-service-box' ).length; const template = $( '#cb-service-template' ).html(); const newHtml = template.replace( /__INDEX__/g, index ); const $box = $( newHtml ); $( '#cb-services-list' ).append( $box ); bindNameSync( $box ); bindToggle( $box ); $box.find( '.cb-remove-service' ).on( 'click', handleRemove ); if ( preset ) { fillPreset( $box, preset ); } setExpanded( $box, true ); // new rows start expanded for editing syncTitle( $box ); return $box; } /* ── Fill a row from a preset object ── */ function fillPreset( $box, p ) { const setText = function ( field, val ) { $box.find( '[name$="[' + field + ']"]' ).val( val != null ? val : '' ); }; const setBool = function ( field, val ) { $box.find( '[name$="[' + field + ']"]' ).prop( 'checked', !! val ); }; setText( 'id', p.id ); setText( 'name', p.name ); setText( 'match_pattern', p.match_pattern ); setText( 'recipient', p.recipient ); setText( 'privacy_url', p.privacy_url ); setText( 'purpose', p.purpose ); setBool( 'third_country', p.third_country ); setBool( 'sets_cookie', p.sets_cookie ); setBool( 'loads_script', p.loads_script ); $box.find( '.cb-service-title' ).text( p.name || cbAdmin.newServiceLbl ); } /* ── Add empty service ── */ $( '#cb-add-service' ).on( 'click', function () { addServiceRow( null ); } ); /* ── Insert preset ── */ $( '#cb-preset-select' ).on( 'change', function () { const key = $( this ).val(); if ( ! key || ! cbAdmin.presets || ! cbAdmin.presets[ key ] ) { return; } addServiceRow( cbAdmin.presets[ key ] ); $( this ).val( '' ); // reset so the same preset can be added again } ); /* ── Remove service ── */ function handleRemove() { if ( ! window.confirm( cbAdmin.confirmRemove ) ) { return; } $( this ).closest( '.cb-service-box' ).remove(); reindexRows(); } /* ── Tab switching ── */ $( '[data-cb-tab]' ).on( 'click', function ( e ) { e.preventDefault(); activateTab( $( this ).data( 'cb-tab' ) ); } ); /* ── Website scan ── */ $( '#cb-scan-btn' ).on( 'click', function () { const $btn = $( this ).prop( 'disabled', true ); const i18n = cbAdmin.i18n || {}; $( '#cb-scan-status' ).text( i18n.scanning || 'Scanning…' ); $( '#cb-scan-results' ).empty(); $.post( cbAdmin.ajaxUrl, { action: 'cb_scan', nonce: cbAdmin.scanNonce } ) .done( function ( resp ) { if ( ! resp || ! resp.success ) { const msg = resp && resp.data && resp.data.message ? resp.data.message : 'Error'; $( '#cb-scan-status' ).text( ( i18n.scanError || 'Scan failed:' ) + ' ' + msg ); return; } $( '#cb-scan-status' ).text( '' ); renderScan( resp.data ); } ) .fail( function ( xhr ) { $( '#cb-scan-status' ).text( ( i18n.scanError || 'Scan failed:' ) + ' ' + xhr.status ); } ) .always( function () { $btn.prop( 'disabled', false ); } ); } ); function renderScan( data ) { const i18n = cbAdmin.i18n || {}; const findings = ( data && data.findings ) || []; const $out = $( '#cb-scan-results' ).empty(); // Scanned pages summary if ( data && data.scanned && data.scanned.length ) { const $p = $( '
' ).text( ( i18n.scannedPages || 'Scanned:' ) + ' ' ); data.scanned.forEach( function ( s, i ) { if ( i > 0 ) $p.append( ', ' ); $p.append( $( '' ).text( s.url + ( s.error ? ' (!)' : '' ) ) );
} );
$out.append( $p );
}
if ( ! findings.length ) {
$out.append( $( '' ).text( i18n.noFindings || 'No external resources found.' ) );
return;
}
const $table = $( '' ).css( { fontSize: '11px', wordBreak: 'break-all' } ).text( sample ) );
$tr.append( $ex );
// Does a ready-made template exist for this finding?
const preset = ( f.preset && cbAdmin.presets && cbAdmin.presets[ f.preset ] )
? cbAdmin.presets[ f.preset ]
: null;
// Status
const $st = $( '