diff --git a/CHANGELOG.md b/CHANGELOG.md index afff9b7..a6ea72b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,52 @@ ## Не выпущено -Новые изменения будут добавлены после build 0.38. +Новые изменения будут добавлены после build 0.39. + +## 3.3 build 0.39 — 25 августа 2026 + +### Документы и публичные шаблоны + +- Карта публичных шаблонов показывает, из каких штатных компонентов AVE.cms + собираются основные типы страниц и где каждый компонент редактируется. +- Поля оформленных информационных страниц снова доступны в редакторе документа, + включая подписи, адреса и содержимое карт на странице контактов. +- Исправлено сохранение документа из режима исходного HTML-кода редактора. +- Публичный адрес под названием документа в таблице стал активной ссылкой и + открывается в новой вкладке. +- Существующий документ можно сохранять со своим URL, даже если рядом с ним + позднее появился системный маршрут установленного модуля. + +### Рубрики и темы + +- Дополнительные шаблоны рубрики открываются в полноразмерной рабочей панели, + поддерживают проверку и корректно возвращаются из полноэкранного режима. +- Из редактора дополнительного шаблона можно перейти к связанному документу. +- Улучшено отображение представлений и публичных шаблонов в разделе темы. + +### Поиск + +- Поиск распознаёт артикулы без разделителя между буквами и цифрами, сохраняет + правила русской и английской раскладки и учитывает управляемые синонимы. +- Добавлена осторожная коррекция опечаток с подсказкой «Возможно, вы искали»; + исходный запрос пользователя не заменяется без объяснения. +- Переиндексация получила более устойчивый пошаговый прогресс и словарь + поисковых вариантов. + +### Каталог модулей + +- Модуль слайдеров добавлен в публичный каталог: слайды, ссылки, навигация, + адаптивные изображения и внешний вид управляются из панели. +- Галереи получили обновлённый публичный просмотр изображений. +- Модуль SMS-входа получил журнал событий и расширенную диагностику отправки. +- Обновлены модули поиска и связанных материалов. +- Торговые, проектные и служебные модули по-прежнему исключены из публичной + core-сборки и каталога. + +### Выпуск + +- Для build 0.39 подготовлены чистая core-сборка, компактный установщик и + накопительное обновление с build 0.20. ## 3.3 build 0.38 — 5 августа 2026 diff --git a/PACKAGE-MANIFEST.json b/PACKAGE-MANIFEST.json index af4c335..a703c34 100644 --- a/PACKAGE-MANIFEST.json +++ b/PACKAGE-MANIFEST.json @@ -2,18 +2,19 @@ "format": "ave-core-package-v2", "product": "AVE.cms", "version": "3.3", - "build": "0.38", + "build": "0.39", "package": "core", - "built_at": "2026-08-05T18:33:56+00:00", + "built_at": "2026-08-25T09:00:39+00:00", "installed_modules": 0, "bundled_optional_modules": [], "optional_after_install": [ "setup/" ], - "core_fingerprint": "a8ac3d2be6a3c4b43c7d871c4e5ece44b1641f1fdace69329e296468e1d192d2", + "core_fingerprint": "cd348589924dbf95a20d6e41994c39f036bd55372250ad6caa8c3484158bd6a5", "files": { ".gitignore": "20d4fb177d47da6944a7a1c2dbf5918fd62766881aa52b00901f9054b1db4b49", ".htaccess": "71c06b7bc41b09c347a562ca72768acaa0ee1ef8388c749fc67956c793d8a826", + "CHANGELOG.md": "58ab5f834aad74ac1f8101983102fce3f0708d720999efadcdff9efdefa2ed64", "README.md": "19b820f1b092780039aae011e133dc6a1e5f1cf213b435e0ff1962b592b9095b", "adminx/.htaccess": "d03ea2d2972af8b7545a2d57c6253f303d15adeb30b775e161d887ca5ff73378", "adminx/Support/AdminLocale.php": "a7fe84d86d65c9f021106172b1789c8bc6221c36b2fe39cf883ca9a505e3e8ad", @@ -28,7 +29,7 @@ "adminx/Support/Roles.php": "6be335dd643317f77bd7c2db92f25895e601fe72818befd62f6aeb3ecac9fce7", "adminx/Support/RouteGuard.php": "e9e20c097c0db354851546585be72bfc71a5d14652871f8bd1160e845d4dab1b", "adminx/Support/SavedViews.php": "4548ca129f270184e61cb670e7f44a1c103099a6a6c2820bed1a11bc18f227c4", - "adminx/Support/SectionHelp.php": "6a5101c1f7b61ea1b94aa4a37985d3a5955aaed8b73537f918f90f7749dfa08b", + "adminx/Support/SectionHelp.php": "4ce72b8895ad4f813d3a49e56a895c20f2821ad7f546c87f6e891793592dee4c", "adminx/Support/SensitiveRoutes.php": "d14d809310b43fdb66ec141b0573ec1020aea3720d20269d39f201f411d9f9c5", "adminx/Support/SystemFeatures.php": "f18ada623710f8c3efc6588c037227f6074e75bad9a3820aeef60b4d8d4b20a4", "adminx/Support/SystemHealth.php": "286aee452e90f71ad64437bd39d6dd985d312eb85bbb711490d3a0b631a16aea", @@ -36,9 +37,9 @@ "adminx/Support/Twig/AdminLocaleExtension.php": "1fb6c1d1c35d74fdb4a578cd15b3f19441725db6f11b336dc6948ed982842f3a", "adminx/Support/Twig/AdminLocaleNodeVisitor.php": "ccf387680fe8b0e11bd0fe0d23769be8b7ed9afc363cb9a802db5c4aeb7d405b", "adminx/Support/Twig/AdminTextNode.php": "e51d8d3ee49411f42c8a874cd283f60c1fa0af6506b34568a119ebe2d18d7268", - "adminx/Support/ViewOverrideEditor.php": "c3804e0b399cacd604ad2765885366a4baefe0ee7a441475276fe7d3074dab36", + "adminx/Support/ViewOverrideEditor.php": "9704c974f36b6f9e204b6c609582d61b0a0f65aa182a3f1381fe7a7d1c0b15e7", "adminx/Support/WorkItemContext.php": "d4b87b78ff1f2bdd89d77bc0483ebb46e5c11616635211ead9a43b34568e3a59", - "adminx/assets/css/adminkit.css": "15409efc9387120866479c3351a4a291ee7d8207694a84b228fc5d35fc184cbe", + "adminx/assets/css/adminkit.css": "0883ec02682b3069765388c61e0d9f8262786599fbd8bec51701affbab585a5e", "adminx/assets/fonts/NunitoSans-Bold.woff2": "2d48580b7e1be60fa94b8092ebe86471fe0adfe5ca75242a7af2042ac9da825f", "adminx/assets/fonts/NunitoSans-ExtraBold.woff2": "66612ee9d1cdc341c9eec8a43104bbf515e7cc52821558bfc7dfcf33c8cb0cc1", "adminx/assets/fonts/NunitoSans-Regular.woff2": "878adc25278872933f004783f0ebbe092cebb3f9161aa30cffb2b9a8a07db040", @@ -46,16 +47,16 @@ "adminx/assets/fonts/OpenSans-Regular.woff2": "a26ed465673123933c5510730a7286f49016a40fa94062021d1dc4c9bfeddbd3", "adminx/assets/fonts/OpenSans-SemiBold.woff2": "7d963e1d2f61c11c2e8bd2eb528777b5a55569708d50a7ee7bd097d7fafe6da4", "adminx/assets/img/logo.svg": "685d9bf037b33fbcfc200947d5051c5325762f8ab8a29ac9e1e587076321e463", - "adminx/assets/js/adminx.js": "4303a0a0c89c8e339143e6d1e0269a51b02b1fe72383f83af6a2a8d3b4ee1cf0", + "adminx/assets/js/adminx.js": "34d38f1291372e5ce10d051d9cbc144f61020f833fce263f5041fdc6926c20d1", "adminx/assets/js/bulk-actions.js": "d7ee80678e6703aff2418a4679ba8e5027e7220cb089848bcced6d9f100b3aae", "adminx/assets/js/command-palette.js": "f62f0bad5ddf2b6e813e7eda094d73df63dce09a6e581025971e8f10430e8d9f", "adminx/assets/js/editor-codemirror.js": "90a04c219e84f5391a40b0d1fc807ecfe4ca582a198bc202bdc5aa6dccec51fa", - "adminx/assets/js/editor-tiptap.js": "b924d1deccda0e85d947ec936ead0d32f85aa5517893d197316f75a614ac5092", - "adminx/assets/js/media-picker.js": "eec036a03bd1d0d7995708a15f3337cc6e5d2e8ede7d5be3b0c5eeaeed782ebc", + "adminx/assets/js/editor-tiptap.js": "d5c7596bb17de87cb061c18daf629f322d03e2c81be19dab78897e93691d52de", + "adminx/assets/js/media-picker.js": "74481279a7d352c7c72893b4043e02454ff3cc28b6582c5463dfa712b17e23a2", "adminx/assets/js/saved-views.js": "30c02121634f6f035dcff6a730e6fe300a1892fc9321971f142dcff600802f30", "adminx/assets/src/bulk-actions.js": "29bcc568366ce4a86a71b12a0f8be050bd71a9eabb0f65af6d9ca57281db9201", "adminx/assets/src/command-palette.js": "ff86b0dc0f1ad59d551af772643dbe094cdfb2367d402eca49fd1a4c5b1bb9db", - "adminx/assets/src/editor-tiptap.js": "e4cf6d82b1759708e9e2df5bb54136570e572a99138cd57f6eee7f91257ed7c4", + "adminx/assets/src/editor-tiptap.js": "1cb23f5262b50aa8ac0fbf19d98b77ce063af966f47d9b2ab6b0e5e3fadf28ae", "adminx/assets/vendor/codemirror/addon/dialog/dialog.css": "5df690d771f12118348562dd2a90060433ae2edeccd0908abcaa4480b1e3e468", "adminx/assets/vendor/codemirror/addon/dialog/dialog.js": "1eea0e500dce10d8594d8d681a91d1b71a4209355c9c29885e86e26b2d76685e", "adminx/assets/vendor/codemirror/addon/edit/closetag.js": "700b8aa7c46e040287e32ffd1edb86a42d09edc5b2a9594241590b154c0232bd", @@ -184,8 +185,8 @@ "adminx/modules/Blocks/migrations/012_merge_visual_blocks.php": "5c9cd6efd66a027134621859da1059b2c403bacb732885d6b405699cbce8fc14", "adminx/modules/Blocks/module.php": "53eb434566d820814f5b25382200b75ed02b0067c066c8f8cb62bee13529b964", "adminx/modules/Blocks/view/index.twig": "39f9225b6a95c65549d0c861afb7db7879ca338c251290653dded6ab7cb715cc", - "adminx/modules/Catalog/Controller.php": "425ebd7b8e54ef659879e7bf8212120feda968a7560e2a614b505be882fed410", - "adminx/modules/Catalog/Model.php": "e7c7cffd91754e04dac322c31a64b420739c671079a7f8e7effb550f5019ee13", + "adminx/modules/Catalog/Controller.php": "22a19db35e22824abf3bea9053050c2cdd74c937022de905684c5b627d52de57", + "adminx/modules/Catalog/Model.php": "d524730981ad388928cfc29208a821ed1d474bd01d6db1749fd37fdfb4e4958e", "adminx/modules/Catalog/assets/catalog-drawer.css": "b3e4f798d7bdf329aa91987ae5be435910ddccfeb8a32211059846ab9dc6b7c4", "adminx/modules/Catalog/assets/catalog.css": "49e7a33fc444f8330806e1cc5cbb0d523b673c64faafd25dbf0fe33067643efd", "adminx/modules/Catalog/assets/catalog.js": "1fc4acc30b05fd702dee9ff62958141aeab7593ca38d6f6360567af7c3dc9742", @@ -196,8 +197,8 @@ "adminx/modules/Catalog/language/ru/interface.xml": "15d8de452eef296375ba40d557ce15ac0363881a7b763b7111c8cc221e9861ff", "adminx/modules/Catalog/language/ru/runtime.xml": "fe59945f4ceb2bf2d85699623369e7e5889613b8cecd8551a390c78023531d14", "adminx/modules/Catalog/migrations/005_add_catalog_purpose.sql": "006ff237e25042a4fa9b9f74d5079741eeee1aa52db0cd996ea4c8b817e6700f", - "adminx/modules/Catalog/module.php": "69f6f46206bec880a6f08329e0b44e35bcf3c7e57ad5e85e3b720b7b4adb7f38", - "adminx/modules/Catalog/view/edit.twig": "7fa6f39eec641b23f2191a9df2186a4d4855e50d4b1cc506118a94313cf481a7", + "adminx/modules/Catalog/module.php": "c36086c3162d1eba433af05c879dcfb9cff830ee3c53da38705a72cc19b3777b", + "adminx/modules/Catalog/view/edit.twig": "13bd9ebabdc8bb470a6c8ceb813b122d33da5c5604a23bb7ad3a840cc061cde2", "adminx/modules/Catalog/view/index.twig": "754c7c4dc81176e8c99b3d9e8c1fda2f62f03df341c3df1f7393f72d43c6f8e2", "adminx/modules/Console/Controller.php": "af0309a50d7f4366279be8ea12959cf7718a3c68b895a65ec5846554fd6a4857", "adminx/modules/Console/Model.php": "53aad480b8d4e5d68c4e9345d219ea5cbff6d04eee7ce4aa15deab6f00dac1cc", @@ -253,11 +254,11 @@ "adminx/modules/Dashboard/view/widgets/recent-documents.twig": "d03f36f047574f8ce57fdcfd79b26d9b20ca01dba69ce7c71a3e9a277f0105d0", "adminx/modules/Dashboard/view/widgets/shortcuts.twig": "af165425ea7889cdc3edbd72c7f0dd9dc5c4c06486bc4ab37816112cfb696718", "adminx/modules/Dashboard/view/widgets/system-kpis.twig": "52dab540a189443b76811ac4b457a566cf90134366749aa9c7d82e2d23ffdaa3", - "adminx/modules/Database/Backup.php": "08192cdadd31b0d304393cec761ca78d696d10e7b9585389662fa71f53e8e4c0", + "adminx/modules/Database/Backup.php": "131bcff544bf3d2093ae5d14d984070fe5819bf0ae1aa9ec02a48d42b85d1e1b", "adminx/modules/Database/BackupRestore.php": "1fb34abdec27ed24665ec0749f4ed44167f3881d3477129d5d4de6c7b36d6653", "adminx/modules/Database/Controller.php": "87577df32e3cacc36edb57747ac9169d0e32a30b2b2f11dbbc4db18be486e3e6", "adminx/modules/Database/Model.php": "52c23131d07bc798fb2a3489f91ae909985e60d2965e3cd5fbaf5ab441d85477", - "adminx/modules/Database/SqlDumpReader.php": "f0b3a501d0afea0ae50d35b43e901844e14d9faec286738956dc6f2b1c5ea4b3", + "adminx/modules/Database/SqlDumpReader.php": "e71f81a1fd4859fddced14da210f1530eee41131287e84d82d43d3033dca5ae2", "adminx/modules/Database/assets/database.css": "9bbcaefb3c3f3e6230250cf90cb20ffe933f86812ddb8c49d17a3f65097aef5d", "adminx/modules/Database/assets/database.js": "191c97d3d7586440ca736c5cffc228e4ea9f8915ba61e5a55146f849df7e9d12", "adminx/modules/Database/language/en/client.xml": "4464d65adfd150e597436cade1d36b0c0436654fb4c710218fe2fad117b12369", @@ -269,7 +270,7 @@ "adminx/modules/Database/migrations/001_mysql_legacy_index_compatibility.php": "e9a021b5643933d6ca000d54bd1a12e339080939aa84fd3ec28d0093a5b8222c", "adminx/modules/Database/migrations/002_module_lifecycle_recovery.php": "779b04c8b35f3d81657848016536a9e3ef70fb76dd3ce5b1ba4b4a72166f7a2d", "adminx/modules/Database/migrations/003_document_fields_text_composite_index.php": "541a8df87dd5fec6946f26dcca88f78a2bf5e09608f9300baa8532202020ffbf", - "adminx/modules/Database/module.php": "550471695f5bf7ab5045f0b22c891f65b398346fb03f5f0a0cc3bcf3fed379a7", + "adminx/modules/Database/module.php": "1592d603f73695883643df7aa3fe90c257cd120f99e272b4759b0cdf5c3d3da3", "adminx/modules/Database/view/index.twig": "4e3d3a8ccdeeb2812d4b6d3ae471c8f162d8ac0e30c5dfcc4847356b4cc063a9", "adminx/modules/Directories/Controller.php": "bae664ccff5a63a215fa1b59b721d0b0a4055ac3633319476d09889ead0d7d27", "adminx/modules/Directories/Model.php": "ead423e3d0a07badf5a773780ee37d92394240fc753c10fad274a3131db7c2ce", @@ -283,23 +284,23 @@ "adminx/modules/Directories/module.php": "f6b7f0bfb96d1c2c7aa52c51e60abaa09cdba7a4309d8363394a3a02a8df96a0", "adminx/modules/Directories/view/index.twig": "0bde23bc578b9ffad3c47534c304c0016b661a36588d6d3c9ffb92e2daa388a0", "adminx/modules/Documents/BulkEditor.php": "6ca33e4ee73f83e043b13363bddb391199a1da902e74dfa7709a10ac32be574b", - "adminx/modules/Documents/Controller.php": "e461ac2766b15194741b0a4ca2c2aafac9edab9b9f602516011dd5168269104e", + "adminx/modules/Documents/Controller.php": "283aec04707c7b7fdd01e2ba69c1961b925f259655e9a455889bdd5dfc66f4fe", "adminx/modules/Documents/DocumentHookRunner.php": "7e0cd24ed5791b6d5010e4a05351b709be09b6df1e700a3ff06685b9078b2b1d", "adminx/modules/Documents/DocumentMediaReplacement.php": "e97d960c852162e655a4389cc5f477f0178597da50e733b00bdf5bcab076c65d", "adminx/modules/Documents/EditConflict.php": "ebc3ebb92c3fc3ccf3909d2ff517014fc888ee20576a520b4979f68bde632b97", - "adminx/modules/Documents/Model.php": "6ac1f3e85c73e5e7c8a531b31f9b72ea1a78ba561355102301e386baf0eafdac", + "adminx/modules/Documents/Model.php": "5287c9adc603c942d1ffae135df360717ee18b1d1b2b9c29bb35d183b477b54a", "adminx/modules/Documents/Revisions.php": "8caef88f7456000b001757cff13393ae36991b33c4c3070c27f3eaa4e8bf6492", - "adminx/modules/Documents/assets/documents.css": "5e9dbbbfbf276ad94a32657dac8a8cf0a5c184e77fb6b1d40e0261876dbe84eb", - "adminx/modules/Documents/assets/documents.js": "b65c2396c0f866e1895d84637875a935ca4a0886378c65068e5b4215b6dd94c8", + "adminx/modules/Documents/assets/documents.css": "396d4cc7625b3331a41d94f040ac3fabafd9c0b993181b490ceea8f365e1a5ad", + "adminx/modules/Documents/assets/documents.js": "dce151189d8244be41fb6b1bbb85a26241c788d91111ccb5314c361150024c3d", "adminx/modules/Documents/assets/redirects.js": "95ca395c6b4fd3814da37450c27da351e75f509e26421c975dd8e0ee5f657efd", "adminx/modules/Documents/language/en/bulk-editor.xml": "b7af92bd151c7899a56cc461f4a09edaa842213cb6e6b4b4363af31aee228e50", "adminx/modules/Documents/language/en/client.xml": "9ccb6f2aa9a83862abff2c1fa1c6b10760600c3202293fd7e42073c9cfb5fae4", - "adminx/modules/Documents/language/en/interface.xml": "f3a30b3c565d2e01c841c843dc529fed9844dc2e095f90b7902008ded7214ed2", + "adminx/modules/Documents/language/en/interface.xml": "87b858717419a48ed12e1181183b8de0285483df4c9de37403730f8a7c034b52", "adminx/modules/Documents/language/en/runtime.xml": "7009fa27d67ab168fecd9d9bf182216dfb0397d9c006eb6563ee3c464daa5b5e", "adminx/modules/Documents/language/en/zz-interface.xml": "839ea37d585ff10d7b819a4fcd4bda876c94d51019489cc8d35af15fbc905f2b", "adminx/modules/Documents/language/ru/bulk-editor.xml": "29500cbda63189ed9a0afdb57b20f998241594b254d0225a776a8be32d108834", "adminx/modules/Documents/language/ru/client.xml": "3e14cb51de149aca6c3f309ffb3973a47f80f638805325ff0a5cc23dd1025302", - "adminx/modules/Documents/language/ru/interface.xml": "718386366f913c590c2bb881f49ad3b7d436de82faeec30655a7c2f9b14d58e0", + "adminx/modules/Documents/language/ru/interface.xml": "f8d60edba8ac5b6d0eb6deaa3b9b89733cd0b8d3eb951c105a9874ea6769c305", "adminx/modules/Documents/language/ru/runtime.xml": "6c3e9a2dbf862bef5a76ff0bb600084fcd9d5d1a7f0cbfd02377242b74fcd759", "adminx/modules/Documents/language/ru/zz-interface.xml": "2d819845ff2ae5246203374a685f8a5ad881ba9067166161eb96d5c9271026dd", "adminx/modules/Documents/migrations/001_correct_breadcrumb_title.sql": "e2b612f19cbc2c419d1a3d2c684909b4055811a7121f4debdf6b83e99bd214cf", @@ -318,12 +319,12 @@ "adminx/modules/Documents/migrations/014_document_relation_edges.sql": "3491ade2987535f8db1b3b00ff27f5a2062b02a3a1cb2e707d2752ff446b566c", "adminx/modules/Documents/migrations/015_document_creation_presets.sql": "a123f8867ab6f6346002d08317acac37062c2792913ad14102c81812d45571bd", "adminx/modules/Documents/migrations/016_reconcile_document_content_columns.php": "06671bb26bf29479dce24888fb3712c0d20e2aac5b3d70196604ce4097c875fc", - "adminx/modules/Documents/module.php": "36069766b3397735293f9f7d491c6f874eb8fc3c12c7d5d983ec8eee6b4655a8", - "adminx/modules/Documents/view/_product_panels.twig": "e07898ea6a7cc0004ac7545b689afdc6b474e6d8b24357f5c5190b4ca5589142", + "adminx/modules/Documents/module.php": "dc7642c19f3fabda2ce0577dbf2002de389ee2f5616c26a6f6cdd88c639f91c9", + "adminx/modules/Documents/view/_product_panels.twig": "d0e681a94f6e48c061dbc61cc47c384bd52c4eb66d648e36784b68d0c8ada603", "adminx/modules/Documents/view/api.twig": "a035a2d566298587ce8530c98915e80e4e7f9b0f41a60e0e55d4547b996a6c40", "adminx/modules/Documents/view/bulk-editor.twig": "27d9baca8cf591dc2ee81b26fda3efc9017c6809c1d23168a749d01bddfebdfa", - "adminx/modules/Documents/view/edit.twig": "a7934bde27ca84a47b9a5865b8bedb3e28756b91337e479592e1fefba93ec6aa", - "adminx/modules/Documents/view/index.twig": "004594c77dba92188e58d73228af397ac825e723c3c1aba9ee7b94072f828ba1", + "adminx/modules/Documents/view/edit.twig": "94eb351309fb3d6fdab844e253ab2d7e3b03e1d846b35da19b7e498733ad27a2", + "adminx/modules/Documents/view/index.twig": "8bb67e66a55007fda1374d83a3bc0b19fdc518a47d191a04913772d8c8ce132c", "adminx/modules/Documents/view/redirects.twig": "4a4903edc81e4770220852d9be9f02a983ddde6f829a4360ea01d3b68456582b", "adminx/modules/Documents/view/views.twig": "821f19085ba3997b6ef8f005e838f6fd449f0b32bce0d2804271311856cce8f0", "adminx/modules/Events/Controller.php": "c57fc25e815c47c14626371d044079e6711f0a4bce2004d2b9256db62f0d0e85", @@ -367,7 +368,7 @@ "adminx/modules/Groups/module.php": "fcc5b6212c5d6b77d9a17c9a4878c50233a5b48b373cb6a113825a82c82b248a", "adminx/modules/Groups/view/list.twig": "15af0a1544c7933f57e6bb45ec2a3302d12a025b671c98e1009bae01f5bce605", "adminx/modules/Groups/view/simulator.twig": "82f0c5aba5acc6e7a079c03e355edefe4061efca60d34b3195ee16ffdc951306", - "adminx/modules/Media/Controller.php": "cf853d384714160ef9fdb8d4ad108fefe331572fa2cd43e3d05faf67c3e0d368", + "adminx/modules/Media/Controller.php": "fa78cff18ddba8d3f3c4db74caf65039e5144d982031e71c394425d31fce2514", "adminx/modules/Media/GlobalSearchProvider.php": "799e9b9f1455ad1070bb388245ea6adc5c76b9bf5756bfe0d46b96f3378be92d", "adminx/modules/Media/ImagePresets.php": "8874cbf436a1a33f655c9a395b5f16e143c04c7df1d957c43e3d4ce3ae0645d5", "adminx/modules/Media/MediaAudit.php": "2deeacd899b4410cc620b40b6e448c388f54eb553b5a57a23475ac0b5cae02f3", @@ -376,7 +377,7 @@ "adminx/modules/Media/MediaUsageIndex.php": "d39d232bc56352c9cc2335a2e3bd2a7b7f415709c70ece4b38f1a462c2969415", "adminx/modules/Media/Model.php": "1ac78ca828c6f492857e731a715d54939525dd29545bf81fb4065fcc02f0bc50", "adminx/modules/Media/assets/media.css": "e7db9f602bc1a46644ccf172f977ebe0798c572c73d33f64584c9569d531611f", - "adminx/modules/Media/assets/media.js": "1ce96968f03008c9e0d536070579962e80070b946920ee03d9f4e965664044e3", + "adminx/modules/Media/assets/media.js": "2fdd0c2541150e5c2bbb4ac3ef54f1f40edc029d48383297d432af0431607111", "adminx/modules/Media/language/en/analyzer.xml": "5c6e8bec29fe73d0403cf041c7580800ecc2677d94f2148ffaf44c04d337c6d4", "adminx/modules/Media/language/en/client.xml": "06cecdb6cacdd0871334a3da0a3c7be27d7f835e2a048d37ea31ae4f37469270", "adminx/modules/Media/language/en/improvements.xml": "5873d8eb9c43db0a584161ae3f086dfd101a8df25bbd4d518a2fd283f4f8cb3d", @@ -389,7 +390,7 @@ "adminx/modules/Media/language/ru/runtime.xml": "538db360abf2d61e32d6476846173ea4f5115703021362314a9100df3854d6f7", "adminx/modules/Media/migrations/001_image_presets.sql": "303dec5f331135ab3fda9d264b7a7b674b987cdefa0a7904c544a5d63554f15a", "adminx/modules/Media/migrations/002_media_search_index.sql": "e84168429acdd900d494c91e398a8974ae97023d8bee3385321c2947dd627378", - "adminx/modules/Media/module.php": "af83896b4cef13943f197b4c121a534a7ebea86a771ae12714a2c8c4d51e4495", + "adminx/modules/Media/module.php": "45634e3fc5bd65c1bf545d1aa79912692a38297d390288d956af0f646dbc8c1c", "adminx/modules/Media/view/audit.twig": "06936cd87c80b5c7f6ecec8729f227c2ab3fd492e61b11ae7040e6423939b518", "adminx/modules/Media/view/file.twig": "b317dacbc61411831a9029e30fb1ff3457fa1d34164df3b891b6a9a2fdbe32ce", "adminx/modules/Media/view/index.twig": "c3a4c42477df3a10fcc8ee558bb03fe25782a58f6f47734cb078686798a2d06a", @@ -409,42 +410,44 @@ "adminx/modules/Modules/language/ru/runtime.xml": "271e31a8ae1586ed045861933a6db150427c78be7560942185633f35cf90686a", "adminx/modules/Modules/module.php": "aad8c5f3a11dec21eb14a5d9a83e30c88cb4ea1206e78bc758804d015a828456", "adminx/modules/Modules/view/index.twig": "2ca402c0886f611129e884129f6e0b0022e14a8c385d5d4ad55abe49ee39f5c2", - "adminx/modules/Navigation/Controller.php": "99dca17606ed02b4554db50bb99c0414efac51f871c7fab9113f0c6ce77df4fc", - "adminx/modules/Navigation/Model.php": "f9e59561d2c1b918af994e827d206ea7f0683dff7aa342a6de9193bd877348ba", + "adminx/modules/Navigation/Controller.php": "968da27af968f5f6e29b0e015f4c5df438c17735daf646a9d6343c055acfd48c", + "adminx/modules/Navigation/Model.php": "58d08733e246f92abc02d9ccfa74b88627970588fd2223688a59d03a4d6c4b87", "adminx/modules/Navigation/Revisions.php": "165a2e2d8ad218c1437fffbed9297b7be25d0ae6567f0d72aa78da872cefa1b8", "adminx/modules/Navigation/assets/navigation.css": "e7ad029b253b19546ed2c0eb2a3527dbb3b03a56db13c6f3089c3da9c12933ca", "adminx/modules/Navigation/assets/navigation.js": "72d68867419fab1b3e7e822a42a7fbcd866ccdbef8fa3051a245e23f23f5ec30", "adminx/modules/Navigation/language/en/client.xml": "9a0ad0248941cd6377ada049666387581bea0dd76353d34779b4c1343b74ba50", - "adminx/modules/Navigation/language/en/interface.xml": "5ec5a64240356c4b87f65baea911762e64e88dd652c1fd7c801079247d697b79", + "adminx/modules/Navigation/language/en/interface.xml": "2a6bfcf0fdfc36fd87d666842008635dc12b73c3038fa486e45a4d117956a53e", "adminx/modules/Navigation/language/en/runtime.xml": "341b984ede453a135b6e155fd29c08d9d5a2ab16e62046379f982d9a56dc4a81", "adminx/modules/Navigation/language/ru/client.xml": "46f18714dea8e751f33baa049f3684d824109e49e23b1b325ef37c8a043f1c7e", - "adminx/modules/Navigation/language/ru/interface.xml": "cd5ac333b85534be6a81377a1b40fbd449174cf2d1f019d25b3bb3f5ba0713a5", + "adminx/modules/Navigation/language/ru/interface.xml": "6b460827a6f170057ca6c4310d747a73f67d8468eb98c12cf4238a54ab6c6918", "adminx/modules/Navigation/language/ru/runtime.xml": "45d994c39fa7fa092525ed4a61d6775008f3993f4cdcdd615d61e5f15a749cff", "adminx/modules/Navigation/migrations/001_create_navigation_tables.sql": "43c937b8d7d7f5b70569c591db58ee8592386b988e8cf148fae723b1f68b3012", "adminx/modules/Navigation/migrations/002_navigation_revisions.sql": "cf24c9e9cdb95c2ba4ccea63ec4375d62f29370d5ef909a82a0c990624b8ad02", - "adminx/modules/Navigation/module.php": "8420e2f45024b5a1b076cd86a6658d19fe04156d337f87bcbe597b30a56dfce0", - "adminx/modules/Navigation/view/index.twig": "39092089d109c382f1714e5d724d1e857a8e579ca44b929b40708c9a3f6697e8", - "adminx/modules/PublicSite/Controller.php": "5805f86bed300709232e0a45fedf6950857dc8f23cb499f9c17786b61a67c722", + "adminx/modules/Navigation/module.php": "5eb07314b6c156893288f1616e248ac316ae3a3b561c996d63e772e4ea4e8b6f", + "adminx/modules/Navigation/view/index.twig": "b7dd1784238fc53456b1676a7bfd4d14c2d1efdd7f15cee34c2c4613bd0e7590", + "adminx/modules/PublicSite/Controller.php": "8c00240eca08149df4572732d1e8b03eeca5910d40f03c2742021035f16aa621", "adminx/modules/PublicSite/Model.php": "912fcd71f2ba7215fc9a411882c1eb5e0953b6ebaedfbb92f01b7d3de477a015", "adminx/modules/PublicSite/PresentationModel.php": "3407e5e29165c264c65527433cb94d7d13a80f724dc4d1bf23a49cd2de88b125", "adminx/modules/PublicSite/PresentationsController.php": "e2c7cc517f1a38d6b5e6828b1d652caa6b63622532d2f1f3c5f176e164ba6533", "adminx/modules/PublicSite/PublicViewTemplates.php": "d1d7f7bff22703500f17807d5fe6b02d42a2fcc4cb6d7e7224fe0a47f7dc1ffa", + "adminx/modules/PublicSite/TemplateMap.php": "22bc2649771e972ea23f2387c6bd9abb02ea3ee89054f38e5492e9401b400959", "adminx/modules/PublicSite/assets/presentations.css": "fddb0b4300129f7d7c33853b7e31bce131eb6f867e577443429dcafac8cc67d4", "adminx/modules/PublicSite/assets/presentations.js": "3a74e7c7ae3269b98eca52d2d61db1f4f21871c6f4a5425cc7bab58d24efd963", - "adminx/modules/PublicSite/assets/public-site.css": "69a17727b3a18a88d103886c2d7f79f2c59539ac70d735379e591657e7f04489", + "adminx/modules/PublicSite/assets/public-site.css": "b61c2c699e85ef1ae36e306d83d7d9508bde41702f06037a7ec8c6e69744cb67", "adminx/modules/PublicSite/language/en/client.xml": "5a93fd6babc20670e54795211cf44ed155417aa933e5d4a50be21aebfa7bd510", "adminx/modules/PublicSite/language/en/interface.xml": "e5e868af542e9fe6c981dff18e31a0050d2d7ae2b8b217e7b71bd98b496b5f5b", "adminx/modules/PublicSite/language/ru/client.xml": "f49060544db65a516b2a643420871571b4da5911ae800075c01ae35e55a5d639", "adminx/modules/PublicSite/language/ru/interface.xml": "67a7d1a651d8dd4ca3edc6c281d68c15146a8e84cb18833f9f4041fbbd57a619", "adminx/modules/PublicSite/migrations/001_create_presentations.sql": "023d97f077af57107549dd9e420f5ed55a278fb8318caeb8d86f2dc7750dbfbb", - "adminx/modules/PublicSite/module.php": "10fc91443e4a98b3f529d07fe1cde7bbced8f4f84335fb125d4b2bf509edc2f0", + "adminx/modules/PublicSite/module.php": "46694327d2ac6315da3f9ae02b87a038cfea4da4314ef30c1bc451efe6b279b7", "adminx/modules/PublicSite/view/_placement_pagination.twig": "b10413bdba07695500803625486b56ae5283c5a0a6dff83c668c8f93d1eab182", - "adminx/modules/PublicSite/view/_tabs.twig": "16229bf10dcfc7fa2da84a7041912f52fe597ea4209088826236c454d98bd52c", + "adminx/modules/PublicSite/view/_tabs.twig": "92db2936b265d3b07056ea3aea8ab9dc30e05849b6b3f7d04bf86231fc273643", "adminx/modules/PublicSite/view/diagnostics.twig": "242682325bd7c99c75f9694d0e7ff6217124bf093364c027d13f609db660f4b7", "adminx/modules/PublicSite/view/index.twig": "54ea9422b90235e2926924f11c43b56d90ca8e6c4f255501fcc9c52068cb6f92", "adminx/modules/PublicSite/view/map.twig": "11fba1f54578b4908c669a7dae128949f53a7f1f03746f45a5059c92f473385d", "adminx/modules/PublicSite/view/placements.twig": "9e1ef173a28ed883ea236da0611a4c2e74de09937c5ca4b5a28ff8caa98c9776", "adminx/modules/PublicSite/view/presentations.twig": "d0b245362001ef2a1508fc5c4fa462895b4bbff104025544656828c4513d4cc1", + "adminx/modules/PublicSite/view/template-map.twig": "274f8754d8276caa92ff56678b7309dc9d3cf6ff672c96cf3dab78318f7bb3c5", "adminx/modules/Requests/Controller.php": "b0171c1bfcbf1674b9ba0f8e9461dfa7b3ba5d7bce368b8a0e0dcc2659d32a67", "adminx/modules/Requests/Model.php": "3ab6c5b11cccb31512e61026ae650c414e4bc30debaac3c2b306e9116e3fc49d", "adminx/modules/Requests/Revisions.php": "78483f6667f25c050cbb2d224baa8ccf8d977b30eb84538c3cfb18c7af764bdc", @@ -475,7 +478,7 @@ "adminx/modules/Requests/view/index.twig": "164490c16e041b928e1ecf604915656399690055d1f7de4bc88caf5f5abd485d", "adminx/modules/Requests/view/native-audit.twig": "42120fd41aa4afa39560fea3f2625a4e78a61cb4f9ccc0c0388ca319d4f39c06", "adminx/modules/Rubrics/AdminView.php": "a866300dda84253046f88d19a4467ae1a545c8b1dcac7672d35be986bb38a180", - "adminx/modules/Rubrics/Controller.php": "f3895259809f9b536fbe8d827dec5c3ea2909133ea7b98391bdde6b999c223bf", + "adminx/modules/Rubrics/Controller.php": "d60d21f8d90048a59eb97e924d7f7539f4ea3979aade0883109118b05b0fc1d4", "adminx/modules/Rubrics/FieldAdapter.php": "edc4b730499111917360670632573b8d28cb7c192f71e88e8c60c7c8c3e981d1", "adminx/modules/Rubrics/FieldAdminEditors.php": "d3bb0a8cd7e4b44db93b780ec95c49d3974bb3fc3167110a2f8ef044e921c348", "adminx/modules/Rubrics/FieldConditionImpact.php": "77600152ef7e6a98cbfcdff1bc638aa6b1a664048bc2b839188b56a1ebf0a735", @@ -487,7 +490,7 @@ "adminx/modules/Rubrics/FieldEditors/RelationFieldEditor.php": "9504549a3b81893ec8a114a286a960450bbd302cb2f8f9af97660c8332f91925", "adminx/modules/Rubrics/FieldEditors/SimpleFieldEditor.php": "e961e7ab2bf3a16d6d9131513f11d2d4b9520ecee5572ae7e1b7ae8475d1cacb", "adminx/modules/Rubrics/FieldTypes.php": "c6cc64b0e1b1fb29b65275d337e5747b9f9f68ca46171e7e7f07129cd27b8409", - "adminx/modules/Rubrics/Model.php": "97007d19f651bf8fce9599d542bace4ed4408bc0f65407383ba5589b8b7eaa48", + "adminx/modules/Rubrics/Model.php": "21f19765b1ca8e4ca7bd43fa8bd9737e26008cc152e77737215bbcc0572855c7", "adminx/modules/Rubrics/RubricFieldPresets.php": "80109bd9f066f077ad19e48d7c7599e4dbf7b1d0c06c54db9fc921992bca2e77", "adminx/modules/Rubrics/RubricFieldSetLinks.php": "41cd27e5947680eb184dafba5fd95f707ccad0c20fab2ca948cf882ada0adefe", "adminx/modules/Rubrics/RubricRevisions.php": "83d3659ae0b1d2ce75fe02b0ebfc11d04857556ff352dc2b5408a1481291c658", @@ -495,11 +498,11 @@ "adminx/modules/Rubrics/RubricTrash.php": "0496ca44ac1ba27cc7af1fe9673ee27c7fc4b174507b0038549b90733d22570b", "adminx/modules/Rubrics/assets/field-sets.css": "fe5253279caa882f9623b058c92ab461c476c080baf2399425e522a36b75336c", "adminx/modules/Rubrics/assets/field-sets.js": "efbb011014f756dd59ac1357441d06c9b69b278a9d934f7cd9d2d1d7398cd313", - "adminx/modules/Rubrics/assets/rubrics.css": "98ec76c4301d02bdfef75de9af85e3ae493bfb3c491827b2a9c6e2552fdcae10", - "adminx/modules/Rubrics/assets/rubrics.js": "38ddc91374036bf9aa12cc55abd5ee412b829a729379ed7f9727d84bc12be84d", - "adminx/modules/Rubrics/language/en/interface.xml": "b13fb75bc6770cc6970ee314b2f3d8c492d6227532533d46381c8919fce8bc78", + "adminx/modules/Rubrics/assets/rubrics.css": "72898787697fd0e26c61105c6f1fe5b509d731234e60b438742e30cda8fd6cc9", + "adminx/modules/Rubrics/assets/rubrics.js": "d0384f3fedd7a765a5d0006a1ca5080a9cc37fade556e95c2561927d197ea2ca", + "adminx/modules/Rubrics/language/en/interface.xml": "7edfdc6fe447448dbed987bfbfb8244557b2a7fab89a2ff3dd1e29eca57a6033", "adminx/modules/Rubrics/language/en/runtime.xml": "4cad3d97c6a2695d038286cedc2c4509230c3bc9fa789dba2da9db89e8d9c93d", - "adminx/modules/Rubrics/language/ru/interface.xml": "3654fb74ac081dbb291f5ad13f0c83b2a83b9ce9bc2ebdfa06f9e0a49417b2b0", + "adminx/modules/Rubrics/language/ru/interface.xml": "7df4b3f148b367ca3185174c0feb3129f7ce28f99791a2f49de256d78bae7730", "adminx/modules/Rubrics/language/ru/runtime.xml": "1bf3f8341af4561a4b6b1da98a28b689105285758da0fed959a6222fd83757d1", "adminx/modules/Rubrics/migrations/001_create_rubrics_tables.sql": "a827a92e9d83361569b7e1e7c65b65cb019d1675a9078e05002de25b3e62c72c", "adminx/modules/Rubrics/migrations/002_rubric_field_settings.sql": "4406f7ce1a9e9b0a105c4a33588791d41f12a55449baeca2565d5573e79f798d", @@ -517,10 +520,10 @@ "adminx/modules/Rubrics/migrations/014_rubric_purpose.php": "2913a1a7bb6f4c5665ad05704dcbbde78c7ab6b75b0ad7643fd00e482af69411", "adminx/modules/Rubrics/migrations/015_merge_directory_permissions.php": "648b3e232e9426f84d69238295515342e42695e46288b901950cde2e8979b0e6", "adminx/modules/Rubrics/migrations/016_rubric_trash.sql": "09385e8d14d5d4d977db59c60035338404019783cc44c6c784cc2172faab08f0", - "adminx/modules/Rubrics/module.php": "4aec29585bc8cb20be30b4a741eeb124f5836bd714593ff717f0ce59a889ebb1", + "adminx/modules/Rubrics/module.php": "ae3e957e9c3e099e66fcd14d9ddcf76a172207ff68d77d6279ca7a4c15c37c36", "adminx/modules/Rubrics/view/_content_tabs.twig": "e4c0a9b899b5085aeaec2e1793b8eeac4a7619959fffc7ce39151af1250e0d9f", "adminx/modules/Rubrics/view/field-sets.twig": "911dd7cc9546411e1b29724466328c7d2db8db630b2b52d33e8443a066b16810", - "adminx/modules/Rubrics/view/index.twig": "896fb1f4b8e56803f857857b288f78207efe60cd659277f257abf85b2e8e1cc8", + "adminx/modules/Rubrics/view/index.twig": "4c01e7b020d16528b2a2df68e35bb2e4639efabe30adc4f19508d85701e788e3", "adminx/modules/Security/Controller.php": "c7f2263f460057191402dacf8948b822f9b33bbacbe94e6e9ad871613147fc86", "adminx/modules/Security/assets/security.css": "fd8c477d07c38450587153402380040b72fa9a92c60edd532c4b21046cfe375a", "adminx/modules/Security/assets/security.js": "f270dd0b910b9aa4815680b8d80d66ffb31bc7862f74e628cc60efba4205a99b", @@ -533,7 +536,7 @@ "adminx/modules/Security/migrations/001_create_ip_blocks.sql": "832aff733e2c25a43164c60a601dba08c21fa29ac9e826568055dcdb65417a76", "adminx/modules/Security/module.php": "557308dd9dbe114e5c7129e1cfbc06f25ded104e08c473513e2f388ba945198f", "adminx/modules/Security/view/index.twig": "b70bb298a3e1aed377d31bc6dd6b7937cbdcb71cd7098113b8b026ba9dbfab84", - "adminx/modules/Settings/Constants.php": "03c0af9ffe9c17fe879974c49396567ac0584f2474101715baf6ada847ac3ff4", + "adminx/modules/Settings/Constants.php": "5f8d15924c33f2e23e6f57f2934229e9c16333334f8ce3679793b35e5acbe0c2", "adminx/modules/Settings/Controller.php": "90aff255d936753ab763ec534a097e9988f6c737bd5be2ba1194a7700a372e72", "adminx/modules/Settings/Model.php": "9e16004c78a03d39db1bdfd5e23b88b77e8afc7b8f57a2a21997602ace277440", "adminx/modules/Settings/ProductionDiagnostics.php": "b23d473a5f6e7c231c68abe4d48159b177699b5f0c23020e96252b240f86c87d", @@ -577,8 +580,8 @@ "adminx/modules/Themes/Revisions.php": "f3927eadf841873b7a64976e28f2752b6d1be839327922720a0cd33e30d0884d", "adminx/modules/Themes/assets/themes.css": "c54dd5451693f5117a22c9b7d7a742847e6c6d97a7700d38dd28111337392d38", "adminx/modules/Themes/assets/themes.js": "1ab50ed9c1ff67ad4e4b8b295c245ad5f040c7b11bab102d007953ba1f79042e", - "adminx/modules/Themes/assets/view-overrides.css": "62e6d1a90c8819f50318240e93941054aaeb1b15442d3cebb954a4e839075699", - "adminx/modules/Themes/assets/view-overrides.js": "e531167445281fe7beb93110d6e089ab258a4d110108c3fd44fd4ff981dc7c6d", + "adminx/modules/Themes/assets/view-overrides.css": "0edd417ee79470e3a650a232b859fb68390b38dfd0b401a5367326a6dd416ca8", + "adminx/modules/Themes/assets/view-overrides.js": "480b8a128320f633d68fc439065fd6706c4208ac07828f438019563d783a6aae", "adminx/modules/Themes/language/en/client.xml": "5f9d0a1ca7320e8590468e626433fff92b55cb9ca38d8723d4a363feb77dc3b5", "adminx/modules/Themes/language/en/interface.xml": "30365f6c02c048fa2d0e94feb82bda45bdf8cc9fa665a7943593bb60636f368a", "adminx/modules/Themes/language/en/runtime.xml": "66f4efbea3acf5be49cda9931841873e7c8bd68e263ef7a247233b4d762e9887", @@ -587,7 +590,7 @@ "adminx/modules/Themes/language/ru/runtime.xml": "f8046256e75de65f6f20c8d5b5bd6a927653ca4dc8b6b8f205756b255b624c51", "adminx/modules/Themes/migrations/001_create_theme_asset_revisions.sql": "21a2ce27d0b97be6493cdb86bffbfb0cb8b16762cc7b0025d83bec71d56a760c", "adminx/modules/Themes/migrations/002_place_theme_navigation.php": "62a2f2953f3d5bb8df7e39c83a1de83a56008952540c8c28c6a12f33a8fd7f95", - "adminx/modules/Themes/module.php": "7f961194564ff6b2d7a6c450fad2f966118d71589a6e2d9f1f183d4726f35c7b", + "adminx/modules/Themes/module.php": "5f84abd13c0d03f6be58f7c0f4693bc9ba9486401baf957cf620c680fda562f3", "adminx/modules/Themes/view/index.twig": "68a06ac9ee43b0052c877e89c411a1d149f212418def78e44a1f4a73d80344a9", "adminx/modules/Themes/view/view-overrides.twig": "876f8f47ff598962614198fd89e5f112f04294215d1ffbe5f6ea3bb294af60ea", "adminx/modules/Updates/Controller.php": "1aef3e6cec043e4e66ab862b4f0c7081d452bc8a1295fc125860eb0b02fa89ce", @@ -627,7 +630,7 @@ "adminx/view/main.twig": "4aa00f5a2c50e3cc4d339c0ad9377526db6e8a65575843be59dfd20df5210344", "configs/db.config.example.php": "e42bdb47aa7d1bc9cd85cb36e05acf940cafd951d6220664c485d1b971f18809", "configs/index.php": "48e6b249e3d83530187c095ede0198af498c59f384bd458db74f9e0c2306eba9", - "configs/public.config.php": "54ad564eeb68979b3040fc3cddda8e9b5607c016fd91a045bdb2ef3d0a1afa03", + "configs/public.config.php": "882ea6a03ee8df191be8ea68ba78d39ae600d918a0880ebdff158fc38f534aa6", "help/README.md": "d12965e7851dec5241dd74db731c110a7e0f4acfd7139ae28ce21d53193b1123", "help/administration/README.md": "af3efa4bcd54eb23236735d461484e13b6319751904ca8856412b931e2ae032d", "help/administration/console.md": "5efb2adbee857eaf0b8c2816ef1556addb2c9b21420bf972c6bdf62911fa9ad4", @@ -647,14 +650,14 @@ "help/content/README.md": "273451d12b6360df56cc58323bfb8fd7521b4e3daf8f7ad93c874fe6877af048", "help/content/blocks.md": "1d55be2a9f1a48df426e5856a54307d77b352d0037d68f08ed7e16a322d9ef8c", "help/content/bulk-editor.md": "821107322b125c9344bd04346037fbd19f8ccd0ad6da822fe78af3299d01f746", - "help/content/catalog.md": "2e278644df3a40d05fad7b2a753a90398667b4bb6cbd88dcee8177e3a930b3b8", + "help/content/catalog.md": "8ca86447bc45f8f14688d7f74521569b50d4176b9ec2ecca0bad25d91a0ef0b8", "help/content/content-model-tools.md": "baaf738aec454b1855ea110b8f5e1ef3ceaaad51cb920d4551cd088daeab7e76", "help/content/content-studio.md": "91ef485e614a9a71a07d4e6c143377f7052ddf3b00d3f2f0d0a32258bdb14dbe", "help/content/directories.md": "ff6c5ea9bd7fe1fb9d0aa1875d03fc3bc00b2bd2b0ec83d6496cd55168db294c", "help/content/documents.md": "273851452c0fb8fddd47019fea600da187025dcca271bdd91d59acae15d6b4c5", - "help/content/navigation.md": "a02d0f88b5a3aa67fd14a2c26a48c9c3c4bb73f4824fa453c20f3e2ef4ef24b8", + "help/content/navigation.md": "50425db83ae70b8be72c69ecc6c54f77a15f029a244185021de1cb56efbb344f", "help/content/presentations.md": "6e349bb4d1d1577617e6bf3d987b86ca6b255f64a47cd1ddb0e38c5242b788cb", - "help/content/public-site.md": "ea0edea4b3afda64987e5643397237fab227f5fdfa9d9551b73b93b32558f818", + "help/content/public-site.md": "9b7cd51d6d36d21daa73b47cb243b84eeb79f0ff48e9eb61c5951e82c24f7c73", "help/content/requests.md": "c008b1026520c85400fb9240cb117fcaf384531c06e859c1e36ccbb3a79a8590", "help/content/rubrics.md": "2c9842ce5647fc85663b02cef14f141c673694f0a20856c9262b6ccbea436c3c", "help/content/templates.md": "c6fae2ef91c741479d1f34fe66d00e83f2d2ec1aba1a4099773a04a6e1b6552c", @@ -676,7 +679,7 @@ "help/database/security.md": "581d5a89b5ea7cc01f7800878dd879b48e48a912f4a4c81c5f5dadd9b990e556", "help/database/tables.md": "a027eb9c5e3c65bce645e6a7afd8ad9e37adfcf2e514926836d8a14cb0258075", "help/database/transactions.md": "da679da1e7656be20048566f25b51c6018a0d7eff1f2e5d54228fb3d54071aff", - "help/debug/README.md": "41b7954c443330efe28cd3a14519c7c8076165a9d96c0dc3d3781a111e757085", + "help/debug/README.md": "665915c103ebb1bba4360508d2bd111b2bc093fbd7989f3ab7adafd01e8d145d", "help/debug/custom-data.md": "445ed27dbda5b0ca035504e2f0cda023746def5edd3aa1f62189e133946e293b", "help/en/README.md": "cdf84634ac731f1f434ec496b171307c38fccd6e6df335dd4dbf074e3e2cc12e", "help/en/administration/README.md": "478a59925324a3dfb3da193b8e83b9a45e38fe77cf41644efbc35cb0b65e0298", @@ -696,14 +699,14 @@ "help/en/content/README.md": "7c871512fea7f1bf635d5a816e322161dedbd8c158d520cd0385467e8dadd1ff", "help/en/content/blocks.md": "34657f0a7ab977bf78d5b7645bf80a0755f40830bab4d4620ca7f39ea5992210", "help/en/content/bulk-editor.md": "c99d5eb5058d6714f0281b84bfdf9020fc63ef27519c095af5f92fa2d5e96b44", - "help/en/content/catalog.md": "99a6e5c3e17ac0c7f2e04cbde4f790334f687b3aebed5815be5006ab361e530a", + "help/en/content/catalog.md": "8f12199f4d727e0ad715f91e980de638357fe1fa5af0702351fd3ee30afe29e1", "help/en/content/content-model-tools.md": "fc50f8c334a129d3ead4a58503a7659abc2b1fdea7c9d277feff1e3ba4bb7b6b", "help/en/content/content-studio.md": "194fe41a1eefdf7da3c9a47b8539ed3ed9d785d2a75816a39da6d2784ec40925", "help/en/content/directories.md": "cfadf2361ead3bed9b63435041af8c91e24ec8b492906f0d9b976047edc123fb", "help/en/content/documents.md": "2831a54d7c9e02b89231c48c406475dff64721e48ce76d3bd92b768043422333", - "help/en/content/navigation.md": "18f6e033c5c01eecbd7a3bc4b7c557f272f0039c811ea6f4ec2354206b0a5f21", + "help/en/content/navigation.md": "585f6212c72faf32fd67bca6f03715b5e5754ae9d6b162174cf40e76cd9c2454", "help/en/content/presentations.md": "f255470ae47453d2e458b1829316c0e1e8e7fae73c9a1c1190d89f522b78d871", - "help/en/content/public-site.md": "619cf5d38d49f6dc1c54836d4e27853da03a82f3404b69ce7e0c395a3222ec45", + "help/en/content/public-site.md": "17352cd32290a5172ce7ec149b53de83a63f7ac60d0e42e7cbbbc17363a74c76", "help/en/content/requests.md": "71aea0d1fa6dc9b6f6dd41f1c7a4d80af93c0b5e18341dc26f59d1f0c156604b", "help/en/content/rubrics.md": "bd69370ac19ab0aaf6d4c1cba615ae21f57cc3e241ecb6706f23a69a794fb3c0", "help/en/content/templates.md": "f91c141dfee841a1af8321625788cecb9dabaef75901e188127815b6d5b5ce6b", @@ -725,7 +728,7 @@ "help/en/database/security.md": "f2d0b218fe9ba8c8c5fcef2b6a832cebc58e0af26400a13f0c4a32d7d2ce1d93", "help/en/database/tables.md": "d117e9b6ecf04f8b8cbcc99e81874a09b84871dc8273a248ba676304f37e8c67", "help/en/database/transactions.md": "9cd1b15425647281d40d11d7d0453f8758a1c41859ce3bf1de5d091ccbf2246d", - "help/en/debug/README.md": "4000fae72a034ec3be9d1059fd0e0a850efa8911dbd4b8498d8cb0b23ddfa4a0", + "help/en/debug/README.md": "e148c32ba9c0c3231c02094263410c19519b81b38f5e74564dfaec4f91dc6f7b", "help/en/debug/custom-data.md": "0cd068b8d74bd98240bb86d9d4bc01d2630129eaeff8eec88b1630a094016f32", "help/en/fields/README.md": "46c4fb2b44f1fef2f25ed2be3c730dd1d4e1aa0f48950e6069c3772acdcc5b17", "help/en/fields/development.md": "4a953779ec8f08a79e235bd658d58ebc69f5758e2d8c55d49d5bc074e5aa0a41", @@ -753,7 +756,7 @@ "help/en/helpers/Request.md": "3e919b34a2559e818938895a6e92d3ca87550774712d03913044e58a4d304d99", "help/en/helpers/Response.md": "ca68c1d5cdd133daaa78077e00a15fd702bc47890ad33c224656ab4c33c17e52", "help/en/helpers/RussianStemmer.md": "c55946a78392ac8c0534187cb2b4232f5f0aa6276114e0c8e31aeb75beaf9fa0", - "help/en/helpers/SearchText.md": "42213dae0a4634936c01a67a4beff51167921b5e2e7f71c62179acc1eb2ddc1e", + "help/en/helpers/SearchText.md": "7962291f5e82ae3ce3a5c6749b479e2e5a02d83202910f57d4d9bef03791e657", "help/en/helpers/Secure.md": "c95d170799ea7bae219b16f55385db17fd5f52db2898b59fb949fd87fa0a8e50", "help/en/helpers/SoftDelete.md": "34912f62fa21bff29d5124280f11ce911f74f2a9fe836ac230879d0f992094a8", "help/en/helpers/Str.md": "8c850a76b9932046bdf0232735a0050bbaa8ba4dcc2526d819862adfe2af368f", @@ -769,7 +772,7 @@ "help/en/hooks/lifecycle.md": "ec82cd9ccb2bc48e9054ec1876c40552859da4ead45129f920026f821f84e87f", "help/en/installation/README.md": "a122a89fc4a910064f02fc906a0fdf3a9098147f9ed2f98a75185ed66d190f29", "help/en/installation/admin-directory.md": "26a7b2198078f8ea11dba7fa6a0699cf35c66e78fc88279c82012e6a01f59a38", - "help/en/media/README.md": "1f346b26bd6cb0f7238204ed0cb1d56cea9f6bac7f96e06d062fc8d01226d702", + "help/en/media/README.md": "3e6f40e20bc3e7e5c359600b0047534690e9e6f61b119aae91b282f797b68bda", "help/en/media/analyzer.md": "d49175369396da1cc3d50ec4cbc7684f36971021532c648375999e37f90a4f20", "help/en/modules/README.md": "fac8da620ec1f087bef3c7cc3a4178d95747ccece3524ee6c53ba6c3a65b4a21", "help/en/modules/antispam.md": "1808f910d530f7068e60e2a9306c15ae5b69cccc30ee3e492f35cd535004f65d", @@ -777,9 +780,9 @@ "help/en/modules/benchmark.md": "e7b9d233abd386db41413f45c79639a3bebfc37241bdbab461028e87a5615f87", "help/en/modules/cache-warmup.md": "d92183948e03dd4f9a18308d36df7d5ba57e7e87f268b5f3f1de38ed99c518dc", "help/en/modules/comments.md": "55f45f748f32fbd36233c43574e212f3fa3fdd1ce8eb819f9d1cafb53215ed97", - "help/en/modules/commerce.md": "d916b293c7bfb3567fee02f5d9f15de0d5329dde60d5c5d43f24bce660860156", + "help/en/modules/commerce.md": "e31cbf7ead9d758401e35d7723f0189a354ce818a4fcf5a0118c73795088dcf0", "help/en/modules/commerceml.md": "610f6b2f9abbeeac604da0408192ae52dae7d6f3fb09e0d321e14d1cc190b808", - "help/en/modules/contacts.md": "3d4d7b109a7a7bf20ceda0cb0da65634131a837c7d39c4a1433f317c3bad3512", + "help/en/modules/contacts.md": "81c818e9cbcd1d61f34d9199219ea160a04bf88af110b32c3527c65fba65d39e", "help/en/modules/content-packages.md": "4b89df6d05fa75e484e38e404d53fa7ecc6b61aa6930fbf74cf9b6611bfbf532", "help/en/modules/contributions.md": "ec283e61f09d6008a7208fced495a2748685c50bbfe22b384f458cf338e63125", "help/en/modules/crossposting.md": "7b8fc0b89c90e27c8e90431221cfbf7eca4c3cd2b5495a0c8ed5d76906dc1daa", @@ -818,10 +821,10 @@ "help/en/modules/rss.md": "22958cb500ddfcd83201086b36e43365d51f9f125b8663ec38e2e30eded4d0ae", "help/en/modules/scheduler.md": "fc0c34af054e0081c6ad8cb1abddcff014c0a6eb77178c111fb0b15e0585c75f", "help/en/modules/search-analytics.md": "3e21c935d76171a5a74cba9fc2904092d2d30062918c2f7ff1988aae0e499264", - "help/en/modules/search.md": "6bd582bc687436d99d292655ab4f9c3e3726c53a5dcc7d9dd94744545d22daf0", + "help/en/modules/search.md": "10cec34b6a4eb452b514f224e59e9f600904548887c63f19a2cb61e6ed6bbe62", "help/en/modules/seo-audit.md": "e18adcb79847fb5a1cedc8cfff03b5938eac1c2e2d22816ecc5e5b02b48b95d3", "help/en/modules/site-readiness.md": "dbccccf0633f0e72d32cc8a2b0de319dea576f28b67f0d9c2907106c97fef1c1", - "help/en/modules/smsc-auth.md": "d66bdd5cb748db83b565e7cbc8150bd38099de778e94c9c4cb0ff1d065703479", + "help/en/modules/smsc-auth.md": "1c7a3337404e92da4e7f60f53d11fb6e791c18ee8e1533590deec111e3efe1ec", "help/en/modules/system-health.md": "f43c3745ee1437f392724d35299d208dd73ff344a3efff60273cc7b23c6fa731", "help/en/modules/traffic-analytics.md": "5ed8a48a4d05350d8dced3db8fadcedbf32a2bf80147da39872a0f591ca8ce84", "help/en/modules/tutorial.md": "2e6bcf3e7de1799fadddbe5b5dd56de613c91baf2a4d6c45232eb2144279780c", @@ -852,7 +855,7 @@ "help/helpers/Request.md": "93b98e898273dc5a1e0cc77babd14487181464bff2c30cb8e08f5425c520ae61", "help/helpers/Response.md": "d96965599876b9244a6a2deaee2f18f9d033959a0f0f7b942c33e3aa1fcf143f", "help/helpers/RussianStemmer.md": "10a849612da6b01d3fba062550a7765b1bfd6f558c2751e5ceb67887924bd2c3", - "help/helpers/SearchText.md": "314fcbffaa95ba52840bf07d0a0070372b51f0db62dcea4ff770184a467d6152", + "help/helpers/SearchText.md": "cb28d568ffefe43002611300c8273f2e8a489742c3123a3a4ca0795324e88d56", "help/helpers/Secure.md": "17ffdeb9c226be816e0c00dc92c90bd86643261709bc889fd238afef5963b61a", "help/helpers/SoftDelete.md": "787d30d2880a304d22b3086a3a5f8deb5d282b5617bb0c74e0b642295f54c39d", "help/helpers/Str.md": "34b54c40ba492a5899e32fcd695380ec458518ca287ccaafbda4c0f38d9bfcf7", @@ -868,17 +871,17 @@ "help/hooks/lifecycle.md": "0d73b7eea62dbc1cc5f3a07449f465105ad8a477adf85b22d2adbc53529b81d2", "help/installation/README.md": "6a9c434bbe81f493ad3b07ad83fd8c8a8739423f67f3e657b5a9a3dba0d2738a", "help/installation/admin-directory.md": "fcb31d8bad1c18dd7e5c6843dc4f7b8c4139dbceaa670a7c4e0c060479f5ef9d", - "help/media/README.md": "9a8027ffa29ad342e194868890174fbdf59b5dbbbd7ef39db9f1cf79888b2070", + "help/media/README.md": "517d9f25119bcac6910f49a9a4c9876fca9dcf6f128e0ce8eb4160648e3bc20d", "help/media/analyzer.md": "a057f3e95842d8d5168f9d456be656c91dc2382c26ce9f205bb620a902132ad4", - "help/modules/README.md": "01f2d804dbc841e849e41fc07e9d86d5118adc30a3da98a39672200c2ae17d65", + "help/modules/README.md": "7baf0060effebd1f0f6870b75e617eb3aeabc8bd36bf174de790cd23717e69d6", "help/modules/antispam.md": "ddcb858c6c80ee140addbdcd0e27ae3f7900100f1745ee006edabf52d0955fff", "help/modules/banners.md": "e8faa2a923c5f5c39a0b7caf80a511d03fb680bd2604ddc59ec0362a244ee77f", "help/modules/benchmark.md": "6c31f16fc3f083f29c65398c38b78609a3d94da168d30a93825af8ee9650eb0d", "help/modules/cache-warmup.md": "56c05ec252b44a1a0d1c4b09efa90cf9d450b0b138787903c898f56b377b8749", "help/modules/comments.md": "04bcdea5aa7740e3749b51dcc9fc2954e98b22298d3e4fcdcc9865d94e1d0376", - "help/modules/commerce.md": "7fac85f0cea873bc57baa79c5bc57bd4d5bdb11af291d105e01785ab84f3cedc", + "help/modules/commerce.md": "0255c08bdf10f7db8e530c15e987c5d137ee115434ca0a0d71a831cc9fbfad9f", "help/modules/commerceml.md": "60a0a5c541b560b5a6a4ed8213d9145caace68c15be534af13f5f817eb5251ba", - "help/modules/contacts.md": "8df21307a300a335aaf243cb42a107829114ac031da128cfdfc6f4b94452dd3a", + "help/modules/contacts.md": "cb4284709f7b469164e3ef4c817893cdcaf4eba1b460164fb36f75a798bc457d", "help/modules/content-packages.md": "8dde0ebc897b7891a6afadb6491f4797bef26622918addab67f0f4ebfd719678", "help/modules/contributions.md": "3213f68af10e1b6a200aa61a3aaa9dad270da7ccd675b43bf7cc1ded90b55e60", "help/modules/crossposting.md": "d6d0922c8d48d3f35418a00227a96d9343de024ecbc8affc1712c0a223f4547d", @@ -917,10 +920,11 @@ "help/modules/rss.md": "0f8fe5fa5bd4991b432068a5a520d4a45d41dd6a2c6011f7f293f74c8d9c1588", "help/modules/scheduler.md": "a39cf392ce9cf5af63e92063b95aea63979a24b27218a4b090b94834ef90b536", "help/modules/search-analytics.md": "0444e0dacabe408358bcdfda4b6b2a475095e8b1c0ffc1361ff58c4db0576d35", - "help/modules/search.md": "3dd37c32598c12654dd4ab97ec0c50d42ffc5083485ed37be0f135296af23afe", + "help/modules/search.md": "a39ffbd45e7d5786cd16d2678f5386c55c3081063177f6525b12849da1c251d3", "help/modules/seo-audit.md": "b0fb78eda0e83c0711b7717fcc730e7bc0cb86c6d692f21aa749cc4975f0ee27", "help/modules/site-readiness.md": "2c7f845ece693ef14f23ea2b3b226f38ebfed305fc67bf842fae971f0e12255a", - "help/modules/smsc-auth.md": "13b844d102adb451d154ee9aff9b44d8b5faaac67c4491d73c832962f9a194d2", + "help/modules/sliders.md": "f3022a36b5c483f49d63b86b4651989e98636018fc8a7449ca45b2875277a3fe", + "help/modules/smsc-auth.md": "361b46fbc4812513f59e8ba15d095607851f835d7765ac396c3efd79ecde10e3", "help/modules/system-health.md": "671d44d89f0d3ada4fcaa4ef3d8a7662a6c77dea6c0cd567d8f3e923d29e12a5", "help/modules/traffic-analytics.md": "12f966acc6ffdf73e2d40682c6db203f8dc3918ba5461a78607c1d783ed54d02", "help/modules/tutorial.md": "4239eef8d793b7bb799c901c821b229e456c7602ac694c0e3ffc5028b4eb57c8", @@ -944,7 +948,7 @@ "system/App/Common/AdminAssets.php": "dcd58f19fda48263b2912a10dfdc24e3f12967683649c4f614a8d54c62d51b86", "system/App/Common/AdminLocation.php": "d2729b0d627ddbdeb7f0c4b110664ed949f373946f80929c51688391c64352de", "system/App/Common/ApiTokenRepository.php": "0795e1add3723708240949b7aeada364fbeadd74366884b57e9142efcfaf617c", - "system/App/Common/AuditLog.php": "4e2dfceba55fd653d071261766c9051322a03a994034677463782ca0d09f3f87", + "system/App/Common/AuditLog.php": "5306d21085ff7ef7313f5798fbd416872825ff7d2831f94cd9744de010e1cc2b", "system/App/Common/Auth.php": "647421cae2ec8bbf273d687ac1fda134c7bcc28db4977e01f5896c79e7c2c83d", "system/App/Common/Auth/IdentityLinker.php": "7da4d902405bb4ead2278e5bc3578cd0318422fe82318bec94257ed44d5ba98c", "system/App/Common/Auth/PublicUserNames.php": "0345d1f452e0a9accaa9b98eea71f27a428692a5b4f2ad225a10ad8bcf777684", @@ -1019,7 +1023,7 @@ "system/App/Common/Registry.php": "7b4ddbb3f96a7ad54a8d43e151cb595e598d3620b368d21721927ce9d54e1ea3", "system/App/Common/ResponseSecurityHeaders.php": "b159a7105d3c1fb3ffdefbbc5997741d7b0f83bfb26fabcac96f61b53969364f", "system/App/Common/Router.php": "4b0dd3fd9f732177070ce3326b691a8decfbe698aa0d8cf687a18f6c02b73d91", - "system/App/Common/RuntimeConstantSchema.php": "1ea1a029a29e4b0284d047f6ee6ec97dd50f4b42556e909a1a03481a4a380105", + "system/App/Common/RuntimeConstantSchema.php": "e67a2de96a2496e0463a3b9e9d66fa6b2ef0e4b7dff768469ef472ba639797d7", "system/App/Common/RuntimeConstants.php": "decb1277dada75ee2b5c7d531f064db7ffecef5b3ad71d306111b2a45121d34f", "system/App/Common/RuntimeDirectoryGuard.php": "2263f100530f7b0a7790f698581dff14181d4e2a917c12ad1ea888e5df1f59b2", "system/App/Common/Session.php": "4a870a109c75ca941bebfd798d64b1396dde7d56ec060d9491f7d71b70a13deb", @@ -1041,7 +1045,7 @@ "system/App/Common/WebMaintenance.php": "a91f9ee8371da6c6a020d9ce39e1f9f7b517b2644ea51ada65f1f487ff337e6b", "system/App/Content/BasketTables.php": "1c4d1d9a5ff894c6ebb0edbcfd7bb6f791124e46dd8bed3b70fb0ef2c15069a0", "system/App/Content/Blocks/ContentBlockRegistry.php": "53bc204e7dd1f9d61781049627162341a4d7e656783915161fa5c4eae4cfa228", - "system/App/Content/CatalogMenuRepository.php": "d2b384255fb9e67264f071064dafd645913a73ee640e559d600b1671455443eb", + "system/App/Content/CatalogMenuRepository.php": "6ee0890c5407fa37f5f4a88c5e27ca58b27407a8362e012320bc26fd072cf523", "system/App/Content/CatalogTables.php": "5abd93b17142ea5c57a0726c8c6e3dcaf896790cf4ba31ea69be19a828ac9517", "system/App/Content/ContactsTables.php": "d0042c761b854903b483e1b3a30d6014c596eef1a03c40cdbedae4fecb3c25d8", "system/App/Content/ContentPlacementMap.php": "55950a599eb5385e2d81833815f0e2c08bdd06c61450565052ec1c19d38e00fe", @@ -1050,7 +1054,7 @@ "system/App/Content/Directories/DirectoryRepository.php": "47d4f7a91841ff437c4448aa71f6a2b38c621dcf5a1204bd2ff4948f3ad671c1", "system/App/Content/DocumentTerms.php": "353d0a36e0cef77d4016f9edf9c2a2a3a27db953a3eb4cb91d7ec49af18b0609", "system/App/Content/Documents/ContentCacheInvalidator.php": "d2bfd72d4df1a05e281b88543fabb8356ffc9799d37286c3767c6a0173ea91b1", - "system/App/Content/Documents/DocumentAliasRegistry.php": "aa87cb8b65990f480f5b4f5dea83948dec9758fb4069b43eeba4be7f7752be51", + "system/App/Content/Documents/DocumentAliasRegistry.php": "803ccfa70c3648e2e4c625aaa827597431d4ea54dbf83618b904f699f9560846", "system/App/Content/Documents/DocumentAliasTemplate.php": "47bbcead460d5d4160daea31ebfd36ecc3657f74f905162f20ee0d1eae78e3db", "system/App/Content/Documents/DocumentCreationPresetRepository.php": "a58de0560e194d8386932a4e2e0e807a097ba1bad1f56cc8d11587f6c20e54c3", "system/App/Content/Documents/DocumentExcerpt.php": "8c5742f976a492531af95f2291e8c824c3a9804a54a27997f9f51a716a57f19d", @@ -1061,7 +1065,7 @@ "system/App/Content/Documents/DocumentMediaFinalization.php": "5ea218f79f835a4fc25da0199aab87137e620b60c31d8e2f587a1b911b3af6b1", "system/App/Content/Documents/DocumentMediaFinalizer.php": "785487028e221726c6bc15662f83ed985701a8e5d21e9fc9605e816ef4c835b7", "system/App/Content/Documents/DocumentMediaPath.php": "23b40c98d3cf9a73df3b7f7083b58b60dd80b8bda71e3e3a6354342cc72322a8", - "system/App/Content/Documents/DocumentMutationService.php": "5ad32bacb4ad5c2b2760db613be291f154ea3882695c2aa05607b1c5bc80f25f", + "system/App/Content/Documents/DocumentMutationService.php": "868e1301cf822516debe1f441f80eb1897d0a1617f8d27a6a2a1dced8bafa6f1", "system/App/Content/Documents/DocumentPickerRepository.php": "0e8efb5b42aadd74725213b8302b53b5147d7e0eb2e83d301a5f073bb0c13142", "system/App/Content/Documents/DocumentRevisionPayload.php": "c7f83350de98b6d98531508eafecc4a2b5a0551c7f2ba77a9e5b954fd1287ea0", "system/App/Content/Documents/DocumentRubricCodeRunner.php": "a9c04196b76ab91c7b1f8b53afbd45fc6727805c953fb5fe5ff36b69846d389f", @@ -1091,10 +1095,10 @@ "system/App/Content/Fields/FieldSettingsForm.php": "e436743e17fab7aaf14dab6ce034fa2ece2f5d165a4aa04450d034606c8e2a73", "system/App/Content/Fields/FieldType.php": "47979aaa49b773e2a00288ffccb746218b58ece8fa6d178a90d0cc9c853055d9", "system/App/Content/Fields/FieldValidationException.php": "1a1d6d5278d6f8ff697e5afe75e0a6f59db2b12121c93b786fd87f8b81287717", - "system/App/Content/Fields/FieldValidator.php": "5408849670818b379a66d5db9b7aa0d94ebbd8438d7788124f62cd221dae5561", + "system/App/Content/Fields/FieldValidator.php": "49a2342783f994d054ca037907cc7101a9cf3a4ad5f288804673c609eb2b0d63", "system/App/Content/Fields/FieldValueCodec.php": "5868e9aaa11a8aa2c4dde33e8b358861b4a5a49f6ff235c1d0e22b836dc3df55", "system/App/Content/Fields/HtmlSanitizer.php": "003ddd83bc6b3c89e1ccdbfe4abf94e013c4a6b1272cf29c1ed36790f3ac7919", - "system/App/Content/Fields/MediaFieldValue.php": "5821060785f859b414a448d4998a9e7b40df69d536574f0fbe600f1d7611ea35", + "system/App/Content/Fields/MediaFieldValue.php": "2cc5db5159f68eb0132937d63641eced0b79fd1465c69cdb1340afadfe88381e", "system/App/Content/Fields/PublicFieldRuntime.php": "9abd8e5dd43c56b27dcbf87d258cd9764ae1d67e95a397a63a6c6516f7a417f8", "system/App/Content/Fields/PublicFieldTemplateContext.php": "785d6757710dee59d8d30756917235bb4f49eb5bd743c01d2365c05d74bf0a5a", "system/App/Content/Fields/PublicFieldTemplateResolver.php": "72c0750c50129cbabc0a97147fe2f2f4b2b3811cd77f4de197dc3753db46903a", @@ -1188,7 +1192,7 @@ "system/App/Content/Rubrics/RubricMutationService.php": "e3190ef1ddd94bdaf077148ce84c5758b2a32683369730a2b847dbbd0d72a74c", "system/App/Content/Templates/TemplateMutationService.php": "8c7e52202454e35eb0c8176325cc23ba760ac40ff0430cbba5e1446c83cf7a87", "system/App/Frontend/Auth/AuthService.php": "1cef24cffd7773f3783ec96479b8e7daa1808b03a34dfc8da37b84e6e09144b8", - "system/App/Frontend/Auth/Controller.php": "04793123f0d4bef77141e3f8471d454ac5b4d2b17dce4630eca40da0e2f0b576", + "system/App/Frontend/Auth/Controller.php": "14a425c24653fdfda4225550635130bcdf67a6d63a1eb3817ad86a41d292efe9", "system/App/Frontend/Auth/Feature.php": "dbaeac564886c7949e0e47c85fc5496c25221d880c4f03cee40cc5e15d042a1c", "system/App/Frontend/Auth/FormTemplateRepository.php": "bcd8797e63cb67803aef2267a2c62e3ad368b5fd947057a768adbb1288ee9281", "system/App/Frontend/Auth/OAuth/HttpClient.php": "b09acf92b312bd05ca78500fccaac3b77d36a1046d64d3615a00d60af4e3594f", @@ -1197,9 +1201,9 @@ "system/App/Frontend/Auth/OAuth/OAuthService.php": "c310a2a6756425a4b2875b12c048b0476dd5b424e89561ac1fa73aebfb3cf045", "system/App/Frontend/Auth/OAuth/ProviderInterface.php": "c99525fd51a1bebc24c189f52f1a08bcef087b98ffa960d1b378deb68022d9ba", "system/App/Frontend/Auth/OAuth/ProviderRegistry.php": "e0ff4bc12ef2349d4f914299c78715438d9fbd44ab98e00937534786baa07800", - "system/App/Frontend/Auth/Phone/ChallengeRepository.php": "1e53d355aaf0adcc8e10a2b1b50e638916fd688c62a7ed6a4bd9c161c14a6390", + "system/App/Frontend/Auth/Phone/ChallengeRepository.php": "2bfd7ad7b4640e653d3ad0e1ed5f1779ad8df2b569bee071c040d44996c15ea8", "system/App/Frontend/Auth/Phone/Controller.php": "bb07bfb74a89742c2dbeeb7edf79f02ae43ef6a252d02a3bb7c3c78144cf280d", - "system/App/Frontend/Auth/Phone/PhoneAuthService.php": "783b671cb6b6f80eb4ecbd7bec86d417dd7030c7768ba01f742600e4a6b55a89", + "system/App/Frontend/Auth/Phone/PhoneAuthService.php": "4f31afa6d600a754cf76805b2a475bf47ffbf7a540b65fb99df098f227211a5a", "system/App/Frontend/Auth/Phone/ProviderInterface.php": "55107c8f6a89bea01b91314dfe523b684bccf5bf9f1a3c8f047fd3a509aa6d00", "system/App/Frontend/Auth/Phone/ProviderRegistry.php": "fbeb488c9b63843085b680500ecafd61389a29f55e0d76692550939e378d2f16", "system/App/Frontend/Auth/ProfileRepository.php": "9cd7be35b048faf407a925e6369a5895b8bfafe6cf756eb3c4321ea4979a9af6", @@ -1233,7 +1237,7 @@ "system/App/Frontend/ConfiguredPaginationRenderer.php": "df4d28a386e4180fd0dbddbc30f08ca8c6345e2f3b0d196482fa9d2a5d4f4d32", "system/App/Frontend/ContentCollectionTags.php": "337085d73f0ad609b5a37a4fa72537459f4ae2e5f503e39a8750be95127d89b5", "system/App/Frontend/Debug/PublicDebugCollector.php": "6755ad710e9d045b2bfa74745354f717c101236b5d64ad5530fd779468969a00", - "system/App/Frontend/Debug/PublicDebugToolbar.php": "89a0fd4a1cab3ac8e3576cd8116332edbaaf6e09d3e05b0daa5798cd8f59c6ff", + "system/App/Frontend/Debug/PublicDebugToolbar.php": "7a92630b59483e63d623fa769e13c246e6bd657c6d027a5d14ab8f95986da0de", "system/App/Frontend/Debug/PublicLayoutInspector.php": "8a7f5ea4cff9834ad13cac7e0d2380d878978e406e71860e1ad9ca183e427dab", "system/App/Frontend/DocumentAccessPolicy.php": "13102e35dada9eb0e174189b976605257b48a32756e801d1ec5c358d0c0912b8", "system/App/Frontend/DocumentApi/Controller.php": "7c5ffecf7e1515710931d7c31b5b2c5f555f8d35778a1fc202a8136b07c2490c", @@ -1336,7 +1340,7 @@ "system/App/Helpers/Request.php": "29cc2cf20e1e4acd6e2f23c3de9b9606aec3f44d0b3577613b4fde376f7ae858", "system/App/Helpers/Response.php": "beea1596703526b7a2424459e392487e8bc8a9ce216f8d70bd2b09564709e0b9", "system/App/Helpers/RussianStemmer.php": "60a896c8254290ae554273132c103c1c209a14944f52cfd631e7a3ae13145529", - "system/App/Helpers/SearchText.php": "1747521adb640161c6f4df648134c8349769e3cd7ddbc726118af81f1a4dcbf0", + "system/App/Helpers/SearchText.php": "12e2fa63a99dd47dd00316eba33f9e162cbfb90e5a5fb9c816fc9c21de0c6ec1", "system/App/Helpers/Secure.php": "99a5a170cd574e5b6a6c3b433c5b8bac92407fba62088c93e893e215f18162a3", "system/App/Helpers/SoftDelete.php": "9b85f227bbbc12e4bddd9bcf211b477044041b87bf94d1a422f80d46a10c3ccd", "system/App/Helpers/SplitTest.php": "d0c875c264df66509b53693dccae8d9f482b069dfe98eb5820481077f3c4508c", @@ -1350,7 +1354,7 @@ "system/language/ru/lang.xml": "7d46cc9822f064a1af4d6528ccfe2dd4a9cc318912e327fd807befd2ca3dfd11", "system/preload.php": "66bfb1aaf36ba85945b729b09a37e96ead0be1cc2749ebd9abd4b9da4f25ba0e", "system/public.php": "3f72b5bf44bc0ba5ba6fb6b3adc2e2f9d5e9902d9cdfa3d7b748f4aebd179b87", - "system/release.php": "e9aeb913c895912f8dae625b0311fb38cd871c20232eede2948e934ba4bff656", + "system/release.php": "73af5bab9ab6ad78aa6c4fc4509dd4419cf68e66142381c1500c01a72b655c8e", "system/vendor/Captcha/fonts/palatino_linotype_bold.png": "38b6a1d4a4bd1d0c056205119c5e24176913ac0d898371f53a0339952a319365", "system/vendor/Captcha/fonts/perpetua_bold.png": "55dbbe97dae128dea47b5e8d640414b3d813119c854c688037a20a581ec8fdc4", "system/vendor/Captcha/fonts/times_bold.png": "d3d32ce1f418e3c3c3b1afe3b6acabadb36207bc12368f5e86420cf1a529ff8f", @@ -1932,7 +1936,7 @@ "system/vendor/Twig/Util/TemplateDirIterator.php": "b52ad2c2cda8efdb9b6b3719fdd64c5a3e38bba1ca440c1941132ac60d756ec7", "templates/index.php": "1a0b826446e8c8211372f1f45a6ace298395116cd80bc1cbb2cdef7762038a95", "templates/public/index.php": "c57a4bb3eb5ae6c0394cc748a14dc7f703a9d819333f181f0edffffa680100bc", - "templates/public/templates/.htaccess": "ef94d4c2ac2a038b6c2ae673d9573333a0a20f7fac9e2d75af11c6c387a157a3", + "templates/public/templates/.htaccess": "ca761a92f2b6eb47feffcf200a8fd846e7fdd8abe065008d29beff0319ca3496", "templates/public/theme.json": "4fb596d58dbda7f58c26c4f3640c56d6f6981f402ffbd368229adddc23683690", "tmp/.htaccess": "ca761a92f2b6eb47feffcf200a8fd846e7fdd8abe065008d29beff0319ca3496", "uploads/.htaccess": "90cd571b4c9f09a63732254fbcdca92cc7da8560a6e5b4d9ec7e58ac40e528bf", @@ -1942,6 +1946,7 @@ "file_owners": { ".gitignore": "core", ".htaccess": "core", + "CHANGELOG.md": "core", "README.md": "core", "adminx/.htaccess": "core", "adminx/Support/AdminLocale.php": "core", @@ -2357,6 +2362,7 @@ "adminx/modules/PublicSite/PresentationModel.php": "core", "adminx/modules/PublicSite/PresentationsController.php": "core", "adminx/modules/PublicSite/PublicViewTemplates.php": "core", + "adminx/modules/PublicSite/TemplateMap.php": "core", "adminx/modules/PublicSite/assets/presentations.css": "core", "adminx/modules/PublicSite/assets/presentations.js": "core", "adminx/modules/PublicSite/assets/public-site.css": "core", @@ -2373,6 +2379,7 @@ "adminx/modules/PublicSite/view/map.twig": "core", "adminx/modules/PublicSite/view/placements.twig": "core", "adminx/modules/PublicSite/view/presentations.twig": "core", + "adminx/modules/PublicSite/view/template-map.twig": "core", "adminx/modules/Requests/Controller.php": "core", "adminx/modules/Requests/Model.php": "core", "adminx/modules/Requests/Revisions.php": "core", @@ -2848,6 +2855,7 @@ "help/modules/search.md": "core", "help/modules/seo-audit.md": "core", "help/modules/site-readiness.md": "core", + "help/modules/sliders.md": "core", "help/modules/smsc-auth.md": "core", "help/modules/system-health.md": "core", "help/modules/traffic-analytics.md": "core", diff --git a/adminx/Support/SectionHelp.php b/adminx/Support/SectionHelp.php index ff86803..59aab58 100644 --- a/adminx/Support/SectionHelp.php +++ b/adminx/Support/SectionHelp.php @@ -81,6 +81,7 @@ self::item('#^/documents/(?:create|\d+/edit)$#', 'Редактор документа', 'Создаёт и изменяет страницу сайта: её адрес, публикацию, SEO и значения полей выбранной рубрики.', array('Набор полей и их группы задаются рубрикой.', 'Изменение alias может автоматически создать редирект со старого URL.', 'Ctrl+S сохраняет изменения и оставляет редактор открытым; ревизии позволяют вернуться к прошлой версии.'), 'Смена рубрики существующего документа запрещена без отдельной миграции полей.'), self::item('#^/documents#', 'Документы', 'Основной реестр страниц и товарных карточек сайта, построенных на рубриках и их полях.', array('Фильтруйте документы по рубрике, состоянию и названию.', 'Публикацию, копирование и удаление можно выполнять из списка или пакетно.', 'Удалённый документ сначала попадает в корзину и только затем может быть удалён окончательно.'), 'Документ №1 и системная страница 404 защищены от окончательного удаления.', 'content/documents'), self::item('#^/public-site/presentations$#', 'Представления', 'Создаёт повторно используемое оформление карточек, списков, слайдеров и других результатов.', array('Черновик проверяется на реальном материале и не меняет публичный сайт.', 'Публикация фиксирует версию, а назначение выбирает место и режим применения.', 'Представление меняет внешний вид готовых данных, но не заменяет рубрику, запрос, блок или модуль.'), 'Для совместимости каждое новое назначение начинает работу в режиме «Текущий вывод».', 'content/public-site'), + self::item('#^/public-site/template-map$#', 'Карта шаблонов', 'Показывает фактическую цепочку сборки обычных страниц, списков, каталога и товаров.', array('Общий шаблон создаёт внешний каркас страницы.', 'Шаблон рубрики размещает поля, блоки, запросы и модульные теги.', 'Тема оформляет только подключённые компоненты, если не включён отдельный режим оболочки темы.'), 'Карта работает только на чтение; каждая кнопка открывает штатный редактор выбранного слоя.', 'content/public-site'), self::item('#^/public-site/map$#', 'Визуальная карта сайта', 'Показывает деревья меню, связанные страницы и опубликованные документы вне навигации.', array('Уровни строятся из действующих пунктов навигации.', 'Ссылка документа открывает его штатный редактор.', 'Документ вне меню может использоваться запросом, каталогом или прямой ссылкой.'), 'Карта является обзором и ничего не публикует.', 'content/public-site'), self::item('#^/public-site/placements$#', 'Размещения компонентов', 'Показывает, в каких сохранённых шаблонах используются блоки, подборки, навигации и модульные теги.', array('Вкладка «Размещения» показывает каждое найденное место отдельно.', 'Вкладка «Где используется» объединяет одинаковые компоненты и показывает число связей.', 'Кнопки справа открывают конкретный исходный шаблон и конкретный подключённый компонент.'), 'Карта предназначена для поиска связей и ничего не меняет на публичном сайте.', 'content/public-site'), self::item('#^/public-site/templates$#', 'Шаблоны публичного сайта', 'Редактирует общие файловые Twig-компоненты активной темы.', array('Список материалов имеет системный резерв.', 'Оболочка страницы и остальные компоненты темы редактируются без поиска файла вручную.', 'Сохранение проверяет Twig, создаёт ревизию и очищает публичный кеш.'), 'Шаблоны рубрик, запросов и блоков остаются в собственных разделах.', 'content/public-site'), diff --git a/adminx/Support/ViewOverrideEditor.php b/adminx/Support/ViewOverrideEditor.php index 0809695..af9f085 100644 --- a/adminx/Support/ViewOverrideEditor.php +++ b/adminx/Support/ViewOverrideEditor.php @@ -100,6 +100,7 @@ } try { + ThemeAssets::registerViewOverrides(); Twig::twig()->createTemplate($content, 'public_view_' . preg_replace('/[^a-z0-9_]/i', '_', (string) $code)); } catch (\Throwable $e) { return array('ok' => false, 'message' => 'Ошибка Twig: ' . $e->getMessage()); diff --git a/adminx/assets/css/adminkit.css b/adminx/assets/css/adminkit.css index e7e6b82..67c68ce 100644 --- a/adminx/assets/css/adminkit.css +++ b/adminx/assets/css/adminkit.css @@ -5088,6 +5088,30 @@ ul.sortable { flex: 0 0 auto; white-space: nowrap; } +.media-picker-manage { + display: flex; + align-items: center; + gap: 8px; +} +.media-picker-manage[hidden] { + display: none; +} +.media-picker-folder-form { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 12px; +} +.media-picker-folder-form[hidden] { + display: none; +} +.media-picker-folder-form .input-wrap { + min-width: 0; + flex: 1 1 auto; +} +.media-picker-folder-form .btn-icon { + min-width: 40px; +} .media-picker-url { display: flex; gap: 8px; @@ -5279,6 +5303,20 @@ ul.sortable { .media-picker-tools .media-picker-search { flex-basis: calc(100% - 50px); } + .media-picker-manage { + width: 100%; + } + .media-picker-manage .btn-primary { + min-width: 0; + flex: 1 1 auto; + } + .media-picker-folder-form { + align-items: stretch; + flex-wrap: wrap; + } + .media-picker-folder-form .input-wrap { + flex-basis: 100%; + } .media-picker-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } diff --git a/adminx/assets/js/adminx.js b/adminx/assets/js/adminx.js index 1fe7019..f2de9b9 100644 --- a/adminx/assets/js/adminx.js +++ b/adminx/assets/js/adminx.js @@ -221,6 +221,87 @@ } }; + // ------------------------------------------------------------------ // + // Простые формы модулей: стандартный Ajax-контракт без отдельного JS. + // ------------------------------------------------------------------ // + Adminx.initAjaxForms = function () { + document.addEventListener('submit', function (event) { + var form = event.target.closest ? event.target.closest('form[data-ax-ajax-form]') : null; + if (!form || form.getAttribute('data-ax-submitting') === '1') { return; } + event.preventDefault(); + + var submit = event.submitter || form.querySelector('button[type="submit"],input[type="submit"]'); + var data = new FormData(form); + if (submit && submit.name && !data.has(submit.name)) { data.append(submit.name, submit.value || '1'); } + + form.setAttribute('data-ax-submitting', '1'); + form.setAttribute('aria-busy', 'true'); + if (submit) { submit.disabled = true; } + Adminx.Loader.show(); + + Adminx.Ajax.request(form.getAttribute('action') || window.location.href, { + method: (form.getAttribute('method') || 'POST').toUpperCase(), + body: data + }).then(function (payload) { + var response = Adminx.Ajax.handle(payload); + if (payload.ok && response.success !== false) { + form.dispatchEvent(new CustomEvent('adminx:form-saved', { bubbles: true, detail: response })); + if (form.hasAttribute('data-ax-reset-on-success')) { form.reset(); } + } + }).catch(function (error) { + Adminx.Toast.show(error && error.message ? error.message : Adminx.t('server_unavailable', 'Сервер недоступен. Повторите попытку.'), 'error'); + }).then(function () { + Adminx.Loader.hide(); + form.removeAttribute('data-ax-submitting'); + form.removeAttribute('aria-busy'); + if (submit) { submit.disabled = false; } + }); + }); + }; + + // ------------------------------------------------------------------ // + // Пакетная загрузка обходит серверный max_file_uploads без изменения php.ini. + // ------------------------------------------------------------------ // + Adminx.Upload = { + BATCH_SIZE: 20, + + files: function (url, files, makeData, onProgress) { + files = Array.prototype.slice.call(files || []); + if (!files.length) { return Promise.resolve({ files: [], batches: 0, total: 0 }); } + + var self = this; + var uploaded = []; + var batches = Math.ceil(files.length / self.BATCH_SIZE); + var run = function (batch) { + if (batch >= batches) { + return Promise.resolve({ files: uploaded, batches: batches, total: files.length }); + } + + var start = batch * self.BATCH_SIZE; + var chunk = files.slice(start, start + self.BATCH_SIZE); + var data = makeData(chunk, batch, batches); + return Adminx.Ajax.post(url, data).then(function (payload) { + var response = payload.data || {}; + if (!payload.ok || response.success === false) { + var error = new Error(response.message || 'Не удалось загрузить файлы'); + error.uploaded = uploaded.slice(); + error.batch = batch; + throw error; + } + + var result = response.data || {}; + uploaded = uploaded.concat(result.files || []); + if (typeof onProgress === 'function') { + onProgress(Math.min(start + chunk.length, files.length), files.length, uploaded.length, response); + } + return run(batch + 1); + }); + }; + + return run(0); + } + }; + // ------------------------------------------------------------------ // Adminx.Sidebar = { KEY: 'adminx-sidebar', @@ -900,6 +981,7 @@ Adminx.Tabs.init(); Adminx.Drawer.init(); Adminx.Tooltip.init(); + Adminx.initAjaxForms(); Adminx.initLogout(); Adminx.initCopyTag(); Adminx.initSectionHelp(); diff --git a/adminx/assets/js/editor-tiptap.js b/adminx/assets/js/editor-tiptap.js index 4fe4ea6..b541414 100644 --- a/adminx/assets/js/editor-tiptap.js +++ b/adminx/assets/js/editor-tiptap.js @@ -152,4 +152,4 @@ ${t} `,h=Array.from({length:o}).map((m,g)=>u&&c[g]&&c[g].text||"");return f+=`| ${h.map((m,g)=>a(m,l[g])).join(" | ")} | `,f+=`| ${l.map((m,g)=>{let y=Math.max(3,m),b=d[g];return b==="left"?`:${"-".repeat(y)}`:b==="right"?`${"-".repeat(y)}:`:b==="center"?`:${"-".repeat(y)}:`:"-".repeat(y)}).join(" | ")} | `,(u?s.slice(1):s).forEach(m=>{f+=`| ${Array.from({length:o}).fill(0).map((g,y)=>a(m[y]&&m[y].text||"",l[y])).join(" | ")} | -`}),f}var Xx=Gx,ba=_.create({name:"table",addOptions(){return{HTMLAttributes:{},resizable:!1,renderWrapper:!1,handleWidth:5,cellMinWidth:25,View:Vx,lastColumnResizable:!0,allowTableNodeSelection:!1}},content:"tableRow+",tableRole:"table",isolating:!0,group:"block",parseHTML(){return[{tag:"table"}]},renderHTML({node:n,HTMLAttributes:e}){let{colgroup:t,tableWidth:r,tableMinWidth:i}=Wx(n,this.options.cellMinWidth),s=e.style;function o(){return s||(r?`width: ${r}`:`min-width: ${i}`)}let l=["table",I(this.options.HTMLAttributes,e,{style:o()}),t,["tbody",0]];return this.options.renderWrapper?["div",{class:"tableWrapper"},l]:l},parseMarkdown:(n,e)=>{let t=[],r=Array.isArray(n.align)?n.align:[];if(n.header){let i=[];n.header.forEach((s,o)=>{var l;let a=ws((l=r[o])!=null?l:s.align),c=a?{align:a}:{};i.push(e.createNode("tableHeader",c,[{type:"paragraph",content:e.parseInline(s.tokens)}]))}),t.push(e.createNode("tableRow",{},i))}return n.rows&&n.rows.forEach(i=>{let s=[];i.forEach((o,l)=>{var a;let c=ws((a=r[l])!=null?a:o.align),u=c?{align:c}:{};s.push(e.createNode("tableCell",u,[{type:"paragraph",content:e.parseInline(o.tokens)}]))}),t.push(e.createNode("tableRow",{},s))}),e.createNode("table",void 0,t)},renderMarkdown:(n,e)=>Xx(n,e),addCommands(){return{insertTable:({rows:n=3,cols:e=3,withHeaderRow:t=!0}={})=>({tr:r,dispatch:i,editor:s})=>{let o=Kx(s.schema,n,e,t);if(i){let l=r.selection.from+1;r.replaceSelectionWith(o).scrollIntoView().setSelection(T.near(r.doc.resolve(l)))}return!0},addColumnBefore:()=>({state:n,dispatch:e})=>_h(n,e),addColumnAfter:()=>({state:n,dispatch:e})=>Vh(n,e),deleteColumn:()=>({state:n,dispatch:e})=>Wh(n,e),addRowBefore:()=>({state:n,dispatch:e})=>Kh(n,e),addRowAfter:()=>({state:n,dispatch:e})=>Jh(n,e),deleteRow:()=>({state:n,dispatch:e})=>qh(n,e),deleteTable:()=>({state:n,dispatch:e})=>Xh(n,e),mergeCells:()=>({state:n,dispatch:e})=>pa(n,e),splitCell:()=>({state:n,dispatch:e})=>ma(n,e),toggleHeaderColumn:()=>({state:n,dispatch:e})=>Sn("column")(n,e),toggleHeaderRow:()=>({state:n,dispatch:e})=>Sn("row")(n,e),toggleHeaderCell:()=>({state:n,dispatch:e})=>Gh(n,e),mergeOrSplit:()=>({state:n,dispatch:e})=>pa(n,e)?!0:ma(n,e),setCellAttribute:(n,e)=>({state:t,dispatch:r})=>Uh(n,e)(t,r),goToNextCell:()=>({state:n,dispatch:e})=>ga(1)(n,e),goToPreviousCell:()=>({state:n,dispatch:e})=>ga(-1)(n,e),fixTables:()=>({state:n,dispatch:e})=>(e&&ha(n),!0),setCellSelection:n=>({tr:e,dispatch:t})=>{if(t){let r=K.create(e.doc,n.anchorCell,n.headCell);e.setSelection(r)}return!0}}},addKeyboardShortcuts(){return{Tab:()=>this.editor.commands.goToNextCell()?!0:this.editor.can().addRowAfter()?this.editor.chain().addRowAfter().goToNextCell().run():!1,"Shift-Tab":()=>this.editor.commands.goToPreviousCell(),Backspace:xs,"Mod-Backspace":xs,Delete:xs,"Mod-Delete":xs}},addProseMirrorPlugins(){return[...this.options.resizable&&this.editor.isEditable?[Qh({handleWidth:this.options.handleWidth,cellMinWidth:this.options.cellMinWidth,defaultCellMinWidth:this.options.cellMinWidth,View:this.options.View,lastColumnResizable:this.options.lastColumnResizable})]:[],ep({allowTableNodeSelection:this.options.allowTableNodeSelection})]},addNodeView(){let n=this.options.resizable&&this.editor.isEditable,e=this.options.View;return n||!e?null:({node:t,view:r,HTMLAttributes:i})=>{let s=I(this.options.HTMLAttributes,i);return new e(t,this.options.cellMinWidth,r,s)}},extendNodeSchema(n){let e={name:n.name,options:n.options,storage:n.storage};return{tableRole:V(E(n,"tableRole",e))}}}),iM=$.create({name:"tableKit",addExtensions(){let n=[];return this.options.table!==!1&&n.push(ba.configure(this.options.table)),this.options.tableCell!==!1&&n.push(Ss.configure(this.options.tableCell)),this.options.tableHeader!==!1&&n.push(vs.configure(this.options.tableHeader)),this.options.tableRow!==!1&&n.push(Cs.configure(this.options.tableRow)),n}});var ip=Cs;var sp=Ss;var op=vs;var Yx=$.create({name:"textAlign",addOptions(){return{types:[],alignments:["left","center","right","justify"],defaultAlignment:null}},addGlobalAttributes(){return[{types:this.options.types,attributes:{textAlign:{default:this.options.defaultAlignment,parseHTML:n=>{let e=n.style.textAlign;return this.options.alignments.includes(e)?e:this.options.defaultAlignment},renderHTML:n=>n.textAlign?{style:`text-align: ${n.textAlign}`}:{}}}}]},addCommands(){return{setTextAlign:n=>({commands:e})=>this.options.alignments.includes(n)?this.options.types.map(t=>e.updateAttributes(t,{textAlign:n})).some(t=>t):!1,unsetTextAlign:()=>({commands:n})=>this.options.types.map(e=>n.resetAttributes(e,"textAlign")).some(e=>e),toggleTextAlign:n=>({editor:e,commands:t})=>this.options.alignments.includes(n)?e.isActive({textAlign:n})?t.unsetTextAlign():t.setTextAlign(n):!1}},addKeyboardShortcuts(){return{"Mod-Shift-l":()=>this.editor.commands.setTextAlign("left"),"Mod-Shift-e":()=>this.editor.commands.setTextAlign("center"),"Mod-Shift-r":()=>this.editor.commands.setTextAlign("right"),"Mod-Shift-j":()=>this.editor.commands.setTextAlign("justify")}}}),lp=Yx;var Qx=Th.extend({addAttributes:function(){return Object.assign({},this.parent?this.parent():{},{class:{default:null},webp:{default:null}})},parseHTML:function(){return[{tag:"picture",getAttrs:function(n){var e=n.querySelector("img[src]"),t=n.querySelector('source[type="image/webp"], source[srcset$=".webp"]');return e?{src:e.getAttribute("src"),alt:e.getAttribute("alt"),title:e.getAttribute("title"),class:e.getAttribute("class"),width:e.getAttribute("width"),height:e.getAttribute("height"),webp:t?t.getAttribute("srcset"):null}:!1}},{tag:'img[src]:not([src^="data:"])'}]},renderHTML:function(n){var e=Object.assign({},n.HTMLAttributes||{}),t=e.webp;delete e.webp;var r=["img",I(this.options.HTMLAttributes,e)];return t?["picture",{},["source",{srcset:t,type:"image/webp"}],r]:r}});(function(n,e){"use strict";var t=n.Adminx||(n.Adminx={});function r(o,l,a){var c=e.createElement(o);return Object.keys(l||{}).forEach(function(u){u==="class"?c.className=l[u]:u==="dataset"?Object.keys(l[u]).forEach(function(d){c.dataset[d]=l[u][d]}):c.setAttribute(u,l[u])}),a!=null&&(c.innerHTML=a),c}function i(o){return''}function s(o,l,a){t.RichEditor.modalInput({title:o,value:l||""},a)}t.RichEditor={instances:[],init:function(o){o=o||e;var l=o.querySelectorAll("textarea[data-rich-editor]:not([data-rich-editor-ready])");Array.prototype.forEach.call(l,this.create.bind(this))},extensions:function(){return[Mh.configure({link:!1}),jf.configure({openOnClick:!1,autolink:!0,protocols:["http","https","mailto","tel"],HTMLAttributes:{rel:"noopener noreferrer nofollow"}}),Qx.configure({allowBase64:!1}),ba.configure({resizable:!0}),ip,op,sp,lp.configure({types:["heading","paragraph"]})]},create:function(o){var l=o.getAttribute("data-rich-preset")||"full",a=r("div",{class:"rich-editor rich-editor-"+l}),c=r("div",{class:"rich-editor-toolbar",role:"toolbar"}),u=r("div",{class:"rich-editor-surface"}),d=r("div",{class:"rich-editor-content"}),f=parseInt(o.getAttribute("data-editor-height"),10)||0;f>0&&(f=Math.max(140,Math.min(900,f)),a.classList.add("rich-editor-fixed-height"),a.style.setProperty("--rich-editor-height",f+"px")),o.style.display="none",o.parentNode.insertBefore(a,o),a.appendChild(c),a.appendChild(u),u.appendChild(d),a.appendChild(o);var h=new zd({element:d,extensions:this.extensions(),content:o.value||"",editorProps:{attributes:{class:"rich-editor-prose",spellcheck:o.getAttribute("spellcheck")||"true"},handleDoubleClickOn:function(p,m,g,y){return!g||g.type.name!=="image"?!1:(h.chain().setNodeSelection(y).run(),t.RichEditor.openImageEditor(h,g.attrs,y),!0)}},onUpdate:function(){o.value=h.getHTML(),o.setAttribute("data-rich-editor-dirty","1"),o.dispatchEvent(new Event("input",{bubbles:!0}))},onSelectionUpdate:function(){t.RichEditor.syncToolbar(a,h)},onTransaction:function(){t.RichEditor.syncToolbar(a,h)}});this.buildToolbar(c,h),o.setAttribute("data-rich-editor-ready","1"),o._adminxTiptap=h,this.instances.push(h),this.bindForm(o,h),this.syncToolbar(a,h)},button:function(o,l,a,c){var u=r("button",{class:"btn btn-ghost btn-icon btn-sm rich-editor-btn",type:"button","data-rich-command":o,"data-tooltip":l,"aria-label":l},i(a));return u.addEventListener("click",function(){c()}),u},buildToolbar:function(o,l){var a,c=this;function u(){a=r("div",{class:"rich-editor-group"}),o.appendChild(a)}function d(h,p,m,g){a.appendChild(c.button(h,p,m,g))}function f(){var h=r("select",{class:"select rich-editor-block-select","data-rich-block-select":"","aria-label":"\u0424\u043E\u0440\u043C\u0430\u0442 \u0431\u043B\u043E\u043A\u0430","data-tooltip":"\u0424\u043E\u0440\u043C\u0430\u0442 \u0431\u043B\u043E\u043A\u0430"});[["paragraph","\u0410\u0431\u0437\u0430\u0446"],["heading-1","\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A H1"],["heading-2","\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A H2"],["heading-3","\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A H3"],["heading-4","\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A H4"],["heading-5","\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A H5"],["heading-6","\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A H6"]].forEach(function(p){var m=r("option",{value:p[0]});m.textContent=p[1],h.appendChild(m)}),h.addEventListener("change",function(){if(h.value==="paragraph"){l.chain().focus().setParagraph().run();return}l.chain().focus().setHeading({level:parseInt(h.value.replace("heading-",""),10)}).run()}),a.appendChild(h)}u(),d("undo","\u041E\u0442\u043C\u0435\u043D\u0438\u0442\u044C","arrow-back-up",function(){l.chain().focus().undo().run()}),d("redo","\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C","arrow-forward-up",function(){l.chain().focus().redo().run()}),u(),d("bold","\u0416\u0438\u0440\u043D\u044B\u0439","bold",function(){l.chain().focus().toggleBold().run()}),d("italic","\u041A\u0443\u0440\u0441\u0438\u0432","italic",function(){l.chain().focus().toggleItalic().run()}),d("strike","\u0417\u0430\u0447\u0435\u0440\u043A\u043D\u0443\u0442\u044C","strikethrough",function(){l.chain().focus().toggleStrike().run()}),d("code","\u0411\u043B\u043E\u043A \u043A\u043E\u0434\u0430","code",function(){l.chain().focus().toggleCodeBlock().run()}),u(),f(),d("bulletList","\u041C\u0430\u0440\u043A\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0441\u043F\u0438\u0441\u043E\u043A","list",function(){l.chain().focus().toggleBulletList().run()}),d("orderedList","\u041D\u0443\u043C\u0435\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0441\u043F\u0438\u0441\u043E\u043A","list-numbers",function(){l.chain().focus().toggleOrderedList().run()}),d("blockquote","\u0426\u0438\u0442\u0430\u0442\u0430","blockquote",function(){l.chain().focus().toggleBlockquote().run()}),u(),d("alignLeft","\u041F\u043E \u043B\u0435\u0432\u043E\u043C\u0443 \u043A\u0440\u0430\u044E","align-left",function(){l.chain().focus().setTextAlign("left").run()}),d("alignCenter","\u041F\u043E \u0446\u0435\u043D\u0442\u0440\u0443","align-center",function(){l.chain().focus().setTextAlign("center").run()}),d("alignRight","\u041F\u043E \u043F\u0440\u0430\u0432\u043E\u043C\u0443 \u043A\u0440\u0430\u044E","align-right",function(){l.chain().focus().setTextAlign("right").run()}),u(),d("link","\u0421\u0441\u044B\u043B\u043A\u0430","link",function(){c.openLink(l)}),d("image","\u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435","photo-plus",function(){c.openMediaPicker(l)}),d("table","\u0422\u0430\u0431\u043B\u0438\u0446\u0430","table-plus",function(){l.chain().focus().insertTable({rows:3,cols:3,withHeaderRow:!0}).run()}),d("showBlocks","\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0431\u043B\u043E\u043A\u0438","box-model-2",function(){var h=o.closest(".rich-editor");h&&(h.classList.toggle("rich-editor-show-blocks"),c.syncToolbar(h,l))}),u(),n.CodeMirror&&d("source","\u0418\u0441\u0445\u043E\u0434\u043D\u0438\u043A","code-dots",function(){c.openSource(l)}),d("clear","\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C \u0444\u043E\u0440\u043C\u0430\u0442","eraser",function(){l.chain().focus().unsetAllMarks().clearNodes().run()})},syncToolbar:function(o,l){var a={bold:l.isActive("bold"),italic:l.isActive("italic"),strike:l.isActive("strike"),code:l.isActive("codeBlock"),bulletList:l.isActive("bulletList"),orderedList:l.isActive("orderedList"),blockquote:l.isActive("blockquote"),alignLeft:l.isActive({textAlign:"left"}),alignCenter:l.isActive({textAlign:"center"}),alignRight:l.isActive({textAlign:"right"}),link:l.isActive("link"),showBlocks:o.classList.contains("rich-editor-show-blocks"),source:o.classList.contains("rich-editor-source-open")};Object.keys(a).forEach(function(f){var h=o.querySelector('[data-rich-command="'+f+'"]');h&&h.setAttribute("aria-pressed",a[f]?"true":"false")});var c=o.querySelector("[data-rich-block-select]");if(c){for(var u="paragraph",d=1;d<=6;d++)if(l.isActive("heading",{level:d})){u="heading-"+d;break}c.value=u}},bindForm:function(o,l){var a=o.closest("form");a&&a.addEventListener("submit",function(){var c=o.closest(".rich-editor");if(c&&c.classList.contains("rich-editor-source-open")&&c._richSourceEditor){c._richSourceEditor.save(),o.value=c._richSourceEditor.getValue();return}o.getAttribute("data-rich-editor-dirty")==="1"&&(o.value=l.getHTML())})},openSource:function(o){var l=o.view.dom.closest(".rich-editor");if(!(!l||!n.CodeMirror)){var a=l.querySelector(".rich-editor-surface"),c=l.querySelector("textarea[data-rich-editor]"),u=l.querySelector("[data-rich-inline-source]"),d=!l.classList.contains("rich-editor-source-open");if(!d){var f=l._richSourceEditor?l._richSourceEditor.getValue():c?c.value:"";f!==o.getHTML()&&o.commands.setContent(f||"

