Skip to content

Instantly share code, notes, and snippets.

@Pathologic
Created March 15, 2026 11:11
Show Gist options
  • Select an option

  • Save Pathologic/f9da96cce9de50872e505ab74a64351f to your computer and use it in GitHub Desktop.

Select an option

Save Pathologic/f9da96cce9de50872e505ab74a64351f to your computer and use it in GitHub Desktop.
Evo snippets call converter to php
<!DOCTYPE html>
<html>
<head>
<title>Конвертер вызовов сниппетов MODX</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 20px auto; padding: 0 20px; }
textarea { width: 100%; height: 200px; margin-bottom: 10px; font-family: monospace; }
.button-group { display: flex; gap: 10px; margin-bottom: 10px; }
button { padding: 10px 20px; background: #4CAF50; color: white; border: none; cursor: pointer; border-radius: 4px; }
button:hover { background: #45a049; }
.clear-btn { background: #f44336; }
.clear-btn:hover { background: #da190b; }
.result { margin-top: 20px; }
pre { background: #f4f4f4; padding: 10px; border-radius: 4px; overflow-x: auto; }
.example { background: #e8f4f8; padding: 10px; border-radius: 4px; margin-bottom: 15px; font-size: 14px; }
.note { color: #666; font-size: 12px; margin-top: 5px; }
</style>
</head>
<body>
<h2>Конвертер MODX: [!...!] / [[...]] → evo()->runSnippet()</h2>
<div class="example">
<strong>Примеры:</strong><br>
[!mySnippet? &param=`value` &number=`123` &json=`{"key":"value"}` !]<br>
[[getResources? &parents=`3` &tpl=`item` &limit=`10` ]]<br>
[!DocLister? &display=`12` &tpl=`item` !]
</div>
<label for="input">Введите вызов сниппета:</label>
<textarea id="input" placeholder="[!mySnippet? &param=`value` !] или [[mySnippet? &param=`value` ]]">[[getResources?
&parents=`3`
&tpl=`item`
&limit=`10`
&includeTVs=`1`
&tvPrefix=``
]]</textarea>
<div class="button-group">
<button onclick="convert()">Конвертировать</button>
<button onclick="clearInput()" class="clear-btn">Очистить поле</button>
</div>
<div class="result">
<label for="output">Результат:</label>
<pre id="output"></pre>
<button onclick="copyToClipboard()" id="copyBtn" style="margin-top: 5px;">Копировать</button>
</div>
<script>
function escapeSingleQuotes(str) {
// Экранируем одинарные кавычки, но не трогаем уже экранированные
return str.replace(/(?<!\\)'/g, "\\'");
}
function formatJSONValue(value, indent = 4) {
const spaces = ' '.repeat(indent);
if (Array.isArray(value)) {
if (value.length === 0) return '[]';
const items = value.map(item => {
if (typeof item === 'string') {
return `'${escapeSingleQuotes(item)}'`;
} else if (Array.isArray(item) || typeof item === 'object') {
return formatJSONValue(item, indent + 4);
} else {
return item;
}
}).join(',\n' + spaces);
return `[\n${spaces}${items}\n${' '.repeat(indent - 4)}]`;
}
if (typeof value === 'object' && value !== null) {
const entries = Object.entries(value).map(([k, v]) => {
let formattedValue;
if (typeof v === 'string') {
formattedValue = `'${escapeSingleQuotes(v)}'`;
} else if (Array.isArray(v) || typeof v === 'object') {
formattedValue = formatJSONValue(v, indent + 4);
} else {
formattedValue = v;
}
return ` '${k}' => ${formattedValue}`;
}).join(',\n' + spaces);
return `[\n${spaces}${entries}\n${' '.repeat(indent - 4)}]`;
}
return value;
}
function processJSONObject(obj) {
if (Array.isArray(obj)) {
return obj.map(item => {
if (typeof item === 'object' && item !== null) {
return processJSONObject(item);
} else if (typeof item === 'string') {
if (/^\d+$/.test(item)) {
return parseInt(item, 10);
} else if (/^\d+\.\d+$/.test(item)) {
return parseFloat(item);
}
return item;
}
return item;
});
} else if (typeof obj === 'object' && obj !== null) {
const result = {};
for (const [key, val] of Object.entries(obj)) {
if (typeof val === 'object' && val !== null) {
result[key] = processJSONObject(val);
} else if (typeof val === 'string') {
if (/^\d+$/.test(val)) {
result[key] = parseInt(val, 10);
} else if (/^\d+\.\d+$/.test(val)) {
result[key] = parseFloat(val);
} else {
result[key] = val;
}
} else {
result[key] = val;
}
}
return result;
}
return obj;
}
function extractSnippetName(input) {
// Улучшенное регулярное выражение для извлечения имени сниппета
// Ищем после [! или [[ до ? или пробела или конца строки
const match = input.match(/\[\!?(\w+)(?:\?|\s|\])/);
if (match && match[1]) {
return match[1];
}
// Если не нашли с ? или пробелом, пробуем просто взять слово после тега
const fallbackMatch = input.match(/\[\!?(\w+)/);
return fallbackMatch ? fallbackMatch[1] : 'SnippetName';
}
function cleanInput(input) {
// Удаляем внешние теги [! !] или [[ ]]
// Более аккуратная очистка, сохраняющая все параметры
let cleaned = input.replace(/^\[\!?/, '').replace(/\!?\]$/, '').trim();
// Убираем знак вопроса после имени сниппета, если он есть
cleaned = cleaned.replace(/^(\w+)\?/, '$1');
return cleaned;
}
function unescapeBackslashes(str) {
// Преобразуем обратно экранированные символы, кроме одинарных кавычек
return str.replace(/\\([^'])/g, '$1');
}
function convertCallToEvo(input) {
// Извлекаем имя сниппета
const snippetName = extractSnippetName(input);
// Очищаем входную строку от тегов
const cleanString = cleanInput(input);
// Регулярное выражение для извлечения параметров
const regex = /&(\w+)=`([^`]*)`/g;
const params = {};
let match;
while ((match = regex.exec(cleanString)) !== null) {
const key = match[1];
let value = match[2];
// Пробуем распарсить JSON
try {
const trimmed = value.trim();
if ((trimmed.startsWith('{') && trimmed.endsWith('}')) ||
(trimmed.startsWith('[') && trimmed.endsWith(']'))) {
const parsed = JSON.parse(trimmed);
if (Array.isArray(parsed)) {
value = parsed.map(item => {
if (typeof item === 'string') {
if (/^\d+$/.test(item)) {
return parseInt(item, 10);
} else if (/^\d+\.\d+$/.test(item)) {
return parseFloat(item);
}
}
return item;
});
} else if (typeof parsed === 'object' && parsed !== null) {
value = processJSONObject(parsed);
} else {
value = parsed;
}
} else {
// Не JSON, обрабатываем как обычную строку
value = unescapeBackslashes(value);
if (/^\d+$/.test(value)) {
value = parseInt(value, 10);
} else if (/^\d+\.\d+$/.test(value)) {
value = parseFloat(value);
}
}
} catch {
// Не JSON, обрабатываем как обычную строку
value = unescapeBackslashes(value);
if (/^\d+$/.test(value)) {
value = parseInt(value, 10);
} else if (/^\d+\.\d+$/.test(value)) {
value = parseFloat(value);
}
}
params[key] = value;
}
// Форматируем массив параметров в строку
const paramsString = Object.entries(params)
.map(([key, value]) => {
if (typeof value === 'string') {
return ` '${key}' => '${escapeSingleQuotes(value)}'`;
} else if (Array.isArray(value) || typeof value === 'object') {
const formattedValue = formatJSONValue(value);
return ` '${key}' => ${formattedValue}`;
} else {
return ` '${key}' => ${value}`;
}
})
.join(',\n');
// Если параметров нет
if (paramsString.length === 0) {
return `evo()->runSnippet('${snippetName}')`;
}
return `evo()->runSnippet('${snippetName}', [\n${paramsString}\n])`;
}
function convert() {
const input = document.getElementById('input').value;
const output = document.getElementById('output');
try {
const result = convertCallToEvo(input);
output.textContent = result;
} catch (error) {
output.textContent = 'Ошибка конвертации: ' + error.message;
}
}
function clearInput() {
document.getElementById('input').value = '';
document.getElementById('output').textContent = '';
}
function copyToClipboard() {
const output = document.getElementById('output').textContent;
navigator.clipboard.writeText(output).then(() => {
const btn = document.getElementById('copyBtn');
btn.textContent = 'Скопировано!';
setTimeout(() => {
btn.textContent = 'Копировать';
}, 2000);
});
}
window.onload = convert;
</script>
<div class="note">
<strong>Примечание:</strong> Конвертер поддерживает оба формата: [!snippet!] и [[snippet]].
Числовые значения и JSON преобразуются автоматически. Одинарные кавычки в строках правильно экранируются.
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment