SYAN

SYAN

С нами с 22 февраля 2017; Место в рейтинге пользователей: #325
Вчера в 01:40
0
Далее код оставил без изменений
<script type="text/javascript">
    // <![CDATA[
    {literal}
    Ext.onReady(function () {
        var fld = MODx.load({
            {/literal}
            xtype: 'textfield',
            applyTo: 'tv{$tv->id}',
            width: '99%',
            id: 'tv{$tv->id}',
            enableKeyEvents: true,
            allowBlank: {if $params.allowBlank == 1 || $params.allowBlank == 'true'}true{else}false{/if},
            value: '{$tv->value}',
            {literal}
            listeners: {'change': {fn: MODx.fireResourceFormChange, scope: this}},
        });
        Ext.getCmp('modx-panel-resource').getForm().add(fld);
        MODx.makeDroppable(fld);
    });
    {/literal}
    // ]]>
</script>

{$fields = [
'title' => $_config.videogallery_field_title,
'desc' => $_config.videogallery_field_desc,
'image' => $_config.videogallery_field_image,
'video' => $_config.videogallery_field_video,
'videoId' => $_config.videogallery_field_videoId,
'videoDuration' => $_config.videogallery_field_videoDuration
]}
{foreach from=$fields key=name item=item}
    {if $item != ''}
        {if substr($item, 0,3) == 'tv.'}
            {$vg_fields[$name] = str_replace('tv.', '', $item)}
            {$input_ids_data = "tv`$modx->getObject('modTemplateVar', ['name'=>$vg_fields[$name]] )->id`"}

            {if $input_ids_data != 'tv' AND $input_ids_data != ''}
                {$input_ids[$name] = $input_ids_data}
            {/if}
        {else}
            {$vg_fields[$name] = $item}
            {$input_ids[$name] = "modx-resource-`$vg_fields[$name]`"}
        {/if}
    {/if}
{/foreach}

<script type="text/javascript">
    // <![CDATA[
    Ext.onReady(function () {
        if (typeof vgHandlers == 'undefined') {
            vgHandlers = {
                /* */
            };
        }
        vgHandlers['{$tv->id}'] = new videoGalleryHandler({
            tv: '{$tv->id}',
            tvid: '{$tvid}',
            resource: {$modx->resource->id},
            actionUrl: MODx.config.assets_url + 'components/videogallery/connector.php?HTTP_MODAUTH=' + MODx.siteId + '&wctx=mgr&action=mgr/gallery/handle',
            selectors: {
                tvInput: '#tv{$tv->id}',
            },
            callbacks: {
                success: function (resp) {
                    var element = {
                        /* */
                    };
                    element['{$tv->id}'] = {
                        /* */
                    };

                    {foreach from=$fields key=name item=field}
                    {if $field != '' AND $field != 'tv'}
                    if (resp.object.hasOwnProperty('{$name}')) {
                        element['{$tv->id}']['{$name}'] = document.querySelector('#{$input_ids[$name]}');
                        if (element['{$tv->id}']['{$name}']) {
                            element['{$tv->id}']['{$name}'].value = resp.object['{$name}'];
                        }
                    }
                    {/if}
                    {/foreach}
                },
                reset: function () {
                    var element = {
                        /* */
                    };
                    element['{$tv->id}'] = {
                        /* */
                    };

                    {foreach from=$fields key=name item=field}
                    {if $field != '' AND $field != 'tv'}
                    element['{$tv->id}']['{$name}'] = document.querySelector('#{$input_ids[$name]}');
                    if (element['{$tv->id}']['{$name}']) {
                        element['{$tv->id}']['{$name}'].value = '';
                    }
                    {/if}
                    {/foreach}
                },
            },
        });
    });
    // ]]>
</script>

