Skip to content

Commit 5e45f11

Browse files
committed
fix: refactor version switch JS
ref: #251 (comment)
1 parent 79b0e56 commit 5e45f11

File tree

5 files changed

+207
-107
lines changed

5 files changed

+207
-107
lines changed

src/js/services/settings/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { handleSettingsTabs } from './tabs'
22
export { handleEditorPreviewUpdates } from './editor-preview'
3+
export { initVersionSwitch } from './version'
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
// Handles version switching UI on the settings screen.
2+
// Exported init function so callers can opt-in like other settings modules.
3+
// Uses vanilla DOM APIs and the global `code_snippets_version_switch` config
4+
// injected by PHP via wp_add_inline_script.
5+
6+
interface VersionConfig {
7+
ajaxurl?: string
8+
nonce_switch?: string
9+
nonce_refresh?: string
10+
11+
}
12+
13+
interface AjaxResponse {
14+
success?: boolean
15+
data?: {
16+
message?: string
17+
}
18+
}
19+
20+
declare global {
21+
interface Window {
22+
code_snippets_version_switch?: VersionConfig
23+
__code_snippets_i18n?: Record<string, string>
24+
}
25+
}
26+
27+
const el = (id: string): HTMLElement | null => document.getElementById(id)
28+
29+
const getConfig = (): VersionConfig => {
30+
const w = <{ code_snippets_version_switch?: VersionConfig }><unknown>window
31+
return w.code_snippets_version_switch ?? {}
32+
}
33+
34+
const getCurrentVersion = (): string => (document.querySelector('.current-version')?.textContent ?? '').trim()
35+
36+
const getI18n = (key: string, fallback: string): string => window.__code_snippets_i18n?.[key] ?? fallback
37+
38+
const bindDropdown = (
39+
dropdown: HTMLSelectElement,
40+
button: HTMLButtonElement | null,
41+
currentVersion: string,
42+
): void => {
43+
dropdown.addEventListener('change', (): void => {
44+
const selectedVersion = dropdown.value
45+
if (!button) {
46+
return
47+
}
48+
if (!selectedVersion || selectedVersion === currentVersion) {
49+
button.disabled = true
50+
const warn = el('version-switch-warning')
51+
if (warn) { warn.setAttribute('style', 'display: none;') }
52+
} else {
53+
button.disabled = false
54+
const warn = el('version-switch-warning')
55+
if (warn) { warn.setAttribute('style', '') }
56+
}
57+
})
58+
}
59+
60+
const SUCCESS_RELOAD_MS = 3000
61+
62+
const postForm = async (data: Record<string, string>, cfg: VersionConfig): Promise<AjaxResponse> => {
63+
const body = new URLSearchParams()
64+
Object.keys(data).forEach(k => body.append(k, data[k]))
65+
const resp = await fetch(cfg.ajaxurl ?? '/wp-admin/admin-ajax.php', {
66+
method: 'POST',
67+
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
68+
body: body.toString(),
69+
credentials: 'same-origin',
70+
})
71+
const json = <AjaxResponse> await resp.json()
72+
return json
73+
}
74+
75+
const bindSwitch = (
76+
button: HTMLButtonElement,
77+
dropdown: HTMLSelectElement,
78+
result: HTMLDivElement,
79+
cfg: VersionConfig,
80+
currentVersion: string,
81+
): void => {
82+
button.addEventListener('click', (): void => {
83+
void (async (): Promise<void> => {
84+
const targetVersion = dropdown.value
85+
if (!targetVersion || targetVersion === currentVersion) {
86+
result.className = 'notice notice-warning'
87+
result.innerHTML = `<p>${getI18n('selectDifferent', 'Please select a different version to switch to.')}</p>`
88+
result.style.display = ''
89+
return
90+
}
91+
92+
button.disabled = true
93+
const originalText = button.textContent ?? ''
94+
button.textContent = getI18n('switching', 'Switching...')
95+
96+
result.className = 'notice notice-info'
97+
result.innerHTML = `<p>${getI18n('processing', 'Processing version switch. Please wait...')}</p>`
98+
result.style.display = ''
99+
100+
try {
101+
const response = await postForm({
102+
action: 'code_snippets_switch_version',
103+
target_version: targetVersion,
104+
nonce: cfg.nonce_switch ?? '',
105+
}, cfg)
106+
107+
if (response.success) {
108+
result.className = 'notice notice-success'
109+
result.innerHTML = `<p>${response.data?.message ?? ''}</p>`
110+
setTimeout(() => window.location.reload(), SUCCESS_RELOAD_MS)
111+
return
112+
}
113+
114+
result.className = 'notice notice-error'
115+
result.innerHTML = `<p>${response.data?.message ?? getI18n('error', 'An error occurred.')}</p>`
116+
button.disabled = false
117+
button.textContent = originalText
118+
} catch (_err) {
119+
result.className = 'notice notice-error'
120+
result.innerHTML = `<p>${getI18n('errorSwitch', 'An error occurred while switching versions. Please try again.')}</p>`
121+
button.disabled = false
122+
button.textContent = originalText
123+
}
124+
})()
125+
})
126+
}
127+
128+
const REFRESH_RELOAD_MS = 1000
129+
130+
const bindRefresh = (
131+
btn: HTMLButtonElement,
132+
cfg: VersionConfig,
133+
): void => {
134+
btn.addEventListener('click', (): void => {
135+
void (async (): Promise<void> => {
136+
const original = btn.textContent ?? ''
137+
btn.disabled = true
138+
btn.textContent = getI18n('refreshing', 'Refreshing...')
139+
140+
try {
141+
await postForm({
142+
action: 'code_snippets_refresh_versions',
143+
nonce: cfg.nonce_refresh ?? '',
144+
}, cfg)
145+
146+
btn.textContent = getI18n('refreshed', 'Refreshed!')
147+
setTimeout(() => {
148+
btn.disabled = false
149+
btn.textContent = original
150+
window.location.reload()
151+
}, REFRESH_RELOAD_MS)
152+
} catch {
153+
btn.disabled = false
154+
btn.textContent = original
155+
}
156+
})()
157+
})
158+
}
159+
160+
export const initVersionSwitch = (): void => {
161+
const cfg = getConfig()
162+
const currentVersion = getCurrentVersion()
163+
164+
const button = <HTMLButtonElement | null> el('switch-version-btn')
165+
const dropdown = <HTMLSelectElement | null> el('target_version')
166+
const result = <HTMLDivElement | null> el('version-switch-result')
167+
const refreshBtn = <HTMLButtonElement | null> el('refresh-versions-btn')
168+
169+
if (dropdown) {
170+
bindDropdown(dropdown, button, currentVersion)
171+
}
172+
173+
if (button && dropdown && result) {
174+
bindSwitch(button, dropdown, result, cfg, currentVersion)
175+
}
176+
177+
if (refreshBtn) {
178+
bindRefresh(refreshBtn, cfg)
179+
}
180+
}
181+
182+

