// SCToolbox WebView initialization script
// Uses IPC (window.ipc.postMessage) to communicate with Rust backend
(function () {
'use strict';
if (window._sctInitialized) return;
window._sctInitialized = true;
// ========== IPC Communication ==========
// Send message to Rust backend
function sendToRust(type, payload) {
if (window.ipc && typeof window.ipc.postMessage === 'function') {
window.ipc.postMessage(JSON.stringify({ type, payload }));
}
}
// ========== 导航栏 UI ==========
const icons = {
back: '',
forward: '',
reload: ''
};
// Global state from Rust
window._sctNavState = {
canGoBack: false,
canGoForward: false,
isLoading: true,
url: window.location.href
};
function createNavBar() {
if (window.location.href === 'about:blank') return;
if (document.getElementById('sct-navbar')) return;
if (!document.body) {
setTimeout(createNavBar, 50);
return;
}
const nav = document.createElement('div');
nav.id = 'sct-navbar';
nav.innerHTML = `
`;
document.body.insertBefore(nav, document.body.firstChild);
// Navigation buttons - send commands to Rust
document.getElementById('sct-back').onclick = () => {
sendToRust('nav_back', {});
};
document.getElementById('sct-forward').onclick = () => {
sendToRust('nav_forward', {});
};
document.getElementById('sct-reload').onclick = () => {
sendToRust('nav_reload', {});
};
// Apply initial state from Rust
updateNavBarFromState();
// Request initial state from Rust
sendToRust('get_nav_state', {});
}
// Update navbar UI based on state from Rust
function updateNavBarFromState() {
const state = window._sctNavState;
const backBtn = document.getElementById('sct-back');
const forwardBtn = document.getElementById('sct-forward');
const urlEl = document.getElementById('sct-navbar-url');
const spinner = document.getElementById('sct-spinner');
const faviconSlot = document.getElementById('sct-favicon-slot');
if (backBtn) {
backBtn.disabled = !state.canGoBack;
}
if (forwardBtn) {
forwardBtn.disabled = !state.canGoForward;
}
if (urlEl && state.url) {
urlEl.value = state.url;
}
// Show spinner when loading, show favicon when complete
if (state.isLoading) {
if (spinner) {
spinner.style.display = 'block';
spinner.setAttribute('aria-hidden', 'false');
spinner.setAttribute('aria-busy', 'true');
}
if (faviconSlot) {
faviconSlot.style.display = 'none';
}
} else {
if (spinner) {
spinner.style.display = 'none';
spinner.setAttribute('aria-hidden', 'true');
spinner.setAttribute('aria-busy', 'false');
}
// Show favicon when page is loaded
showFaviconIfAvailable();
}
}
// Extract and show favicon from page
function showFaviconIfAvailable() {
const faviconSlot = document.getElementById('sct-favicon-slot');
const faviconImg = document.getElementById('sct-favicon');
if (!faviconSlot || !faviconImg) return;
// Try to find favicon from page
let faviconUrl = null;
// 1. Look for link[rel="icon"] or link[rel="shortcut icon"]
const linkIcon = document.querySelector('link[rel="icon"], link[rel="shortcut icon"], link[rel="apple-touch-icon"]');
if (linkIcon && linkIcon.href) {
faviconUrl = linkIcon.href;
}
// 2. Look for og:image in meta tags (fallback)
if (!faviconUrl) {
const ogImage = document.querySelector('meta[property="og:image"]');
if (ogImage && ogImage.content) {
faviconUrl = ogImage.content;
}
}
// 3. Try default favicon.ico
if (!faviconUrl) {
try {
const origin = window.location.origin;
if (origin && origin !== 'null') {
faviconUrl = origin + '/favicon.ico';
}
} catch (e) {
// Ignore
}
}
// Display favicon if found
if (faviconUrl) {
faviconImg.src = faviconUrl;
faviconImg.onerror = () => {
faviconSlot.style.display = 'none';
};
faviconImg.onload = () => {
faviconSlot.style.display = 'flex';
};
} else {
faviconSlot.style.display = 'none';
}
}
// ========== Rust -> JS Message Handler ==========
// Rust will call this function to update navigation state
window._sctUpdateNavState = function (state) {
if (state) {
window._sctNavState = {
canGoBack: !!state.can_go_back,
canGoForward: !!state.can_go_forward,
isLoading: !!state.is_loading,
url: state.url || window.location.href
};
updateNavBarFromState();
}
};
// 在 DOM 准备好时创建导航栏
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', createNavBar);
} else {
createNavBar();
}
})();