"),c&&(c.value=o.getHTML()),l.classList.remove("rich-editor-source-open"),this.setSourceControls(l,!1),this.syncToolbar(l,o),o.commands.focus();return}if(!u){u=r("div",{class:"rich-editor-inline-source","data-rich-inline-source":""});var h=r("textarea",{"data-rich-source-textarea":""});u.appendChild(h),a.parentNode.insertBefore(u,a.nextSibling),l._richSourceEditor=n.CodeMirror.fromTextArea(h,{mode:"htmlmixed",theme:e.documentElement.getAttribute("data-theme")==="dark"?"material-ocean":"default",lineNumbers:!0,lineWrapping:!0,matchBrackets:!0,autoCloseTags:!0,styleActiveLine:!0,indentUnit:2}),l._richSourceEditor.on("change",function(m){!c||l._richSourceSyncing||(c.value=m.getValue(),c.setAttribute("data-rich-editor-dirty","1"),c.dispatchEvent(new Event("input",{bubbles:!0})))})}var p=Math.max(260,Math.round(a.getBoundingClientRect().height||0));l._richSourceSyncing=!0,l._richSourceEditor.setValue(o.getHTML()),l._richSourceSyncing=!1,l._richSourceEditor.setSize("100%",p),l.classList.add("rich-editor-source-open"),this.setSourceControls(l,!0),this.syncToolbar(l,o),setTimeout(function(){l._richSourceEditor.refresh(),l._richSourceEditor.focus()},0)}},setSourceControls:function(o,l){o.querySelectorAll(".rich-editor-toolbar [data-rich-command], .rich-editor-toolbar [data-rich-block-select]").forEach(function(a){a.getAttribute("data-rich-command")!=="source"&&(a.disabled=!!l)})},openLink:function(o){var l=this,a=o.getAttributes("link")||{},c=r("div",{class:"overlay rich-editor-link-overlay"}),u=r("div",{class:"modal rich-editor-link-modal",role:"dialog","aria-modal":"true","aria-labelledby":"richEditorLinkTitle"});u.innerHTML='',c.appendChild(u),e.body.appendChild(c),requestAnimationFrame(function(){c.classList.add("show")});var d=c.querySelector("[data-link-url]"),f=c.querySelector("[data-link-class]"),h=c.querySelector("[data-link-selection]"),p=function(){c.classList.remove("show"),setTimeout(function(){c.remove(),e.removeEventListener("keydown",y)},180)},m=function(){var b=String(d.value||"").trim(),k=String(f.value||"").trim().replace(/\s+/g," ");if(!b){o.chain().focus().unsetLink().run(),p();return}o.chain().focus().extendMarkRange("link").setLink({href:b,class:k||null}).run(),p()},g=function(b,k){d.value=b||"",h.textContent=k||"\u0410\u0434\u0440\u0435\u0441 \u0432\u044B\u0431\u0440\u0430\u043D",d.dispatchEvent(new Event("input",{bubbles:!0}))},y=function(b){if(b.key==="Escape"){if(e.querySelector(".rich-editor-document-picker-overlay.show, .media-picker-overlay.show"))return;p()}b.key==="Enter"&&b.target!==f&&(b.preventDefault(),m())};c.addEventListener("click",function(b){if(b.target===c||b.target.closest("[data-link-cancel]")){p();return}if(b.target.closest("[data-link-apply]")){m();return}if(b.target.closest("[data-link-unset]")){o.chain().focus().unsetLink().run(),p();return}if(b.target.closest("[data-link-document]")){l.openDocumentLinkPicker(function(k){var w=String(k.alias||"").trim(),C=w?/^(?:[a-z]+:|\/|#)/i.test(w)?w:"/"+w:"/index.php?id="+k.id;g(C,"\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442 #"+k.id+" \xB7 "+(k.title||"\u0411\u0435\u0437 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u044F"))});return}b.target.closest("[data-link-media]")&&t.MediaPicker&&t.MediaPicker.open({type:"all",title:"\u0424\u0430\u0439\u043B \u0434\u043B\u044F \u0441\u0441\u044B\u043B\u043A\u0438",description:"\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u0438\u043B\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u0438\u0437 \u043C\u0435\u0434\u0438\u0430\u0442\u0435\u043A\u0438.",onPick:function(k){k&&k.url&&g(k.url,"\u041C\u0435\u0434\u0438\u0430 \xB7 "+(k.name||k.url))},onUrl:function(k){k&&g(k,"\u0412\u043D\u0435\u0448\u043D\u0438\u0439 \u0430\u0434\u0440\u0435\u0441 \u043C\u0435\u0434\u0438\u0430")}})}),e.addEventListener("keydown",y),d.focus(),d.select()},openDocumentLinkPicker:function(o){var l=this,a=r("div",{class:"overlay rich-editor-document-picker-overlay"}),c=r("div",{class:"modal picker-modal rich-editor-document-picker",role:"dialog","aria-modal":"true","aria-labelledby":"richEditorDocumentPickerTitle"});c.innerHTML='',a.appendChild(c),e.body.appendChild(a),requestAnimationFrame(function(){a.classList.add("show")});var u=a.querySelector("[data-document-link-search]"),d=a.querySelector("[data-document-link-list]"),f=a.querySelector("[data-document-link-status]"),h=a.querySelector("[data-document-link-count]"),p=[],m=null,g=0,y=function(){a.classList.remove("show"),setTimeout(function(){a.remove(),e.removeEventListener("keydown",b)},160)},b=function(w){w.key==="Escape"&&(w.stopImmediatePropagation(),y())},k=function(){var w=++g,C=new URLSearchParams;C.set("q",u.value.trim()),C.set("limit",40),f.hidden=!1,f.textContent="\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430...",fetch((n.ADMINX_BASE||(t.base?t.base():""))+"/documents/picker?"+C.toString(),{headers:{Accept:"application/json"},credentials:"same-origin"}).then(function(O){return O.json()}).then(function(O){w===g&&(p=(O.data||{}).items||[],d.innerHTML=p.map(function(M,D){return'"}).join(""),f.hidden=p.length>0,f.textContent=u.value.trim()?"\u041D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E":"\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u044B",h.textContent=p.length?"\u041F\u043E\u043A\u0430\u0437\u0430\u043D\u043E: "+p.length:"")}).catch(function(){p=[],d.innerHTML="",f.hidden=!1,f.textContent="\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B"})};a.addEventListener("click",function(w){if(w.target===a||w.target.closest("[data-document-link-close]")){y();return}var C=w.target.closest("[data-document-link-index]");if(C){var O=p[parseInt(C.getAttribute("data-document-link-index"),10)];O&&(o(O),y())}}),u.addEventListener("input",function(){clearTimeout(m),m=setTimeout(k,220)}),e.addEventListener("keydown",b),k(),u.focus()},openMediaPicker:function(o){this.openImageEditor(o,{},null)},openImageEditor:function(o,l,a){var c=this;l=l||{};var u=typeof a=="number",d=r("div",{class:"overlay rich-editor-image-overlay"}),f=r("div",{class:"modal rich-editor-image-modal",role:"dialog","aria-modal":"true","aria-labelledby":"richEditorImageTitle"});f.innerHTML='",d.appendChild(f),e.body.appendChild(d),requestAnimationFrame(function(){d.classList.add("show")});var h=d.querySelector("[data-image-src]"),p=d.querySelector("[data-image-webp]"),m=d.querySelector("[data-image-picture]"),g=d.querySelector("[data-image-webp-field]"),y=d.querySelector("[data-image-alt]"),b=d.querySelector("[data-image-class]"),k=d.querySelector("[data-image-width]"),w=d.querySelector("[data-image-height]"),C=d.querySelector("[data-image-scale]"),O=d.querySelector("[data-image-scale-value]"),M=d.querySelector("[data-image-preview-img]"),D=d.querySelector("[data-image-empty]"),B=d.querySelector("[data-image-preview-size]"),P={naturalWidth:parseInt(l.width,10)||0,naturalHeight:parseInt(l.height,10)||0,ratio:l.width&&l.height?parseInt(l.width,10)/parseInt(l.height,10):0,loadingSrc:""},Se=function(){var L=parseInt(k.value,10)||0,F=P.naturalWidth&&L?Math.round(L/P.naturalWidth*100):100;F=Math.max(10,Math.min(200,F)),C.value=F,O.textContent=F+"%",B.textContent=L&&w.value?L+" x "+w.value+" px":""},Te=function(L,F,Ct){L=Math.max(1,Math.round(Number(L)||0)),F=Math.max(1,Math.round(Number(F)||0)),!(!L||!F)&&(Ct?(P.naturalWidth=L,P.naturalHeight=F,P.ratio=L/F):P.ratio||(P.ratio=L/F),k.value=L,w.value=F,Se())},Q=function(L,F){if(L=String(L||"").trim(),P.loadingSrc=L,!L){M.hidden=!0,D.hidden=!1,B.textContent="";return}var Ct=new n.Image;Ct.onload=function(){if(P.loadingSrc===L){M.src=L,M.hidden=!1,D.hidden=!0;var xa=F&&F.width?F.width:Ct.naturalWidth,wa=F&&F.height?F.height:Ct.naturalHeight;!k.value||!w.value||L!==l.src?Te(xa,wa,!0):(P.naturalWidth=xa||parseInt(k.value,10),P.naturalHeight=wa||parseInt(w.value,10),P.ratio=P.naturalWidth/P.naturalHeight,Se())}},Ct.onerror=function(){P.loadingSrc===L&&(M.hidden=!0,D.hidden=!1,D.querySelector("span").textContent="\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435")},Ct.src=L},Z=function(L){t.MediaPicker&&t.MediaPicker.open({type:"image",title:L==="webp"?"\u0412\u044B\u0431\u0440\u0430\u0442\u044C WebP":"\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435",description:L==="webp"?"\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0444\u0430\u0439\u043B WebP \u0434\u043B\u044F \u0442\u0435\u0433\u0430 source.":"\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u043E\u0441\u043D\u043E\u0432\u043D\u043E\u0435 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u0438\u0437 \u043C\u0435\u0434\u0438\u0430\u0442\u0435\u043A\u0438.",onPick:function(F){if(!(!F||!F.url)){if(L==="webp"){p.value=F.url,m.checked=!0,g.hidden=!1;return}h.value=F.url,!y.value&&F.name&&(y.value=String(F.name).replace(/\.[^.]+$/,"").replace(/[-_]+/g," ")),k.value="",w.value="",Q(F.url,F)}},onUrl:function(F){F&&(L==="webp"?(p.value=F,m.checked=!0,g.hidden=!1):(h.value=F,k.value="",w.value="",Q(F)))}})},J=function(){d.classList.remove("show"),setTimeout(function(){d.remove(),e.removeEventListener("keydown",ka)},180)},dt=function(){var L=String(h.value||"").trim();if(!L){h.focus();return}var F={src:L,webp:m.checked&&String(p.value||"").trim()||null,alt:String(y.value||"").trim()||null,class:String(b.value||"").trim().replace(/\s+/g," ")||null,width:parseInt(k.value,10)||null,height:parseInt(w.value,10)||null};u?o.chain().focus().setNodeSelection(a).updateAttributes("image",F).run():o.chain().focus().setImage(F).run(),J()},ka=function(L){if(L.key==="Escape"){if(e.querySelector(".media-picker-overlay.show"))return;J()}};m.addEventListener("change",function(){g.hidden=!m.checked,m.checked&&p.focus()}),h.addEventListener("change",function(){k.value="",w.value="",Q(h.value)}),k.addEventListener("input",function(){var L=parseInt(k.value,10)||0;L&&P.ratio&&(w.value=Math.max(1,Math.round(L/P.ratio))),Se()}),w.addEventListener("input",function(){var L=parseInt(w.value,10)||0;L&&P.ratio&&(k.value=Math.max(1,Math.round(L*P.ratio))),Se()}),C.addEventListener("input",function(){var L=parseInt(C.value,10)||100;O.textContent=L+"%",P.naturalWidth&&P.naturalHeight&&(k.value=Math.max(1,Math.round(P.naturalWidth*L/100)),w.value=Math.max(1,Math.round(P.naturalHeight*L/100)),B.textContent=k.value+" x "+w.value+" px")}),d.addEventListener("click",function(L){if(L.target===d||L.target.closest("[data-image-cancel]")){J();return}var F=L.target.closest("[data-image-pick]");if(F){Z(F.getAttribute("data-image-pick"));return}if(L.target.closest("[data-image-original]")&&P.naturalWidth&&P.naturalHeight){Te(P.naturalWidth,P.naturalHeight,!1);return}if(L.target.closest("[data-image-apply]")){dt();return}L.target.closest("[data-image-remove]")&&u&&(o.chain().focus().setNodeSelection(a).deleteSelection().run(),J())}),e.addEventListener("keydown",ka),l.src?Q(l.src):h.focus()},modalInput:function(o,l){var a=r("div",{class:"overlay"}),c=r("div",{class:"modal rich-editor-prompt",role:"dialog","aria-modal":"true"});c.innerHTML='',a.appendChild(c),e.body.appendChild(a),requestAnimationFrame(function(){a.classList.add("show")});var u=a.querySelector("[data-input]"),d=function(){a.classList.remove("show"),setTimeout(function(){a.remove(),e.removeEventListener("keydown",h)},180)},f=function(){var p=u.value||"";d(),l(p)},h=function(p){p.key==="Escape"&&d(),p.key==="Enter"&&f()};a.addEventListener("click",function(p){(p.target===a||p.target.closest("[data-cancel]"))&&d(),p.target.closest("[data-ok]")&&f()}),e.addEventListener("keydown",h),u.focus(),u.select()},escape:function(o){return String(o==null?"":o).replace(/[&<>"]/g,function(l){return{"&":"&","<":"<",">":">",'"':"""}[l]})}},e.addEventListener("adminx:content-ready",function(o){t.RichEditor.init(o.detail&&o.detail.root?o.detail.root:e)}),e.readyState==="loading"?e.addEventListener("DOMContentLoaded",function(){t.RichEditor.init()}):t.RichEditor.init()})(window,document);})(); +`}),f}var Xx=Gx,ba=_.create({name:"table",addOptions(){return{HTMLAttributes:{},resizable:!1,renderWrapper:!1,handleWidth:5,cellMinWidth:25,View:Vx,lastColumnResizable:!0,allowTableNodeSelection:!1}},content:"tableRow+",tableRole:"table",isolating:!0,group:"block",parseHTML(){return[{tag:"table"}]},renderHTML({node:n,HTMLAttributes:e}){let{colgroup:t,tableWidth:r,tableMinWidth:i}=Wx(n,this.options.cellMinWidth),s=e.style;function o(){return s||(r?`width: ${r}`:`min-width: ${i}`)}let l=["table",I(this.options.HTMLAttributes,e,{style:o()}),t,["tbody",0]];return this.options.renderWrapper?["div",{class:"tableWrapper"},l]:l},parseMarkdown:(n,e)=>{let t=[],r=Array.isArray(n.align)?n.align:[];if(n.header){let i=[];n.header.forEach((s,o)=>{var l;let a=ws((l=r[o])!=null?l:s.align),c=a?{align:a}:{};i.push(e.createNode("tableHeader",c,[{type:"paragraph",content:e.parseInline(s.tokens)}]))}),t.push(e.createNode("tableRow",{},i))}return n.rows&&n.rows.forEach(i=>{let s=[];i.forEach((o,l)=>{var a;let c=ws((a=r[l])!=null?a:o.align),u=c?{align:c}:{};s.push(e.createNode("tableCell",u,[{type:"paragraph",content:e.parseInline(o.tokens)}]))}),t.push(e.createNode("tableRow",{},s))}),e.createNode("table",void 0,t)},renderMarkdown:(n,e)=>Xx(n,e),addCommands(){return{insertTable:({rows:n=3,cols:e=3,withHeaderRow:t=!0}={})=>({tr:r,dispatch:i,editor:s})=>{let o=Kx(s.schema,n,e,t);if(i){let l=r.selection.from+1;r.replaceSelectionWith(o).scrollIntoView().setSelection(T.near(r.doc.resolve(l)))}return!0},addColumnBefore:()=>({state:n,dispatch:e})=>_h(n,e),addColumnAfter:()=>({state:n,dispatch:e})=>Vh(n,e),deleteColumn:()=>({state:n,dispatch:e})=>Wh(n,e),addRowBefore:()=>({state:n,dispatch:e})=>Kh(n,e),addRowAfter:()=>({state:n,dispatch:e})=>Jh(n,e),deleteRow:()=>({state:n,dispatch:e})=>qh(n,e),deleteTable:()=>({state:n,dispatch:e})=>Xh(n,e),mergeCells:()=>({state:n,dispatch:e})=>pa(n,e),splitCell:()=>({state:n,dispatch:e})=>ma(n,e),toggleHeaderColumn:()=>({state:n,dispatch:e})=>Sn("column")(n,e),toggleHeaderRow:()=>({state:n,dispatch:e})=>Sn("row")(n,e),toggleHeaderCell:()=>({state:n,dispatch:e})=>Gh(n,e),mergeOrSplit:()=>({state:n,dispatch:e})=>pa(n,e)?!0:ma(n,e),setCellAttribute:(n,e)=>({state:t,dispatch:r})=>Uh(n,e)(t,r),goToNextCell:()=>({state:n,dispatch:e})=>ga(1)(n,e),goToPreviousCell:()=>({state:n,dispatch:e})=>ga(-1)(n,e),fixTables:()=>({state:n,dispatch:e})=>(e&&ha(n),!0),setCellSelection:n=>({tr:e,dispatch:t})=>{if(t){let r=K.create(e.doc,n.anchorCell,n.headCell);e.setSelection(r)}return!0}}},addKeyboardShortcuts(){return{Tab:()=>this.editor.commands.goToNextCell()?!0:this.editor.can().addRowAfter()?this.editor.chain().addRowAfter().goToNextCell().run():!1,"Shift-Tab":()=>this.editor.commands.goToPreviousCell(),Backspace:xs,"Mod-Backspace":xs,Delete:xs,"Mod-Delete":xs}},addProseMirrorPlugins(){return[...this.options.resizable&&this.editor.isEditable?[Qh({handleWidth:this.options.handleWidth,cellMinWidth:this.options.cellMinWidth,defaultCellMinWidth:this.options.cellMinWidth,View:this.options.View,lastColumnResizable:this.options.lastColumnResizable})]:[],ep({allowTableNodeSelection:this.options.allowTableNodeSelection})]},addNodeView(){let n=this.options.resizable&&this.editor.isEditable,e=this.options.View;return n||!e?null:({node:t,view:r,HTMLAttributes:i})=>{let s=I(this.options.HTMLAttributes,i);return new e(t,this.options.cellMinWidth,r,s)}},extendNodeSchema(n){let e={name:n.name,options:n.options,storage:n.storage};return{tableRole:V(E(n,"tableRole",e))}}}),iM=$.create({name:"tableKit",addExtensions(){let n=[];return this.options.table!==!1&&n.push(ba.configure(this.options.table)),this.options.tableCell!==!1&&n.push(Ss.configure(this.options.tableCell)),this.options.tableHeader!==!1&&n.push(vs.configure(this.options.tableHeader)),this.options.tableRow!==!1&&n.push(Cs.configure(this.options.tableRow)),n}});var ip=Cs;var sp=Ss;var op=vs;var Yx=$.create({name:"textAlign",addOptions(){return{types:[],alignments:["left","center","right","justify"],defaultAlignment:null}},addGlobalAttributes(){return[{types:this.options.types,attributes:{textAlign:{default:this.options.defaultAlignment,parseHTML:n=>{let e=n.style.textAlign;return this.options.alignments.includes(e)?e:this.options.defaultAlignment},renderHTML:n=>n.textAlign?{style:`text-align: ${n.textAlign}`}:{}}}}]},addCommands(){return{setTextAlign:n=>({commands:e})=>this.options.alignments.includes(n)?this.options.types.map(t=>e.updateAttributes(t,{textAlign:n})).some(t=>t):!1,unsetTextAlign:()=>({commands:n})=>this.options.types.map(e=>n.resetAttributes(e,"textAlign")).some(e=>e),toggleTextAlign:n=>({editor:e,commands:t})=>this.options.alignments.includes(n)?e.isActive({textAlign:n})?t.unsetTextAlign():t.setTextAlign(n):!1}},addKeyboardShortcuts(){return{"Mod-Shift-l":()=>this.editor.commands.setTextAlign("left"),"Mod-Shift-e":()=>this.editor.commands.setTextAlign("center"),"Mod-Shift-r":()=>this.editor.commands.setTextAlign("right"),"Mod-Shift-j":()=>this.editor.commands.setTextAlign("justify")}}}),lp=Yx;var Qx=Th.extend({addAttributes:function(){return Object.assign({},this.parent?this.parent():{},{class:{default:null},webp:{default:null}})},parseHTML:function(){return[{tag:"picture",getAttrs:function(n){var e=n.querySelector("img[src]"),t=n.querySelector('source[type="image/webp"], source[srcset$=".webp"]');return e?{src:e.getAttribute("src"),alt:e.getAttribute("alt"),title:e.getAttribute("title"),class:e.getAttribute("class"),width:e.getAttribute("width"),height:e.getAttribute("height"),webp:t?t.getAttribute("srcset"):null}:!1}},{tag:'img[src]:not([src^="data:"])'}]},renderHTML:function(n){var e=Object.assign({},n.HTMLAttributes||{}),t=e.webp;delete e.webp;var r=["img",I(this.options.HTMLAttributes,e)];return t?["picture",{},["source",{srcset:t,type:"image/webp"}],r]:r}});(function(n,e){"use strict";var t=n.Adminx||(n.Adminx={});function r(o,l,a){var c=e.createElement(o);return Object.keys(l||{}).forEach(function(u){u==="class"?c.className=l[u]:u==="dataset"?Object.keys(l[u]).forEach(function(d){c.dataset[d]=l[u][d]}):c.setAttribute(u,l[u])}),a!=null&&(c.innerHTML=a),c}function i(o){return''}function s(o,l,a){t.RichEditor.modalInput({title:o,value:l||""},a)}t.RichEditor={instances:[],init:function(o){o=o||e;var l=o.querySelectorAll("textarea[data-rich-editor]:not([data-rich-editor-ready])");Array.prototype.forEach.call(l,this.create.bind(this))},extensions:function(){return[Mh.configure({link:!1}),jf.configure({openOnClick:!1,autolink:!0,protocols:["http","https","mailto","tel"],HTMLAttributes:{rel:"noopener noreferrer nofollow"}}),Qx.configure({allowBase64:!1}),ba.configure({resizable:!0}),ip,op,sp,lp.configure({types:["heading","paragraph"]})]},create:function(o){var l=o.getAttribute("data-rich-preset")||"full",a=r("div",{class:"rich-editor rich-editor-"+l}),c=r("div",{class:"rich-editor-toolbar",role:"toolbar"}),u=r("div",{class:"rich-editor-surface"}),d=r("div",{class:"rich-editor-content"}),f=parseInt(o.getAttribute("data-editor-height"),10)||0;f>0&&(f=Math.max(140,Math.min(900,f)),a.classList.add("rich-editor-fixed-height"),a.style.setProperty("--rich-editor-height",f+"px")),o.style.display="none",o.parentNode.insertBefore(a,o),a.appendChild(c),a.appendChild(u),u.appendChild(d),a.appendChild(o);var h=new zd({element:d,extensions:this.extensions(),content:o.value||"",editorProps:{attributes:{class:"rich-editor-prose",spellcheck:o.getAttribute("spellcheck")||"true"},handleDoubleClickOn:function(p,m,g,y){return!g||g.type.name!=="image"?!1:(h.chain().setNodeSelection(y).run(),t.RichEditor.openImageEditor(h,g.attrs,y),!0)}},onUpdate:function(){o.value=h.getHTML(),o.setAttribute("data-rich-editor-dirty","1"),o.dispatchEvent(new Event("input",{bubbles:!0}))},onSelectionUpdate:function(){t.RichEditor.syncToolbar(a,h)},onTransaction:function(){t.RichEditor.syncToolbar(a,h)}});this.buildToolbar(c,h),o.setAttribute("data-rich-editor-ready","1"),o._adminxTiptap=h,this.instances.push(h),this.bindForm(o,h),this.syncToolbar(a,h)},button:function(o,l,a,c){var u=r("button",{class:"btn btn-ghost btn-icon btn-sm rich-editor-btn",type:"button","data-rich-command":o,"data-tooltip":l,"aria-label":l},i(a));return u.addEventListener("click",function(){c()}),u},buildToolbar:function(o,l){var a,c=this;function u(){a=r("div",{class:"rich-editor-group"}),o.appendChild(a)}function d(h,p,m,g){a.appendChild(c.button(h,p,m,g))}function f(){var h=r("select",{class:"select rich-editor-block-select","data-rich-block-select":"","aria-label":"\u0424\u043E\u0440\u043C\u0430\u0442 \u0431\u043B\u043E\u043A\u0430","data-tooltip":"\u0424\u043E\u0440\u043C\u0430\u0442 \u0431\u043B\u043E\u043A\u0430"});[["paragraph","\u0410\u0431\u0437\u0430\u0446"],["heading-1","\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A H1"],["heading-2","\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A H2"],["heading-3","\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A H3"],["heading-4","\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A H4"],["heading-5","\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A H5"],["heading-6","\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A H6"]].forEach(function(p){var m=r("option",{value:p[0]});m.textContent=p[1],h.appendChild(m)}),h.addEventListener("change",function(){if(h.value==="paragraph"){l.chain().focus().setParagraph().run();return}l.chain().focus().setHeading({level:parseInt(h.value.replace("heading-",""),10)}).run()}),a.appendChild(h)}u(),d("undo","\u041E\u0442\u043C\u0435\u043D\u0438\u0442\u044C","arrow-back-up",function(){l.chain().focus().undo().run()}),d("redo","\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C","arrow-forward-up",function(){l.chain().focus().redo().run()}),u(),d("bold","\u0416\u0438\u0440\u043D\u044B\u0439","bold",function(){l.chain().focus().toggleBold().run()}),d("italic","\u041A\u0443\u0440\u0441\u0438\u0432","italic",function(){l.chain().focus().toggleItalic().run()}),d("strike","\u0417\u0430\u0447\u0435\u0440\u043A\u043D\u0443\u0442\u044C","strikethrough",function(){l.chain().focus().toggleStrike().run()}),d("code","\u0411\u043B\u043E\u043A \u043A\u043E\u0434\u0430","code",function(){l.chain().focus().toggleCodeBlock().run()}),u(),f(),d("bulletList","\u041C\u0430\u0440\u043A\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0441\u043F\u0438\u0441\u043E\u043A","list",function(){l.chain().focus().toggleBulletList().run()}),d("orderedList","\u041D\u0443\u043C\u0435\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0441\u043F\u0438\u0441\u043E\u043A","list-numbers",function(){l.chain().focus().toggleOrderedList().run()}),d("blockquote","\u0426\u0438\u0442\u0430\u0442\u0430","blockquote",function(){l.chain().focus().toggleBlockquote().run()}),u(),d("alignLeft","\u041F\u043E \u043B\u0435\u0432\u043E\u043C\u0443 \u043A\u0440\u0430\u044E","align-left",function(){l.chain().focus().setTextAlign("left").run()}),d("alignCenter","\u041F\u043E \u0446\u0435\u043D\u0442\u0440\u0443","align-center",function(){l.chain().focus().setTextAlign("center").run()}),d("alignRight","\u041F\u043E \u043F\u0440\u0430\u0432\u043E\u043C\u0443 \u043A\u0440\u0430\u044E","align-right",function(){l.chain().focus().setTextAlign("right").run()}),u(),d("link","\u0421\u0441\u044B\u043B\u043A\u0430","link",function(){c.openLink(l)}),d("image","\u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435","photo-plus",function(){c.openMediaPicker(l)}),d("table","\u0422\u0430\u0431\u043B\u0438\u0446\u0430","table-plus",function(){l.chain().focus().insertTable({rows:3,cols:3,withHeaderRow:!0}).run()}),d("showBlocks","\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0431\u043B\u043E\u043A\u0438","box-model-2",function(){var h=o.closest(".rich-editor");h&&(h.classList.toggle("rich-editor-show-blocks"),c.syncToolbar(h,l))}),u(),n.CodeMirror&&d("source","\u0418\u0441\u0445\u043E\u0434\u043D\u0438\u043A","code-dots",function(){c.openSource(l)}),d("clear","\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C \u0444\u043E\u0440\u043C\u0430\u0442","eraser",function(){l.chain().focus().unsetAllMarks().clearNodes().run()})},syncToolbar:function(o,l){var a={bold:l.isActive("bold"),italic:l.isActive("italic"),strike:l.isActive("strike"),code:l.isActive("codeBlock"),bulletList:l.isActive("bulletList"),orderedList:l.isActive("orderedList"),blockquote:l.isActive("blockquote"),alignLeft:l.isActive({textAlign:"left"}),alignCenter:l.isActive({textAlign:"center"}),alignRight:l.isActive({textAlign:"right"}),link:l.isActive("link"),showBlocks:o.classList.contains("rich-editor-show-blocks"),source:o.classList.contains("rich-editor-source-open")};Object.keys(a).forEach(function(f){var h=o.querySelector('[data-rich-command="'+f+'"]');h&&h.setAttribute("aria-pressed",a[f]?"true":"false")});var c=o.querySelector("[data-rich-block-select]");if(c){for(var u="paragraph",d=1;d<=6;d++)if(l.isActive("heading",{level:d})){u="heading-"+d;break}c.value=u}},bindForm:function(o,l){var a=o.closest("form"),c=this;a&&a.addEventListener("submit",function(){c.syncTextarea(o,l)})},syncTextarea:function(o,l){var a;return o?(a=o.closest(".rich-editor"),a&&a.classList.contains("rich-editor-source-open")&&a._richSourceEditor?(a._richSourceEditor.save(),o.value=a._richSourceEditor.getValue(),o.setAttribute("data-rich-editor-dirty","1"),o.value):(l&&o.getAttribute("data-rich-editor-dirty")==="1"&&(o.value=l.getHTML()),o.value)):""},openSource:function(o){var l=o.view.dom.closest(".rich-editor");if(!(!l||!n.CodeMirror)){var a=l.querySelector(".rich-editor-surface"),c=l.querySelector("textarea[data-rich-editor]"),u=l.querySelector("[data-rich-inline-source]"),d=!l.classList.contains("rich-editor-source-open");if(!d){var f=l._richSourceEditor?l._richSourceEditor.getValue():c?c.value:"";f!==o.getHTML()&&o.commands.setContent(f||"