src/js/settings.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { handleEditorPreviewUpdates, handleSettingsTabs } from './services/settings'
1+
import { handleEditorPreviewUpdates, handleSettingsTabs, initVersionSwitch } from './services/settings'
22

33
handleSettingsTabs()
44
handleEditorPreviewUpdates()
5+
initVersionSwitch()

src/php/settings/editor-preview.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,25 @@ function enqueue_editor_preview_assets() {
6363
$inline_script = 'var code_snippets_editor_settings = ' . wp_json_encode( $editor_fields ) . ';';
6464

6565
wp_add_inline_script( 'code-snippets-settings-menu', $inline_script, 'before' );
66+
67+
// Provide configuration and simple i18n for the version switch JS module.
68+
$version_switch = array(
69+
'ajaxurl' => admin_url( 'admin-ajax.php' ),
70+
'nonce_switch' => wp_create_nonce( 'code_snippets_version_switch' ),
71+
'nonce_refresh' => wp_create_nonce( 'code_snippets_refresh_versions' ),
72+
);
73+
74+
$strings = array(
75+
'selectDifferent' => esc_html__( 'Please select a different version to switch to.', 'code-snippets' ),
76+
'switching' => esc_html__( 'Switching...', 'code-snippets' ),
77+
'processing' => esc_html__( 'Processing version switch. Please wait...', 'code-snippets' ),
78+
'error' => esc_html__( 'An error occurred.', 'code-snippets' ),
79+
'errorSwitch' => esc_html__( 'An error occurred while switching versions. Please try again.', 'code-snippets' ),
80+
'refreshing' => esc_html__( 'Refreshing...', 'code-snippets' ),
81+
'refreshed' => esc_html__( 'Refreshed!', 'code-snippets' ),
82+
);
83+
84+
wp_add_inline_script( 'code-snippets-settings-menu', 'var code_snippets_version_switch = ' . wp_json_encode( $version_switch ) . '; var __code_snippets_i18n = ' . wp_json_encode( $strings ) . ';', 'before' );
6685
}
6786

