From f70b97c2eb7f32f8d0b5e9bd86e8b506272b5ced Mon Sep 17 00:00:00 2001 From: Ivan Bochkarev Date: Sat, 28 Mar 2026 13:10:28 +0600 Subject: [PATCH] =?UTF-8?q?fix(manager):=20=D0=BE=D1=82=D0=BA=D1=80=D1=8B?= =?UTF-8?q?=D1=82=D0=B8=D0=B5=20=D1=81=D1=81=D1=8B=D0=BB=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D1=82=D0=BE=D0=B2=D0=B0=D1=80=20=D0=B2=20=D1=82?= =?UTF-8?q?=D0=B5=D0=BA=D1=83=D1=89=D0=B5=D0=B9=20=D0=B2=D0=BA=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Убран target="_blank" у ссылки названия товара в гриде категории: дефолтный шаблон в CategoryProductsGrid, сидер grid-config, миграция для существующих БД. --- CHANGELOG.md | 1 + ...000_seed_category_products_grid_config.php | 2 +- ...egory_products_pagetitle_link_same_tab.php | 102 ++++++++++++++++++ .../src/components/CategoryProductsGrid.vue | 2 +- 4 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 core/components/minishop3/migrations/20260328120000_category_products_pagetitle_link_same_tab.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 5869cffd..74b9019c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,6 +78,7 @@ - **Некорректные URL в ЛК заказов клиента (#141):** кнопка «Сбросить» фильтра и ссылки пагинации вели на корень сайта (`/?`) из-за `` в шаблоне MODX — URL формируются server-side через `makeUrl()` + `http_build_query()`, пагинация сохраняет фильтр по статусу. Добавлены недостающие SVG-иконки в спрайт (`icon-arrow-left`, `icon-truck`, `icon-credit-card`, `icon-message`), исправлен `fill` → `stroke` для Feather-иконок в деталях заказа - **Некорректные URL и хардкод английских сообщений в ЛК адресов (#142):** кнопки «Добавить адрес», «Редактировать», «Отмена» вели на корень сайта — URL формируются server-side через `makeUrl()` + `http_build_query()`. API-контроллер `CustomerAddressController` содержал хардкод английских строк вместо лексиконов — все сообщения заменены на `$this->modx->lexicon()`, добавлено 7 ключей в ru/en лексиконы - **Отсутствие ключа `desc` в свойствах сниппетов и источников при сборке пакета (#127):** добавлена инициализация `desc` пустой строкой если ключ отсутствует в определении свойства — устраняет warning/ошибку в `resolver_04_sources` и `resolver_08_snippet_properties` +- **Ссылка на товар в таблице категории открывалась в новой вкладке:** у шаблона колонки `pagetitle` убран `target="_blank"` в дефолтном конфиге Vue, в сидере грида и миграцией для уже сохранённых записей `ms3_grid_fields` #### ⚠️ Breaking changes diff --git a/core/components/minishop3/migrations/20251231140000_seed_category_products_grid_config.php b/core/components/minishop3/migrations/20251231140000_seed_category_products_grid_config.php index 6cce055d..3ae3c2f8 100644 --- a/core/components/minishop3/migrations/20251231140000_seed_category_products_grid_config.php +++ b/core/components/minishop3/migrations/20251231140000_seed_category_products_grid_config.php @@ -60,7 +60,7 @@ public function up() 'min_width' => '200px', 'config' => json_encode([ 'type' => 'template', - 'template' => '({id}) {pagetitle}' + 'template' => '({id}) {pagetitle}' ], JSON_UNESCAPED_UNICODE), 'is_system' => 0, 'is_default' => 1, diff --git a/core/components/minishop3/migrations/20260328120000_category_products_pagetitle_link_same_tab.php b/core/components/minishop3/migrations/20260328120000_category_products_pagetitle_link_same_tab.php new file mode 100644 index 00000000..ac1b8c05 --- /dev/null +++ b/core/components/minishop3/migrations/20260328120000_category_products_pagetitle_link_same_tab.php @@ -0,0 +1,102 @@ +gridFieldsTable(); + $stmt = $this->getAdapter()->getConnection()->prepare( + "UPDATE `{$table}` SET config = ? WHERE id = ?" + ); + + foreach ($this->fetchPagetitleFieldRows() as $row) { + $config = json_decode($row['config'], true); + if (!is_array($config) || empty($config['template']) || !is_string($config['template'])) { + continue; + } + $template = $config['template']; + if (!$this->templateHasBlankTarget($template)) { + continue; + } + $config['template'] = $this->stripBlankTargetFromTemplate($template); + $stmt->execute([json_encode($config, JSON_UNESCAPED_UNICODE), (int) $row['id']]); + } + } + + public function down(): void + { + $table = $this->gridFieldsTable(); + $stmt = $this->getAdapter()->getConnection()->prepare( + "UPDATE `{$table}` SET config = ? WHERE id = ?" + ); + + foreach ($this->fetchPagetitleFieldRows() as $row) { + $config = json_decode($row['config'], true); + if (!is_array($config) || empty($config['template']) || !is_string($config['template'])) { + continue; + } + $template = $config['template']; + if ($this->templateHasBlankTarget($template)) { + continue; + } + $restored = $this->restoreBlankTargetBeforeProductLinkClass($template); + if ($restored === null) { + continue; + } + $config['template'] = $restored; + $stmt->execute([json_encode($config, JSON_UNESCAPED_UNICODE), (int) $row['id']]); + } + } + + private function gridFieldsTable(): string + { + $prefix = $this->getAdapter()->getOption('table_prefix'); + + return $prefix . 'ms3_grid_fields'; + } + + /** + * @return list + */ + private function fetchPagetitleFieldRows(): array + { + $table = $this->gridFieldsTable(); + + return $this->fetchAll( + "SELECT id, config FROM `{$table}` WHERE grid_key = 'category-products' AND field_name = 'pagetitle'" + ); + } + + private function templateHasBlankTarget(string $template): bool + { + return str_contains($template, 'target="_blank"') + || str_contains($template, "target='_blank'"); + } + + private function stripBlankTargetFromTemplate(string $template): string + { + return str_replace([' target="_blank"', " target='_blank'"], '', $template); + } + + /** + * Re-inserts target="_blank" only for templates that use class product-link (stock layout). + */ + private function restoreBlankTargetBeforeProductLinkClass(string $template): ?string + { + if (str_contains($template, 'class="product-link"')) { + return str_replace(' class="product-link"', ' target="_blank" class="product-link"', $template); + } + if (str_contains($template, "class='product-link'")) { + return str_replace(" class='product-link'", " target='_blank' class='product-link'", $template); + } + + return null; + } +} diff --git a/vueManager/src/components/CategoryProductsGrid.vue b/vueManager/src/components/CategoryProductsGrid.vue index 2e2b213c..e765408c 100644 --- a/vueManager/src/components/CategoryProductsGrid.vue +++ b/vueManager/src/components/CategoryProductsGrid.vue @@ -540,7 +540,7 @@ function getDefaultColumns() { minWidth: '12.5rem', type: 'template', template: - '({id}) {pagetitle}', + '({id}) {pagetitle}', }, { name: 'article',