"),c&&(c.value=o.getHTML()),l.classList.remove("rich-editor-source-open"),this.setSourceControls(l,!1),this.syncToolbar(l,o),o.commands.focus();return}if(!u){u=r("div",{class:"rich-editor-inline-source","data-rich-inline-source":""});var h=r("textarea",{"data-rich-source-textarea":""});u.appendChild(h),a.parentNode.insertBefore(u,a.nextSibling),l._richSourceEditor=n.CodeMirror.fromTextArea(h,{mode:"htmlmixed",theme:e.documentElement.getAttribute("data-theme")==="dark"?"material-ocean":"default",lineNumbers:!0,lineWrapping:!0,matchBrackets:!0,autoCloseTags:!0,styleActiveLine:!0,indentUnit:2}),l._richSourceEditor.on("change",function(m){!c||l._richSourceSyncing||(c.value=m.getValue(),c.setAttribute("data-rich-editor-dirty","1"),c.dispatchEvent(new Event("input",{bubbles:!0})))})}var p=Math.max(260,Math.round(a.getBoundingClientRect().height||0));l._richSourceSyncing=!0,l._richSourceEditor.setValue(o.getHTML()),l._richSourceSyncing=!1,l._richSourceEditor.setSize("100%",p),l.classList.add("rich-editor-source-open"),this.setSourceControls(l,!0),this.syncToolbar(l,o),setTimeout(function(){l._richSourceEditor.refresh(),l._richSourceEditor.focus()},0)}},setSourceControls:function(o,l){o.querySelectorAll(".rich-editor-toolbar [data-rich-command], .rich-editor-toolbar [data-rich-block-select]").forEach(function(a){a.getAttribute("data-rich-command")!=="source"&&(a.disabled=!!l)})},openLink:function(o){var l=this,a=o.getAttributes("link")||{},c=r("div",{class:"overlay rich-editor-link-overlay"}),u=r("div",{class:"modal rich-editor-link-modal",role:"dialog","aria-modal":"true","aria-labelledby":"richEditorLinkTitle"});u.innerHTML='',c.appendChild(u),e.body.appendChild(c),requestAnimationFrame(function(){c.classList.add("show")});var d=c.querySelector("[data-link-url]"),f=c.querySelector("[data-link-class]"),h=c.querySelector("[data-link-selection]"),p=function(){c.classList.remove("show"),setTimeout(function(){c.remove(),e.removeEventListener("keydown",y)},180)},m=function(){var b=String(d.value||"").trim(),k=String(f.value||"").trim().replace(/\s+/g," ");if(!b){o.chain().focus().unsetLink().run(),p();return}o.chain().focus().extendMarkRange("link").setLink({href:b,class:k||null}).run(),p()},g=function(b,k){d.value=b||"",h.textContent=k||"\u0410\u0434\u0440\u0435\u0441 \u0432\u044B\u0431\u0440\u0430\u043D",d.dispatchEvent(new Event("input",{bubbles:!0}))},y=function(b){if(b.key==="Escape"){if(e.querySelector(".rich-editor-document-picker-overlay.show, .media-picker-overlay.show"))return;p()}b.key==="Enter"&&b.target!==f&&(b.preventDefault(),m())};c.addEventListener("click",function(b){if(b.target===c||b.target.closest("[data-link-cancel]")){p();return}if(b.target.closest("[data-link-apply]")){m();return}if(b.target.closest("[data-link-unset]")){o.chain().focus().unsetLink().run(),p();return}if(b.target.closest("[data-link-document]")){l.openDocumentLinkPicker(function(k){var w=String(k.alias||"").trim(),C=w?/^(?:[a-z]+:|\/|#)/i.test(w)?w:"/"+w:"/index.php?id="+k.id;g(C,"\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442 #"+k.id+" \xB7 "+(k.title||"\u0411\u0435\u0437 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u044F"))});return}b.target.closest("[data-link-media]")&&t.MediaPicker&&t.MediaPicker.open({type:"all",title:"\u0424\u0430\u0439\u043B \u0434\u043B\u044F \u0441\u0441\u044B\u043B\u043A\u0438",description:"\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u0438\u043B\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u0438\u0437 \u043C\u0435\u0434\u0438\u0430\u0442\u0435\u043A\u0438.",onPick:function(k){k&&k.url&&g(k.url,"\u041C\u0435\u0434\u0438\u0430 \xB7 "+(k.name||k.url))},onUrl:function(k){k&&g(k,"\u0412\u043D\u0435\u0448\u043D\u0438\u0439 \u0430\u0434\u0440\u0435\u0441 \u043C\u0435\u0434\u0438\u0430")}})}),e.addEventListener("keydown",y),d.focus(),d.select()},openDocumentLinkPicker:function(o){var l=this,a=r("div",{class:"overlay rich-editor-document-picker-overlay"}),c=r("div",{class:"modal picker-modal rich-editor-document-picker",role:"dialog","aria-modal":"true","aria-labelledby":"richEditorDocumentPickerTitle"});c.innerHTML='',a.appendChild(c),e.body.appendChild(a),requestAnimationFrame(function(){a.classList.add("show")});var u=a.querySelector("[data-document-link-search]"),d=a.querySelector("[data-document-link-list]"),f=a.querySelector("[data-document-link-status]"),h=a.querySelector("[data-document-link-count]"),p=[],m=null,g=0,y=function(){a.classList.remove("show"),setTimeout(function(){a.remove(),e.removeEventListener("keydown",b)},160)},b=function(w){w.key==="Escape"&&(w.stopImmediatePropagation(),y())},k=function(){var w=++g,C=new URLSearchParams;C.set("q",u.value.trim()),C.set("limit",40),f.hidden=!1,f.textContent="\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430...",fetch((n.ADMINX_BASE||(t.base?t.base():""))+"/documents/picker?"+C.toString(),{headers:{Accept:"application/json"},credentials:"same-origin"}).then(function(O){return O.json()}).then(function(O){w===g&&(p=(O.data||{}).items||[],d.innerHTML=p.map(function(M,D){return'"}).join(""),f.hidden=p.length>0,f.textContent=u.value.trim()?"\u041D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E":"\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u044B",h.textContent=p.length?"\u041F\u043E\u043A\u0430\u0437\u0430\u043D\u043E: "+p.length:"")}).catch(function(){p=[],d.innerHTML="",f.hidden=!1,f.textContent="\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B"})};a.addEventListener("click",function(w){if(w.target===a||w.target.closest("[data-document-link-close]")){y();return}var C=w.target.closest("[data-document-link-index]");if(C){var O=p[parseInt(C.getAttribute("data-document-link-index"),10)];O&&(o(O),y())}}),u.addEventListener("input",function(){clearTimeout(m),m=setTimeout(k,220)}),e.addEventListener("keydown",b),k(),u.focus()},openMediaPicker:function(o){this.openImageEditor(o,{},null)},openImageEditor:function(o,l,a){var c=this;l=l||{};var u=typeof a=="number",d=r("div",{class:"overlay rich-editor-image-overlay"}),f=r("div",{class:"modal rich-editor-image-modal",role:"dialog","aria-modal":"true","aria-labelledby":"richEditorImageTitle"});f.innerHTML='",d.appendChild(f),e.body.appendChild(d),requestAnimationFrame(function(){d.classList.add("show")});var h=d.querySelector("[data-image-src]"),p=d.querySelector("[data-image-webp]"),m=d.querySelector("[data-image-picture]"),g=d.querySelector("[data-image-webp-field]"),y=d.querySelector("[data-image-alt]"),b=d.querySelector("[data-image-class]"),k=d.querySelector("[data-image-width]"),w=d.querySelector("[data-image-height]"),C=d.querySelector("[data-image-scale]"),O=d.querySelector("[data-image-scale-value]"),M=d.querySelector("[data-image-preview-img]"),D=d.querySelector("[data-image-empty]"),B=d.querySelector("[data-image-preview-size]"),P={naturalWidth:parseInt(l.width,10)||0,naturalHeight:parseInt(l.height,10)||0,ratio:l.width&&l.height?parseInt(l.width,10)/parseInt(l.height,10):0,loadingSrc:""},Se=function(){var L=parseInt(k.value,10)||0,F=P.naturalWidth&&L?Math.round(L/P.naturalWidth*100):100;F=Math.max(10,Math.min(200,F)),C.value=F,O.textContent=F+"%",B.textContent=L&&w.value?L+" x "+w.value+" px":""},Te=function(L,F,Ct){L=Math.max(1,Math.round(Number(L)||0)),F=Math.max(1,Math.round(Number(F)||0)),!(!L||!F)&&(Ct?(P.naturalWidth=L,P.naturalHeight=F,P.ratio=L/F):P.ratio||(P.ratio=L/F),k.value=L,w.value=F,Se())},Q=function(L,F){if(L=String(L||"").trim(),P.loadingSrc=L,!L){M.hidden=!0,D.hidden=!1,B.textContent="";return}var Ct=new n.Image;Ct.onload=function(){if(P.loadingSrc===L){M.src=L,M.hidden=!1,D.hidden=!0;var xa=F&&F.width?F.width:Ct.naturalWidth,wa=F&&F.height?F.height:Ct.naturalHeight;!k.value||!w.value||L!==l.src?Te(xa,wa,!0):(P.naturalWidth=xa||parseInt(k.value,10),P.naturalHeight=wa||parseInt(w.value,10),P.ratio=P.naturalWidth/P.naturalHeight,Se())}},Ct.onerror=function(){P.loadingSrc===L&&(M.hidden=!0,D.hidden=!1,D.querySelector("span").textContent="\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435")},Ct.src=L},Z=function(L){t.MediaPicker&&t.MediaPicker.open({type:"image",title:L==="webp"?"\u0412\u044B\u0431\u0440\u0430\u0442\u044C WebP":"\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435",description:L==="webp"?"\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0444\u0430\u0439\u043B WebP \u0434\u043B\u044F \u0442\u0435\u0433\u0430 source.":"\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u043E\u0441\u043D\u043E\u0432\u043D\u043E\u0435 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u0438\u0437 \u043C\u0435\u0434\u0438\u0430\u0442\u0435\u043A\u0438.",onPick:function(F){if(!(!F||!F.url)){if(L==="webp"){p.value=F.url,m.checked=!0,g.hidden=!1;return}h.value=F.url,!y.value&&F.name&&(y.value=String(F.name).replace(/\.[^.]+$/,"").replace(/[-_]+/g," ")),k.value="",w.value="",Q(F.url,F)}},onUrl:function(F){F&&(L==="webp"?(p.value=F,m.checked=!0,g.hidden=!1):(h.value=F,k.value="",w.value="",Q(F)))}})},J=function(){d.classList.remove("show"),setTimeout(function(){d.remove(),e.removeEventListener("keydown",ka)},180)},dt=function(){var L=String(h.value||"").trim();if(!L){h.focus();return}var F={src:L,webp:m.checked&&String(p.value||"").trim()||null,alt:String(y.value||"").trim()||null,class:String(b.value||"").trim().replace(/\s+/g," ")||null,width:parseInt(k.value,10)||null,height:parseInt(w.value,10)||null};u?o.chain().focus().setNodeSelection(a).updateAttributes("image",F).run():o.chain().focus().setImage(F).run(),J()},ka=function(L){if(L.key==="Escape"){if(e.querySelector(".media-picker-overlay.show"))return;J()}};m.addEventListener("change",function(){g.hidden=!m.checked,m.checked&&p.focus()}),h.addEventListener("change",function(){k.value="",w.value="",Q(h.value)}),k.addEventListener("input",function(){var L=parseInt(k.value,10)||0;L&&P.ratio&&(w.value=Math.max(1,Math.round(L/P.ratio))),Se()}),w.addEventListener("input",function(){var L=parseInt(w.value,10)||0;L&&P.ratio&&(k.value=Math.max(1,Math.round(L*P.ratio))),Se()}),C.addEventListener("input",function(){var L=parseInt(C.value,10)||100;O.textContent=L+"%",P.naturalWidth&&P.naturalHeight&&(k.value=Math.max(1,Math.round(P.naturalWidth*L/100)),w.value=Math.max(1,Math.round(P.naturalHeight*L/100)),B.textContent=k.value+" x "+w.value+" px")}),d.addEventListener("click",function(L){if(L.target===d||L.target.closest("[data-image-cancel]")){J();return}var F=L.target.closest("[data-image-pick]");if(F){Z(F.getAttribute("data-image-pick"));return}if(L.target.closest("[data-image-original]")&&P.naturalWidth&&P.naturalHeight){Te(P.naturalWidth,P.naturalHeight,!1);return}if(L.target.closest("[data-image-apply]")){dt();return}L.target.closest("[data-image-remove]")&&u&&(o.chain().focus().setNodeSelection(a).deleteSelection().run(),J())}),e.addEventListener("keydown",ka),l.src?Q(l.src):h.focus()},modalInput:function(o,l){var a=r("div",{class:"overlay"}),c=r("div",{class:"modal rich-editor-prompt",role:"dialog","aria-modal":"true"});c.innerHTML='',a.appendChild(c),e.body.appendChild(a),requestAnimationFrame(function(){a.classList.add("show")});var u=a.querySelector("[data-input]"),d=function(){a.classList.remove("show"),setTimeout(function(){a.remove(),e.removeEventListener("keydown",h)},180)},f=function(){var p=u.value||"";d(),l(p)},h=function(p){p.key==="Escape"&&d(),p.key==="Enter"&&f()};a.addEventListener("click",function(p){(p.target===a||p.target.closest("[data-cancel]"))&&d(),p.target.closest("[data-ok]")&&f()}),e.addEventListener("keydown",h),u.focus(),u.select()},escape:function(o){return String(o==null?"":o).replace(/[&<>"]/g,function(l){return{"&":"&","<":"<",">":">",'"':"""}[l]})}},e.addEventListener("adminx:content-ready",function(o){t.RichEditor.init(o.detail&&o.detail.root?o.detail.root:e)}),e.readyState==="loading"?e.addEventListener("DOMContentLoaded",function(){t.RichEditor.init()}):t.RichEditor.init()})(window,document);})(); diff --git a/adminx/assets/js/media-picker.js b/adminx/assets/js/media-picker.js index 9340a11..66140d9 100644 --- a/adminx/assets/js/media-picker.js +++ b/adminx/assets/js/media-picker.js @@ -47,8 +47,14 @@ + '
' + '' + '' + + '' + (onUrl ? '' : '') + '
' + + '' + (onUrl ? '' : '') + '
' + '
Загрузка…
' @@ -63,12 +69,16 @@ document.body.appendChild(overlay); window.requestAnimationFrame(function () { overlay.classList.add('show'); }); - var state = { dir: options.dir || '/uploads', parent: '', page: 1, pages: 1, q: '', type: type }; + var state = { dir: options.dir || '/uploads', parent: '', page: 1, pages: 1, q: '', type: type, canManage: false, busy: false }; var grid = overlay.querySelector('[data-mp-grid]'); var crumbs = overlay.querySelector('[data-mp-crumbs]'); var status = overlay.querySelector('[data-mp-status]'); var count = overlay.querySelector('[data-mp-count]'); var search = overlay.querySelector('[data-mp-search]'); + var manage = overlay.querySelector('[data-mp-manage]'); + var uploadInput = overlay.querySelector('[data-mp-upload-input]'); + var folderForm = overlay.querySelector('[data-mp-folder-form]'); + var folderName = overlay.querySelector('[data-mp-folder-name]'); var timer = null; function close() { @@ -89,6 +99,8 @@ var folders = data.folders || []; var files = data.files || []; renderCrumbs(data.breadcrumbs || []); + state.canManage = !!data.can_manage; + manage.hidden = !state.canManage; grid.innerHTML = ''; folders.forEach(function (folder) { var folderMeta = state.q @@ -111,6 +123,74 @@ overlay.querySelector('[data-mp-up]').disabled = !state.parent; } + function responseData(payload) { + var response = payload && payload.data ? payload.data : {}; + if (!payload || !payload.ok || response.success === false) { + throw new Error(response.message || (response.error && response.error.message) || 'Не удалось выполнить действие'); + } + return response; + } + + function setBusy(value, message) { + state.busy = !!value; + manage.querySelectorAll('button').forEach(function (button) { button.disabled = state.busy; }); + status.hidden = !message; + if (message) { status.textContent = message; } + } + + function clearSearch() { + state.q = ''; + search.value = ''; + } + + function createFolder() { + var name = folderName.value.trim(); + if (!name || state.busy) { folderName.focus(); return; } + var data = new FormData(); + data.set('_csrf', Adminx.csrf()); + data.set('dir', state.dir); + data.set('name', name); + setBusy(true, 'Создаём папку…'); + Adminx.Ajax.post(base + '/media/folders', data).then(responseData).then(function (response) { + var result = response.data || {}; + folderForm.hidden = true; + folderName.value = ''; + clearSearch(); + Adminx.Toast.show(response.message || 'Папка создана', 'success'); + load(result.path || state.dir, 1); + }).catch(function (error) { + setBusy(false, ''); + Adminx.Toast.show(error.message || 'Не удалось создать папку', 'error'); + folderName.focus(); + }); + } + + function upload(files) { + if (!files || !files.length || state.busy) { return; } + setBusy(true, 'Подготовка к загрузке: ' + files.length + '…'); + Adminx.Upload.files(base + '/media/upload', files, function (chunk) { + var data = new FormData(); + data.set('_csrf', Adminx.csrf()); + data.set('dir', state.dir); + chunk.forEach(function (file) { data.append('files[]', file); }); + return data; + }, function (processed, total) { + status.textContent = 'Загружено: ' + processed + ' из ' + total + '…'; + }).then(function (result) { + uploadInput.value = ''; + clearSearch(); + Adminx.Toast.show('Загружено файлов: ' + result.files.length, 'success'); + load(state.dir, 1); + }).catch(function (error) { + uploadInput.value = ''; + setBusy(false, ''); + var uploaded = error && error.uploaded ? error.uploaded.length : 0; + var message = error.message || 'Не удалось загрузить файлы'; + if (uploaded) { message += '. До ошибки загружено: ' + uploaded; } + Adminx.Toast.show(message, 'error'); + }); + } + function load(dir, page) { state.dir = dir || state.dir; state.page = page || 1; @@ -131,9 +211,10 @@ state.parent = data.parent_dir || ''; state.page = data.page || 1; state.pages = data.pages || 1; + setBusy(false, ''); render(data); }) - .catch(function () { status.textContent = 'Не удалось загрузить медиа'; status.hidden = false; }); + .catch(function () { setBusy(false, ''); status.textContent = 'Не удалось загрузить медиа'; status.hidden = false; }); } overlay.addEventListener('click', function (e) { @@ -146,6 +227,10 @@ if (e.target.closest('[data-mp-prev]') && state.page > 1) { load(state.dir, state.page - 1); } if (e.target.closest('[data-mp-next]') && state.page < state.pages) { load(state.dir, state.page + 1); } if (e.target.closest('[data-mp-up]') && state.parent) { load(state.parent, 1); } + if (e.target.closest('[data-mp-folder-toggle]')) { folderForm.hidden = !folderForm.hidden; if (!folderForm.hidden) { folderName.focus(); } return; } + if (e.target.closest('[data-mp-folder-cancel]')) { folderForm.hidden = true; folderName.value = ''; return; } + if (e.target.closest('[data-mp-folder-create]')) { createFolder(); return; } + if (e.target.closest('[data-mp-upload]')) { uploadInput.click(); return; } if (onUrl) { if (e.target.closest('[data-mp-url-toggle]')) { var box = overlay.querySelector('[data-mp-url]'); @@ -163,6 +248,10 @@ window.clearTimeout(timer); timer = window.setTimeout(function () { state.q = search.value.trim(); load(state.dir, 1); }, 220); }); + folderName.addEventListener('keydown', function (e) { + if (e.key === 'Enter') { e.preventDefault(); createFolder(); } + }); + uploadInput.addEventListener('change', function () { upload(uploadInput.files); }); document.addEventListener('keydown', onKey); load(state.dir, 1); search.focus(); diff --git a/adminx/assets/src/editor-tiptap.js b/adminx/assets/src/editor-tiptap.js index d30aeda..c3e3cb6 100644 --- a/adminx/assets/src/editor-tiptap.js +++ b/adminx/assets/src/editor-tiptap.js @@ -290,20 +290,29 @@ var EnhancedImage = Image.extend({ bindForm: function (textarea, editor) { var form = textarea.closest('form'); + var self = this; if (!form) { return; } form.addEventListener('submit', function () { - var root = textarea.closest('.rich-editor'); - if (root && root.classList.contains('rich-editor-source-open') && root._richSourceEditor) { - root._richSourceEditor.save(); - textarea.value = root._richSourceEditor.getValue(); - return; - } - if (textarea.getAttribute('data-rich-editor-dirty') === '1') { - textarea.value = editor.getHTML(); - } + self.syncTextarea(textarea, editor); }); }, + syncTextarea: function (textarea, editor) { + var root; + if (!textarea) { return ''; } + root = textarea.closest('.rich-editor'); + if (root && root.classList.contains('rich-editor-source-open') && root._richSourceEditor) { + root._richSourceEditor.save(); + textarea.value = root._richSourceEditor.getValue(); + textarea.setAttribute('data-rich-editor-dirty', '1'); + return textarea.value; + } + if (editor && textarea.getAttribute('data-rich-editor-dirty') === '1') { + textarea.value = editor.getHTML(); + } + return textarea.value; + }, + openSource: function (editor) { var root = editor.view.dom.closest('.rich-editor'); if (!root || !window.CodeMirror) { return; } diff --git a/adminx/modules/Catalog/Controller.php b/adminx/modules/Catalog/Controller.php index 85c7819..5872e77 100644 --- a/adminx/modules/Catalog/Controller.php +++ b/adminx/modules/Catalog/Controller.php @@ -90,12 +90,15 @@ 'state' => Request::getStr('state', ''), 'issue' => Request::getStr('issue', ''), 'payment' => Request::getStr('payment', ''), + 'view' => Request::getStr('view', 'table') === 'cards' ? 'cards' : 'table', 'page' => Request::getInt('page', 1), 'per_page' => Request::getInt('per_page', 25), ); + $statsSnapshot = Model::productStatsSnapshot(); return $this->render('@products/products.twig', array( 'result' => Model::products($filters), - 'stats' => Model::productStats(), + 'stats' => $statsSnapshot['stats'], + 'stats_loaded' => $statsSnapshot['loaded'], 'filters' => $filters, 'saved_views' => SavedViews::all('catalog_products', Auth::id(), $this->savedViewFields('products')), 'can_manage' => Permission::check('manage_products'), @@ -104,26 +107,32 @@ )); } + public function productStats(array $params = array()) + { + if (!Permission::check('view_products')) { return $this->error('Недостаточно прав', array(), 403); } + $stats = Model::productStats(); + $stats['indexed_label'] = !empty($stats['indexed_at']) ? date('d.m H:i', (int) $stats['indexed_at']) : '—'; + return $this->success('', array('data' => array('stats' => $stats))); + } + public function productQuality(array $params = array()) { if (!Permission::check('view_products')) { return $this->renderStatus('@adminx/404.twig', array('title' => 'Недостаточно прав'), 403); } if (!Model::hasCommerceCatalogs()) { return $this->renderStatus('@adminx/404.twig', array('title' => 'Товарные каталоги не настроены'), 404); } $this->assets(); - $stats = Model::productStats(); + $stats = Model::productQualityStats(); $issues = Model::productQualityIssues($stats); $allowed = array(); foreach ($issues as $item) { $allowed[(string) $item['code']] = true; } $issue = Request::getStr('issue', ''); if ($issue !== '' && !isset($allowed[$issue])) { $issue = ''; } - $state = Request::getStr('state', ''); - if (!in_array($state, array('', 'active', 'inactive'), true)) { $state = ''; } $filters = array( 'q' => Request::getStr('q', ''), 'issue' => $issue, - 'state' => $state, 'page' => Request::getInt('page', 1), 'per_page' => Request::getInt('per_page', 25), 'include_quality' => true, + 'quality_scope' => true, ); return $this->render('@products/product-quality.twig', array( 'result' => Model::products($filters), @@ -1050,6 +1059,7 @@ $search = Request::getStr('q', ''); return $this->render('@products/variant-group.twig', array( 'group' => $group, 'search' => $search, + 'focus_product_id' => Request::getInt('focus', 0), 'variant_fields' => VariantGroups::fields((int) $group['id']), 'variant_attributes' => VariantGroups::nativeAttributes(), 'package_templates' => ShippingPackageTemplates::all(), @@ -1169,6 +1179,7 @@ public function copyVariantProduct(array $params = array()) { if (($error = $this->productGuard()) !== null) { return $error; } + if (!Request::postBool('confirmed', false)) { return $this->error('Подтвердите создание варианта', array(), 409); } $sourceId = (int) $params['product']; $newId = 0; try { @@ -1181,12 +1192,15 @@ } $this->audit('catalog.variant_copied', (int) $params['id'], array('source_id' => $sourceId, 'product_id' => $newId)); - return $this->success('Вариант создан копированием', array('redirect' => $this->base() . '/catalog/products/' . $newId . '/edit')); + return $this->success('Вариант создан копированием', array( + 'redirect' => $this->base() . '/catalog/products/' . $newId . '/edit?variant_group=' . (int) $params['id'], + )); } public function copyProduct(array $params = array()) { if (($error = $this->guardPermission('manage_products', 'manage_documents')) !== null) { return $error; } + if (!Request::postBool('confirmed', false)) { return $this->error('Подтвердите создание копии товара', array(), 409); } $sourceId = isset($params['id']) ? (int) $params['id'] : 0; try { $copy = ProductDuplicator::copy($sourceId, Auth::id()); @@ -1269,7 +1283,23 @@ VariantGroups::add($groupId, $productId); } catch (\Throwable $e) { return $this->error($e->getMessage(), array(), 422); } $this->audit('catalog.variant_group_created_from_product', $groupId, array('product_id' => $productId)); - return $this->success('Группа вариантов создана', array('redirect' => $this->base() . '/catalog/variant-groups/' . $groupId)); + return $this->success('Группа вариантов создана', array('redirect' => $this->variantGroupUrl($groupId, $productId))); + } + + public function attachProductVariantGroup(array $params = array()) + { + if (($error = $this->productGuard()) !== null) { return $error; } + $productId = isset($params['id']) ? (int) $params['id'] : 0; + $groupId = Request::postInt('group_id', 0); + if (!Model::product($productId)) { return $this->error('Товар не найден', array(), 404); } + if ($groupId <= 0) { return $this->error('Выберите группу вариантов', array(), 422); } + if (VariantGroups::membership($productId)) { return $this->error('Товар уже состоит в группе', array(), 422); } + try { VariantGroups::add($groupId, $productId); } + catch (\Throwable $e) { return $this->error($e->getMessage(), array(), 422); } + $this->audit('catalog.variant_added_from_product', $groupId, array('product_id' => $productId)); + return $this->success('Товар добавлен в группу вариантов', array( + 'redirect' => $this->variantGroupUrl($groupId, $productId), + )); } public function editProduct(array $params = array()) @@ -1287,8 +1317,17 @@ CodeEditor::useRichEditor(); $this->attributeAssets(); $variantGroup = VariantGroups::membership($id); + $returnUrl = $this->base() . '/catalog/products'; + $returnLabel = 'Товары'; + $returnGroupId = Request::getInt('variant_group', 0); + if ($variantGroup && $returnGroupId === (int) $variantGroup['id']) { + $returnUrl = $this->variantGroupUrl((int) $variantGroup['id'], $id); + $returnLabel = 'Группа вариантов'; + } + $shippingProfile = ProductShipping::profile($id); $nativeAttributes = Attributes::productEditor($id); + $searchAliasesAvailable = $this->productSearchAliasesAvailable(); $mediaDraftToken = DocumentMediaDraft::issue(Auth::id(), $id); return $this->render('@documents/edit.twig', array( 'document' => $document, @@ -1301,6 +1340,7 @@ 'is_new' => false, 'can_manage' => true, 'quick_edit' => Request::getBool('quick_edit', false), 'actor_id' => Auth::id(), 'catalog_mode' => true, 'product' => $product, 'variant_group' => $variantGroup, + 'variant_groups' => $variantGroup ? array() : VariantGroups::all(), 'shipping_profile' => $shippingProfile, 'package_templates' => ShippingPackageTemplates::all(), 'native_attributes' => $nativeAttributes, @@ -1308,7 +1348,12 @@ 'product_promotions_available' => Promotions::available(), 'product_promotions' => Promotions::forProduct($id), 'can_manage_product_promotions' => Permission::check('manage_orders'), - 'return_url' => $this->base() . '/catalog/products', + 'product_search_aliases_available' => $searchAliasesAvailable, + 'product_search_aliases' => $searchAliasesAvailable + ? \App\Modules\Search\DocumentAliases::forDocument($id) + : array(), + 'return_url' => $returnUrl, + 'return_label' => $returnLabel, 'product_copy_url' => $this->base() . '/catalog/products/' . $id . '/copy', 'submit_url' => $this->base() . '/documents/' . $id, )); @@ -1419,6 +1464,47 @@ if(($error=$this->productGuard())!==null){return $error;}$productId=isset($params['id'])?(int)$params['id']:0;if(!Model::product($productId)){return $this->error('Товар не найден',array(),404);}try{$data=Attributes::saveProductValues($productId,Request::postAll(),Auth::id());}catch(\Throwable $e){return $this->error($e->getMessage(),array(),422);}$this->audit('catalog.product_attributes_saved',$productId,$data);return $this->success('Характеристики товара сохранены',array('data'=>$data)); } + public function saveProductSearchAliases(array $params = array()) + { + if (($error = $this->productGuard()) !== null) { return $error; } + $productId = isset($params['id']) ? (int) $params['id'] : 0; + if (!Model::product($productId)) { return $this->error('Товар не найден', array(), 404); } + if (!$this->productSearchAliasesAvailable()) { + return $this->error('Обновите и включите модуль «Поиск по сайту»', array(), 409); + } + + try { + $aliases = \App\Modules\Search\DocumentAliases::saveDocument( + $productId, + (array) Request::post('aliases', array()), + Auth::id() + ); + } catch (\Throwable $e) { + return $this->error($e->getMessage(), array(), 422); + } + + $this->audit('catalog.product_search_aliases_saved', $productId, array('count' => count($aliases))); + return $this->success('Поисковые названия сохранены', array('data' => array('aliases' => $aliases))); + } + + public function productSearchAliasSuggestions(array $params = array()) + { + if (!Permission::check('manage_products')) { + return $this->error('Недостаточно прав', array(), 403); + } + + if (!$this->productSearchAliasesAvailable()) { + return $this->error('Обновите и включите модуль «Поиск по сайту»', array(), 409); + } + + $query = Request::getStr('q', ''); + $documentId = Request::getInt('document_id', 0); + $items = mb_strlen(trim($query), 'UTF-8') >= 2 + ? \App\Modules\Search\DocumentAliases::suggestions($query, $documentId, 12) + : array(); + return $this->success('', array('data' => array('items' => $items))); + } + public function copyProductShippingToVariants(array $params = array()) { if (($error = $this->productGuard()) !== null) { return $error; } @@ -1521,14 +1607,24 @@ $allowed = Model::productRubrics(); $rubricId = Request::getInt('rubric_id', 0); - if (!in_array($rubricId, $allowed, true)) { $rubricId = !empty($allowed) ? (int) reset($allowed) : 0; } - if ($rubricId <= 0) { return $this->renderStatus('@adminx/404.twig', array('title' => 'Товарная рубрика не настроена'), 404); } + if (!$allowed) { return $this->renderStatus('@adminx/404.twig', array('title' => 'Товарная рубрика не настроена'), 404); } + if (!in_array($rubricId, $allowed, true)) { + $this->assets(); + return $this->render('@products/product-create.twig', array( + 'rubrics' => Model::productRubricOptions(), + 'return_url' => $this->base() . '/catalog/products', + )); + } + $document = DocumentsModel::blank($rubricId); + $mediaDraftToken = DocumentMediaDraft::issue(Auth::id(), 0); AdminAssets::addStyle($this->base() . '/modules/Documents/assets/documents.css', 50); AdminAssets::addScript($this->base() . '/modules/Documents/assets/documents.js', 50); CodeEditor::useRichEditor(); $this->assets(); return $this->render('@documents/edit.twig', array( - 'document' => $document, 'field_groups' => DocumentsModel::fieldsForRubric($rubricId, 0), + 'document' => $document, + 'field_groups' => DocumentsModel::fieldsForRubric($rubricId, 0, $mediaDraftToken), + 'media_draft_token' => $mediaDraftToken, 'rubrics' => array_values(array_filter(DocumentsModel::rubrics(), function ($rubric) use ($allowed) { return in_array((int) $rubric['Id'], $allowed, true); })), 'templates' => DocumentsModel::rubricTemplates($rubricId), 'navigation_items' => DocumentsModel::navigationItems(), 'authors' => DocumentsModel::authors(), 'is_new' => true, 'can_manage' => true, @@ -1774,8 +1870,8 @@ protected function savedViewFields($scope) { return $scope === 'quality' - ? array('q', 'issue', 'state', 'per_page') - : array('q', 'state', 'issue', 'payment', 'per_page'); + ? array('q', 'issue', 'per_page') + : array('q', 'state', 'issue', 'payment', 'per_page', 'view'); } protected function quickEditData() @@ -1801,6 +1897,16 @@ 'quick_profiles_available' => QuickEditorProfiles::available()); } + protected function variantGroupUrl($groupId, $productId = 0) + { + $url = $this->base() . '/catalog/variant-groups/' . (int) $groupId; + if ((int) $productId > 0) { + $url .= '?focus=' . (int) $productId . '#variant-' . (int) $productId; + } + + return $url; + } + protected function assets() { AdminAssets::addStyle($this->base() . '/modules/Catalog/assets/catalog.css', 50); @@ -1827,6 +1933,16 @@ && is_file(BASEPATH . '/modules/products/admin/module.php'); } + protected function productSearchAliasesAvailable() + { + $module = ModuleManager::get('search'); + return is_array($module) + && !empty($module['installed']) + && !empty($module['enabled']) + && class_exists('App\\Modules\\Search\\DocumentAliases') + && \App\Modules\Search\DocumentAliases::available(); + } + protected function attributeAssets() { $this->assets(); diff --git a/adminx/modules/Catalog/Model.php b/adminx/modules/Catalog/Model.php index 5826da4..795f55b 100644 --- a/adminx/modules/Catalog/Model.php +++ b/adminx/modules/Catalog/Model.php @@ -257,8 +257,8 @@ protected static function filterTemplateSettings(array $input, $submitted = false) { - $zero = isset($input['zero_behavior']) ? (string) $input['zero_behavior'] : 'disable'; - if (!in_array($zero, array('show', 'disable', 'hide'), true)) { $zero = 'disable'; } + $zero = isset($input['zero_behavior']) ? (string) $input['zero_behavior'] : 'hide'; + if (!in_array($zero, array('show', 'disable', 'hide'), true)) { $zero = 'hide'; } return array( 'show_counts' => $submitted ? !empty($input['show_counts']) : (!array_key_exists('show_counts', $input) || !empty($input['show_counts'])), 'zero_behavior' => $zero, @@ -519,6 +519,47 @@ return $out; } + /** Разделы каталога, доступные как родители в редакторе документа. */ + public static function searchParentDocuments($query, $limit = 30) + { + $query = trim((string) $query); + $limit = max(1, min(50, (int) $limit)); + $sql = 'SELECT i.id AS catalog_item_id,i.name,i.status AS catalog_status,i.document_id,d.rubric_id,' + . ' d.document_title,d.document_alias,r.rubric_title' + . ' FROM ' . self::itemsTable() . ' i' + . ' INNER JOIN ' . self::documentsTable() . ' d ON d.Id=i.document_id' + . ' LEFT JOIN ' . self::rubricsTable() . ' r ON r.Id=d.rubric_id' + . " WHERE i.document_id>0 AND d.document_deleted!='1'"; + $args = array(); + if ($query !== '') { + $sql .= ' AND (i.name LIKE %ss OR d.document_title LIKE %ss' + . ' OR d.document_alias LIKE %ss OR d.Id=%i)'; + $args[] = $query; + $args[] = $query; + $args[] = $query; + $args[] = (int) $query; + } + + $sql .= ' ORDER BY i.level ASC,i.position ASC,i.name ASC LIMIT ' . $limit; + $rows = call_user_func_array(array('DB', 'query'), array_merge(array($sql), $args))->getAll(); + $out = array(); + foreach ($rows ?: array() as $row) { + $out[] = array( + 'id' => (int) $row['document_id'], + 'rubric_id' => (int) $row['rubric_id'], + 'title' => self::decode($row['name']), + 'alias' => (string) $row['document_alias'], + 'status' => (int) $row['catalog_status'], + 'rubric_title' => 'Раздел каталога' + . ((int) $row['catalog_status'] === 1 ? '' : ' · выключен') + . ' · ' . self::decode($row['rubric_title']), + 'catalog_item_id' => (int) $row['catalog_item_id'], + ); + } + + return $out; + } + public static function parseValue($value) { $data = FieldValueCodec::decodeStructured($value, array()); @@ -543,7 +584,35 @@ { return self::productsAvailable() ? ProductIndexer::stats() - : array('total' => 0, 'active' => 0, 'inactive' => 0, 'categories' => 0); + : self::emptyProductStats(); + } + + public static function productQualityStats() + { + return self::productsAvailable() + ? ProductIndexer::qualityStats() + : self::emptyProductStats(); + } + + public static function productStatsSnapshot() + { + $stats = self::productsAvailable() ? ProductIndexer::cachedStats() : self::emptyProductStats(); + return array( + 'loaded' => is_array($stats), + 'stats' => array_merge(self::emptyProductStats(), is_array($stats) ? $stats : array()), + ); + } + + protected static function emptyProductStats() + { + return array( + 'total'=>0,'quality_total'=>0,'active'=>0,'inactive'=>0,'without_category'=>0, + 'without_image'=>0,'without_article'=>0,'without_price'=>0,'without_stock'=>0, + 'without_excerpt'=>0,'without_seo'=>0,'stale'=>0,'shipping_incomplete'=>0, + 'shipping_disabled'=>0,'duplicate_articles'=>0,'legacy_attributes'=>0, + 'filter_index_errors'=>0,'registration_incomplete'=>0,'without_video'=>0, + 'variant_errors'=>0,'description_markup'=>0,'sfr'=>0,'issues'=>0,'recommendations'=>0,'indexed_at'=>0, + ); } public static function productQualityIssues(array $stats) @@ -561,6 +630,14 @@ return self::productsAvailable() ? ProductIndexer::productRubrics() : array(); } + public static function productRubricOptions() + { + $allowed = array_flip(self::productRubrics()); + return array_values(array_filter(self::rubricOptions(), function ($rubric) use ($allowed) { + return isset($allowed[(int) $rubric['id']]); + })); + } + public static function reindexProducts($limit = 0) { return self::productsAvailable() diff --git a/adminx/modules/Catalog/module.php b/adminx/modules/Catalog/module.php index 9280b17..86a4106 100644 --- a/adminx/modules/Catalog/module.php +++ b/adminx/modules/Catalog/module.php @@ -14,7 +14,7 @@ defined('BASEPATH') || die('Direct access to this location is not allowed.'); return array( - 'code' => 'catalog', 'name' => 'Каталог', 'version' => '0.3.2', + 'code' => 'catalog', 'name' => 'Каталог', 'version' => '0.3.5', 'permissions' => array('key' => 'catalog', 'items' => array( array( 'code' => 'view_catalog', diff --git a/adminx/modules/Catalog/view/edit.twig b/adminx/modules/Catalog/view/edit.twig index 8087f74..812591a 100644 --- a/adminx/modules/Catalog/view/edit.twig +++ b/adminx/modules/Catalog/view/edit.twig @@ -47,7 +47,7 @@