6887
/**

src/php/settings/version-switch.php

Lines changed: 3 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -286,40 +286,33 @@ function log_version_switch_attempt( string $target_version, $result, string $de
286286
* @return array Result array with success status and message
287287
*/
288288
function handle_version_switch( string $target_version ): array {
289-
// Check user capabilities
289+
290290
if ( ! current_user_can( 'update_plugins' ) ) {
291291
return create_error_response( __( 'You do not have permission to update plugins.', 'code-snippets' ) );
292292
}
293293

294-
// Validate target version
295294
$available_versions = get_available_versions();
296295
$validation = validate_target_version( $target_version, $available_versions );
297296

298297
if ( ! $validation['success'] ) {
299298
return create_error_response( $validation['message'] );
300299
}
301300

302-
// Check if already on target version
303301
if ( get_current_version() === $target_version ) {
304302
return create_error_response( __( 'Already on the specified version.', 'code-snippets' ) );
305303
}
306304

307-
// Set switch in progress
308305
set_transient( PROGRESS_KEY, $target_version, PROGRESS_TIMEOUT );
309306

310-
// Perform the version installation
311307
$install_result = perform_version_install( $validation['download_url'] );
312308

313-
// Clear progress transient
314309
delete_transient( PROGRESS_KEY );
315310

316-
// Handle the result
317311
if ( is_wp_error( $install_result ) ) {
318312
return create_error_response( $install_result->get_error_message() );
319313
}
320314

321315
if ( $install_result ) {
322-
// Clear version cache on success
323316
delete_transient( VERSION_CACHE_KEY );
324317

325318
return [
@@ -331,7 +324,6 @@ function handle_version_switch( string $target_version ): array {
331324
];
332325
}
333326

334-
// If we get here, the installation failed but didn't return a WP_Error
335327
return handle_installation_failure( $target_version, $validation['download_url'], $install_result );
336328
}
337329

@@ -384,76 +376,7 @@ function render_version_switch_field( array $args ): void {
384376

385377
<div id="version-switch-result" class="notice" style="display: none;"></div>
386378
<?php endif; ?>
387-
</div>
388-
389-
<script type="text/javascript">
390-
jQuery(document).ready(function($) {
391-
var currentVersion = '<?php echo esc_js( $current_version ); ?>';
392-
var $button = $('#switch-version-btn');
393-
var $dropdown = $('#target_version');
394-
var $result = $('#version-switch-result');
395-
396-
// Handle dropdown changes - enable/disable button and show/hide warning
397-
$dropdown.on('change', function() {
398-
var selectedVersion = $(this).val();
399-
400-
if (!selectedVersion || selectedVersion === currentVersion) {
401-
// Current version or no selection - disable button and hide warning
402-
$button.prop('disabled', true);
403-
$('#version-switch-warning').hide();
404-
} else {
405-
// Different version selected - enable button and show warning
406-
$button.prop('disabled', false);
407-
$('#version-switch-warning').show();
408-
}
409-
});
410-
411-
$button.on('click', function() {
412-
var targetVersion = $dropdown.val();
413-
414-
if (!targetVersion || targetVersion === currentVersion) {
415-
$result.removeClass('notice-success notice-error').addClass('notice-warning')
416-
.html('<p><?php esc_html_e( 'Please select a different version to switch to.', 'code-snippets' ); ?></p>')
417-
.show();
418-
return;
419-
}
420-
421-
// Disable button and show loading
422-
$button.prop('disabled', true).text('<?php esc_html_e( 'Switching...', 'code-snippets' ); ?>');
423-
$result.removeClass('notice-success notice-error notice-warning').addClass('notice-info')
424-
.html('<p><?php esc_html_e( 'Processing version switch. Please wait...', 'code-snippets' ); ?></p>')
425-
.show();
426-
427-
// Make AJAX request
428-
$.post(ajaxurl, {
429-
action: 'code_snippets_switch_version',
430-
target_version: targetVersion,
431-
nonce: '<?php echo esc_js( wp_create_nonce( 'code_snippets_version_switch' ) ); ?>'
432-
})
433-
.done(function(response) {
434-
if (response.success) {
435-
$result.removeClass('notice-info notice-error').addClass('notice-success')
436-
.html('<p>' + response.data.message + '</p>');
437-
438-
// Refresh page after 3 seconds
439-
setTimeout(function() {
440-
window.location.reload();
441-
}, 3000);
442-
} else {
443-
$result.removeClass('notice-info notice-success').addClass('notice-error')
444-
.html('<p>' + response.data.message + '</p>');
445-
$button.prop('disabled', false).text('<?php esc_html_e( 'Switch Version', 'code-snippets' ); ?>');
446-
}
447-
})
448-
.fail(function() {
449-
$result.removeClass('notice-info notice-success').addClass('notice-error')
450-
.html('<p><?php esc_html_e( 'An error occurred while switching versions. Please try again.', 'code-snippets' ); ?></p>');
451-
$button.prop('disabled', false).text('<?php esc_html_e( 'Switch Version', 'code-snippets' ); ?>');
452-
});
453-
});
454-
});
455-
</script>
456-
<?php
379+
</div><?php
457380
}
458381

459382
/**
@@ -504,33 +427,7 @@ function render_refresh_versions_field( array $args ): void {
504427
</button>
505428
<p class="description">
506429
<?php esc_html_e( 'Check for the latest available plugin versions from WordPress.org.', 'code-snippets' ); ?>
507-
</p>
508-
509-
<script type="text/javascript">
510-
jQuery(document).ready(function($) {
511-
$('#refresh-versions-btn').on('click', function() {
512-
var $button = $(this);
513-
$button.prop('disabled', true).text('<?php esc_html_e( 'Refreshing...', 'code-snippets' ); ?>');
514-
515-
$.post(ajaxurl, {
516-
action: 'code_snippets_refresh_versions',
517-
nonce: '<?php echo esc_js( wp_create_nonce( 'code_snippets_refresh_versions' ) ); ?>'
518-
})
519-
.done(function(response) {
520-
$button.text('<?php esc_html_e( 'Refreshed!', 'code-snippets' ); ?>');
521-
setTimeout(function() {
522-
$button.prop('disabled', false).text('<?php esc_html_e( 'Refresh Available Versions', 'code-snippets' ); ?>');
523-
// Reload page to show updated versions
524-
window.location.reload();
525-
}, 1000);
526-
})
527-
.fail(function() {
528-
$button.prop('disabled', false).text('<?php esc_html_e( 'Refresh Available Versions', 'code-snippets' ); ?>');
529-
});
530-
});
531-
});
532-
</script>
533-
<?php
430+
</p><?php
534431
}
535432

536433
/**

0 commit comments

Comments
 (0)