(function ($) { "use strict"; const qs = (selector, root = document) => root.querySelector(selector); const qsa = (selector, root = document) => Array.from(root.querySelectorAll(selector)); const config = window.wpawSettingsV2 || {}; function showToast(message, type = "success") { const toast = qs("#wpaw2-toast"); const body = qs("#wpaw2-toast-message"); if (!toast || !body) return; body.textContent = message; toast.className = "toast show toast-" + type; clearTimeout(toast._timer); toast._timer = setTimeout(() => { toast.classList.remove("show"); }, 2600); } function bindToastHover() { const toast = qs("#wpaw2-toast"); if (!toast) return; toast.addEventListener("mouseenter", () => { clearTimeout(toast._timer); }); toast.addEventListener("mouseleave", () => { toast._timer = setTimeout(() => { toast.classList.remove("show"); }, 1200); }); } function activateTab(target) { qsa("[data-aw2-tab]").forEach((button) => { const active = button.dataset.aw2Tab === target; button.setAttribute("aria-selected", active ? "true" : "false"); }); qsa(".tab-panel").forEach((panel) => { panel.classList.toggle("active", panel.id === target); }); const crumb = qs("#wpaw2-crumb-tab"); const activeButton = qs(`[data-aw2-tab="${target}"]`); if (crumb && activeButton) crumb.textContent = activeButton.dataset.label || activeButton.textContent.trim(); } function bindTabs() { qsa("[data-aw2-tab]").forEach((button) => { button.addEventListener("click", () => activateTab(button.dataset.aw2Tab), ); }); qsa("[data-aw2-subtab-target]").forEach((button) => { button.addEventListener("click", (e) => { const target = e.currentTarget.dataset.aw2SubtabTarget; const nav = e.currentTarget.closest(".subtab-nav"); const panelContainer = nav.parentElement; nav.querySelectorAll("[data-aw2-subtab-target]").forEach((btn) => { btn.setAttribute( "aria-selected", btn === e.currentTarget ? "true" : "false", ); }); panelContainer.querySelectorAll(".subtab-panel").forEach((panel) => { if (panel.id === target) { panel.classList.add("active"); } else { panel.classList.remove("active"); } }); }); }); } function bindPasswordToggles() { qsa("[data-aw2-toggle-password]").forEach((button) => { button.addEventListener("click", () => { const input = qs(button.dataset.aw2TogglePassword); if (!input) return; const isPassword = input.type === "password"; input.type = isPassword ? "text" : "password"; button.textContent = isPassword ? "Hide" : "Show"; }); }); } function bindCopyButtons() { qsa("[data-aw2-copy]").forEach((button) => { button.addEventListener("click", async () => { const source = qs(button.dataset.aw2Copy); if (!source) return; try { await navigator.clipboard.writeText(source.textContent.trim()); showToast("Copied command"); } catch (error) { showToast("Copy failed", "error"); } }); }); } function getModelsForType(type) { const bucket = config.models?.[type] || config.models?.execution || config.models?.planning || {}; const all = Array.isArray(bucket.all) ? bucket.all : []; const recommended = Array.isArray(bucket.recommended) ? bucket.recommended : []; const merged = [...all]; recommended.forEach((model) => { if (!merged.find((item) => item.id === model.id)) merged.push(model); }); return merged; } function modelTypeFromSelect(select) { const match = select.name.match(/\[(.+?)_model\]/); return match ? match[1] : "writing"; } function formatModelData(models) { return models.map((model) => ({ id: model.id, text: model.name || model.id, pricing: model.pricing || {}, is_free: Boolean(model.is_free), is_custom: Boolean(model.is_custom), })); } function formatModelOption(model) { if (!model.id) return model.text; const $row = $('
'); const $name = $('').text(model.text); $row.append($name); if (model.is_custom) { $row.append('Custom'); } else if (model.is_free) { $row.append('Free'); } else { const prompt = parseFloat(model.pricing?.prompt) || 0; const image = parseFloat(model.pricing?.image) || 0; const price = image > 0 ? image : prompt; if (price > 0) $row.append( $('').text( `$${(price * 1000000).toFixed(2)}/1M`, ), ); } return $row; } function initSelect2() { if (!$.fn.select2) return; const $languageSelect = $("#preferred_languages"); if ($languageSelect.length) { if ($languageSelect.data("select2")) { $languageSelect.select2("destroy"); } $languageSelect.select2({ width: "100%", placeholder: "Select preferred languages...", dropdownCssClass: "wpaw2-select2-dropdown", }); } qsa(".wpaw2-model-select").forEach((select) => { const type = modelTypeFromSelect(select); const models = getModelsForType(type); const currentValue = select.value || config.currentModels?.[type] || ""; const $select = $(select); if ($select.data("select2")) { $select.select2("destroy"); } $select.empty().select2({ width: "100%", data: formatModelData(models), placeholder: config.i18n?.searchPlaceholder || "Search models...", allowClear: true, dropdownCssClass: "wpaw2-select2-dropdown", templateResult: formatModelOption, templateSelection: (model) => model.text || model.id, language: { noResults: () => config.i18n?.noResults || "No models found", }, }); if (currentValue) { const model = models.find((item) => item.id === currentValue); const option = new Option( model?.name || currentValue, currentValue, true, true, ); $select.append(option).trigger("change"); } }); } function setSelectValue(select, value) { if (!select || !value) return; let option = Array.from(select.options).find( (item) => item.value === value, ); if (!option) { option = new Option(value, value, true, true); select.add(option); } select.value = value; if ($.fn.select2 && $(select).data("select2")) $(select).trigger("change"); else select.dispatchEvent(new Event("change", { bubbles: true })); } function bindPresetCards() { const presets = config.presets || {}; qsa("[data-aw2-preset]").forEach((card) => { card.addEventListener("click", () => { const preset = presets[card.dataset.aw2Preset]; if (!preset) return; Object.entries(preset).forEach(([key, value]) => { setSelectValue( qs(`[name="wp_agentic_writer_settings[${key}_model]"]`), value, ); }); qsa("[data-aw2-preset]").forEach((item) => item.classList.remove("active"), ); card.classList.add("active"); updateEstimate(); showToast("Preset applied"); }); }); } function updateEstimate() { const writing = qs('[name="wp_agentic_writer_settings[writing_model]"]')?.value || ""; const image = qs('[name="wp_agentic_writer_settings[image_model]"]')?.value || ""; let estimate = 0.14; const text = `${writing} ${image}`.toLowerCase(); if (text.includes("mistral") || text.includes("flash")) estimate = 0.06; if ( text.includes("gpt-4.1") || text.includes("opus") || text.includes("premium") ) estimate = 0.31; const output = qs("#wpaw2-cost-estimate"); if (output) output.textContent = `~$${estimate.toFixed(2)}`; } function bindEstimateInputs() { qsa(".wpaw2-model-select").forEach((select) => select.addEventListener("change", updateEstimate), ); updateEstimate(); } function bindTogglePanels() { qsa("[data-aw2-toggle-panel]").forEach((input) => { const panel = qs(input.dataset.aw2TogglePanel); if (!panel) return; const sync = () => { panel.hidden = !input.checked; }; input.addEventListener("change", sync); sync(); }); } function bindCustomModels() { const list = qs("#wpaw2-custom-models"); const add = qs("#wpaw2-add-custom-model"); if (!list || !add) return; add.addEventListener("click", () => { const row = document.createElement("div"); row.className = "custom-row"; row.innerHTML = ''; list.appendChild(row); }); list.addEventListener("click", (event) => { if (event.target.matches("[data-remove]")) event.target.closest(".custom-row")?.remove(); }); } function ajaxPost(action, data) { return $.ajax({ url: config.ajaxUrl, type: "POST", data: { action, nonce: config.nonce, ...data, }, }); } function bindAjaxButton(selector, action, getData, loadingText, onSuccess) { const button = qs(selector); if (!button) return; const original = button.textContent; button.addEventListener("click", () => { button.disabled = true; button.textContent = loadingText || "Testing..."; ajaxPost(action, getData ? getData() : {}) .done((response) => { if (response?.success && typeof onSuccess === "function") { onSuccess(response); } let message = response?.data?.message || (response?.success ? "Connection successful" : "Connection failed"); if (response?.data?.models_count) { message += ` (${response.data.models_count} models)`; } showToast(message, response?.success ? "success" : "error"); }) .fail((xhr) => { showToast( xhr.responseJSON?.data?.message || "Request failed", "error", ); }) .always(() => { button.disabled = false; button.textContent = original; }); }); } function loadCostLog() { const tbody = qs("#wpaw-cost-log-tbody"); if (!tbody) return; tbody.innerHTML = '| Action | Calls | Models | Input | Output | Cost |
|---|