Files
MyTemplateGenerator/src/webview/templateVarsWebview.ts

193 lines
9.5 KiB
TypeScript

// Webview для выбора шаблона и переменных
import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';
import { getAllTemplateVariables } from '../core/templateUtils';
import { I18N_DICTIONARIES } from '../core/i18n';
import { writeConfig, readConfig } from '../core/config';
export async function showTemplateAndVarsWebview(
context: vscode.ExtensionContext,
templatesDir: string,
targetPath: string,
initialLanguage: string
): Promise<{ template: string, vars: Record<string, string> } | undefined> {
let language = initialLanguage;
function getDict() {
return I18N_DICTIONARIES[language] || I18N_DICTIONARIES['ru'];
}
const templates = fs.readdirSync(templatesDir).filter(f => fs.statSync(path.join(templatesDir, f)).isDirectory());
// Стили теперь лежат в media/styles.css (папка для статики)
const stylePath = vscode.Uri.joinPath(context.extensionUri, 'media', 'styles.css');
return new Promise((resolve) => {
const panel = vscode.window.createWebviewPanel(
'templateVars',
getDict().create,
vscode.ViewColumn.Active,
{ enableScripts: true }
);
const styleUri = panel.webview.asWebviewUri(stylePath);
let currentVars: string[] = [];
let currentTemplate = templates[0] || '';
let disposed = false;
function getVarsHtml(vars: string[], values: Record<string, string> = {}) {
const dict = getDict();
if (!vars.length) return '';
return `<h3>${dict.enterVariables}</h3>
<div class="var-hint">${dict.varInputHint}</div>
<form id="varsForm">
${vars.map(v => `
<label><input name="${v}" placeholder="{{${v}}}" value="${values[v] || ''}" required /></label><br/><br/>
`).join('')}
<button type="submit" class="btn">${dict.create}</button>
</form>`;
}
function getTemplatesRadioHtml(templates: string[], selected: string) {
const dict = getDict();
return `<form id="templateForm">
<h3>${dict.chooseTemplate}:</h3>
<div class="template-list">
${templates.map(t => `
<label><input type="radio" name="templateRadio" value="${t}" ${selected === t ? 'checked' : ''}/> ${t}</label>
`).join('')}
</div>
</form>`;
}
function getLanguageSelectorHtml(selected: string) {
return `<label class="lang-select">
<select id="languageSelect">
<option value="ru" ${selected === 'ru' ? 'selected' : ''}>Русский</option>
<option value="en" ${selected === 'en' ? 'selected' : ''}>English</option>
</select>
</label>`;
}
function setHtml(templatesHtml: string, varsHtml: string) {
const dict = getDict();
panel.webview.html = `
<!DOCTYPE html>
<html lang="${language}">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${panel.webview.cspSource}; script-src 'unsafe-inline';">
<title>${dict.create}</title>
<link rel="stylesheet" href="${styleUri}">
</head>
<body>
<div class="create-container">
<div class="head-wrap">
<h2>${dict.create}</h2>
${getLanguageSelectorHtml(language)}
</div>
<div id="templatesBlock">
${templatesHtml}
</div>
<div id="varsBlock">
${varsHtml}
</div>
</div>
<script>
(function() {
const vscode = acquireVsCodeApi();
function initHandlers() {
// Template radio
const templateRadios = document.querySelectorAll('input[name="templateRadio"]');
templateRadios.forEach(radio => {
radio.addEventListener('change', (e) => {
vscode.postMessage({ type: 'selectTemplate', template: e.target.value, language: document.getElementById('languageSelect').value });
});
});
// Vars form
const varsForm = document.getElementById('varsForm');
if (varsForm) {
varsForm.addEventListener('submit', (e) => {
e.preventDefault();
const data = {};
Array.from(varsForm.elements).forEach(el => {
if (el.name) data[el.name] = el.value;
});
vscode.postMessage({ type: 'submit', template: document.querySelector('input[name="templateRadio"]:checked')?.value || '', data, language: document.getElementById('languageSelect').value });
});
}
// Language select
const langSel = document.getElementById('languageSelect');
if (langSel) {
langSel.addEventListener('change', (e) => {
vscode.postMessage({ type: 'setLanguage', language: e.target.value, template: document.querySelector('input[name="templateRadio"]:checked')?.value || '' });
});
}
}
window.initHandlers = initHandlers;
document.addEventListener('DOMContentLoaded', initHandlers);
})();
</script>
</body>
</html>
`;
// После перерисовки HTML вызываем initHandlers
setTimeout(() => {
panel.webview.postMessage({ type: 'callInitHandlers' });
}, 0);
}
// Инициализация: сразу выбран первый шаблон и форма переменных
let initialVars: string[] = [];
if (currentTemplate) {
const templateDir = path.join(templatesDir, currentTemplate);
const allVars = getAllTemplateVariables(templateDir);
initialVars = Array.from(allVars);
currentVars = initialVars;
}
setHtml(getTemplatesRadioHtml(templates, currentTemplate), getVarsHtml(initialVars));
// Обработка сообщений
panel.webview.onDidReceiveMessage(
async message => {
if (message.type === 'selectTemplate') {
currentTemplate = message.template;
if (message.language) language = message.language;
if (!currentTemplate) {
setHtml(getTemplatesRadioHtml(templates, ''), '');
return;
}
// Получаем переменные для выбранного шаблона
const templateDir = path.join(templatesDir, currentTemplate);
const allVars = getAllTemplateVariables(templateDir);
currentVars = Array.from(allVars);
setHtml(getTemplatesRadioHtml(templates, currentTemplate), getVarsHtml(currentVars));
} else if (message.type === 'setLanguage') {
if (message.language) language = message.language;
// Сохраняем язык в конфиг
const oldConfig = readConfig();
writeConfig({ ...oldConfig, language });
currentTemplate = message.template || templates[0] || '';
// Получаем переменные для выбранного шаблона
let baseVars: string[] = [];
if (currentTemplate) {
const templateDir = path.join(templatesDir, currentTemplate);
const allVars = getAllTemplateVariables(templateDir);
baseVars = Array.from(allVars);
currentVars = baseVars;
}
setHtml(getTemplatesRadioHtml(templates, currentTemplate), getVarsHtml(currentVars));
} else if (message.type === 'changeLanguage') {
// legacy, не нужен
} else if (message.type === 'submit') {
if (message.language) language = message.language;
if (!disposed) {
disposed = true;
panel.dispose();
resolve({ template: message.template, vars: message.data });
}
} else if (message.type === 'callInitHandlers') {
// Ничего не делаем, скрипт внутри webview вызовет window.initHandlers
}
},
undefined,
context.subscriptions
);
panel.onDidDispose(() => {
if (!disposed) {
disposed = true;
resolve(undefined);
}
}, null, context.subscriptions);
});
}