Карточка товара

Единый вид для главной страницы и разделов товарного каталога.

- +
@@ -66,7 +66,7 @@
- +
Показывать количество товаровВ Twig значение доступно как option.count.
{% endif %} diff --git a/adminx/modules/Database/Backup.php b/adminx/modules/Database/Backup.php index e2a8b94..f1a75d2 100644 --- a/adminx/modules/Database/Backup.php +++ b/adminx/modules/Database/Backup.php @@ -337,9 +337,13 @@ /** Заменяет префикс только внутри SQL-идентификаторов, не затрагивая данные строк. */ protected static function portableDdl($ddl) { + $ddl = preg_replace_callback('/\bCONSTRAINT\s+`([^`]+)`/i', function ($match) { + return 'CONSTRAINT `{{prefix}}_fk_' . substr(hash('sha256', (string) $match[1]), 0, 16) . '`'; + }, (string) $ddl); + $ddl = preg_replace_callback('/`([^`]+)`/', function ($match) { return '`' . Model::portableTableName($match[1]) . '`'; - }, (string) $ddl); + }, $ddl); //-- MariaDB выводит DEFAULT NULL у TEXT/BLOB, тогда как MySQL 5.7 //-- запрещает default для этих типов. NULL и без clause остаётся default. diff --git a/adminx/modules/Database/SqlDumpReader.php b/adminx/modules/Database/SqlDumpReader.php index fe861ca..510fab6 100644 --- a/adminx/modules/Database/SqlDumpReader.php +++ b/adminx/modules/Database/SqlDumpReader.php @@ -96,7 +96,7 @@ throw new \RuntimeException('SQL-дамп оборван или содержит незавершённую команду'); } - if ($meta['format'] !== 'adminx full dump') { + if ($meta['format'] !== 'ave.cms full dump') { throw new \RuntimeException('Файл не является полным дампом AVE.cms'); } @@ -309,8 +309,9 @@ protected static function readMetadata($line, array &$meta) { $value = trim(substr(ltrim((string) $line), 2)); - if (strcasecmp($value, 'adminx full dump') === 0) { - $meta['format'] = 'adminx full dump'; + if (strcasecmp($value, 'AVE.cms full dump') === 0 + || strcasecmp($value, 'adminx full dump') === 0) { + $meta['format'] = 'ave.cms full dump'; return; } diff --git a/adminx/modules/Database/module.php b/adminx/modules/Database/module.php index 256f011..c0f8b0c 100644 --- a/adminx/modules/Database/module.php +++ b/adminx/modules/Database/module.php @@ -21,7 +21,7 @@ return [ 'code' => 'database', 'name' => 'База данных', - 'version' => '0.2.0', + 'version' => '0.2.2', 'permissions' => [ 'key' => 'database', diff --git a/adminx/modules/Documents/Controller.php b/adminx/modules/Documents/Controller.php index 15a8d62..3514a20 100644 --- a/adminx/modules/Documents/Controller.php +++ b/adminx/modules/Documents/Controller.php @@ -361,13 +361,22 @@ return $this->error('Недостаточно прав', array(), 403); } + $scope = Request::getStr('scope', 'document'); + $items = $scope === 'parent' + ? Model::parentDocumentPicker( + Request::getStr('q', ''), + Request::getInt('limit', 20), + Request::getInt('exclude_id', 0) + ) + : Model::documentPicker( + Request::getStr('q', ''), + Request::getStr('rubric_id', ''), + Request::getInt('limit', 20) + ); + return $this->success('', array( 'data' => array( - 'items' => Model::documentPicker( - Request::getStr('q', ''), - Request::getStr('rubric_id', ''), - Request::getInt('limit', 20) - ), + 'items' => $items, ), )); } diff --git a/adminx/modules/Documents/Model.php b/adminx/modules/Documents/Model.php index ce029ba..794618e 100644 --- a/adminx/modules/Documents/Model.php +++ b/adminx/modules/Documents/Model.php @@ -304,10 +304,21 @@ if (!empty($allowed)) { $catalogAllowed = array_values(array_unique(array_merge($catalogAllowed, $allowed))); } } + $conditionReferences = $conditionsEnabled ? self::conditionReferences($rows) : array(); + $conditionSources = array(); $groups = array(); foreach ($rows as $row) { $settings = FieldSettings::effective($row); - if (array_key_exists('placed', $settings) && empty($settings['placed'])) { continue; } + if (array_key_exists('placed', $settings) && empty($settings['placed'])) { + $idReference = 'id:' . (int) $row['Id']; + $aliasReference = 'alias:' . strtolower(trim((string) $row['rubric_field_alias'])); + if (isset($conditionReferences[$idReference]) || isset($conditionReferences[$aliasReference])) { + $conditionSources[(int) $row['Id']] = self::conditionSourceRow($row); + } + + continue; + } + $groupId = (int) $row['rubric_field_group']; if (!isset($groups[$groupId])) { $groups[$groupId] = array( @@ -324,7 +335,12 @@ $groups[$groupId]['items'][] = $field; } - return array_values($groups); + $groups = array_values($groups); + if (!empty($groups) && !empty($conditionSources)) { + $groups[0]['condition_sources'] = array_values($conditionSources); + } + + return $groups; } /** @@ -338,13 +354,11 @@ return array(); } - $fields = array(); + $fieldGroups = self::resolveFieldGroups($rubricId, (int) $documentId, $fieldGroups); + $fields = self::conditionAwareFields($fieldGroups); $effectiveValues = array(); - foreach (self::resolveFieldGroups($rubricId, (int) $documentId, $fieldGroups) as $group) { - foreach ($group['items'] as $field) { - $fields[] = $field; - $effectiveValues[(int) $field['Id']] = isset($field['field_value']) ? $field['field_value'] : ''; - } + foreach ($fields as $field) { + $effectiveValues[(int) $field['Id']] = isset($field['field_value']) ? $field['field_value'] : ''; } foreach ($values as $id => $value) { @@ -356,14 +370,14 @@ public static function computedFieldValues($rubricId, array $values, array $document = array(), $documentId = 0, $fieldGroups = null) { + $fieldGroups = self::resolveFieldGroups((int) $rubricId, (int) $documentId, $fieldGroups); + $fields = self::conditionAwareFields($fieldGroups); $definitions = array(); $effectiveValues = array(); - foreach (self::resolveFieldGroups((int) $rubricId, (int) $documentId, $fieldGroups) as $group) { - foreach ($group['items'] as $field) { - $fieldId = (int) $field['Id']; - $definitions[$fieldId] = $field; - $effectiveValues[$fieldId] = isset($field['field_value']) ? $field['field_value'] : ''; - } + foreach ($fields as $field) { + $fieldId = (int) $field['Id']; + $definitions[$fieldId] = $field; + $effectiveValues[$fieldId] = isset($field['field_value']) ? $field['field_value'] : ''; } foreach ($values as $fieldId => $value) { @@ -387,18 +401,19 @@ return $values; } - $fields = array(); + $fieldGroups = self::resolveFieldGroups((int) $rubricId, (int) $documentId, $fieldGroups); + $fields = self::conditionAwareFields($fieldGroups); $fieldMap = array(); $storedValues = array(); $effectiveValues = array(); - foreach (self::resolveFieldGroups((int) $rubricId, (int) $documentId, $fieldGroups) as $group) { - foreach ($group['items'] as $field) { - $fields[] = $field; + foreach ($fields as $field) { $fieldId = (int) $field['Id']; + if (empty($field['_condition_source'])) { $fieldMap[$fieldId] = $field; + } + $storedValues[$fieldId] = (int) $documentId > 0 && isset($field['field_value']) ? $field['field_value'] : ''; $effectiveValues[$fieldId] = isset($field['field_value']) ? $field['field_value'] : ''; - } } foreach ($values as $id => $value) { @@ -821,6 +836,29 @@ : self::fieldsForRubric((int) $rubricId, (int) $documentId); } + protected static function conditionAwareFields(array $fieldGroups) + { + $fields = array(); + $seen = array(); + foreach ($fieldGroups as $group) { + foreach (isset($group['condition_sources']) && is_array($group['condition_sources']) ? $group['condition_sources'] : array() as $field) { + $fieldId = isset($field['Id']) ? (int) $field['Id'] : 0; + if ($fieldId <= 0 || isset($seen[$fieldId])) { continue; } + $seen[$fieldId] = true; + $fields[] = $field; + } + + foreach (isset($group['items']) && is_array($group['items']) ? $group['items'] : array() as $field) { + $fieldId = isset($field['Id']) ? (int) $field['Id'] : 0; + if ($fieldId <= 0 || isset($seen[$fieldId])) { continue; } + $seen[$fieldId] = true; + $fields[] = $field; + } + } + + return $fields; + } + public static function delete($id) { $id = (int) $id; @@ -1331,6 +1369,33 @@ return (new \App\Content\Documents\DocumentPickerRepository())->search($q, $rubricId, $limit); } + public static function parentDocumentPicker($q, $limit = 20, $excludeId = 0) + { + $limit = max(1, min(50, (int) $limit)); + $excludeId = max(0, (int) $excludeId); + $items = CatalogModel::searchParentDocuments($q, $limit); + $seen = array(); + $result = array(); + foreach ($items as $item) { + $id = (int) $item['id']; + if ($id <= 0 || $id === $excludeId || isset($seen[$id])) { continue; } + $seen[$id] = true; + $result[] = $item; + if (count($result) >= $limit) { return $result; } + } + + $documents = (new \App\Content\Documents\DocumentPickerRepository())->search($q, array(), $limit); + foreach ($documents as $item) { + $id = (int) $item['id']; + if ($id <= 0 || $id === $excludeId || isset($seen[$id])) { continue; } + $seen[$id] = true; + $result[] = $item; + if (count($result) >= $limit) { break; } + } + + return $result; + } + /** Existing keywords/tags for the searchable tag inputs in document editor. */ public static function termSuggestions($kind, $q = '', $rubricId = 0, $limit = 12) { @@ -1673,11 +1738,7 @@ { $type = (string) $row['rubric_field_type']; $hasInitialValue = array_key_exists('__initial_value', $row); - $raw = $hasInitialValue - ? (string) $row['__initial_value'] - : ($row['document_field_id'] - ? (string) $row['field_value'] . (string) $row['field_value_more'] - : self::initialFieldValue($type, (string) $row['rubric_field_default'])); + $raw = self::rawFieldValue($row); $editor = FieldAdminEditors::describe($type); $kind = self::documentEditorKind($editor); $settings = FieldSettings::effective($row); @@ -1777,6 +1838,60 @@ return $field; } + protected static function rawFieldValue(array $row) + { + if (array_key_exists('__initial_value', $row)) { return (string) $row['__initial_value']; } + if (!empty($row['document_field_id'])) { + return (string) $row['field_value'] . (string) $row['field_value_more']; + } + + return self::initialFieldValue((string) $row['rubric_field_type'], (string) $row['rubric_field_default']); + } + + protected static function conditionSourceRow(array $row) + { + return array( + 'Id' => (int) $row['Id'], + 'rubric_id' => (int) $row['rubric_id'], + 'rubric_field_group' => (int) $row['rubric_field_group'], + 'rubric_field_title' => self::decode($row['rubric_field_title']), + 'rubric_field_alias' => (string) $row['rubric_field_alias'], + 'rubric_field_type' => (string) $row['rubric_field_type'], + 'rubric_field_settings' => isset($row['rubric_field_settings']) ? (string) $row['rubric_field_settings'] : '', + 'group_settings' => isset($row['group_settings']) ? (string) $row['group_settings'] : '', + 'field_value' => self::rawFieldValue($row), + '_condition_source' => true, + ); + } + + protected static function conditionReferences(array $rows) + { + $references = array(); + foreach ($rows as $row) { + foreach (array(FieldConditionEvaluator::condition($row), FieldConditionEvaluator::groupCondition($row)) as $condition) { + if (!empty($condition['tree']) && is_array($condition['tree'])) { + self::collectConditionReferences($condition['tree'], $references); + } + } + } + + return $references; + } + + protected static function collectConditionReferences(array $node, array &$references) + { + if (isset($node['items']) && is_array($node['items'])) { + foreach ($node['items'] as $item) { + if (is_array($item)) { self::collectConditionReferences($item, $references); } + } + + return; + } + + $reference = isset($node['field']) ? strtolower(trim((string) $node['field'])) : ''; + if ($reference !== '') { $references[$reference] = true; } + } + protected static function hasGroupSettingsColumn() { static $has = null; @@ -1941,7 +2056,9 @@ } if ($kind === 'relation') { - return isset($parsed['document_id']) ? (string) $parsed['document_id'] : (string) $raw; + return array( + 'document_id' => isset($parsed['document_id']) ? (string) $parsed['document_id'] : (string) $raw, + ); } if (in_array($kind, array('lines', 'relation_list'), true)) { diff --git a/adminx/modules/Documents/assets/documents.css b/adminx/modules/Documents/assets/documents.css index c0a4abf..787a282 100644 --- a/adminx/modules/Documents/assets/documents.css +++ b/adminx/modules/Documents/assets/documents.css @@ -571,6 +571,40 @@ text-overflow: ellipsis; white-space: nowrap; } +.documents-public-link { + display: inline-flex; + align-items: center; + gap: 5px; + min-width: 0; + max-width: 100%; + width: fit-content; + color: var(--blue-600); + font-size: 11.5px; + line-height: 1.35; + text-decoration: none; +} +.documents-public-link i { + flex: 0 0 auto; + color: var(--blue-600); + font-size: 13px; +} +.documents-public-link span { + overflow: hidden; + min-width: 0; + white-space: nowrap; + text-overflow: ellipsis; +} +.documents-public-link:hover, +.documents-public-link:focus-visible { + color: var(--blue-700); +} +.documents-public-alias-empty { + color: var(--text-muted); + font-size: 11.5px; +} +.documents-admin-card-title .documents-public-link { + margin-top: 3px; +} .documents-search-flag { display: inline-flex; align-items: center; @@ -1462,13 +1496,15 @@ .documents-editor-workspace[data-active-panel="attributes"] #documentForm, .documents-editor-workspace[data-active-panel="promotions"] #documentForm, .documents-editor-workspace[data-active-panel="variants"] #documentForm, -.documents-editor-workspace[data-active-panel="shipping"] #documentForm { +.documents-editor-workspace[data-active-panel="shipping"] #documentForm, +.documents-editor-workspace[data-active-panel="search"] #documentForm { display: none; } .documents-editor-workspace[data-active-panel="attributes"] [data-document-workspace-panel="attributes"], .documents-editor-workspace[data-active-panel="promotions"] [data-document-workspace-panel="promotions"], .documents-editor-workspace[data-active-panel="variants"] [data-document-workspace-panel="variants"], -.documents-editor-workspace[data-active-panel="shipping"] [data-document-workspace-panel="shipping"] { +.documents-editor-workspace[data-active-panel="shipping"] [data-document-workspace-panel="shipping"], +.documents-editor-workspace[data-active-panel="search"] [data-document-workspace-panel="search"] { display: block; } .documents-editor-workspace [data-document-workspace-panel] { diff --git a/adminx/modules/Documents/assets/documents.js b/adminx/modules/Documents/assets/documents.js index b2c6d6a..2eb4160 100644 --- a/adminx/modules/Documents/assets/documents.js +++ b/adminx/modules/Documents/assets/documents.js @@ -1124,6 +1124,13 @@ documentFieldConditionContext: function () { var context = {}; + this.form.querySelectorAll('[data-document-condition-source]').forEach(function (source) { + var id = String(parseInt(source.getAttribute('data-field-id'), 10) || 0); + var alias = String(source.getAttribute('data-field-alias') || '').trim().toLowerCase(); + var values = [String(source.value == null ? '' : source.value)]; + context['id:' + id] = values; + if (alias) { context['alias:' + alias] = values; } + }); this.form.querySelectorAll('.ax-document-field[data-rubric-field-id]').forEach(function (field) { var values = []; var controls = Array.prototype.slice.call(field.querySelectorAll('input[name], select[name], textarea[name]')); @@ -1349,9 +1356,24 @@ searchCatalog: function (catalog, value) { if (!catalog) { return; } - value = String(value || '').trim().toLowerCase(); - catalog.querySelectorAll('[data-document-catalog-node]').forEach(function (node) { - node.classList.toggle('is-filtered', value && String(node.getAttribute('data-search') || '').toLowerCase().indexOf(value) < 0); + var normalize = function (input) { + return String(input || '').toLowerCase().replace(/ё/g, 'е').replace(/[^0-9a-zа-я]+/gi, ' ').trim(); + }; + var query = normalize(value); + var tokens = query ? query.split(/\s+/) : []; + var nodes = Array.prototype.slice.call(catalog.querySelectorAll('[data-document-catalog-node]')); + nodes.forEach(function (node) { + var haystack = normalize(node.getAttribute('data-search')); + var matches = !tokens.length || tokens.every(function (token) { return haystack.indexOf(token) >= 0; }); + node.classList.toggle('is-filtered', !matches); + }); + nodes.forEach(function (node) { + if (node.classList.contains('is-filtered')) { return; } + var parent = node.parentElement ? node.parentElement.closest('[data-document-catalog-node]') : null; + while (parent) { + parent.classList.remove('is-filtered'); + parent = parent.parentElement ? parent.parentElement.closest('[data-document-catalog-node]') : null; + } }); }, @@ -1496,7 +1518,7 @@ saveActiveWorkspace: function () { var workspace = document.querySelector('[data-document-workspace]'); var panel = workspace ? workspace.getAttribute('data-active-panel') || 'main' : 'main'; - if (panel === 'attributes' || panel === 'shipping' || panel === 'promotions') { + if (panel === 'attributes' || panel === 'shipping' || panel === 'promotions' || panel === 'search') { var form = workspace.querySelector('[data-document-workspace-panel="' + panel + '"] form'); if (form && typeof form.requestSubmit === 'function') { form.requestSubmit(); } else if (form) { form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true })); } @@ -1772,6 +1794,16 @@ if (textarea._adminxCodeMirror) { textarea._adminxCodeMirror.save(); } }); this.form.querySelectorAll('textarea[data-rich-editor]').forEach(function (textarea) { + if (window.Adminx && Adminx.RichEditor && typeof Adminx.RichEditor.syncTextarea === 'function') { + Adminx.RichEditor.syncTextarea(textarea, textarea._adminxTiptap || null); + return; + } + var root = textarea.closest('.rich-editor'); + if (root && root.classList.contains('rich-editor-source-open') && root._richSourceEditor) { + root._richSourceEditor.save(); + textarea.value = root._richSourceEditor.getValue(); + return; + } if (textarea._adminxTiptap && textarea.getAttribute('data-rich-editor-dirty') === '1') { textarea.value = textarea._adminxTiptap.getHTML(); } @@ -2467,7 +2499,11 @@ applyPickedMedia: function (target, file) { var input = target ? target.querySelector('[data-document-media-url]') : null; - if (input && file && file.url) { input.value = file.url; input.dispatchEvent(new Event('input', { bubbles: true })); } + if (input && file && file.url) { + input.value = file.url; + input.dispatchEvent(new Event('input', { bubbles: true })); + this.sortMediaRowsByName(target.closest('[data-document-media-list]')); + } }, mediaPickerType: function (target) { @@ -2507,25 +2543,40 @@ uploadMediaFiles: function (container, files, replace) { if (!container || !files || !files.length) { return; } - var data = new FormData(); - data.append('_csrf', this.csrf()); - data.append('dir', container.getAttribute('data-upload-dir') || '/uploads'); - data.append('field_id', container.getAttribute('data-field-id') || '0'); - data.append('document_id', (this.field('id') || {}).value || '0'); - data.append('media_draft_token', (this.field('media_draft_token') || {}).value || ''); - Array.prototype.forEach.call(files, function (file) { data.append('files[]', file); }); var self = this; - this.ajax(container.getAttribute('data-upload-url') || (this.base() + '/media/upload'), data, function (payload) { - var uploaded = ((payload.data || {}).files) || []; - if (replace && uploaded.length) { - self.prepareMediaReplacement(container); + var buttons = container.querySelectorAll('[data-document-media-upload]'); + buttons.forEach(function (button) { button.disabled = true; }); + Adminx.Loader.show(); + Adminx.Upload.files( + container.getAttribute('data-upload-url') || (this.base() + '/media/upload'), + files, + function (chunk) { + var data = new FormData(); + data.append('_csrf', self.csrf()); + data.append('dir', container.getAttribute('data-upload-dir') || '/uploads'); + data.append('field_id', container.getAttribute('data-field-id') || '0'); + data.append('document_id', (self.field('id') || {}).value || '0'); + data.append('media_draft_token', (self.field('media_draft_token') || {}).value || ''); + chunk.forEach(function (file) { data.append('files[]', file); }); + return data; } + ).then(function (result) { + var uploaded = result.files || []; + if (replace && uploaded.length) { self.prepareMediaReplacement(container); } if (container.matches('[data-document-media-single]')) { self.applyUploadedSingle(container, uploaded[0] || null); } else { self.appendMediaFiles(container, uploaded); } - Adminx.Toast.show(payload.message || 'Файлы загружены', 'success'); + Adminx.Toast.show('Загружено файлов: ' + uploaded.length, 'success'); + }).catch(function (error) { + var uploaded = error && error.uploaded ? error.uploaded.length : 0; + var message = (error && error.message) || 'Не удалось загрузить файлы'; + if (uploaded) { message += '. До ошибки загружено: ' + uploaded; } + Adminx.Toast.show(message, 'error'); + }).finally(function () { + Adminx.Loader.hide(); + buttons.forEach(function (button) { button.disabled = false; }); }); }, @@ -2606,10 +2657,43 @@ seen[url] = true; added++; }); + if (added) { this.sortMediaRowsByName(list); } this.updateMediaListEmpty(list); if (!added && files.length) { Adminx.Toast.show('Эти файлы уже есть в поле', 'info'); } }, + sortMediaRowsByName: function (list) { + if (!list || list.getAttribute('data-media-accept') !== 'image') { return; } + var box = list.querySelector('[data-document-media-items]'); + if (!box) { return; } + var rows = Array.prototype.slice.call(box.querySelectorAll('[data-document-media-row]')); + if (rows.length < 2) { return; } + var self = this; + var collator = window.Intl && window.Intl.Collator + ? new window.Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }) + : null; + rows.sort(function (left, right) { + var leftName = self.mediaRowFileName(left); + var rightName = self.mediaRowFileName(right); + if (!leftName && !rightName) { return 0; } + if (!leftName) { return 1; } + if (!rightName) { return -1; } + return collator ? collator.compare(leftName, rightName) : leftName.localeCompare(rightName); + }); + rows.forEach(function (row) { box.appendChild(row); }); + this.reindexMediaList(list); + }, + + mediaRowFileName: function (row) { + var input = row ? row.querySelector('[data-media-key="url"]') : null; + var value = input ? String(input.value || '').trim() : ''; + if (!value) { return ''; } + value = value.split(/[?#]/, 1)[0].replace(/\\/g, '/'); + var name = value.slice(value.lastIndexOf('/') + 1); + try { name = decodeURIComponent(name); } catch (e) {} + return name; + }, + createMediaRow: function (list) { this.addMediaRow(list); var rows = list.querySelectorAll('[data-document-media-row]'); @@ -3016,11 +3100,15 @@ var rubricEl = target ? (target.querySelector && target.querySelector('[data-document-picker-rubric]')) : null; if (!rubricEl && target && target.matches && target.matches('[data-document-picker-rubric]')) { rubricEl = target; } var rubric = rubricEl ? (rubricEl.getAttribute('data-document-picker-rubric') || '') : ''; + var scope = target && target.getAttribute ? (target.getAttribute('data-document-picker-scope') || '') : ''; + var excludeId = target && target.getAttribute ? (target.getAttribute('data-document-picker-exclude') || '') : ''; var load = function () { var params = new URLSearchParams(); params.set('q', search.value.trim()); params.set('limit', 20); if (rubric) { params.set('rubric_id', rubric); } + if (scope) { params.set('scope', scope); } + if (excludeId) { params.set('exclude_id', excludeId); } status.textContent = 'Загрузка...'; status.hidden = false; fetch(self.base() + '/documents/picker?' + params.toString(), { headers: { 'Accept': 'application/json' }, credentials: 'same-origin' }) diff --git a/adminx/modules/Documents/language/en/interface.xml b/adminx/modules/Documents/language/en/interface.xml index f055a43..e3350ea 100644 --- a/adminx/modules/Documents/language/en/interface.xml +++ b/adminx/modules/Documents/language/en/interface.xml @@ -493,6 +493,8 @@ Refresh page Published Published + Open on site + Open page in a new tab Open the desired folder and confirm your selection. All suitable files from it will be added to the field. Cancel Cancel change diff --git a/adminx/modules/Documents/language/ru/interface.xml b/adminx/modules/Documents/language/ru/interface.xml index 003f43d..248bdc7 100644 --- a/adminx/modules/Documents/language/ru/interface.xml +++ b/adminx/modules/Documents/language/ru/interface.xml @@ -493,6 +493,8 @@ Обновить страницу Опубликован Опубликованные + Открыть на сайте + Открыть страницу в новой вкладке Откройте нужную папку и подтвердите выбор. В поле добавятся все подходящие файлы из неё. Отменить Отменить изменение diff --git a/adminx/modules/Documents/module.php b/adminx/modules/Documents/module.php index 45ba32d..89191c7 100644 --- a/adminx/modules/Documents/module.php +++ b/adminx/modules/Documents/module.php @@ -17,7 +17,7 @@ return array( 'code' => 'documents', 'name' => 'Документы', - 'version' => '0.3.3', + 'version' => '0.3.9', 'permissions' => array( 'key' => 'documents', diff --git a/adminx/modules/Documents/view/_product_panels.twig b/adminx/modules/Documents/view/_product_panels.twig index 08368c2..7e7d5a9 100644 --- a/adminx/modules/Documents/view/_product_panels.twig +++ b/adminx/modules/Documents/view/_product_panels.twig @@ -1,3 +1,26 @@ +{% if catalog_mode and not is_new and product_search_aliases_available %} +
+
+ +
+