{* Fix "Smarty Compiler: Syntax error {/foreach} unclosed {foreach} tag" *}
{foreach from=$fields key=name item=field}
{/foreach}
Вчера в 01:38
0
Функция сохранения
<script type="text/javascript">
// <![CDATA[
Ext.onReady(function () {
    // Сохраняем исходные значения при загрузке
    const originalValues = {
        title: document.getElementById('vgTitle_{$tv->id}').value,
        desc: document.getElementById('vgDesc_{$tv->id}').value,
        video: document.getElementById('vgVideo_{$tv->id}').value,
        videoId: document.getElementById('vgVideoId_{$tv->id}').value,
        image: document.getElementById('vgImage_{$tv->id}').value,
        videoDuration: document.getElementById('vgVideoDuration_{$tv->id}').value
    };

    window.compareAndSave = function(tvId) {
        const currentValues = {
            title: document.getElementById('vgTitle_' + tvId).value,
            desc: document.getElementById('vgDesc_' + tvId).value,
            video: document.getElementById('vgVideo_' + tvId).value,
            videoId: document.getElementById('vgVideoId_' + tvId).value,
            image: document.getElementById('vgImage_' + tvId).value,
            videoDuration: document.getElementById('vgVideoDuration_' + tvId).value
        };

        // Проверяем, есть ли изменения
        let hasChanges = false;
        for (const key in currentValues) {
            if (currentValues[key] !== originalValues[key]) {
                hasChanges = true;
                break;
            }
        }

        if (!hasChanges) {
            alert('Нет изменений для сохранения.');
            return;
        }

        // Формируем новый JSON
        const newJson = JSON.stringify(currentValues);

        // Обновляем скрытое поле
        document.getElementById('tv' + tvId).value = newJson;

        // Сигнализируем MODX об изменении
        if (typeof MODx !== 'undefined' && MODx.fireResourceFormChange) {
            MODx.fireResourceFormChange();
        }

        alert('Данные сохранены!');

        // Обновляем исходные значения (чтобы следующие изменения сравнивались корректно)
        Object.assign(originalValues, currentValues);
    };

    // Интеграция с videoGalleryHandler
    if (typeof vgHandlers !== 'undefined' && vgHandlers['{$tv->id}']) {
        vgHandlers['{$tv->id}'].callbacks.success = function(resp) {
            // Обновляем поля формы
            document.getElementById('vgVideo_{$tv->id}').value = resp.object.video || '';
            document.getElementById('vgVideoId_{$tv->id}').value = resp.object.videoId || '';
            document.getElementById('vgImage_{$tv->id}').value = resp.object.image || '';
        };
    }
});
// ]]>
</script>

