diff --git a/Lib/WeDevs_Settings_API.php b/Lib/WeDevs_Settings_API.php index 48cffe45b..836d73ddb 100644 --- a/Lib/WeDevs_Settings_API.php +++ b/Lib/WeDevs_Settings_API.php @@ -345,11 +345,15 @@ function callback_multicheck( $args ) { } /** - * Displays a Texty-style card grid for selecting payment gateways + * Displays a card grid for selecting payment gateways. * - * Renders each gateway as a clickable card with icon and name. - * Multiple cards can be checked (multi-select). Clicking a card - * also reveals that gateway's settings panel below the grid. + * Each gateway renders as a focusable card. Clicking (or pressing + * Enter/Space on) a card opens its settings panel; settings rows for + * non-focused gateways stay hidden. The hidden card checkbox is driven + * by an "Enable Gateway" toggle injected at the top of each panel by + * the settings JS — that is the only control that enables/disables + * the gateway. Pro-preview gateways are filtered out before reaching + * this callback (see wpuf_get_gateways() with 'gateway_selector' context). * * @since 4.3.1 * @@ -361,8 +365,8 @@ function callback_gateway_selector( $args ) { $value = $this->get_option( $args['id'], $args['section'], $args['std'] ); $value = $value ? $value : []; - // Inline SVG fallback icons (no image files exist for these) - $bank_svg = ''; + // Generic fallback icon for unknown gateways without a registered icon URL. + // Known gateways (paypal/bank/stripe) get branded icons via assets/css/admin/settings.css. $generic_svg = ''; ?>
@@ -370,49 +374,36 @@ function callback_gateway_selector( $args ) {
$gateway ) : - $is_checked = in_array( $key, $value, true ); - $is_pro = ! empty( $gateway['is_pro_preview'] ) && $gateway['is_pro_preview']; - $disabled = $is_pro ? 'disabled' : ''; - $active_class = $is_checked ? ' wpuf-gateway-card--active' : ''; - $pro_class = $is_pro ? ' wpuf-gateway-card--pro-locked' : ''; - $icon = ! empty( $gateway['icon'] ) ? $gateway['icon'] : ''; - $admin_label = $gateway['admin_label']; + $is_checked = in_array( $key, $value, true ); + $active_class = $is_checked ? ' wpuf-gateway-card--active' : ''; + $icon = ! empty( $gateway['icon'] ) ? $gateway['icon'] : ''; + // Strip any HTML embedded in the registered admin_label so it cannot + // leak markup into the card name or downstream JS read of textContent. + $admin_label = wp_strip_all_tags( $gateway['admin_label'] ); ?> -
+
- /> - - + />
<?php echo esc_attr( $admin_label ); ?> - -
- +
diff --git a/assets/css/admin.css b/assets/css/admin.css index 7c1b94ca3..78a95b2b5 100644 --- a/assets/css/admin.css +++ b/assets/css/admin.css @@ -676,7 +676,7 @@ tr.pro-preview .pro-field-overlay, top: 0; left: 0; display: none; - border: 1px dashed #10b981; + border: 1px dashed #059669; } tr.pro-preview-html th { width: 50%; @@ -723,7 +723,7 @@ tr.pro-preview td .wp-picker-container input { background: rgba(236, 253, 245, 0.5); border-radius: 5px; display: none; - border: 1px dashed #10b981; + border: 1px dashed #059669; z-index: 10; pointer-events: auto; } @@ -759,7 +759,7 @@ a.wpuf-button.button-upgrade-to-pro { } .wpuf-subscription-pack-settings nav .tab-current a.wpuf-button.button-upgrade-to-pro:hover, a.wpuf-button.button-upgrade-to-pro:hover { - background: #10b981; + background: #059669; } span.pro-icon { display: inline-flex; @@ -782,12 +782,6 @@ span.pro-icon img { position: relative; top: -1px; } -/* span.pro-icon.icon-white svg path { - fill: #fff; -} */ -/* label span.pro-icon svg path { - fill: #10b981; -} */ img.profile-header, img.user-listing { display: block; @@ -1526,18 +1520,14 @@ body.wpuf-modal-open { box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06); } .wpuf-gateway-card--active:hover { - border-color: #10b981; + border-color: #059669; } .wpuf-gateway-card--focused { - border-color: #10b981; - box-shadow: 0 0 0 1px #10b981; + border-color: #059669; + box-shadow: 0 0 0 1px #059669; } .wpuf-gateway-card--focused:hover { - border-color: #10b981; -} -.wpuf-gateway-card--pro-locked { - opacity: 0.6; - cursor: not-allowed; + border-color: #059669; } .wpuf-gateway-card__checkbox { position: absolute; @@ -1546,30 +1536,6 @@ body.wpuf-modal-open { height: 0; pointer-events: none; } -.wpuf-gateway-card__toggle { - position: absolute; - top: 4px; - right: 4px; - cursor: pointer; - line-height: 1; - padding: 4px; - z-index: 2; -} -.wpuf-gateway-card__toggle:hover { - opacity: 0.8; -} -.wpuf-gateway-card__check-on { - display: none; -} -.wpuf-gateway-card__check-off { - display: block; -} -.wpuf-gateway-card--active .wpuf-gateway-card__check-on { - display: block; -} -.wpuf-gateway-card--active .wpuf-gateway-card__check-off { - display: none; -} .wpuf-gateway-card__icon { display: flex; align-items: center; diff --git a/assets/css/admin/settings.css b/assets/css/admin/settings.css new file mode 100644 index 000000000..4cb20b9d7 --- /dev/null +++ b/assets/css/admin/settings.css @@ -0,0 +1,81 @@ +/* Gateway selector cards — settings-page sizing + brand SVG icons */ +.wpuf-gateway-card { + width: 140px !important; + padding: 18px 14px 14px !important; + border-width: 1px !important; +} +.wpuf-gateway-card:focus-visible { + outline: 2px solid #059669; + outline-offset: 2px; +} +.wpuf-gateway-card__icon { + height: 44px !important; + margin-bottom: 8px !important; + background-repeat: no-repeat; + background-position: center; + background-size: 56px auto !important; + overflow: visible; +} +.wpuf-gateway-card__name { + font-size: 13px !important; +} + +/* Enable Gateway toggle switch (in per-gateway settings panel) */ +.wpuf-gateway-toggle { + position: relative; + display: inline-block; + width: 44px; + height: 24px; + vertical-align: middle; +} +.wpuf-gateway-toggle__input { + opacity: 0; + width: 0; + height: 0; + position: absolute; +} +.wpuf-gateway-toggle__slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + transition: background-color 0.2s ease; + border-radius: 24px; +} +.wpuf-gateway-toggle__slider::before { + position: absolute; + content: ""; + height: 18px; + width: 18px; + left: 3px; + bottom: 3px; + background-color: #fff; + border-radius: 50%; + transition: transform 0.2s ease; +} +.wpuf-gateway-toggle__input:checked + .wpuf-gateway-toggle__slider { + background-color: #0073aa; +} +.wpuf-gateway-toggle__input:checked + .wpuf-gateway-toggle__slider::before { + transform: translateX(20px); +} +.wpuf-gateway-toggle__input:focus-visible + .wpuf-gateway-toggle__slider { + box-shadow: 0 0 0 2px rgba(0, 115, 170, 0.35); +} +.wpuf-gateway-card[data-gateway="paypal"] .wpuf-gateway-card__icon > *, +.wpuf-gateway-card[data-gateway="bank"] .wpuf-gateway-card__icon > *, +.wpuf-gateway-card[data-gateway="stripe"] .wpuf-gateway-card__icon > * { + display: none !important; +} +.wpuf-gateway-card[data-gateway="paypal"] .wpuf-gateway-card__icon { + background-image: url("data:image/svg+xml;utf8,"); +} +.wpuf-gateway-card[data-gateway="bank"] .wpuf-gateway-card__icon { + background-image: url("data:image/svg+xml;utf8,"); +} +.wpuf-gateway-card[data-gateway="stripe"] .wpuf-gateway-card__icon { + background-image: url("data:image/svg+xml;utf8,"); +} diff --git a/assets/js/admin/settings.js b/assets/js/admin/settings.js index 964533b21..082e2a514 100644 --- a/assets/js/admin/settings.js +++ b/assets/js/admin/settings.js @@ -1,59 +1,59 @@ (function () { - document.addEventListener('DOMContentLoaded',function () { - var tabs = document.querySelector('.wpuf-settings-wrap').querySelectorAll('h2 a'); + document.addEventListener('DOMContentLoaded', function () { + var tabs = document.querySelector('.wpuf-settings-wrap').querySelectorAll('h2 a'); var content = document.querySelectorAll('.wpuf-settings-wrap .metabox-holder th'); - var close = document.querySelector('#wpuf-search-section span'); + var close = document.querySelector('#wpuf-search-section span'); var search_input = document.querySelector('#wpuf-settings-search'); search_input.addEventListener('keyup', function (e) { var search_value = e.target.value.toLowerCase(); - var value_tab = []; + var value_tab = []; - if ( search_value.length ) { + if (search_value.length) { close.style.display = 'flex'; content.forEach(function (row, index) { var content_id = row.closest('div').getAttribute('id'); - var tab_id = content_id + '-tab'; - var found_value = row.innerText.toLowerCase().includes( search_value ); + var tab_id = content_id + '-tab'; + var found_value = row.innerText.toLowerCase().includes(search_value); - if ( found_value ){ + if (found_value) { row.closest('tr').style.display = 'table-row'; - }else { + } else { row.closest('tr').style.display = 'none'; } - if ( 'wpuf_mails' === content_id ){ + if ('wpuf_mails' === content_id) { row.closest('tbody').querySelectorAll('tr').forEach(function (tr) { tr.style.display = ''; }); } - if ( found_value === true && ! value_tab.includes( tab_id ) ) { + if (found_value === true && !value_tab.includes(tab_id)) { value_tab.push(tab_id); } }) - if ( value_tab.length ) { + if (value_tab.length) { document.getElementById(value_tab[0]).click(); } tabs.forEach(function (tab) { var tab_id = tab.getAttribute('id'); - if ( ! value_tab.includes( tab_id ) ){ + if (!value_tab.includes(tab_id)) { document.getElementById(tab_id).style.display = 'none'; - }else { + } else { document.getElementById(tab_id).style.display = 'block'; } }); - }else { + } else { wpuf_search_reset(); } }) - close.addEventListener('click',function (event) { + close.addEventListener('click', function (event) { wpuf_search_reset(); search_input.value = ''; close.style.display = 'none'; @@ -65,7 +65,7 @@ function wpuf_search_reset() { content.forEach(function (row, index) { var content_id = row.closest('div').getAttribute('id'); - var tab_id = content_id + '-tab'; + var tab_id = content_id + '-tab'; document.getElementById(content_id).style.display = ''; document.getElementById(tab_id).style.display = ''; document.getElementById('wpuf_general-tab').click(); @@ -75,13 +75,25 @@ }); } + + }); + var wpufI18n = window.wpufSettingsI18n || {}; + function wpufSprintf(template, value) { + return String(template).replace('%s', value); + } + function wpufEscapeRegex(str) { + return String(str).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + /** * Gateway Selector Card Grid * - * Handles card click to toggle checkbox (multi-select) and - * shows only the clicked gateway's settings rows below. + * Card click opens that gateway's settings panel; settings rows for + * non-focused gateways stay hidden. Within the focused gateway, + * non-enable rows stay hidden until the "Enable Gateway" toggle is on. + * The hidden card checkbox is driven by that toggle. */ function wpufInitGatewaySelector() { var container = document.querySelector('.wpuf-gateway-cards'); @@ -90,20 +102,14 @@ return; } - // Map gateway IDs to their settings field name prefixes. - // PayPal fields: paypal_*, gate_instruct_paypal - // Bank fields: bank_*, gate_instruct_bank - // Generic pattern: field name contains the gateway ID var gatewayCards = container.querySelectorAll('.wpuf-gateway-card'); - - // Find the that contains the gateway selector itself - var selectorRow = container.closest('tr'); + var selectorRow = container.closest('tr'); if ( ! selectorRow ) { return; } - // Collect all siblings after the selector row in the same table + // Collect all siblings after the selector row in the same table. var formTable = selectorRow.closest('table'); var allRows = formTable ? formTable.querySelectorAll('tr') : []; var afterRows = []; @@ -114,28 +120,32 @@ pastSelector = true; return; } - if ( pastSelector ) { afterRows.push(row); } }); - // Fields whose names don't contain a gateway ID but belong to one + // Fields whose names don't contain a gateway ID but belong to one. var fieldGatewayMap = { 'failed_retry': 'paypal', }; + // Build gateway id list + boundary regex map once. + var gatewayIds = []; + var gatewayRegexMap = {}; + gatewayCards.forEach(function(card) { + var id = card.getAttribute('data-gateway'); + if ( ! id ) return; + gatewayIds.push(id); + gatewayRegexMap[id] = new RegExp('(^|_)' + wpufEscapeRegex(id) + '(_|$)'); + }); + /** * Determine which gateway a settings row belongs to by * checking the name attribute of inputs/selects/textareas inside it. */ function getRowGatewayId(row) { var inputs = row.querySelectorAll('input, select, textarea'); - var gatewayIds = []; - - gatewayCards.forEach(function(card) { - gatewayIds.push(card.getAttribute('data-gateway')); - }); for ( var i = 0; i < inputs.length; i++ ) { var name = inputs[i].getAttribute('name') || ''; @@ -152,9 +162,7 @@ for ( var j = 0; j < gatewayIds.length; j++ ) { var gid = gatewayIds[j]; - - // Match: gate_instruct_paypal, paypal_email, bank_success, etc. - if ( fieldName.indexOf(gid) !== -1 || fieldName.indexOf('gate_instruct_' + gid) !== -1 ) { + if ( gatewayRegexMap[gid].test(fieldName) ) { return gid; } } @@ -185,7 +193,7 @@ } for ( var m = 0; m < gatewayIds.length; m++ ) { - if ( forFieldName.indexOf(gatewayIds[m]) !== -1 ) { + if ( gatewayRegexMap[gatewayIds[m]].test(forFieldName) ) { return gatewayIds[m]; } } @@ -206,102 +214,123 @@ } }); - /** - * Update the focused (green border) state on gateway cards - */ - function setFocusedCard(gatewayId) { - gatewayCards.forEach(function(card) { - if ( card.getAttribute('data-gateway') === gatewayId ) { - card.classList.add('wpuf-gateway-card--focused'); - } else { - card.classList.remove('wpuf-gateway-card--focused'); - } - }); - } + var formTbody = formTable ? formTable.querySelector('tbody') : null; + + // Hide all gateway settings rows by default; card click reveals one gateway's rows. + // Within the focused gateway, non-enable rows stay hidden until that gateway is enabled. + function showGateway(gatewayId) { + var focusedCard = container.querySelector('.wpuf-gateway-card[data-gateway="' + gatewayId + '"]'); + var focusedCheckbox = focusedCard ? focusedCard.querySelector('.wpuf-gateway-card__checkbox') : null; + var enabled = focusedCheckbox ? focusedCheckbox.checked : false; - /** - * Show settings rows for a specific gateway, hide others - */ - function showGatewaySettings(gatewayId) { afterRows.forEach(function(row) { - if ( ! row.classList.contains('wpuf-gateway-setting-row') ) { + if ( ! row.classList.contains('wpuf-gateway-setting-row') ) return; + + if ( row.getAttribute('data-gateway-id') !== gatewayId ) { + row.classList.add('wpuf-gateway-setting-hidden'); return; } - if ( row.getAttribute('data-gateway-id') === gatewayId ) { + if ( row.classList.contains('wpuf-gateway-enable-row') || enabled ) { row.classList.remove('wpuf-gateway-setting-hidden'); } else { row.classList.add('wpuf-gateway-setting-hidden'); } }); - setFocusedCard(gatewayId); - } - - /** - * Hide all gateway-specific settings rows - */ - function hideAllGatewaySettings() { - afterRows.forEach(function(row) { - if ( row.classList.contains('wpuf-gateway-setting-row') ) { - row.classList.add('wpuf-gateway-setting-hidden'); + gatewayCards.forEach(function(card) { + if ( card.getAttribute('data-gateway') === gatewayId ) { + card.classList.add('wpuf-gateway-card--focused'); + } else { + card.classList.remove('wpuf-gateway-card--focused'); } }); - - setFocusedCard(null); } - // Checkbox change handler (triggered by the