Поисковые названия

Другие названия только этого товара: народные, прежние или разговорные.

+ {{ product_search_aliases|length }} +
+
+
Название товара не изменится

Например, «кушетка» или «стол-чемодан» помогут найти товар, но не появятся в карточке на сайте.

+
+ {% for alias in product_search_aliases %} +
+ {% endfor %} +
+
Дополнительных названий пока нет
+
+
+
+ +
+{% endif %} + {% if catalog_mode and not is_new %}
@@ -88,18 +111,34 @@ {% if catalog_mode and not is_new %}
-

Варианты товара

{% if variant_group %}Группа #{{ variant_group.id }}{% endif %}
-
+

Варианты товара

Цвета, комплектации и другие исполнения одной модели.

{% if variant_group %}Группа #{{ variant_group.id }}{% endif %}
+
{% if variant_group %} -
{{ variant_group.title }}

{{ variant_group.is_primary ? 'Основной вариант группы' : 'Вариант группы' }}

- Управление вариантами +
{{ variant_group.title }}

{{ variant_group.is_primary ? 'Основной вариант группы' : 'Вариант группы' }}

+
+
+ + +
+ Открыть матрицу +
{% else %} -
Товар пока не объединён с вариантами

Создайте группу на основе текущего товара.

-
- - - -
+
Товар пока не входит в группу