<style>
.videogallery-wrapper { padding:10px; border:1px solid #ddd; border-radius:4px; }
.videogallery-fields div { margin:10px 0; }
label { display:inline-block; width:120px; font-weight:bold; }
input,textarea { width:100%; padding:5px; box-sizing:border-box; }
</style>
09 февраля 2026, 20:43
+1
А вот все то же самое, только на fenom сразу вызов на странице без дополнительных чанков
{set $rows = $.php.array_reverse(json_decode($_modx->resource.videogallery, true))}
{if $rows && is_array($rows)}
<!-- Табы (заголовки) -->
<ul class="nav nav-tabs" id="videoTab" role="tablist">
    {foreach $rows as $idx => $row}
    <li class="nav-item" role="presentation">
        <button class="nav-link {if $idx == 0}active{/if}" id="videogal-tab-{$idx}" data-bs-toggle="tab" data-bs-target="#videogal{$idx}" type="button" role="tab" aria-controls="videogal{$idx}" aria-selected="{if $idx == 0}true{else}false{/if}">
            Источник {$idx + 1}
        </button>
    </li>
    {/foreach}
</ul>
<!-- Контент табов -->
<div class="tab-content" id="videoTabContent">
    {foreach $rows as $idx => $row}
    {* Декодируем JSON из поля video *}
    {set $videoData = json_decode(trim($row.video, '"') | replace:'\"':'"', true)}
    {if $videoData}
    <div class="tab-pane fade {if $idx == 0}show active{/if}" id="videogal{$idx}" role="tabpanel" aria-labelledby="videogal-tab-{$idx}">
        <!-- Видео -->
        <div class="pb-3">
            <div class="embed-responsive embed-responsive-16by9" style="width: 100%;">
                <iframe class="embed-responsive-item" src="{$videoData.video}" title="{$videoData.title | default:'Видео'}" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" webkitAllowFullScreen mozallowfullscreen allowFullScreen allowtransparency="true" name="main" style="width:100%; height:100%; background-image:url({$videoData.image | default:''}); background-size: cover; background-repeat: no-repeat; background-position: center center;"></iframe>
            </div>
        </div>
        <!-- Ссылка на источник -->
        <div class="pb-3">
            Видео в источнике: <ignore><a href="{$videoData.video}" target="_blank">{$videoData.video}</a></ignore>
        </div>
        <!-- Описание (если есть) -->
        {if isset($videoData.desc) && $videoData.desc}
        <div class="pb-3">{$videoData.desc | nl2br}</div>
        {/if}
    </div>
    {else}
    <!-- Резервный блок при ошибке декодирования -->
    <div class="tab-pane fade {if $idx == 0}show active{/if}" id="videogal{$idx}" role="tabpanel" aria-labelledby="videogal-tab-{$idx}">
        <p class="text-danger">Не удалось загрузить видео (ошибка JSON).</p>
    </div>
    {/if}
    {/foreach}
</div>
{else}
<p>Нет данных для отображения.</p>
{/if}
09 февраля 2026, 15:03
0
решение в итоге нашлось?
09 февраля 2026, 14:09
0
у меня заработала только эта конструкция. пробелы вокруг условия и двойные кавычки
&sort =`[{ "sortby":"MIGX_id", "sortdir":"DESC" }]`
09 февраля 2026, 13:37
0
Переносим все видео ранее созданные на сайте с tv-полями video =1 и video2 = 26 в новое tv-поле videogallery = 38
-- Шаг 1: увеличиваем лимит для текущей сессии
SET SESSION group_concat_max_len = 1000000;
-- Шаг 2: выполняем основной запрос
INSERT INTO modx_site_tmplvar_contentvalues (tmplvarid, contentid, value)
SELECT
    38 AS tmplvarid,
    src.contentid,
    CONCAT(
        '[',
        GROUP_CONCAT(
            CONCAT(
                '{',
                '"MIGX_id":"', src.migx_num, '",',
                '"video":"',
                REPLACE(
                    REPLACE(
                        REPLACE(src.value, '\\', '\\\\'),
                        '"', '\\"'
                    ),
                    '\n', '\\n'
                ),
                '"}'
            )
            ORDER BY src.migx_num
            SEPARATOR ','
        ),
        ']'
    ) AS value
FROM (
    SELECT t1.contentid, t1.value, 1 AS migx_num
    FROM modx_site_tmplvar_contentvalues t1
    WHERE tmplvarid = 1

    UNION ALL

    SELECT t26.contentid, t26.value, 2 AS migx_num
    FROM modx_site_tmplvar_contentvalues t26
    WHERE tmplvarid = 26
) AS src
GROUP BY src.contentid
ON DUPLICATE KEY UPDATE
    value = VALUES(value);
09 февраля 2026, 10:47
0
Для вывода данной migx videogallery в виде табов Источник1, Источник2 и тд

Чанк videogalleryVideosTabs.tpl
[[!VideoJsonToPlaceholders? &json=`[[+video]]` &prefix=`video[[+idx]].`]]
<li class="nav-item" role="videocase">
        <button class="nav-link [[+idx:isequal=`1`:then=`active`:else=``]]" id="videogal[[+idx]]-tab" data-bs-toggle="tab" data-bs-target="#videogal[[+idx]]" type="button" role="tab" aria-controls="videogal[[+idx]]" aria-selected="true">Источник [[+idx]]</button>
</li>`

Чанк videogalleryVideos.tpl
<div class="tab-pane fade [[+idx:isequal=`1`:then=`show active`:else=``]]"  id="videogal[[+idx]]" role="tabpanel" aria-labelledby="videogal[[+idx]]-tab">
        <div class="pb-3">
            <div class="embed-responsive embed-responsive-16by9" style="width: 100%;"> 
            <iframe class="embed-responsive-item" 
            src="[[+video[[+idx]].video]]" title="[[+video[[+idx]].title]]" 
            frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" 
            webkitAllowFullScreen mozallowfullscreen allowFullScreen allowtransparency="true" name="main" 
            style="width:100%;height:100%;background-image:url([[+video[[+idx]].image]]);background-size: cover; background-repeat: no-repeat;background-position: center center;">
            </iframe> 
            </div>
        </div>
        <div class="pb-3">видео в источнике <ignore><a href="[[+video[[+idx]].video]]" target="_blank">[[+video[[+idx]].video]]</a></ignore></div>
    </div>

Вызов на странице
<ul class="nav nav-tabs" id="videoTab" role="tablist">
[[!getImageList?
    &tvname=`videogallery`
    &tpl=`videogalleryVideosTabs.tpl`
]]
</ul>

<div class="tab-content" id="videoTabContent">
{'!getImageList' | snippet : [
'tvname' => 'videogallery',
'tpl' => 'videogalleryVideos.tpl']}
</div>
09 февраля 2026, 01:44
0
решал эту проблему следующим образом
  1. установил autoRedirector
  2. далее через phpMyAdmin
  3. экспортировал со старого сайта modx_site_content
  4. залил в базу к новому с именем modx_site_content_old
  5. сравнил две базы. если у одинаковых id ресурсов значения uri не совпадают, то добавил новые редиректы в базу modx_ar_rules
  6. удалил дубликаты записей в modx_ar_rules
  7. удалил modx_site_content_old
INSERT INTO `modx_ar_rules` (`res_id`, `context_key`, `uri`)
SELECT
    sc.id AS res_id,
    'web' AS context_key,
    sc2.uri AS uri
FROM
    modx_site_content sc
    LEFT JOIN modx_site_content_old sc2 ON sc.id = sc2.id
WHERE
sc.uri <> sc2.uri; -- uri не совпадают


DELETE FROM `modx_ar_rules`
WHERE id NOT IN (
    SELECT `min_id`
    FROM (
        SELECT MIN(id) AS min_id
        FROM modx_ar_rules
        GROUP BY `res_id`, `context_key`, `uri`
    ) AS keep
);
все четенько на 7К ресурсов в несколько кликов
29 января 2026, 11:29
+1
код для генерации схем MIGXdb
может кому пригодится или доработается
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>XML Generator for MIGX (Table View)</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
            color: #333;
        }
        .config-group {
            margin-bottom: 20px;
            padding: 15px;
            border: 1px solid #ddd;
            border-radius: 6px;
            background-color: #f9f9f9;
        }
        .config-group label {
            display: block;
            margin: 8px 0 4px;
            font-weight: bold;
            font-size: 0.9em;
        }
        .config-group input {
            width: 100%;
            padding: 8px;
            border: 1px solid #ccc;
            border-radius: 4px;
            box-sizing: border-box;
        }
        .mjg_input_rows {
            width: 100%;
            border-collapse: collapse;
            margin-bottom: 20px;
        }
        .mjg_input_rows th {
            background-color: #f2f2f2;
            text-align: left;
            padding: 12px;
            font-weight: bold;
            border: 1px solid #ddd;
        }
        .mjg_input_rows td {
            padding: 10px;
            border: 1px solid #ddd;
            vertical-align: top;
        }
        .mjg_input_field input,
        .mjg_input_caption input,
        .mjg_input_inputTVtype select {
            width: 100%;
            padding: 8px;
            border: 1px solid #ccc;
            border-radius: 4px;
            box-sizing: border-box;
        }
        .mjg_input_showintabs label,
        .mjg_input_sortable label {
            display: flex;
            align-items: center;
            gap: 5px;
        }
        .mjg_input_deleterow_action {
            color: #dc3545;
            cursor: pointer;
            font-weight: bold;
        }
        .mjg_input_rows_add_wr {
            margin: 15px 0;
        }
        .mjg_input_rows_add {
            display: inline-block;
            background: #28a745;
            color: white;
            padding: 10px 15px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 0.9em;
        }
        .mjg_input_rows_add:hover {
            background: #218838;
        }
        textarea {
            width: 100%;
            height: 300px;
            font-family: monospace;
            padding: 12px;
            border: 1px solid #ccc;
            border-radius: 4px;
            resize: vertical;
            box-sizing: border-box;
            margin-top: 10px;
            font-size: 0.95em;
        }
        h1 {
            color: #2c3e50;
            margin-bottom: 20px;
        }
        /* Стили для выпадающего списка опций (скрыт по умолчанию) */
        .mjg_input_inputTVtype_inputOptionValues {
            margin-top: 8px;
            display: none;
        }
        .mjg_input_inputTVtype_inputOptionValues_item {
            display: flex;
            gap: 8px;
            margin-bottom: 5px;
        }
        .mjg_input_inputTVtype_inputOptionValues_item input {
            flex: 1;
            padding: 6px;
        }
        .mjg_input_inputTVtype_inputOptionValues_item_delete {
            color: #dc3545;
            cursor: pointer;
            font-weight: bold;
        }
        .mjg_input_inputTVtype_inputOptionValues_add {
            color: #007bff;
            cursor: pointer;
            font-size: 0.85em;
            margin-top: 5px;
        }
    </style>
</head>
<body>
    <h1>Генератор XML для MIGX/MODX (Таблица)</h1>

    <!-- Основные настройки модели -->
    <div class="config-group">
        <label for="modelPackage">Package (model package)</label>
        <input type="text" id="modelPackage" value="mygallery" placeholder="Например: mygallery">

        <label for="objectClass">Class (object class)</label>
        <input type="text" id="objectClass" value="myGallery" placeholder="Например: myGallery">


        <label for="tableName">Table (table)</label>
        <input type="text" id="tableName" value="migx_gallery" placeholder="Например: migx_gallery">
    </div>

    <div class="mjg_input_rows">
        <table>
            <thead>
                <tr>
                    <th>Ключ (key)
<span style="font-size:12px;color:#888;">Например: title</span></th>
                    <th>Тип БД (dbtype)
<span style="font-size:12px;color:#888;">varchar, int и др.</span></th>
                    <th>Точность (precision)
<span style="font-size:12px;color:#888;">Для varchar/int</span></th>
                    <th>PHP-тип (phptype)
<span style="font-size:12px;color:#888;">string, integer и др.</span></th>
                    <th>NULL?</th>
                    <th>Значение по умолчанию</th>
                    <th>Индекс</th>
                    <th></th>
                </tr>
            </thead>
            <tbody id="fieldsContainer">
                <!-- Первая строка по умолчанию -->
                <tr class="mjg_input_row" id="field_1">
                    <td class="mjg_input_field">
                        <input type="text" name="key" placeholder="title" required>
                    </td>
                    <td class="mjg_input_dbtype">
                        <select name="dbtype" onchange="updatePhpType(this)">
                            <option value="varchar">varchar</option>
                            <option value="text">text</option>
                            <option value="int">int</option>
                            <option value="datetime">datetime</option>
                            <option value="tinyint">tinyint</option>
                            <option value="json">json</option>
                        </select>
                    </td>
                    <td class="mjg_input_precision">
                        <input type="text" name="precision" placeholder="255">
                    </td>
                    <td class="mjg_input_phptype">
                        <select name="phptype" required>
                            <option value="string">string</option>
                            <option value="integer">integer</option>
                            <option value="datetime">datetime</option>
                            <option value="json">json</option>
                        </select>
                    </td>
                    <td class="mjg_input_null">
                        <label><input type="checkbox" name="null" checked> Да</label>
                    </td>
                    <td class="mjg_input_default">
                        <input type="text" name="default" placeholder="0">
                    </td>
                    <td class="mjg_input_index">
                        <select name="index">
                            <option value="">—</option>
                            <option value="index">index</option>
                            <option value="fulltext">fulltext</option>
                                                        <option value="unique">unique</option>
                        </select>
                    </td>
                    <td class="mjg_input_deleterow">
                        <span class="mjg_input_deleterow_action" onclick="removeField('field_1')">X</span>
                    </td>
                </tr>
            </tbody>
        </table>
        <div class="mjg_input_rows_add_wr">
            <div class="mjg_input_rows_add" onclick="addField()">Добавить строку</div>
        </div>
    </div>

    <!-- Кнопка генерации XML -->
    <div style="margin: 20px 0;">
        <button type="button" onclick="generateXML()" style="
            background: #007bff;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 1em;
        ">Сгенерировать XML</button>
    </div>

    <h2>Результат (XML)</h2>
    <textarea id="output" placeholder="Здесь появится сгенерированный XML..." readonly></textarea>

    <script>
        let fieldCount = 1; // Начинаем с 1, т.к. первая строка уже есть

        function addField() {
            fieldCount++;
            const container = document.getElementById('fieldsContainer');

            const newRow = document.createElement('tr');
            newRow.className = 'mjg_input_row';
            newRow.id = `field_${fieldCount}`;

            newRow.innerHTML = `
                <td class="mjg_input_field">
                    <input type="text" name="key" placeholder="title" required>
                </td>
                <td class="mjg_input_dbtype">
                    <select name="dbtype" onchange="updatePhpType(this)">
                        <option value="varchar">varchar</option>
                        <option value="text">text</option>
                        <option value="int">int</option>
                        <option value="datetime">datetime</option>
                        <option value="tinyint">tinyint</option>
                        <option value="json">json</option>
                    </select>
                </td>
                <td class="mjg_input_precision">
                    <input type="text" name="precision" placeholder="255">
                </td>
                <td class="mjg_input_phptype">
                    <select name="phptype" required>
                        <option value="string">string</option>
                        <option value="integer">integer</option>
                        <option value="datetime">datetime</option>
                        <option value="json">json</option>
                    </select>
                </td>
                <td class="mjg_input_null">
                    <label><input type="checkbox" name="null" checked> Да</label>
                </td>
                <td class="mjg_input_default">
                    <input type="text" name="default" placeholder="0">
                </td>
                <td class="mjg_input_index">
                    <select name="index">
                        <option value="">—</option>
                        <option value="index">index</option>
                        <option value="fulltext">fulltext</option>
                        <option value="unique">unique</option>
                    </select>
                </td>
                <td class="mjg_input_deleterow">
                    <span class="mjg_input_deleterow_action" onclick="removeField('field_${fieldCount}')">X</span>
                </td>`;

            container.appendChild(newRow);
        }

        function removeField(id) {
            const el = document.getElementById(id);
            if (el) el.remove();
        }

        function updatePhpType(selectEl) {
            const dbtype = selectEl.value;
            const row = selectEl.closest('tr');
            const phptypeSelect = row.querySelector('select[name="phptype"]');


            let suggestedType = 'string';
            switch (dbtype) {
                case 'int':
                case 'tinyint':
                    suggestedType = 'integer';
                    break;
                case 'datetime':
                    suggestedType = 'datetime';
                    break;
                case 'json':
                    suggestedType = 'json';
                    break;
            }
            phptypeSelect.value = suggestedType;
        }

        function escapeXml(str) {
            if (typeof str !== 'string') return '';
            return str
                .replace(/&/g, '&')
                .replace(/</g, '<')
                .replace(/>/g, '>')
                .replace(/"/g, '"')
                .replace(/'/g, ''');
        }

        function generateXML() {
            // Получаем основные параметры
            const modelPackage = escapeXml(document.getElementById('modelPackage').value.trim() || 'mytable');
            const objectClass = escapeXml(document.getElementById('objectClass').value.trim() || 'myTable');
            const tableName = escapeXml(document.getElementById('tableName').value.trim() || 'migx_table');

            const rows = document.querySelectorAll('#fieldsContainer tr.mjg_input_row');
            const xmlLines = [];

            // Заголовок XML
            xmlLines.push('<?xml version="1.0" encoding="UTF-8"?>');
            xmlLines.push(`<model package="${modelPackage}" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" version="1.1">`);
            xmlLines.push(`    <object class="${objectClass}" table="${tableName}" extends="xPDOSimpleObject">`);


            // Обработка каждой строки таблицы
            rows.forEach(row => {
                const keyInput = row.querySelector('input[name="key"]');
                const key = keyInput ? keyInput.value.trim() : '';

                // Пропускаем строку, если ключ не указан
                if (!key) {
                    console.warn('Пропущена строка без ключа:', row);
                    return;
                }

                let fieldXml = `        <field key="${escapeXml(key)}"`;

                const dbtype = row.querySelector('select[name="dbtype"]').value;
                if (dbtype) fieldXml += ` dbtype="${escapeXml(dbtype)}"`;

                const precision = row.querySelector('input[name="precision"]').value.trim();
                if (precision) fieldXml += ` precision="${escapeXml(precision)}"`;

                const phptype = row.querySelector('select[name="phptype"]').value;
                if (phptype) fieldXml += ` phptype="${escapeXml(phptype)}"`;

                const nullCheckbox = row.querySelector('input[name="null"]');
                const nullVal = nullCheckbox.checked ? 'true' : 'false';
                fieldXml += ` null="${nullVal}"`;

                const defaultVal = row.querySelector('input[name="default"]').value.trim();
                if (defaultVal) fieldXml += ` default="${escapeXml(defaultVal)}"`;

                const indexVal = row.querySelector('select[name="index"]').value;
                if (indexVal) fieldXml += ` index="${escapeXml(indexVal)}"`;
                
                fieldXml += ' />';
                xmlLines.push(fieldXml);
            });

            // Добавляем стандартные агрегации
            xmlLines.push('        <aggregate alias="Resource" class="modResource" local="resource_id" foreign="id" cardinality="one" owner="foreign" />');
            xmlLines.push('        <aggregate alias="Creator" class="modUser" local="createdby" foreign="id" cardinality="one" owner="foreign" />');


            // Закрывающие теги
            xmlLines.push('    </object>');
            xmlLines.push('</model>');


            // Выводим результат в текстовое поле
            document.getElementById('output').value = xmlLines.join('\n');
        }

        // Инициализация: добавляем обработчик для кнопки генерации
        document.addEventListener('DOMContentLoaded', () => {
            document.querySelector('.mjg_input_rows_add').addEventListener('click', addField);
        });
    </script>
</body>
</html>
22 мая 2025, 22:41
0
тот же вопрос по диапозону дат. готового решения так никто и не озвучит?
06 мая 2025, 20:21
0
решил таким способом получение первой картинки
{set $preview = $_modx->runSnippet('ms2Gallery', [
			'resources' => $id,
            'filetype' => 'image', 
            'limit' => 1,
            'tpl' => '@FILE chunks/image_url.tpl'            
            ])}
chunks/image_url.tpl
{if $files?}
{foreach $files as $file}
{$file['medium']}
{/foreach}
{/if}
18 апреля 2025, 00:03
0
Не работает парсинг с vk.com, vkvideo.ru
16 апреля 2025, 11:39
0
Не выводятся товары привязанные к данной категории, как дополнительной
В админке они отображаются в обеих категориях, опубликованы, кэши сняты
Showlog также их не видит

{'!msProducts' | snippet : [
            'parents' => $_modx->resource.id,
            ]}
MODX 3.1.2-pl
MiniShop3 — 1.0.0-alpha
22 января 2024, 13:49
0
стоит добавить в сниппете 'isfolder' => 0
$items = $pdo->getCollection('modResource', array(
    'published' => true,
    'deleted' => false,
    'isfolder' => 0
21 января 2024, 16:15
0
Это сниппет для создания списка с алфавитным указателем
15 декабря 2023, 00:09
0
Не смог разобраться, как удалять и генерировать по одному из ключей настроек источника файлов
У меня два типа превью small и medium
{
"small":{"wp":150,"wl":150,"q":90,"f":"webp"},
"medium":{"wp":350,"wl":350,"q":80,"f":"jpg"}
}
Если необходимо добавить еще один тип или изменить настройки одного из типов, то при выполнении данного кода удаляются все файлы превью обоих типов и пересоздаются заново
$child->remove();
generateThumbnails();
Есть ли возможность пересоздать конкретный?
20 мая 2022, 01:16
0
решено
запуск сниппета в head
<?php
$getid = $_GET['id'];
if ($getid != '' && is_numeric($getid)) { 
    $url=$modx->makeUrl($modx->getOption('id', $scriptProperties, $modx->resource->get('id')));
    header('HTTP/1.1 301 Moved Permanently');
    header('Location: '.$url.'');
    echo '<meta http-equiv="refresh" content="0;URL='.$url.'"/>'; }
25 апреля 2022, 19:45
0
Нашел. ../assets/components/onebooking/js/web/default.js в конце задать minDate и MaxDate в формате yyyy-mm-d
25 апреля 2022, 18:14
0
необходима помощь с one booking, покупал вместе с one period. из магазина оно пропало как и переписка с автором в формате поддержки

Отсутствовала возможность ограничить выборку в календаре по датам. Отель работал толко в летнее время, поэтому необходимо было выставить даты с 01.06.2021 по 30.09.2021
На момент сдачи проекта вручную указал начальную и конечную дату для календаря 2021 года.
прошел год. Пришло время ввести новые даты и хоть убей не помню где я их менял…
Заметки остались в переписке с автором
Сам проект и поддержка через modxstore недоступны
27 ноября 2021, 01:40
0
все еще актуально, буду признателен