Создайте новую группу для этой модели или добавьте товар в уже существующую.

+
+
+ + Новая группаТекущий товар станет первым и основным вариантом. + + +
+
+ + Существующая группаПодходит, если другие исполнения модели уже добавлены. + + + {% if not variant_groups %}Других групп пока нет.{% endif %} +
+
{% endif %}
diff --git a/adminx/modules/Documents/view/edit.twig b/adminx/modules/Documents/view/edit.twig index 329fc4b..adf1ed7 100644 --- a/adminx/modules/Documents/view/edit.twig +++ b/adminx/modules/Documents/view/edit.twig @@ -4,7 +4,7 @@ @@ -15,7 +15,7 @@

{{ is_new ? (catalog_mode ? 'Заполните основные данные. Характеристики, варианты и доставка откроются после первого сохранения.' : 'Создание базовой карточки документа.') : 'ID ' ~ document.Id ~ ', ' ~ (document.state_label|admin_trans) ~ ', изменён: ' ~ document.changed_label }}

- {% if catalog_mode and not is_new and can_manage and product_copy_url %}{% endif %} + {% if catalog_mode and not is_new and can_manage and product_copy_url %}{% endif %} К списку
@@ -30,6 +30,7 @@ + {% if product_search_aliases_available %}{% endif %} {% endif %} @@ -41,8 +42,9 @@ - - {% endif %} + + {% if product_search_aliases_available %}{% endif %} + {% endif %} @@ -71,6 +73,11 @@ + {% if field_groups %} + {% for source in field_groups[0].condition_sources|default([]) %} + + {% endfor %} + {% endif %}