diff options
Diffstat (limited to 'core/modules')
176 files changed, 2565 insertions, 1465 deletions
diff --git a/core/modules/automated_cron/automated_cron.services.yml b/core/modules/automated_cron/automated_cron.services.yml index 0cc66d22384e..69c364b1f250 100644 --- a/core/modules/automated_cron/automated_cron.services.yml +++ b/core/modules/automated_cron/automated_cron.services.yml @@ -4,6 +4,6 @@ parameters: services: _defaults: autoconfigure: true + autowire: true automated_cron.subscriber: class: Drupal\automated_cron\EventSubscriber\AutomatedCron - arguments: ['@cron', '@config.factory', '@state'] diff --git a/core/modules/automated_cron/src/EventSubscriber/AutomatedCron.php b/core/modules/automated_cron/src/EventSubscriber/AutomatedCron.php index c237f07ea34d..80258bad508e 100644 --- a/core/modules/automated_cron/src/EventSubscriber/AutomatedCron.php +++ b/core/modules/automated_cron/src/EventSubscriber/AutomatedCron.php @@ -1,10 +1,12 @@ <?php +declare(strict_types=1); + namespace Drupal\automated_cron\EventSubscriber; use Drupal\Core\Config\ConfigFactoryInterface; -use Drupal\Core\CronInterface; use Drupal\Core\State\StateInterface; +use Symfony\Component\DependencyInjection\Attribute\AutowireServiceClosure; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\TerminateEvent; use Symfony\Component\HttpKernel\KernelEvents; @@ -14,42 +16,12 @@ use Symfony\Component\HttpKernel\KernelEvents; */ class AutomatedCron implements EventSubscriberInterface { - /** - * The cron service. - * - * @var \Drupal\Core\CronInterface - */ - protected $cron; - - /** - * The cron configuration. - * - * @var \Drupal\Core\Config\Config - */ - protected $config; - - /** - * The state key value store. - * - * @var \Drupal\Core\State\StateInterface - */ - protected $state; - - /** - * Constructs a new automated cron runner. - * - * @param \Drupal\Core\CronInterface $cron - * The cron service. - * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory - * The config factory. - * @param \Drupal\Core\State\StateInterface $state - * The state key-value store service. - */ - public function __construct(CronInterface $cron, ConfigFactoryInterface $config_factory, StateInterface $state) { - $this->cron = $cron; - $this->config = $config_factory->get('automated_cron.settings'); - $this->state = $state; - } + public function __construct( + #[AutowireServiceClosure('cron')] + protected readonly \Closure $cron, + protected readonly ConfigFactoryInterface $configFactory, + protected StateInterface $state, + ) {} /** * Run the automated cron if enabled. @@ -57,12 +29,12 @@ class AutomatedCron implements EventSubscriberInterface { * @param \Symfony\Component\HttpKernel\Event\TerminateEvent $event * The Event to process. */ - public function onTerminate(TerminateEvent $event) { - $interval = $this->config->get('interval'); + public function onTerminate(TerminateEvent $event): void { + $interval = $this->configFactory->get('automated_cron.settings')->get('interval'); if ($interval > 0) { $cron_next = $this->state->get('system.cron_last', 0) + $interval; if ((int) $event->getRequest()->server->get('REQUEST_TIME') > $cron_next) { - $this->cron->run(); + ($this->cron)()->run(); } } } diff --git a/core/modules/automated_cron/tests/src/Kernel/AutomatedCronTest.php b/core/modules/automated_cron/tests/src/Kernel/AutomatedCronTest.php new file mode 100644 index 000000000000..40f71d091c26 --- /dev/null +++ b/core/modules/automated_cron/tests/src/Kernel/AutomatedCronTest.php @@ -0,0 +1,46 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\automated_cron\Kernel; + +use Drupal\KernelTests\KernelTestBase; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +/** + * Tests for automated_cron. + * + * @group automated_cron + */ +class AutomatedCronTest extends KernelTestBase { + + /** + * {@inheritdoc} + */ + protected static $modules = ['automated_cron']; + + /** + * Tests that automated cron runs cron on an HTTP request. + * + * @covers \Drupal\automated_cron\EventSubscriber\AutomatedCron::onTerminate + */ + public function testRunsCronOnHttpRequest(): void { + // Set automated_cron interval and times. + // Any interval > 0 should work. + $this->config('automated_cron.settings')->set('interval', 10800)->save(); + $request = new Request(); + + // Cron uses `$_SERVER['REQUEST_TIME']` to set `system.cron_last` + // because there is no request stack, so we set the request time + // to the same. + $expected = $_SERVER['REQUEST_TIME']; + $request->server->set('REQUEST_TIME', $expected); + + // Invoke `AutomatedCron::onTerminate` and check result. + $this->assertNull($this->container->get('state')->get('system.cron_last')); + $this->container->get('kernel')->terminate($request, new Response()); + $this->assertEquals($expected, $this->container->get('state')->get('system.cron_last')); + } + +} diff --git a/core/modules/big_pipe/js/big_pipe.js b/core/modules/big_pipe/js/big_pipe.js index 3c3e106e7037..cc8c7a244961 100644 --- a/core/modules/big_pipe/js/big_pipe.js +++ b/core/modules/big_pipe/js/big_pipe.js @@ -91,8 +91,7 @@ return Boolean( node.nodeType === Node.ELEMENT_NODE && node.nodeName === 'SCRIPT' && - node.dataset && - node.dataset.bigPipeReplacementForPlaceholderWithId && + node.dataset?.bigPipeReplacementForPlaceholderWithId && typeof drupalSettings.bigPipePlaceholderIds[ node.dataset.bigPipeReplacementForPlaceholderWithId ] !== 'undefined', diff --git a/core/modules/block/src/BlockViewBuilder.php b/core/modules/block/src/BlockViewBuilder.php index f33092de869e..b5a1e4643468 100644 --- a/core/modules/block/src/BlockViewBuilder.php +++ b/core/modules/block/src/BlockViewBuilder.php @@ -67,7 +67,11 @@ class BlockViewBuilder extends EntityViewBuilder implements TrustedCallbackInter if ($plugin instanceof MainContentBlockPluginInterface || $plugin instanceof TitleBlockPluginInterface) { // Immediately build a #pre_render-able block, since this block cannot // be built lazily. - $build[$entity_id] += static::buildPreRenderableBlock($entity, $this->moduleHandler()); + $cacheableMetadata = CacheableMetadata::createFromRenderArray($build[$entity_id]); + $preRenderableBlock = static::buildPreRenderableBlock($entity, $this->moduleHandler()); + $cacheableMetadata->addCacheableDependency(CacheableMetadata::createFromRenderArray($preRenderableBlock)); + $build[$entity_id] += $preRenderableBlock; + $cacheableMetadata->applyTo($build[$entity_id]); } else { // Assign a #lazy_builder callback, which will generate a #pre_render- diff --git a/core/modules/block/tests/modules/block_test/src/Hook/BlockTestHooks.php b/core/modules/block/tests/modules/block_test/src/Hook/BlockTestHooks.php index 19afd070f9d0..7954c270df24 100644 --- a/core/modules/block/tests/modules/block_test/src/Hook/BlockTestHooks.php +++ b/core/modules/block/tests/modules/block_test/src/Hook/BlockTestHooks.php @@ -37,6 +37,16 @@ class BlockTestHooks { } /** + * Implements hook_block_view_BASE_BLOCK_ID_alter(). + * + * @see \Drupal\Tests\block\Kernel\BlockViewBuilderTest::testBlockViewBuilderCacheTitleBlock() + */ + #[Hook('block_view_page_title_block_alter')] + public function blockViewPageTitleBlockAlter(array &$build, BlockPluginInterface $block): void { + $build['#cache']['tags'][] = 'custom_cache_tag'; + } + + /** * Implements hook_block_build_BASE_BLOCK_ID_alter(). */ #[Hook('block_build_test_cache_alter')] diff --git a/core/modules/block/tests/src/Functional/BlockLanguageTest.php b/core/modules/block/tests/src/Functional/BlockLanguageTest.php index d7ee92575fe3..4801c308cf54 100644 --- a/core/modules/block/tests/src/Functional/BlockLanguageTest.php +++ b/core/modules/block/tests/src/Functional/BlockLanguageTest.php @@ -72,7 +72,7 @@ class BlockLanguageTest extends BrowserTestBase { public function testLanguageBlockVisibility(): void { // Check if the visibility setting is available. $default_theme = $this->config('system.theme')->get('default'); - $this->drupalGet('admin/structure/block/add/system_powered_by_block' . '/' . $default_theme); + $this->drupalGet('admin/structure/block/add/system_powered_by_block/' . $default_theme); // Ensure that the language visibility field is visible without a type // setting. $this->assertSession()->fieldExists('visibility[language][langcodes][en]'); @@ -84,7 +84,7 @@ class BlockLanguageTest extends BrowserTestBase { 'id' => $this->randomMachineName(8), 'region' => 'sidebar_first', ]; - $this->drupalGet('admin/structure/block/add/system_powered_by_block' . '/' . $default_theme); + $this->drupalGet('admin/structure/block/add/system_powered_by_block/' . $default_theme); $this->submitForm($edit, 'Save block'); // Change the default language. @@ -162,7 +162,7 @@ class BlockLanguageTest extends BrowserTestBase { // Check if the visibility setting is available with a type setting. $default_theme = $this->config('system.theme')->get('default'); - $this->drupalGet('admin/structure/block/add/system_powered_by_block' . '/' . $default_theme); + $this->drupalGet('admin/structure/block/add/system_powered_by_block/' . $default_theme); $this->assertSession()->fieldExists('visibility[language][langcodes][en]'); $this->assertSession()->fieldExists('visibility[language][context_mapping][language]'); @@ -174,7 +174,7 @@ class BlockLanguageTest extends BrowserTestBase { 'id' => $block_id, 'region' => 'sidebar_first', ]; - $this->drupalGet('admin/structure/block/add/system_powered_by_block' . '/' . $default_theme); + $this->drupalGet('admin/structure/block/add/system_powered_by_block/' . $default_theme); $this->submitForm($edit, 'Save block'); // Interface negotiation depends on request arguments. diff --git a/core/modules/block/tests/src/Kernel/BlockViewBuilderTest.php b/core/modules/block/tests/src/Kernel/BlockViewBuilderTest.php index d93e1f819eab..377cd31deacb 100644 --- a/core/modules/block/tests/src/Kernel/BlockViewBuilderTest.php +++ b/core/modules/block/tests/src/Kernel/BlockViewBuilderTest.php @@ -164,6 +164,30 @@ class BlockViewBuilderTest extends KernelTestBase { } /** + * Tests title block render cache handling. + * + * @see \Drupal\block_test\Hook\BlockTestHooks::blockViewPageTitleBlockAlter() + */ + public function testBlockViewBuilderCacheTitleBlock(): void { + // Create title block. + $this->block = $this->controller->create([ + 'id' => 'test_block_title', + 'theme' => 'stark', + 'plugin' => 'page_title_block', + ]); + $this->block->save(); + + $entity = Block::load('test_block_title'); + $builder = \Drupal::entityTypeManager()->getViewBuilder('block'); + $output = $builder->view($entity, 'block'); + + $this->assertSame( + ['block_view', 'config:block.block.test_block_title', 'custom_cache_tag'], + $output['#cache']['tags'] + ); + } + + /** * Verifies render cache handling of the block being tested. * * @see ::testBlockViewBuilderCache() diff --git a/core/modules/block_content/block_content.services.yml b/core/modules/block_content/block_content.services.yml index 2661eda513b5..5d43a1d37f8e 100644 --- a/core/modules/block_content/block_content.services.yml +++ b/core/modules/block_content/block_content.services.yml @@ -1,6 +1,28 @@ parameters: block_content.skip_procedural_hook_scan: false + block_content.moved_classes: + Drupal\block_content\Access\AccessGroupAnd: + class: Drupal\Core\Access\AccessGroupAnd + deprecation_version: drupal:11.2.0 + removed_version: drupal:12.0.0 + change_record: https://www.drupal.org/node/3527501 + Drupal\block_content\Access\DependentAccessInterface: + class: Drupal\Core\Access\DependentAccessInterface + deprecation_version: drupal:11.2.0 + removed_version: drupal:12.0.0 + change_record: https://www.drupal.org/node/3527501 + Drupal\block_content\Access\RefinableDependentAccessInterface: + class: Drupal\Core\Access\RefinableDependentAccessInterface + deprecation_version: drupal:11.2.0 + removed_version: drupal:12.0.0 + change_record: https://www.drupal.org/node/3527501 + Drupal\block_content\Access\RefinableDependentAccessTrait: + class: Drupal\Core\Access\RefinableDependentAccessTrait + deprecation_version: drupal:11.2.0 + removed_version: drupal:12.0.0 + change_record: https://www.drupal.org/node/3527501 + services: _defaults: autoconfigure: true diff --git a/core/modules/block_content/src/Access/AccessGroupAnd.php b/core/modules/block_content/src/Access/AccessGroupAnd.php deleted file mode 100644 index be86d9e97000..000000000000 --- a/core/modules/block_content/src/Access/AccessGroupAnd.php +++ /dev/null @@ -1,49 +0,0 @@ -<?php - -namespace Drupal\block_content\Access; - -use Drupal\Core\Access\AccessibleInterface; -use Drupal\Core\Access\AccessResult; -use Drupal\Core\Session\AccountInterface; - -/** - * An access group where all the dependencies must be allowed. - * - * @internal - */ -class AccessGroupAnd implements AccessibleInterface { - - /** - * The access dependencies. - * - * @var \Drupal\Core\Access\AccessibleInterface[] - */ - protected $dependencies = []; - - /** - * {@inheritdoc} - */ - public function addDependency(AccessibleInterface $dependency) { - $this->dependencies[] = $dependency; - return $this; - } - - /** - * {@inheritdoc} - */ - public function access($operation, ?AccountInterface $account = NULL, $return_as_object = FALSE) { - $access_result = AccessResult::neutral(); - foreach (array_slice($this->dependencies, 1) as $dependency) { - $access_result = $access_result->andIf($dependency->access($operation, $account, TRUE)); - } - return $return_as_object ? $access_result : $access_result->isAllowed(); - } - - /** - * {@inheritdoc} - */ - public function getDependencies() { - return $this->dependencies; - } - -} diff --git a/core/modules/block_content/src/Access/DependentAccessInterface.php b/core/modules/block_content/src/Access/DependentAccessInterface.php deleted file mode 100644 index bc6a6dcec694..000000000000 --- a/core/modules/block_content/src/Access/DependentAccessInterface.php +++ /dev/null @@ -1,35 +0,0 @@ -<?php - -namespace Drupal\block_content\Access; - -/** - * Interface for AccessibleInterface objects that have an access dependency. - * - * Objects should implement this interface when their access depends on access - * to another object that implements \Drupal\Core\Access\AccessibleInterface. - * This interface simply provides the getter method for the access - * dependency object. Objects that implement this interface are responsible for - * checking access of the access dependency because the dependency may not take - * effect in all cases. For instance an entity may only need the access - * dependency set when it is embedded within another entity and its access - * should be dependent on access to the entity in which it is embedded. - * - * To check the access to the dependency the object implementing this interface - * can use code like this: - * @code - * $accessible->getAccessDependency()->access($op, $account, TRUE); - * @endcode - * - * @internal - */ -interface DependentAccessInterface { - - /** - * Gets the access dependency. - * - * @return \Drupal\Core\Access\AccessibleInterface|null - * The access dependency or NULL if none has been set. - */ - public function getAccessDependency(); - -} diff --git a/core/modules/block_content/src/Access/RefinableDependentAccessInterface.php b/core/modules/block_content/src/Access/RefinableDependentAccessInterface.php deleted file mode 100644 index 5d9eaf430b43..000000000000 --- a/core/modules/block_content/src/Access/RefinableDependentAccessInterface.php +++ /dev/null @@ -1,48 +0,0 @@ -<?php - -namespace Drupal\block_content\Access; - -use Drupal\Core\Access\AccessibleInterface; - -/** - * An interface to allow adding an access dependency. - * - * @internal - */ -interface RefinableDependentAccessInterface extends DependentAccessInterface { - - /** - * Sets the access dependency. - * - * If an access dependency is already set this will replace the existing - * dependency. - * - * @param \Drupal\Core\Access\AccessibleInterface $access_dependency - * The object upon which access depends. - * - * @return $this - */ - public function setAccessDependency(AccessibleInterface $access_dependency); - - /** - * Adds an access dependency into the existing access dependency. - * - * If no existing dependency is currently set this will set the dependency - * will be set to the new value. - * - * If there is an existing dependency and it is not an instance of - * AccessGroupAnd the dependency will be set as a new AccessGroupAnd - * instance with the existing and new dependencies as the members of the - * group. - * - * If there is an existing dependency and it is an instance of AccessGroupAnd - * the dependency will be added to the existing access group. - * - * @param \Drupal\Core\Access\AccessibleInterface $access_dependency - * The access dependency to merge. - * - * @return $this - */ - public function addAccessDependency(AccessibleInterface $access_dependency); - -} diff --git a/core/modules/block_content/src/Access/RefinableDependentAccessTrait.php b/core/modules/block_content/src/Access/RefinableDependentAccessTrait.php deleted file mode 100644 index 98b2a547ccfb..000000000000 --- a/core/modules/block_content/src/Access/RefinableDependentAccessTrait.php +++ /dev/null @@ -1,52 +0,0 @@ -<?php - -namespace Drupal\block_content\Access; - -use Drupal\Core\Access\AccessibleInterface; - -/** - * Trait for \Drupal\block_content\Access\RefinableDependentAccessInterface. - * - * @internal - */ -trait RefinableDependentAccessTrait { - - /** - * The access dependency. - * - * @var \Drupal\Core\Access\AccessibleInterface - */ - protected $accessDependency; - - /** - * {@inheritdoc} - */ - public function setAccessDependency(AccessibleInterface $access_dependency) { - $this->accessDependency = $access_dependency; - return $this; - } - - /** - * {@inheritdoc} - */ - public function getAccessDependency() { - return $this->accessDependency; - } - - /** - * {@inheritdoc} - */ - public function addAccessDependency(AccessibleInterface $access_dependency) { - if (empty($this->accessDependency)) { - $this->accessDependency = $access_dependency; - return $this; - } - if (!$this->accessDependency instanceof AccessGroupAnd) { - $accessGroup = new AccessGroupAnd(); - $this->accessDependency = $accessGroup->addDependency($this->accessDependency); - } - $this->accessDependency->addDependency($access_dependency); - return $this; - } - -} diff --git a/core/modules/block_content/src/BlockContentAccessControlHandler.php b/core/modules/block_content/src/BlockContentAccessControlHandler.php index 34d5dd6e5ed0..0d2765e8018a 100644 --- a/core/modules/block_content/src/BlockContentAccessControlHandler.php +++ b/core/modules/block_content/src/BlockContentAccessControlHandler.php @@ -2,10 +2,10 @@ namespace Drupal\block_content; -use Drupal\block_content\Access\DependentAccessInterface; use Drupal\block_content\Event\BlockContentGetDependencyEvent; use Drupal\Core\Access\AccessResult; use Drupal\Core\Access\AccessResultInterface; +use Drupal\Core\Access\DependentAccessInterface; use Drupal\Core\Entity\EntityAccessControlHandler; use Drupal\Core\Entity\EntityHandlerInterface; use Drupal\Core\Entity\EntityInterface; diff --git a/core/modules/block_content/src/BlockContentInterface.php b/core/modules/block_content/src/BlockContentInterface.php index f6763f451c57..e4f80d202541 100644 --- a/core/modules/block_content/src/BlockContentInterface.php +++ b/core/modules/block_content/src/BlockContentInterface.php @@ -2,7 +2,7 @@ namespace Drupal\block_content; -use Drupal\block_content\Access\RefinableDependentAccessInterface; +use Drupal\Core\Access\RefinableDependentAccessInterface; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityChangedInterface; use Drupal\Core\Entity\EntityPublishedInterface; diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php index 0d92bde49300..ed69e44f6f6a 100644 --- a/core/modules/block_content/src/Entity/BlockContent.php +++ b/core/modules/block_content/src/Entity/BlockContent.php @@ -10,13 +10,13 @@ use Drupal\block_content\BlockContentTranslationHandler; use Drupal\block_content\BlockContentViewBuilder; use Drupal\block_content\BlockContentViewsData; use Drupal\block_content\Form\BlockContentDeleteForm; +use Drupal\Core\Access\RefinableDependentAccessTrait; use Drupal\Core\Entity\Attribute\ContentEntityType; use Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider; use Drupal\Core\Entity\Form\RevisionRevertForm; use Drupal\Core\Entity\Form\RevisionDeleteForm; use Drupal\Core\Entity\Sql\SqlContentEntityStorage; use Drupal\Core\StringTranslation\TranslatableMarkup; -use Drupal\block_content\Access\RefinableDependentAccessTrait; use Drupal\Core\Entity\EditorialContentEntityBase; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityTypeInterface; diff --git a/core/modules/block_content/tests/src/Unit/Access/AccessGroupAndTest.php b/core/modules/block_content/tests/src/Unit/Access/AccessGroupAndTest.php deleted file mode 100644 index b9fd73b49fa6..000000000000 --- a/core/modules/block_content/tests/src/Unit/Access/AccessGroupAndTest.php +++ /dev/null @@ -1,57 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace Drupal\Tests\block_content\Unit\Access; - -use Drupal\block_content\Access\AccessGroupAnd; -use Drupal\Core\Access\AccessResult; -use Drupal\Core\Session\AccountInterface; -use Drupal\Tests\UnitTestCase; - -/** - * Tests accessible groups. - * - * @group block_content - */ -class AccessGroupAndTest extends UnitTestCase { - - use AccessibleTestingTrait; - - /** - * {@inheritdoc} - */ - protected function setUp(): void { - parent::setUp(); - $this->account = $this->prophesize(AccountInterface::class)->reveal(); - } - - /** - * @covers \Drupal\block_content\Access\AccessGroupAnd - */ - public function testGroups(): void { - $allowedAccessible = $this->createAccessibleDouble(AccessResult::allowed()); - $forbiddenAccessible = $this->createAccessibleDouble(AccessResult::forbidden()); - $neutralAccessible = $this->createAccessibleDouble(AccessResult::neutral()); - - // Ensure that groups with no dependencies return a neutral access result. - $this->assertTrue((new AccessGroupAnd())->access('view', $this->account, TRUE)->isNeutral()); - - $andNeutral = new AccessGroupAnd(); - $andNeutral->addDependency($allowedAccessible)->addDependency($neutralAccessible); - $this->assertTrue($andNeutral->access('view', $this->account, TRUE)->isNeutral()); - - $andForbidden = $andNeutral; - $andForbidden->addDependency($forbiddenAccessible); - $this->assertTrue($andForbidden->access('view', $this->account, TRUE)->isForbidden()); - - // Ensure that groups added to other groups works. - $andGroupsForbidden = new AccessGroupAnd(); - $andGroupsForbidden->addDependency($andNeutral)->addDependency($andForbidden); - $this->assertTrue($andGroupsForbidden->access('view', $this->account, TRUE)->isForbidden()); - // Ensure you can add a non-group accessible object. - $andGroupsForbidden->addDependency($allowedAccessible); - $this->assertTrue($andGroupsForbidden->access('view', $this->account, TRUE)->isForbidden()); - } - -} diff --git a/core/modules/block_content/tests/src/Unit/Access/AccessibleTestingTrait.php b/core/modules/block_content/tests/src/Unit/Access/AccessibleTestingTrait.php deleted file mode 100644 index a407e2388754..000000000000 --- a/core/modules/block_content/tests/src/Unit/Access/AccessibleTestingTrait.php +++ /dev/null @@ -1,38 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace Drupal\Tests\block_content\Unit\Access; - -use Drupal\Core\Access\AccessibleInterface; -use Drupal\Core\Access\AccessResultInterface; - -/** - * Helper methods testing accessible interfaces. - */ -trait AccessibleTestingTrait { - - /** - * The test account. - * - * @var \Drupal\Core\Session\AccountInterface - */ - protected $account; - - /** - * Creates AccessibleInterface object from access result object for testing. - * - * @param \Drupal\Core\Access\AccessResultInterface $accessResult - * The accessible result to return. - * - * @return \Drupal\Core\Access\AccessibleInterface - * The AccessibleInterface object. - */ - private function createAccessibleDouble(AccessResultInterface $accessResult) { - $accessible = $this->prophesize(AccessibleInterface::class); - $accessible->access('view', $this->account, TRUE) - ->willReturn($accessResult); - return $accessible->reveal(); - } - -} diff --git a/core/modules/block_content/tests/src/Unit/Access/DependentAccessTest.php b/core/modules/block_content/tests/src/Unit/Access/DependentAccessTest.php deleted file mode 100644 index 55c9a89a10ca..000000000000 --- a/core/modules/block_content/tests/src/Unit/Access/DependentAccessTest.php +++ /dev/null @@ -1,161 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace Drupal\Tests\block_content\Unit\Access; - -use Drupal\block_content\Access\AccessGroupAnd; -use Drupal\Core\Access\AccessResult; -use Drupal\block_content\Access\RefinableDependentAccessInterface; -use Drupal\block_content\Access\RefinableDependentAccessTrait; -use Drupal\Core\Session\AccountInterface; -use Drupal\Tests\UnitTestCase; - -/** - * @coversDefaultClass \Drupal\block_content\Access\RefinableDependentAccessTrait - * - * @group block_content - */ -class DependentAccessTest extends UnitTestCase { - use AccessibleTestingTrait; - - /** - * An accessible object that results in forbidden access result. - * - * @var \Drupal\Core\Access\AccessibleInterface - */ - protected $forbidden; - - /** - * An accessible object that results in neutral access result. - * - * @var \Drupal\Core\Access\AccessibleInterface - */ - protected $neutral; - - /** - * {@inheritdoc} - */ - protected function setUp(): void { - parent::setUp(); - $this->account = $this->prophesize(AccountInterface::class)->reveal(); - $this->forbidden = $this->createAccessibleDouble(AccessResult::forbidden('Because I said so')); - $this->neutral = $this->createAccessibleDouble(AccessResult::neutral('I have no opinion')); - } - - /** - * Tests that the previous dependency is replaced when using set. - * - * @covers ::setAccessDependency - * - * @dataProvider providerTestSetFirst - */ - public function testSetAccessDependency($use_set_first): void { - $testRefinable = new RefinableDependentAccessTraitTestClass(); - - if ($use_set_first) { - $testRefinable->setAccessDependency($this->forbidden); - } - else { - $testRefinable->addAccessDependency($this->forbidden); - } - $accessResult = $testRefinable->getAccessDependency()->access('view', $this->account, TRUE); - $this->assertTrue($accessResult->isForbidden()); - $this->assertEquals('Because I said so', $accessResult->getReason()); - - // Calling setAccessDependency() replaces the existing dependency. - $testRefinable->setAccessDependency($this->neutral); - $dependency = $testRefinable->getAccessDependency(); - $this->assertNotInstanceOf(AccessGroupAnd::class, $dependency); - $accessResult = $dependency->access('view', $this->account, TRUE); - $this->assertTrue($accessResult->isNeutral()); - $this->assertEquals('I have no opinion', $accessResult->getReason()); - } - - /** - * Tests merging a new dependency with existing non-group access dependency. - * - * @dataProvider providerTestSetFirst - */ - public function testMergeNonGroup($use_set_first): void { - $testRefinable = new RefinableDependentAccessTraitTestClass(); - if ($use_set_first) { - $testRefinable->setAccessDependency($this->forbidden); - } - else { - $testRefinable->addAccessDependency($this->forbidden); - } - - $accessResult = $testRefinable->getAccessDependency()->access('view', $this->account, TRUE); - $this->assertTrue($accessResult->isForbidden()); - $this->assertEquals('Because I said so', $accessResult->getReason()); - - $testRefinable->addAccessDependency($this->neutral); - /** @var \Drupal\block_content\Access\AccessGroupAnd $dependency */ - $dependency = $testRefinable->getAccessDependency(); - // Ensure the new dependency create a new AND group when merged. - $this->assertInstanceOf(AccessGroupAnd::class, $dependency); - $dependencies = $dependency->getDependencies(); - $accessResultForbidden = $dependencies[0]->access('view', $this->account, TRUE); - $this->assertTrue($accessResultForbidden->isForbidden()); - $this->assertEquals('Because I said so', $accessResultForbidden->getReason()); - $accessResultNeutral = $dependencies[1]->access('view', $this->account, TRUE); - $this->assertTrue($accessResultNeutral->isNeutral()); - $this->assertEquals('I have no opinion', $accessResultNeutral->getReason()); - } - - /** - * Tests merging a new dependency with an existing access group dependency. - * - * @dataProvider providerTestSetFirst - */ - public function testMergeGroup($use_set_first): void { - $andGroup = new AccessGroupAnd(); - $andGroup->addDependency($this->forbidden); - $testRefinable = new RefinableDependentAccessTraitTestClass(); - if ($use_set_first) { - $testRefinable->setAccessDependency($andGroup); - } - else { - $testRefinable->addAccessDependency($andGroup); - } - - $testRefinable->addAccessDependency($this->neutral); - /** @var \Drupal\block_content\Access\AccessGroupAnd $dependency */ - $dependency = $testRefinable->getAccessDependency(); - - // Ensure the new dependency is merged with the existing group. - $this->assertInstanceOf(AccessGroupAnd::class, $dependency); - $dependencies = $dependency->getDependencies(); - $accessResultForbidden = $dependencies[0]->access('view', $this->account, TRUE); - $this->assertTrue($accessResultForbidden->isForbidden()); - $this->assertEquals('Because I said so', $accessResultForbidden->getReason()); - $accessResultNeutral = $dependencies[1]->access('view', $this->account, TRUE); - $this->assertTrue($accessResultNeutral->isNeutral()); - $this->assertEquals('I have no opinion', $accessResultNeutral->getReason()); - } - - /** - * Data provider for all test methods. - * - * Provides test cases for calling setAccessDependency() or - * mergeAccessDependency() first. A call to either should behave the same on a - * new RefinableDependentAccessInterface object. - */ - public static function providerTestSetFirst() { - return [ - [TRUE], - [FALSE], - ]; - } - -} - -/** - * Test class that implements RefinableDependentAccessInterface. - */ -class RefinableDependentAccessTraitTestClass implements RefinableDependentAccessInterface { - - use RefinableDependentAccessTrait; - -} diff --git a/core/modules/ckeditor5/ckeditor5.ckeditor5.yml b/core/modules/ckeditor5/ckeditor5.ckeditor5.yml index 2a2c3fd16587..7624fbfd7083 100644 --- a/core/modules/ckeditor5/ckeditor5.ckeditor5.yml +++ b/core/modules/ckeditor5/ckeditor5.ckeditor5.yml @@ -771,25 +771,25 @@ media_mediaAlign: align: - name: 'right' title: 'Align right and wrap text' - icon: 'objectRight' + icon: 'IconObjectInlineRight' attributeName: 'data-align' attributeValue: 'right' modelElements: [ 'drupalMedia' ] - name: 'left' title: 'Align left and wrap text' - icon: 'objectLeft' + icon: 'IconObjectInlineLeft' attributeName: 'data-align' attributeValue: 'left' modelElements: [ 'drupalMedia' ] - name: 'center' title: 'Align center and break text' - icon: 'objectCenter' + icon: 'IconObjectCenter' attributeName: 'data-align' attributeValue: 'center' modelElements: ['drupalMedia'] - name: 'breakText' title: 'Break text' - icon: 'objectBlockLeft' + icon: 'IconObjectLeft' isDefault: true modelElements: [ 'drupalMedia' ] drupalMedia: diff --git a/core/modules/ckeditor5/css/drupalmedia.css b/core/modules/ckeditor5/css/drupalmedia.css index 07ce32c8fedc..4dd9a4e3afa0 100644 --- a/core/modules/ckeditor5/css/drupalmedia.css +++ b/core/modules/ckeditor5/css/drupalmedia.css @@ -28,7 +28,7 @@ display: table-caption; padding: 0.6em; caption-side: bottom; - word-break: break-word; + overflow-wrap: break-word; color: hsl(0, 0%, 20%); outline-offset: -1px; background-color: hsl(0, 0%, 97%); diff --git a/core/modules/ckeditor5/js/build/ckeditor5.types.jsdoc b/core/modules/ckeditor5/js/build/ckeditor5.types.jsdoc index aef00a7595e7..f6d2bdb0da8c 100644 --- a/core/modules/ckeditor5/js/build/ckeditor5.types.jsdoc +++ b/core/modules/ckeditor5/js/build/ckeditor5.types.jsdoc @@ -209,18 +209,6 @@ */ /** - * Declared in file @ckeditor/ckeditor5-bookmark/src/bookmarkui.js - * - * @typedef {module:bookmark/bookmarkui} module:bookmark/bookmarkui~BookmarkUI - */ - -/** - * Declared in file @ckeditor/ckeditor5-bookmark/src/ui/bookmarkactionsview.js - * - * @typedef {module:bookmark/ui/bookmarkactionsview} module:bookmark/ui/bookmarkactionsview~BookmarkActionsView - */ - -/** * Declared in file @ckeditor/ckeditor5-bookmark/src/ui/bookmarkformview.js * * @typedef {module:bookmark/ui/bookmarkformview} module:bookmark/ui/bookmarkformview~BookmarkFormView @@ -575,6 +563,84 @@ */ /** + * Declared in file @ckeditor/ckeditor5-emoji/src/emoji.js + * + * @typedef {module:emoji/emoji} module:emoji/emoji~Emoji + */ + +/** + * Declared in file @ckeditor/ckeditor5-emoji/src/emojicommand.js + * + * @typedef {module:emoji/emojicommand} module:emoji/emojicommand~EmojiCommand + */ + +/** + * Declared in file @ckeditor/ckeditor5-emoji/src/emojimention.js + * + * @typedef {module:emoji/emojimention} module:emoji/emojimention~EmojiMention + */ + +/** + * Declared in file @ckeditor/ckeditor5-emoji/src/emojipicker.js + * + * @typedef {module:emoji/emojipicker} module:emoji/emojipicker~EmojiPicker + */ + +/** + * Declared in file @ckeditor/ckeditor5-emoji/src/emojirepository.js + * + * @typedef {module:emoji/emojirepository} module:emoji/emojirepository~EmojiRepository + */ + +/** + * Declared in file @ckeditor/ckeditor5-emoji/src/emojiutils.js + * + * @typedef {module:emoji/emojiutils} module:emoji/emojiutils~EmojiUtils + */ + +/** + * Declared in file @ckeditor/ckeditor5-emoji/src/ui/emojicategoriesview.js + * + * @typedef {module:emoji/ui/emojicategoriesview} module:emoji/ui/emojicategoriesview~EmojiCategoriesView + */ + +/** + * Declared in file @ckeditor/ckeditor5-emoji/src/ui/emojigridview.js + * + * @typedef {module:emoji/ui/emojigridview} module:emoji/ui/emojigridview~EmojiGridView + */ + +/** + * Declared in file @ckeditor/ckeditor5-emoji/src/ui/emojipickerformview.js + * + * @typedef {module:emoji/ui/emojipickerformview} module:emoji/ui/emojipickerformview~EmojiPickerFormView + */ + +/** + * Declared in file @ckeditor/ckeditor5-emoji/src/ui/emojipickerview.js + * + * @typedef {module:emoji/ui/emojipickerview} module:emoji/ui/emojipickerview~EmojiPickerView + */ + +/** + * Declared in file @ckeditor/ckeditor5-emoji/src/ui/emojisearchview.js + * + * @typedef {module:emoji/ui/emojisearchview} module:emoji/ui/emojisearchview~EmojiSearchView + */ + +/** + * Declared in file @ckeditor/ckeditor5-emoji/src/ui/emojitoneview.js + * + * @typedef {module:emoji/ui/emojitoneview} module:emoji/ui/emojitoneview~EmojiToneView + */ + +/** + * Declared in file @ckeditor/ckeditor5-emoji/src/utils/isemojisupported.js + * + * @typedef {module:emoji/utils/isemojisupported} module:emoji/utils/isemojisupported~isEmojiSupported + */ + +/** * Declared in file @ckeditor/ckeditor5-engine/src/controller/datacontroller.js * * @typedef {module:engine/controller/datacontroller} module:engine/controller/datacontroller~DataController @@ -851,12 +917,6 @@ */ /** - * Declared in file @ckeditor/ckeditor5-engine/src/model/treewalker.js - * - * @typedef {module:engine/model/treewalker} module:engine/model/treewalker~TreeWalker - */ - -/** * Declared in file @ckeditor/ckeditor5-engine/src/model/utils/deletecontent.js * * @typedef {module:engine/model/utils/deletecontent} module:engine/model/utils/deletecontent~deleteContent @@ -1043,6 +1103,12 @@ */ /** + * Declared in file @ckeditor/ckeditor5-engine/src/view/observer/touchobserver.js + * + * @typedef {module:engine/view/observer/touchobserver} module:engine/view/observer/touchobserver~TouchObserver + */ + +/** * Declared in file @ckeditor/ckeditor5-engine/src/view/position.js * * @typedef {module:engine/view/position} module:engine/view/position~Position @@ -1097,9 +1163,9 @@ */ /** - * Declared in file @ckeditor/ckeditor5-engine/src/view/treewalker.js + * Declared in file @ckeditor/ckeditor5-engine/src/view/tokenlist.js * - * @typedef {module:engine/view/treewalker} module:engine/view/treewalker~TreeWalker + * @typedef {module:engine/view/tokenlist} module:engine/view/tokenlist~TokenList */ /** @@ -1301,6 +1367,42 @@ */ /** + * Declared in file @ckeditor/ckeditor5-fullscreen/src/fullscreen.js + * + * @typedef {module:fullscreen/fullscreen} module:fullscreen/fullscreen~Fullscreen + */ + +/** + * Declared in file @ckeditor/ckeditor5-fullscreen/src/fullscreencommand.js + * + * @typedef {module:fullscreen/fullscreencommand} module:fullscreen/fullscreencommand~FullscreenCommand + */ + +/** + * Declared in file @ckeditor/ckeditor5-fullscreen/src/fullscreenediting.js + * + * @typedef {module:fullscreen/fullscreenediting} module:fullscreen/fullscreenediting~FullscreenEditing + */ + +/** + * Declared in file @ckeditor/ckeditor5-fullscreen/src/fullscreenui.js + * + * @typedef {module:fullscreen/fullscreenui} module:fullscreen/fullscreenui~FullscreenUI + */ + +/** + * Declared in file @ckeditor/ckeditor5-fullscreen/src/handlers/abstracteditorhandler.js + * + * @typedef {module:fullscreen/handlers/abstracteditorhandler} module:fullscreen/handlers/abstracteditorhandler~AbstractEditorHandler + */ + +/** + * Declared in file @ckeditor/ckeditor5-fullscreen/src/handlers/classiceditorhandler.js + * + * @typedef {module:fullscreen/handlers/classiceditorhandler} module:fullscreen/handlers/classiceditorhandler~ClassicEditorHandler + */ + +/** * Declared in file @ckeditor/ckeditor5-heading/src/heading.js * * @typedef {module:heading/heading} module:heading/heading~Heading @@ -1439,6 +1541,12 @@ */ /** + * Declared in file @ckeditor/ckeditor5-html-support/src/integrations/horizontalline.js + * + * @typedef {module:html-support/integrations/horizontalline} module:html-support/integrations/horizontalline~HorizontalLineElementSupport + */ + +/** * Declared in file @ckeditor/ckeditor5-html-support/src/integrations/image.js * * @typedef {module:html-support/integrations/image} module:html-support/integrations/image~ImageElementSupport @@ -1805,9 +1913,9 @@ */ /** - * Declared in file @ckeditor/ckeditor5-link/src/ui/linkactionsview.js + * Declared in file @ckeditor/ckeditor5-link/src/ui/linkbuttonview.js * - * @typedef {module:link/ui/linkactionsview} module:link/ui/linkactionsview~LinkActionsView + * @typedef {module:link/ui/linkbuttonview} module:link/ui/linkbuttonview~LinkButtonView */ /** @@ -1817,6 +1925,24 @@ */ /** + * Declared in file @ckeditor/ckeditor5-link/src/ui/linkpreviewbuttonview.js + * + * @typedef {module:link/ui/linkpreviewbuttonview} module:link/ui/linkpreviewbuttonview~LinkPreviewButtonView + */ + +/** + * Declared in file @ckeditor/ckeditor5-link/src/ui/linkpropertiesview.js + * + * @typedef {module:link/ui/linkpropertiesview} module:link/ui/linkpropertiesview~LinkPropertiesView + */ + +/** + * Declared in file @ckeditor/ckeditor5-link/src/ui/linkprovideritemsview.js + * + * @typedef {module:link/ui/linkprovideritemsview} module:link/ui/linkprovideritemsview~LinkProviderItemsView + */ + +/** * Declared in file @ckeditor/ckeditor5-link/src/unlinkcommand.js * * @typedef {module:link/unlinkcommand} module:link/unlinkcommand~UnlinkCommand @@ -2069,6 +2195,12 @@ */ /** + * Declared in file @ckeditor/ckeditor5-media-embed/src/mediaregistry.js + * + * @typedef {module:media-embed/mediaregistry} module:media-embed/mediaregistry~MediaRegistry + */ + +/** * Declared in file @ckeditor/ckeditor5-media-embed/src/ui/mediaformview.js * * @typedef {module:media-embed/ui/mediaformview} module:media-embed/ui/mediaformview~MediaFormView @@ -2477,6 +2609,12 @@ */ /** + * Declared in file @ckeditor/ckeditor5-table/src/commands/inserttablelayoutcommand.js + * + * @typedef {module:table/commands/inserttablelayoutcommand} module:table/commands/inserttablelayoutcommand~InsertTableLayoutCommand + */ + +/** * Declared in file @ckeditor/ckeditor5-table/src/commands/removecolumncommand.js * * @typedef {module:table/commands/removecolumncommand} module:table/commands/removecolumncommand~RemoveColumnCommand @@ -2615,6 +2753,30 @@ */ /** + * Declared in file @ckeditor/ckeditor5-table/src/tablelayout.js + * + * @typedef {module:table/tablelayout} module:table/tablelayout~TableLayout + */ + +/** + * Declared in file @ckeditor/ckeditor5-table/src/tablelayout/commands/tabletypecommand.js + * + * @typedef {module:table/tablelayout/commands/tabletypecommand} module:table/tablelayout/commands/tabletypecommand~TableTypeCommand + */ + +/** + * Declared in file @ckeditor/ckeditor5-table/src/tablelayout/tablelayoutediting.js + * + * @typedef {module:table/tablelayout/tablelayoutediting} module:table/tablelayout/tablelayoutediting~TableLayoutEditing + */ + +/** + * Declared in file @ckeditor/ckeditor5-table/src/tablelayout/tablelayoutui.js + * + * @typedef {module:table/tablelayout/tablelayoutui} module:table/tablelayout/tablelayoutui~TableLayoutUI + */ + +/** * Declared in file @ckeditor/ckeditor5-table/src/tablemouse.js * * @typedef {module:table/tablemouse} module:table/tablemouse~TableMouse @@ -2693,12 +2855,6 @@ */ /** - * Declared in file @ckeditor/ckeditor5-table/src/ui/formrowview.js - * - * @typedef {module:table/ui/formrowview} module:table/ui/formrowview~FormRowView - */ - -/** * Declared in file @ckeditor/ckeditor5-table/src/ui/inserttableview.js * * @typedef {module:table/ui/inserttableview} module:table/ui/inserttableview~InsertTableView @@ -2801,6 +2957,12 @@ */ /** + * Declared in file @ckeditor/ckeditor5-ui/src/collapsible/collapsibleview.js + * + * @typedef {module:ui/collapsible/collapsibleview} module:ui/collapsible/collapsibleview~CollapsibleView + */ + +/** * Declared in file @ckeditor/ckeditor5-ui/src/colorgrid/colorgridview.js * * @typedef {module:ui/colorgrid/colorgridview} module:ui/colorgrid/colorgridview~ColorGridView @@ -2951,6 +3113,12 @@ */ /** + * Declared in file @ckeditor/ckeditor5-ui/src/editorui/poweredby.js + * + * @typedef {module:ui/editorui/poweredby} module:ui/editorui/poweredby~PoweredBy + */ + +/** * Declared in file @ckeditor/ckeditor5-ui/src/focuscycler.js * * @typedef {module:ui/focuscycler} module:ui/focuscycler~FocusCycler @@ -2963,6 +3131,12 @@ */ /** + * Declared in file @ckeditor/ckeditor5-ui/src/formrow/formrowview.js + * + * @typedef {module:ui/formrow/formrowview} module:ui/formrow/formrowview~FormRowView + */ + +/** * Declared in file @ckeditor/ckeditor5-ui/src/highlightedtext/highlightedtextview.js * * @typedef {module:ui/highlightedtext/highlightedtextview} module:ui/highlightedtext/highlightedtextview~HighlightedTextView @@ -3275,6 +3449,12 @@ */ /** + * Declared in file @ckeditor/ckeditor5-utils/src/collectstylesheets.js + * + * @typedef {module:utils/collectstylesheets} module:utils/collectstylesheets~async + */ + +/** * Declared in file @ckeditor/ckeditor5-utils/src/comparearrays.js * * @typedef {module:utils/comparearrays} module:utils/comparearrays~compareArrays @@ -3371,6 +3551,12 @@ */ /** + * Declared in file @ckeditor/ckeditor5-utils/src/dom/getvisualviewportoffset.js + * + * @typedef {module:utils/dom/getvisualviewportoffset} module:utils/dom/getvisualviewportoffset~getVisualViewportOffset + */ + +/** * Declared in file @ckeditor/ckeditor5-utils/src/dom/indexof.js * * @typedef {module:utils/dom/indexof} module:utils/dom/indexof~indexOf @@ -3497,6 +3683,12 @@ */ /** + * Declared in file @ckeditor/ckeditor5-utils/src/formathtml.js + * + * @typedef {module:utils/formathtml} module:utils/formathtml~formatHtml + */ + +/** * Declared in file @ckeditor/ckeditor5-utils/src/isiterable.js * * @typedef {module:utils/isiterable} module:utils/isiterable~isIterable @@ -3593,6 +3785,18 @@ */ /** + * Declared in file @ckeditor/ckeditor5-watchdog/src/contextwatchdog.js + * + * @typedef {module:watchdog/contextwatchdog} module:watchdog/contextwatchdog~ContextWatchdog + */ + +/** + * Declared in file @ckeditor/ckeditor5-watchdog/src/editorwatchdog.js + * + * @typedef {module:watchdog/editorwatchdog} module:watchdog/editorwatchdog~EditorWatchdog + */ + +/** * Declared in file @ckeditor/ckeditor5-watchdog/src/utils/areconnectedthroughproperties.js * * @typedef {module:watchdog/utils/areconnectedthroughproperties} module:watchdog/utils/areconnectedthroughproperties~areConnectedThroughProperties diff --git a/core/modules/ckeditor5/js/build/drupalImage.js b/core/modules/ckeditor5/js/build/drupalImage.js index 9356c590f56b..6ad80b095eab 100644 --- a/core/modules/ckeditor5/js/build/drupalImage.js +++ b/core/modules/ckeditor5/js/build/drupalImage.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.drupalImage=t())}(globalThis,(()=>(()=>{var e={"ckeditor5/src/core.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/core.js")},"ckeditor5/src/engine.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/engine.js")},"ckeditor5/src/ui.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/ui.js")},"ckeditor5/src/upload.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/upload.js")},"ckeditor5/src/utils.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/utils.js")},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},t={};function i(r){var s=t[r];if(void 0!==s)return s.exports;var n=t[r]={exports:{}};return e[r](n,n.exports,i),n.exports}i.d=(e,t)=>{for(var r in t)i.o(t,r)&&!i.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var r={};return(()=>{"use strict";i.d(r,{default:()=>B});var e=i("ckeditor5/src/core.js");function t(e,t,i){if(t.attributes)for(const[r,s]of Object.entries(t.attributes))e.setAttribute(r,s,i);t.styles&&e.setStyle(t.styles,i),t.classes&&e.addClass(t.classes,i)}var s=i("ckeditor5/src/engine.js");class n extends s.Observer{observe(e){this.listenTo(e,"load",((e,t)=>{const i=t.target;this.checkShouldIgnoreEventFromTarget(i)||"IMG"==i.tagName&&this._fireEvents(t)}),{useCapture:!0})}stopObserving(e){this.stopListening(e)}_fireEvents(e){this.isEnabled&&(this.document.fire("layoutChanged"),this.document.fire("imageLoaded",e))}}function o(e){return e.createEmptyElement("img")}function a(e){const t=parseFloat(e);return!Number.isNaN(t)&&e===String(t)}function l(e){return"string"==typeof e&&e.endsWith("%")?e:`${parseInt(e,10)}`}const u=[{modelValue:"alignCenter",dataValue:"center"},{modelValue:"alignRight",dataValue:"right"},{modelValue:"alignLeft",dataValue:"left"}];class d extends e.Plugin{static get requires(){return["ImageUtils"]}static get pluginName(){return"DrupalImageEditing"}init(){const{editor:e}=this,{conversion:i}=e,{schema:r}=e.model;if(r.isRegistered("imageInline")&&r.extend("imageInline",{allowAttributes:["dataEntityUuid","dataEntityType","isDecorative"]}),r.isRegistered("imageBlock")&&r.extend("imageBlock",{allowAttributes:["dataEntityUuid","dataEntityType","isDecorative"]}),i.for("upcast").add(function(e){function t(t,i,r){const{viewItem:s}=i,{writer:n,consumable:o,safeInsert:a,updateConversionResult:l,schema:d}=r,c=[];let m;if(!o.test(s,{name:!0,attributes:"src"}))return;const g=o.test(s,{name:!0,attributes:"data-caption"});if(m=d.checkChild(i.modelCursor,"imageInline")&&!g?n.createElement("imageInline",{src:s.getAttribute("src")}):n.createElement("imageBlock",{src:s.getAttribute("src")}),e.plugins.has("ImageStyleEditing")&&o.test(s,{name:!0,attributes:"data-align"})){const e=s.getAttribute("data-align"),t=u.find((t=>t.dataValue===e));t&&(n.setAttribute("imageStyle",t.modelValue,m),c.push("data-align"))}if(g){const t=n.createElement("caption"),i=e.data.processor.toView(s.getAttribute("data-caption"));r.consumable.constructor.createFrom(i,r.consumable),r.convertChildren(i,t),n.append(t,m),c.push("data-caption")}o.test(s,{name:!0,attributes:"data-entity-uuid"})&&(n.setAttribute("dataEntityUuid",s.getAttribute("data-entity-uuid"),m),c.push("data-entity-uuid")),o.test(s,{name:!0,attributes:"data-entity-type"})&&(n.setAttribute("dataEntityType",s.getAttribute("data-entity-type"),m),c.push("data-entity-type")),a(m,i.modelCursor)&&(o.consume(s,{name:!0,attributes:c}),l(m,i))}return e=>{e.on("element:img",t,{priority:"high"})}}(e)).attributeToAttribute({view:{name:"img",key:"width"},model:{key:"resizedWidth",value:e=>a(e.getAttribute("width"))?`${parseInt(e.getAttribute("width"),10)}px`:e.getAttribute("width").trim()}}).attributeToAttribute({view:{name:"img",key:"height"},model:{key:"resizedHeight",value:e=>a(e.getAttribute("height"))?`${parseInt(e.getAttribute("height"),10)}px`:e.getAttribute("height").trim()}}),e.plugins.has("DataFilter")){const t=e.plugins.get("DataFilter");i.for("upcast").add(function(e){function t(t,i,r){if(!i.modelRange)return;const s=i.viewItem.parent;if(!s.is("element","a"))return;if(!i.modelRange.getContainedElement().is("element","imageBlock"))return;const n=e.processViewAttributes(s,r);n&&r.writer.setAttribute("htmlLinkAttributes",n,i.modelRange)}return e=>{e.on("element:img",t,{priority:"high"})}}(t))}i.for("downcast").add(function(){function e(e,t,i){const{item:r}=t,{consumable:s,writer:n}=i;if(!s.consume(r,e.name))return;const o=i.mapper.toViewElement(r),a=Array.from(o.getChildren()).find((e=>"img"===e.name));n.setAttribute("data-entity-uuid",t.attributeNewValue,a||o)}return t=>{t.on("attribute:dataEntityUuid",e)}}()).add(function(){function e(e,t,i){const{item:r}=t,{consumable:s,writer:n}=i;if(!s.consume(r,e.name))return;const o=i.mapper.toViewElement(r),a=Array.from(o.getChildren()).find((e=>"img"===e.name));n.setAttribute("data-entity-type",t.attributeNewValue,a||o)}return t=>{t.on("attribute:dataEntityType",e)}}()),i.for("dataDowncast").add(function(e){return t=>{t.on("insert:caption",((t,i,r)=>{const{consumable:s,writer:n,mapper:o}=r;if(!e.plugins.get("ImageUtils").isImage(i.item.parent)||!s.consume(i.item,"insert"))return;const a=e.model.createRangeIn(i.item),l=n.createDocumentFragment();o.bindElements(i.item,l);for(const{item:t}of Array.from(a)){const i={item:t,range:e.model.createRangeOn(t)},s=`insert:${t.name||"$text"}`;e.data.downcastDispatcher.fire(s,i,r);for(const s of t.getAttributeKeys())Object.assign(i,{attributeKey:s,attributeOldValue:null,attributeNewValue:i.item.getAttribute(s)}),e.data.downcastDispatcher.fire(`attribute:${s}`,i,r)}for(const e of n.createRangeIn(l).getItems())o.unbindViewElement(e);o.unbindViewElement(l);const u=e.data.processor.toData(l);if(u){const e=o.toViewElement(i.item.parent);n.setAttribute("data-caption",u,e)}}),{priority:"high"})}}(e)).elementToElement({model:"imageBlock",view:(e,{writer:t})=>o(t),converterPriority:"high"}).elementToElement({model:"imageInline",view:(e,{writer:t})=>o(t),converterPriority:"high"}).add(function(){function e(e,t,i){const{item:r}=t,{consumable:s,writer:n}=i,o=u.find((e=>e.modelValue===t.attributeNewValue));if(!o||!s.consume(r,e.name))return;const a=i.mapper.toViewElement(r),l=Array.from(a.getChildren()).find((e=>"img"===e.name));n.setAttribute("data-align",o.dataValue,l||a)}return t=>{t.on("attribute:imageStyle",e,{priority:"high"})}}()).add(function(){function e(e,i,r){if(!r.consumable.consume(i.item,e.name))return;const s=r.mapper.toViewElement(i.item),n=r.writer,o=n.createContainerElement("a",{href:i.attributeNewValue});n.insert(n.createPositionBefore(s),o),n.move(n.createRangeOn(s),n.createPositionAt(o,0)),r.consumable.consume(i.item,"attribute:htmlLinkAttributes:imageBlock")&&t(r.writer,i.item.getAttribute("htmlLinkAttributes"),o)}return t=>{t.on("attribute:linkHref:imageBlock",e,{priority:"high"})}}()).attributeToAttribute({model:{name:"imageBlock",key:"resizedWidth"},view:e=>({key:"width",value:l(e)}),converterPriority:"high"}).attributeToAttribute({model:{name:"imageInline",key:"resizedWidth"},view:e=>({key:"width",value:l(e)}),converterPriority:"high"}).attributeToAttribute({model:{name:"imageBlock",key:"resizedHeight"},view:e=>({key:"height",value:l(e)}),converterPriority:"high"}).attributeToAttribute({model:{name:"imageInline",key:"resizedHeight"},view:e=>({key:"height",value:l(e)}),converterPriority:"high"}).attributeToAttribute({model:{name:"imageBlock",key:"width"},view:(e,{consumable:t},i)=>i.item.hasAttribute("resizedWidth")?(t.consume(i.item,"attribute:width"),null):{key:"width",value:e},converterPriority:"high"}).attributeToAttribute({model:{name:"imageInline",key:"width"},view:(e,{consumable:t},i)=>i.item.hasAttribute("resizedWidth")?(t.consume(i.item,"attribute:width"),null):{key:"width",value:e},converterPriority:"high"}).attributeToAttribute({model:{name:"imageBlock",key:"height"},view:(e,t,i)=>{if(i.item.hasAttribute("resizedWidth")){if(i.item.getAttribute("resizedWidth").endsWith("%"))return{key:"height",value:i.item.getAttribute("resizedWidth")};const t=parseInt(i.item.getAttribute("resizedWidth"),10),r=parseInt(i.item.getAttribute("width"),10)/parseInt(e,10);return{key:"height",value:`${Math.round(t/r)}`}}return{key:"height",value:e}},converterPriority:"high"}).attributeToAttribute({model:{name:"imageInline",key:"height"},view:(e,t,i)=>{if(i.item.hasAttribute("resizedWidth")){if(i.item.getAttribute("resizedWidth").endsWith("%"))return{key:"height",value:i.item.getAttribute("resizedWidth")};const t=parseInt(i.item.getAttribute("resizedWidth"),10),r=parseInt(i.item.getAttribute("width"),10)/parseInt(e,10);return{key:"height",value:`${Math.round(t/r)}`}}return{key:"height",value:e}},converterPriority:"high"}),e.editing.view.addObserver(n);const s=e.plugins.get("ImageUtils");e.editing.view.document.on("imageLoaded",((t,i)=>{const r=e.editing.view.domConverter.mapDomToView(i.target);if(!r)return;const n=s.getImageWidgetFromImageView(r);if(!n)return;const o=e.editing.mapper.toModelElement(n);o&&e.model.enqueueChange({isUndoable:!1},(()=>{s.setImageNaturalSizeAttributes(o)}))}))}}class c extends e.Command{refresh(){const e=this.editor.plugins.get("ImageUtils").getClosestSelectedImageElement(this.editor.model.document.selection);this.isEnabled=!!e,this.isEnabled&&e.hasAttribute("alt")?this.value=e.getAttribute("alt"):this.value=!1}execute(e){const t=this.editor,i=t.plugins.get("ImageUtils"),r=t.model,s=i.getClosestSelectedImageElement(r.document.selection);r.change((t=>{t.setAttribute("alt",e.newValue,s)}))}}class m extends e.Plugin{static get requires(){return["ImageUtils"]}static get pluginName(){return"DrupalImageAlternativeTextEditing"}constructor(e){super(e),this._missingAltTextViewReferences=new Set}init(){const e=this.editor;e.conversion.for("editingDowncast").add(this._imageEditingDowncastConverter("attribute:alt",e)).add(this._imageEditingDowncastConverter("attribute:src",e)),e.commands.add("imageTextAlternative",new c(this.editor)),e.editing.view.on("render",(()=>{for(const e of this._missingAltTextViewReferences)e.button.element.isConnected||(e.destroy(),this._missingAltTextViewReferences.delete(e))}))}_imageEditingDowncastConverter(e){const t=(e,t,i)=>{const r=this.editor;if(!r.plugins.get("ImageUtils").isImage(t.item))return;const s=i.mapper.toViewElement(t.item),n=Array.from(s.getChildren()).find((e=>e.getCustomProperty("drupalImageMissingAltWarning")));if(t.item.hasAttribute("alt"))return void(n&&i.writer.remove(n));if(n)return;const o=r.ui.componentFactory.create("drupalImageAlternativeTextMissing");o.listenTo(r.ui,"update",(()=>{const e=r.model.document.selection.getFirstRange(),i=r.model.createRangeOn(t.item);o.set({isSelected:e.containsRange(i)||e.isIntersecting(i)})})),o.render(),this._missingAltTextViewReferences.add(o);const a=i.writer.createUIElement("span",{class:"image-alternative-text-missing-wrapper"},(function(e){const t=this.toDomElement(e);return t.appendChild(o.element),t}));i.writer.setCustomProperty("drupalImageMissingAltWarning",!0,a),i.writer.insert(i.writer.createPositionAt(s,"end"),a)};return i=>{i.on(e,t,{priority:"low"})}}}var g=i("ckeditor5/src/ui.js");function h(e){const t=e.plugins.get("ContextualBalloon");if(e.plugins.get("ImageUtils").getClosestSelectedImageWidget(e.editing.view.document.selection)){const i=p(e);t.updatePosition(i)}}function p(e){const t=e.editing.view,i=g.BalloonPanelView.defaultPositions,r=e.plugins.get("ImageUtils");return{target:t.domConverter.mapViewToDom(r.getClosestSelectedImageWidget(t.document.selection)),positions:[i.northArrowSouth,i.northArrowSouthWest,i.northArrowSouthEast,i.southArrowNorth,i.southArrowNorthWest,i.southArrowNorthEast,i.viewportStickyNorth]}}var b=i("ckeditor5/src/utils.js");class f extends g.View{constructor(t){super(t),this.focusTracker=new b.FocusTracker,this.keystrokes=new b.KeystrokeHandler,this.decorativeToggle=this._decorativeToggleView(),this.labeledInput=this._createLabeledInputView(),this.saveButtonView=this._createButton(Drupal.t("Save"),e.icons.check,"ck-button-save"),this.saveButtonView.type="submit",this.saveButtonView.bind("isEnabled").to(this.decorativeToggle,"isOn",this.labeledInput,"isEmpty",((e,t)=>e||!t)),this.cancelButtonView=this._createButton(Drupal.t("Cancel"),e.icons.cancel,"ck-button-cancel","cancel"),this._focusables=new g.ViewCollection,this._focusCycler=new g.FocusCycler({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"form",attributes:{class:["ck","ck-text-alternative-form","ck-text-alternative-form--with-decorative-toggle","ck-responsive-form"],tabindex:"-1"},children:[{tag:"div",attributes:{class:["ck","ck-text-alternative-form__decorative-toggle"]},children:[this.decorativeToggle]},this.labeledInput,this.saveButtonView,this.cancelButtonView]}),(0,g.injectCssTransitionDisabler)(this)}render(){super.render(),this.keystrokes.listenTo(this.element),(0,g.submitHandler)({view:this}),[this.decorativeToggle,this.labeledInput,this.saveButtonView,this.cancelButtonView].forEach((e=>{this._focusables.add(e),this.focusTracker.add(e.element)}))}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}_createButton(e,t,i,r){const s=new g.ButtonView(this.locale);return s.set({label:e,icon:t,tooltip:!0}),s.extendTemplate({attributes:{class:i}}),r&&s.delegate("execute").to(this,r),s}_createLabeledInputView(){const e=new g.LabeledFieldView(this.locale,g.createLabeledInputText);return e.bind("class").to(this.decorativeToggle,"isOn",(e=>e?"ck-hidden":"")),e.label=Drupal.t("Alternative text"),e}_decorativeToggleView(){const e=new g.SwitchButtonView(this.locale);return e.set({withText:!0,label:Drupal.t("Decorative image")}),e.on("execute",(()=>{e.set("isOn",!e.isOn)})),e}}class w extends g.View{constructor(e){super(e);const t=this.bindTemplate;this.set("isVisible"),this.set("isSelected");const i=Drupal.t("Add missing alternative text");this.button=new g.ButtonView(e),this.button.set({label:i,tooltip:!1,withText:!0}),this.setTemplate({tag:"span",attributes:{class:["image-alternative-text-missing",t.to("isVisible",(e=>e?"":"ck-hidden"))],title:i},children:[this.button]})}}class v extends e.Plugin{static get requires(){return[g.ContextualBalloon]}static get pluginName(){return"DrupalImageTextAlternativeUI"}init(){this._createButton(),this._createForm(),this._createMissingAltTextComponent();const e=()=>{this.editor.plugins.get("ImageUtils").getClosestSelectedImageWidget(this.editor.editing.view.document.selection)&&this._showForm()};if(this.editor.commands.get("insertImage")){this.editor.commands.get("insertImage").on("execute",e)}if(this.editor.plugins.has("ImageUploadEditing")){this.editor.plugins.get("ImageUploadEditing").on("uploadComplete",e)}}_createMissingAltTextComponent(){this.editor.ui.componentFactory.add("drupalImageAlternativeTextMissing",(e=>{const t=new w(e);return t.listenTo(t.button,"execute",(()=>{this._isInBalloon&&this._balloon.remove(this._form),this._showForm()})),t.listenTo(this.editor.ui,"update",(()=>{t.set({isVisible:!this._isVisible||!t.isSelected})})),t}))}destroy(){super.destroy(),this._form.destroy()}_createButton(){const t=this.editor;t.ui.componentFactory.add("drupalImageAlternativeText",(i=>{const r=t.commands.get("imageTextAlternative"),s=new g.ButtonView(i);return s.set({label:Drupal.t("Change image alternative text"),icon:e.icons.lowVision,tooltip:!0}),s.bind("isEnabled").to(r,"isEnabled"),this.listenTo(s,"execute",(()=>{this._showForm()})),s}))}_createForm(){const e=this.editor,t=e.editing.view.document,i=e.plugins.get("ImageUtils");this._balloon=this.editor.plugins.get("ContextualBalloon"),this._form=new f(e.locale),this._form.render(),this.listenTo(this._form,"submit",(()=>{e.execute("imageTextAlternative",{newValue:this._form.decorativeToggle.isOn?"":this._form.labeledInput.fieldView.element.value}),this._hideForm(!0)})),this.listenTo(this._form,"cancel",(()=>{this._hideForm(!0)})),this.listenTo(this._form.decorativeToggle,"execute",(()=>{h(e)})),this._form.keystrokes.set("Esc",((e,t)=>{this._hideForm(!0),t()})),this.listenTo(e.ui,"update",(()=>{i.getClosestSelectedImageWidget(t.selection)?this._isVisible&&h(e):this._hideForm(!0)})),(0,g.clickOutsideHandler)({emitter:this._form,activator:()=>this._isVisible,contextElements:[this._balloon.view.element],callback:()=>this._hideForm()})}_showForm(){if(this._isVisible)return;const e=this.editor,t=e.commands.get("imageTextAlternative"),i=this._form.decorativeToggle,r=this._form.labeledInput;this._form.disableCssTransitions(),this._isInBalloon||this._balloon.add({view:this._form,position:p(e)}),i.isOn=""===t.value,r.fieldView.element.value=t.value||"",r.fieldView.value=r.fieldView.element.value,i.isOn?i.focus():r.fieldView.select(),this._form.enableCssTransitions()}_hideForm(e){this._isInBalloon&&(this._form.focusTracker.isFocused&&this._form.saveButtonView.focus(),this._balloon.remove(this._form),e&&this.editor.editing.view.focus())}get _isVisible(){return this._balloon.visibleView===this._form}get _isInBalloon(){return this._balloon.hasView(this._form)}}class y extends e.Plugin{static get requires(){return[m,v]}static get pluginName(){return"DrupalImageAlternativeText"}}class A extends e.Plugin{static get requires(){return[d,y]}static get pluginName(){return"DrupalImage"}}const I=A;class k extends e.Plugin{init(){const{editor:e}=this;e.plugins.get("ImageUploadEditing").on("uploadComplete",((t,{data:i,imageElement:r})=>{e.model.change((e=>{e.setAttribute("dataEntityUuid",i.response.uuid,r),e.setAttribute("dataEntityType",i.response.entity_type,r)}))}))}static get pluginName(){return"DrupalImageUploadEditing"}}var x=i("ckeditor5/src/upload.js");class _{constructor(e,t){this.loader=e,this.options=t}upload(){return this.loader.file.then((e=>new Promise(((t,i)=>{this._initRequest(),this._initListeners(t,i,e),this._sendRequest(e)}))))}abort(){this.xhr&&this.xhr.abort()}_initRequest(){this.xhr=new XMLHttpRequest,this.xhr.open("POST",this.options.uploadUrl,!0),this.xhr.responseType="json"}_initListeners(e,t,i){const r=this.xhr,s=this.loader,n=`Couldn't upload file: ${i.name}.`;r.addEventListener("error",(()=>t(n))),r.addEventListener("abort",(()=>t())),r.addEventListener("load",(()=>{const i=r.response;if(!i||i.error)return t(i?.error?.message||n);e({response:i,urls:{default:i.url}})})),r.upload&&r.upload.addEventListener("progress",(e=>{e.lengthComputable&&(s.uploadTotal=e.total,s.uploaded=e.loaded)}))}_sendRequest(e){const t=this.options.headers||{},i=this.options.withCredentials||!1;Object.keys(t).forEach((e=>{this.xhr.setRequestHeader(e,t[e])})),this.xhr.withCredentials=i;const r=new FormData;r.append("upload",e),this.xhr.send(r)}}class T extends e.Plugin{static get requires(){return[x.FileRepository]}static get pluginName(){return"DrupalFileRepository"}init(){const e=this.editor.config.get("drupalImageUpload");e&&(e.uploadUrl?this.editor.plugins.get(x.FileRepository).createUploadAdapter=t=>new _(t,e):(0,b.logWarning)("simple-upload-adapter-missing-uploadurl"))}}class E extends e.Plugin{static get requires(){return[T,k]}static get pluginName(){return"DrupalImageUpload"}}const V=E;class C extends e.Plugin{init(){const{editor:e}=this;e.ui.componentFactory.add("drupalInsertImage",(()=>e.ui.componentFactory.create("insertImage")))}static get pluginName(){return"DrupalInsertImage"}}const B={DrupalImage:I,DrupalImageUpload:V,DrupalInsertImage:C}})(),r=r.default})()));
\ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.drupalImage=t())}(globalThis,(()=>(()=>{var e={"ckeditor5/src/core.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/core.js")},"ckeditor5/src/engine.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/engine.js")},"ckeditor5/src/ui.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/ui.js")},"ckeditor5/src/upload.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/upload.js")},"ckeditor5/src/utils.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/utils.js")},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},t={};function i(r){var s=t[r];if(void 0!==s)return s.exports;var n=t[r]={exports:{}};return e[r](n,n.exports,i),n.exports}i.d=(e,t)=>{for(var r in t)i.o(t,r)&&!i.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var r={};return(()=>{"use strict";i.d(r,{default:()=>B});var e=i("ckeditor5/src/core.js");function t(e,t,i){if(t.attributes)for(const[r,s]of Object.entries(t.attributes))e.setAttribute(r,s,i);t.styles&&e.setStyle(t.styles,i),t.classes&&e.addClass(t.classes,i)}var s=i("ckeditor5/src/engine.js");class n extends s.Observer{observe(e){this.listenTo(e,"load",((e,t)=>{const i=t.target;this.checkShouldIgnoreEventFromTarget(i)||"IMG"==i.tagName&&this._fireEvents(t)}),{useCapture:!0})}stopObserving(e){this.stopListening(e)}_fireEvents(e){this.isEnabled&&(this.document.fire("layoutChanged"),this.document.fire("imageLoaded",e))}}function a(e){return e.createEmptyElement("img")}function o(e){const t=parseFloat(e);return!Number.isNaN(t)&&e===String(t)}function l(e){return"string"==typeof e&&e.endsWith("%")?e:`${parseInt(e,10)}`}const u=[{modelValue:"alignCenter",dataValue:"center"},{modelValue:"alignRight",dataValue:"right"},{modelValue:"alignLeft",dataValue:"left"}];class d extends e.Plugin{static get requires(){return["ImageUtils"]}static get pluginName(){return"DrupalImageEditing"}init(){const{editor:e}=this,{conversion:i}=e,{schema:r}=e.model;if(r.isRegistered("imageInline")&&r.extend("imageInline",{allowAttributes:["dataEntityUuid","dataEntityType","isDecorative"]}),r.isRegistered("imageBlock")&&r.extend("imageBlock",{allowAttributes:["dataEntityUuid","dataEntityType","isDecorative"]}),i.for("upcast").add(function(e){function t(t,i,r){const{viewItem:s}=i,{writer:n,consumable:a,safeInsert:o,updateConversionResult:l,schema:d}=r,c=[];let m;if(!a.test(s,{name:!0,attributes:"src"}))return;const g=a.test(s,{name:!0,attributes:"data-caption"});if(m=d.checkChild(i.modelCursor,"imageInline")&&!g?n.createElement("imageInline",{src:s.getAttribute("src")}):n.createElement("imageBlock",{src:s.getAttribute("src")}),e.plugins.has("ImageStyleEditing")&&a.test(s,{name:!0,attributes:"data-align"})){const e=s.getAttribute("data-align"),t=u.find((t=>t.dataValue===e));t&&(n.setAttribute("imageStyle",t.modelValue,m),c.push("data-align"))}if(g){const t=n.createElement("caption"),i=e.data.processor.toView(s.getAttribute("data-caption"));r.consumable.constructor.createFrom(i,r.consumable),r.convertChildren(i,t),n.append(t,m),c.push("data-caption")}a.test(s,{name:!0,attributes:"data-entity-uuid"})&&(n.setAttribute("dataEntityUuid",s.getAttribute("data-entity-uuid"),m),c.push("data-entity-uuid")),a.test(s,{name:!0,attributes:"data-entity-type"})&&(n.setAttribute("dataEntityType",s.getAttribute("data-entity-type"),m),c.push("data-entity-type")),o(m,i.modelCursor)&&(a.consume(s,{name:!0,attributes:c}),l(m,i))}return e=>{e.on("element:img",t,{priority:"high"})}}(e)).attributeToAttribute({view:{name:"img",key:"width"},model:{key:"resizedWidth",value:e=>o(e.getAttribute("width"))?`${parseInt(e.getAttribute("width"),10)}px`:e.getAttribute("width").trim()}}).attributeToAttribute({view:{name:"img",key:"height"},model:{key:"resizedHeight",value:e=>o(e.getAttribute("height"))?`${parseInt(e.getAttribute("height"),10)}px`:e.getAttribute("height").trim()}}),e.plugins.has("DataFilter")){const t=e.plugins.get("DataFilter");i.for("upcast").add(function(e){function t(t,i,r){if(!i.modelRange)return;const s=i.viewItem.parent;if(!s.is("element","a"))return;if(!i.modelRange.getContainedElement().is("element","imageBlock"))return;const n=e.processViewAttributes(s,r);n&&r.writer.setAttribute("htmlLinkAttributes",n,i.modelRange)}return e=>{e.on("element:img",t,{priority:"high"})}}(t))}i.for("downcast").add(function(){function e(e,t,i){const{item:r}=t,{consumable:s,writer:n}=i;if(!s.consume(r,e.name))return;const a=i.mapper.toViewElement(r),o=Array.from(a.getChildren()).find((e=>"img"===e.name));n.setAttribute("data-entity-uuid",t.attributeNewValue,o||a)}return t=>{t.on("attribute:dataEntityUuid",e)}}()).add(function(){function e(e,t,i){const{item:r}=t,{consumable:s,writer:n}=i;if(!s.consume(r,e.name))return;const a=i.mapper.toViewElement(r),o=Array.from(a.getChildren()).find((e=>"img"===e.name));n.setAttribute("data-entity-type",t.attributeNewValue,o||a)}return t=>{t.on("attribute:dataEntityType",e)}}()),i.for("dataDowncast").add(function(e){return t=>{t.on("insert:caption",((t,i,r)=>{const{consumable:s,writer:n,mapper:a}=r;if(!e.plugins.get("ImageUtils").isImage(i.item.parent)||!s.consume(i.item,"insert"))return;const o=e.model.createRangeIn(i.item),l=n.createDocumentFragment();a.bindElements(i.item,l);for(const{item:t}of Array.from(o)){const i={item:t,range:e.model.createRangeOn(t)},s=`insert:${t.name||"$text"}`;e.data.downcastDispatcher.fire(s,i,r);for(const s of t.getAttributeKeys())Object.assign(i,{attributeKey:s,attributeOldValue:null,attributeNewValue:i.item.getAttribute(s)}),e.data.downcastDispatcher.fire(`attribute:${s}`,i,r)}for(const e of n.createRangeIn(l).getItems())a.unbindViewElement(e);a.unbindViewElement(l);const u=e.data.processor.toData(l);if(u){const e=a.toViewElement(i.item.parent);n.setAttribute("data-caption",u,e)}}),{priority:"high"})}}(e)).elementToElement({model:"imageBlock",view:(e,{writer:t})=>a(t),converterPriority:"high"}).elementToElement({model:"imageInline",view:(e,{writer:t})=>a(t),converterPriority:"high"}).add(function(){function e(e,t,i){const{item:r}=t,{consumable:s,writer:n}=i,a=u.find((e=>e.modelValue===t.attributeNewValue));if(!a||!s.consume(r,e.name))return;const o=i.mapper.toViewElement(r),l=Array.from(o.getChildren()).find((e=>"img"===e.name));n.setAttribute("data-align",a.dataValue,l||o)}return t=>{t.on("attribute:imageStyle",e,{priority:"high"})}}()).add(function(){function e(e,i,r){if(!r.consumable.consume(i.item,e.name))return;const s=r.mapper.toViewElement(i.item),n=r.writer,a=n.createContainerElement("a",{href:i.attributeNewValue});n.insert(n.createPositionBefore(s),a),n.move(n.createRangeOn(s),n.createPositionAt(a,0)),r.consumable.consume(i.item,"attribute:htmlLinkAttributes:imageBlock")&&t(r.writer,i.item.getAttribute("htmlLinkAttributes"),a)}return t=>{t.on("attribute:linkHref:imageBlock",e,{priority:"high"})}}()).attributeToAttribute({model:{name:"imageBlock",key:"resizedWidth"},view:e=>({key:"width",value:l(e)}),converterPriority:"high"}).attributeToAttribute({model:{name:"imageInline",key:"resizedWidth"},view:e=>({key:"width",value:l(e)}),converterPriority:"high"}).attributeToAttribute({model:{name:"imageBlock",key:"resizedHeight"},view:e=>({key:"height",value:l(e)}),converterPriority:"high"}).attributeToAttribute({model:{name:"imageInline",key:"resizedHeight"},view:e=>({key:"height",value:l(e)}),converterPriority:"high"}).attributeToAttribute({model:{name:"imageBlock",key:"width"},view:(e,{consumable:t},i)=>i.item.hasAttribute("resizedWidth")?(t.consume(i.item,"attribute:width"),null):{key:"width",value:e},converterPriority:"high"}).attributeToAttribute({model:{name:"imageInline",key:"width"},view:(e,{consumable:t},i)=>i.item.hasAttribute("resizedWidth")?(t.consume(i.item,"attribute:width"),null):{key:"width",value:e},converterPriority:"high"}).attributeToAttribute({model:{name:"imageBlock",key:"height"},view:(e,t,i)=>{if(i.item.hasAttribute("resizedWidth")){if(i.item.getAttribute("resizedWidth").endsWith("%"))return{key:"height",value:i.item.getAttribute("resizedWidth")};const t=parseInt(i.item.getAttribute("resizedWidth"),10),r=parseInt(i.item.getAttribute("width"),10)/parseInt(e,10);return{key:"height",value:`${Math.round(t/r)}`}}return{key:"height",value:e}},converterPriority:"high"}).attributeToAttribute({model:{name:"imageInline",key:"height"},view:(e,t,i)=>{if(i.item.hasAttribute("resizedWidth")){if(i.item.getAttribute("resizedWidth").endsWith("%"))return{key:"height",value:i.item.getAttribute("resizedWidth")};const t=parseInt(i.item.getAttribute("resizedWidth"),10),r=parseInt(i.item.getAttribute("width"),10)/parseInt(e,10);return{key:"height",value:`${Math.round(t/r)}`}}return{key:"height",value:e}},converterPriority:"high"}),e.editing.view.addObserver(n);const s=e.plugins.get("ImageUtils");e.editing.view.document.on("imageLoaded",((t,i)=>{const r=e.editing.view.domConverter.mapDomToView(i.target);if(!r)return;const n=s.getImageWidgetFromImageView(r);if(!n)return;const a=e.editing.mapper.toModelElement(n);a&&e.model.enqueueChange({isUndoable:!1},(()=>{s.setImageNaturalSizeAttributes(a)}))}))}}class c extends e.Command{refresh(){const e=this.editor.plugins.get("ImageUtils").getClosestSelectedImageElement(this.editor.model.document.selection);this.isEnabled=!!e,this.isEnabled&&e.hasAttribute("alt")?this.value=e.getAttribute("alt"):this.value=!1}execute(e){const t=this.editor,i=t.plugins.get("ImageUtils"),r=t.model,s=i.getClosestSelectedImageElement(r.document.selection);r.change((t=>{t.setAttribute("alt",e.newValue,s)}))}}class m extends e.Plugin{static get requires(){return["ImageUtils"]}static get pluginName(){return"DrupalImageAlternativeTextEditing"}constructor(e){super(e),this._missingAltTextViewReferences=new Set}init(){const e=this.editor;e.conversion.for("editingDowncast").add(this._imageEditingDowncastConverter("attribute:alt",e)).add(this._imageEditingDowncastConverter("attribute:src",e)),e.commands.add("imageTextAlternative",new c(this.editor)),e.editing.view.on("render",(()=>{for(const e of this._missingAltTextViewReferences)e.button.element.isConnected||(e.destroy(),this._missingAltTextViewReferences.delete(e))}))}_imageEditingDowncastConverter(e){const t=(e,t,i)=>{const r=this.editor;if(!r.plugins.get("ImageUtils").isImage(t.item))return;const s=i.mapper.toViewElement(t.item),n=Array.from(s.getChildren()).find((e=>e.getCustomProperty("drupalImageMissingAltWarning")));if(t.item.hasAttribute("alt"))return void(n&&i.writer.remove(n));if(n)return;const a=r.ui.componentFactory.create("drupalImageAlternativeTextMissing");a.listenTo(r.ui,"update",(()=>{const e=r.model.document.selection.getFirstRange(),i=r.model.createRangeOn(t.item);a.set({isSelected:e.containsRange(i)||e.isIntersecting(i)})})),a.render(),this._missingAltTextViewReferences.add(a);const o=i.writer.createUIElement("span",{class:"image-alternative-text-missing-wrapper"},(function(e){const t=this.toDomElement(e);return t.appendChild(a.element),t}));i.writer.setCustomProperty("drupalImageMissingAltWarning",!0,o),i.writer.insert(i.writer.createPositionAt(s,"end"),o)};return i=>{i.on(e,t,{priority:"low"})}}}var g=i("ckeditor5/src/ui.js");function h(e){const t=e.plugins.get("ContextualBalloon");if(e.plugins.get("ImageUtils").getClosestSelectedImageWidget(e.editing.view.document.selection)){const i=p(e);t.updatePosition(i)}}function p(e){const t=e.editing.view,i=g.BalloonPanelView.defaultPositions,r=e.plugins.get("ImageUtils");return{target:t.domConverter.mapViewToDom(r.getClosestSelectedImageWidget(t.document.selection)),positions:[i.northArrowSouth,i.northArrowSouthWest,i.northArrowSouthEast,i.southArrowNorth,i.southArrowNorthWest,i.southArrowNorthEast,i.viewportStickyNorth]}}var b=i("ckeditor5/src/utils.js");class w extends g.View{constructor(e){super(e),this.focusTracker=new b.FocusTracker,this.keystrokes=new b.KeystrokeHandler,this.decorativeToggle=this._decorativeToggleView(),this.labeledInput=this._createLabeledInputView(),this.saveButtonView=this._createButton(Drupal.t("Save"),'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6.972 16.615a.997.997 0 0 1-.744-.292l-4.596-4.596a1 1 0 1 1 1.414-1.414l3.926 3.926 9.937-9.937a1 1 0 0 1 1.414 1.415L7.717 16.323a.997.997 0 0 1-.745.292z"/></svg>',"ck-button-save"),this.saveButtonView.type="submit",this.saveButtonView.bind("isEnabled").to(this.decorativeToggle,"isOn",this.labeledInput,"isEmpty",((e,t)=>e||!t)),this.cancelButtonView=this._createButton(Drupal.t("Cancel"),'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.591 10.177 4.243 4.242a1 1 0 0 1-1.415 1.415l-4.242-4.243-4.243 4.243a1 1 0 0 1-1.414-1.415l4.243-4.242L4.52 5.934A1 1 0 0 1 5.934 4.52l4.243 4.243 4.242-4.243a1 1 0 1 1 1.415 1.414l-4.243 4.243z"/></svg>',"ck-button-cancel","cancel"),this._focusables=new g.ViewCollection,this._focusCycler=new g.FocusCycler({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"form",attributes:{class:["ck","ck-text-alternative-form","ck-text-alternative-form--with-decorative-toggle","ck-responsive-form"],tabindex:"-1"},children:[{tag:"div",attributes:{class:["ck","ck-text-alternative-form__decorative-toggle"]},children:[this.decorativeToggle]},this.labeledInput,this.saveButtonView,this.cancelButtonView]}),(0,g.injectCssTransitionDisabler)(this)}render(){super.render(),this.keystrokes.listenTo(this.element),(0,g.submitHandler)({view:this}),[this.decorativeToggle,this.labeledInput,this.saveButtonView,this.cancelButtonView].forEach((e=>{this._focusables.add(e),this.focusTracker.add(e.element)}))}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}_createButton(e,t,i,r){const s=new g.ButtonView(this.locale);return s.set({label:e,icon:t,tooltip:!0}),s.extendTemplate({attributes:{class:i}}),r&&s.delegate("execute").to(this,r),s}_createLabeledInputView(){const e=new g.LabeledFieldView(this.locale,g.createLabeledInputText);return e.bind("class").to(this.decorativeToggle,"isOn",(e=>e?"ck-hidden":"")),e.label=Drupal.t("Alternative text"),e}_decorativeToggleView(){const e=new g.SwitchButtonView(this.locale);return e.set({withText:!0,label:Drupal.t("Decorative image")}),e.on("execute",(()=>{e.set("isOn",!e.isOn)})),e}}class f extends g.View{constructor(e){super(e);const t=this.bindTemplate;this.set("isVisible"),this.set("isSelected");const i=Drupal.t("Add missing alternative text");this.button=new g.ButtonView(e),this.button.set({label:i,tooltip:!1,withText:!0}),this.setTemplate({tag:"span",attributes:{class:["image-alternative-text-missing",t.to("isVisible",(e=>e?"":"ck-hidden"))],title:i},children:[this.button]})}}class v extends e.Plugin{static get requires(){return[g.ContextualBalloon]}static get pluginName(){return"DrupalImageTextAlternativeUI"}init(){this._createButton(),this._createForm(),this._createMissingAltTextComponent();const e=()=>{this.editor.plugins.get("ImageUtils").getClosestSelectedImageWidget(this.editor.editing.view.document.selection)&&this._showForm()};if(this.editor.commands.get("insertImage")){this.editor.commands.get("insertImage").on("execute",e)}if(this.editor.plugins.has("ImageUploadEditing")){this.editor.plugins.get("ImageUploadEditing").on("uploadComplete",e)}}_createMissingAltTextComponent(){this.editor.ui.componentFactory.add("drupalImageAlternativeTextMissing",(e=>{const t=new f(e);return t.listenTo(t.button,"execute",(()=>{this._isInBalloon&&this._balloon.remove(this._form),this._showForm()})),t.listenTo(this.editor.ui,"update",(()=>{t.set({isVisible:!this._isVisible||!t.isSelected})})),t}))}destroy(){super.destroy(),this._form.destroy()}_createButton(){const e=this.editor;e.ui.componentFactory.add("drupalImageAlternativeText",(t=>{const i=e.commands.get("imageTextAlternative"),r=new g.ButtonView(t);return r.set({label:Drupal.t("Change image alternative text"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M5.085 6.22 2.943 4.078a.75.75 0 1 1 1.06-1.06l2.592 2.59A11.094 11.094 0 0 1 10 5.068c4.738 0 8.578 3.101 8.578 5.083 0 1.197-1.401 2.803-3.555 3.887l1.714 1.713a.75.75 0 0 1-.09 1.138.488.488 0 0 1-.15.084.75.75 0 0 1-.821-.16L6.17 7.304c-.258.11-.51.233-.757.365l6.239 6.24-.006.005.78.78c-.388.094-.78.166-1.174.215l-1.11-1.11h.011L4.55 8.197a7.2 7.2 0 0 0-.665.514l-.112.098 4.897 4.897-.005.006 1.276 1.276a10.164 10.164 0 0 1-1.477-.117l-.479-.479-.009.009-4.863-4.863-.022.031a2.563 2.563 0 0 0-.124.2c-.043.077-.08.158-.108.241a.534.534 0 0 0-.028.133.29.29 0 0 0 .008.072.927.927 0 0 0 .082.226c.067.133.145.26.234.379l3.242 3.365.025.01.59.623c-3.265-.918-5.59-3.155-5.59-4.668 0-1.194 1.448-2.838 3.663-3.93zm7.07.531a4.632 4.632 0 0 1 1.108 5.992l.345.344.046-.018a9.313 9.313 0 0 0 2-1.112c.256-.187.5-.392.727-.613.137-.134.27-.277.392-.431.072-.091.141-.185.203-.286.057-.093.107-.19.148-.292a.72.72 0 0 0 .036-.12.29.29 0 0 0 .008-.072.492.492 0 0 0-.028-.133.999.999 0 0 0-.036-.096 2.165 2.165 0 0 0-.071-.145 2.917 2.917 0 0 0-.125-.2 3.592 3.592 0 0 0-.263-.335 5.444 5.444 0 0 0-.53-.523 7.955 7.955 0 0 0-1.054-.768 9.766 9.766 0 0 0-1.879-.891c-.337-.118-.68-.219-1.027-.301zm-2.85.21-.069.002a.508.508 0 0 0-.254.097.496.496 0 0 0-.104.679.498.498 0 0 0 .326.199l.045.005c.091.003.181.003.272.012a2.45 2.45 0 0 1 2.017 1.513c.024.061.043.125.069.185a.494.494 0 0 0 .45.287h.008a.496.496 0 0 0 .35-.158.482.482 0 0 0 .13-.335.638.638 0 0 0-.048-.219 3.379 3.379 0 0 0-.36-.723 3.438 3.438 0 0 0-2.791-1.543l-.028-.001h-.013z"/></svg>',tooltip:!0}),r.bind("isEnabled").to(i,"isEnabled"),this.listenTo(r,"execute",(()=>{this._showForm()})),r}))}_createForm(){const e=this.editor,t=e.editing.view.document,i=e.plugins.get("ImageUtils");this._balloon=this.editor.plugins.get("ContextualBalloon"),this._form=new w(e.locale),this._form.render(),this.listenTo(this._form,"submit",(()=>{e.execute("imageTextAlternative",{newValue:this._form.decorativeToggle.isOn?"":this._form.labeledInput.fieldView.element.value}),this._hideForm(!0)})),this.listenTo(this._form,"cancel",(()=>{this._hideForm(!0)})),this.listenTo(this._form.decorativeToggle,"execute",(()=>{h(e)})),this._form.keystrokes.set("Esc",((e,t)=>{this._hideForm(!0),t()})),this.listenTo(e.ui,"update",(()=>{i.getClosestSelectedImageWidget(t.selection)?this._isVisible&&h(e):this._hideForm(!0)})),(0,g.clickOutsideHandler)({emitter:this._form,activator:()=>this._isVisible,contextElements:[this._balloon.view.element],callback:()=>this._hideForm()})}_showForm(){if(this._isVisible)return;const e=this.editor,t=e.commands.get("imageTextAlternative"),i=this._form.decorativeToggle,r=this._form.labeledInput;this._form.disableCssTransitions(),this._isInBalloon||this._balloon.add({view:this._form,position:p(e)}),i.isOn=""===t.value,r.fieldView.element.value=t.value||"",r.fieldView.value=r.fieldView.element.value,i.isOn?i.focus():r.fieldView.select(),this._form.enableCssTransitions()}_hideForm(e){this._isInBalloon&&(this._form.focusTracker.isFocused&&this._form.saveButtonView.focus(),this._balloon.remove(this._form),e&&this.editor.editing.view.focus())}get _isVisible(){return this._balloon.visibleView===this._form}get _isInBalloon(){return this._balloon.hasView(this._form)}}class y extends e.Plugin{static get requires(){return[m,v]}static get pluginName(){return"DrupalImageAlternativeText"}}class A extends e.Plugin{static get requires(){return[d,y]}static get pluginName(){return"DrupalImage"}}const I=A;class x extends e.Plugin{init(){const{editor:e}=this;e.plugins.get("ImageUploadEditing").on("uploadComplete",((t,{data:i,imageElement:r})=>{e.model.change((e=>{e.setAttribute("dataEntityUuid",i.response.uuid,r),e.setAttribute("dataEntityType",i.response.entity_type,r)}))}))}static get pluginName(){return"DrupalImageUploadEditing"}}var k=i("ckeditor5/src/upload.js");class _{constructor(e,t){this.loader=e,this.options=t}upload(){return this.loader.file.then((e=>new Promise(((t,i)=>{this._initRequest(),this._initListeners(t,i,e),this._sendRequest(e)}))))}abort(){this.xhr&&this.xhr.abort()}_initRequest(){this.xhr=new XMLHttpRequest,this.xhr.open("POST",this.options.uploadUrl,!0),this.xhr.responseType="json"}_initListeners(e,t,i){const r=this.xhr,s=this.loader,n=`Couldn't upload file: ${i.name}.`;r.addEventListener("error",(()=>t(n))),r.addEventListener("abort",(()=>t())),r.addEventListener("load",(()=>{const i=r.response;if(!i||i.error)return t(i?.error?.message||n);e({response:i,urls:{default:i.url}})})),r.upload&&r.upload.addEventListener("progress",(e=>{e.lengthComputable&&(s.uploadTotal=e.total,s.uploaded=e.loaded)}))}_sendRequest(e){const t=this.options.headers||{},i=this.options.withCredentials||!1;Object.keys(t).forEach((e=>{this.xhr.setRequestHeader(e,t[e])})),this.xhr.withCredentials=i;const r=new FormData;r.append("upload",e),this.xhr.send(r)}}class T extends e.Plugin{static get requires(){return[k.FileRepository]}static get pluginName(){return"DrupalFileRepository"}init(){const e=this.editor.config.get("drupalImageUpload");e&&(e.uploadUrl?this.editor.plugins.get(k.FileRepository).createUploadAdapter=t=>new _(t,e):(0,b.logWarning)("simple-upload-adapter-missing-uploadurl"))}}class E extends e.Plugin{static get requires(){return[T,x]}static get pluginName(){return"DrupalImageUpload"}}const V=E;class C extends e.Plugin{init(){const{editor:e}=this;e.ui.componentFactory.add("drupalInsertImage",(()=>e.ui.componentFactory.create("insertImage")))}static get pluginName(){return"DrupalInsertImage"}}const B={DrupalImage:I,DrupalImageUpload:V,DrupalInsertImage:C}})(),r=r.default})()));
\ No newline at end of file diff --git a/core/modules/ckeditor5/js/build/drupalMedia.js b/core/modules/ckeditor5/js/build/drupalMedia.js index 38c848e43941..06fbe635bf9c 100644 --- a/core/modules/ckeditor5/js/build/drupalMedia.js +++ b/core/modules/ckeditor5/js/build/drupalMedia.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.drupalMedia=t())}(globalThis,(()=>(()=>{var e={"ckeditor5/src/core.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/core.js")},"ckeditor5/src/engine.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/engine.js")},"ckeditor5/src/ui.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/ui.js")},"ckeditor5/src/utils.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/utils.js")},"ckeditor5/src/widget.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/widget.js")},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},t={};function i(n){var a=t[n];if(void 0!==a)return a.exports;var r=t[n]={exports:{}};return e[n](r,r.exports,i),r.exports}i.d=(e,t)=>{for(var n in t)i.o(t,n)&&!i.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var n={};return(()=>{"use strict";i.d(n,{default:()=>ne});var e=i("ckeditor5/src/core.js"),t=i("ckeditor5/src/widget.js");function a(e){return!!e&&e.is("element","drupalMedia")}function r(e){return(0,t.isWidget)(e)&&!!e.getCustomProperty("drupalMedia")}function o(e){const t=e.getSelectedElement();return a(t)?t:e.getFirstPosition().findAncestor("drupalMedia")}function s(e){const t=e.getSelectedElement();if(t&&r(t))return t;if(null===e.getFirstPosition())return null;let i=e.getFirstPosition().parent;for(;i;){if(i.is("element")&&r(i))return i;i=i.parent}return null}function l(e){const t=typeof e;return null!=e&&("object"===t||"function"===t)}function d(e){for(const t of e){if(t.hasAttribute("data-drupal-media-preview"))return t;if(t.childCount){const e=d(t.getChildren());if(e)return e}}return null}function u(e){return`drupalElementStyle${e[0].toUpperCase()+e.substring(1)}`}class c extends e.Command{execute(e){const t=this.editor.plugins.get("DrupalMediaEditing"),i=Object.entries(t.attrs).reduce(((e,[t,i])=>(e[i]=t,e)),{}),n=Object.keys(e).reduce(((t,n)=>(i[n]&&(t[i[n]]=e[n]),t)),{});if(this.editor.plugins.has("DrupalElementStyleEditing")){const t=this.editor.plugins.get("DrupalElementStyleEditing"),{normalizedStyles:i}=t;for(const a of Object.keys(i))for(const i of t.normalizedStyles[a])if(e[i.attributeName]&&i.attributeValue===e[i.attributeName]){const e=u(a);n[e]=i.name}}this.editor.model.change((e=>{this.editor.model.insertObject(function(e,t){return e.createElement("drupalMedia",t)}(e,n))}))}refresh(){const e=this.editor.model,t=e.document.selection,i=e.schema.findAllowedParent(t.getFirstPosition(),"drupalMedia");this.isEnabled=null!==i}}const m="METADATA_ERROR";class p extends e.Plugin{static get requires(){return[t.Widget]}constructor(e){super(e),this.attrs={drupalMediaAlt:"alt",drupalMediaEntityType:"data-entity-type",drupalMediaEntityUuid:"data-entity-uuid"},this.converterAttributes=["drupalMediaEntityUuid","drupalElementStyleViewMode","drupalMediaEntityType","drupalMediaAlt"]}init(){const e=this.editor.config.get("drupalMedia");if(!e)return;const{previewURL:t,themeError:i}=e;this.previewUrl=t,this.labelError=Drupal.t("Preview failed"),this.themeError=i||`\n <p>${Drupal.t("An error occurred while trying to preview the media. Save your work and reload this page.")}<p>\n `,this._defineSchema(),this._defineConverters(),this._defineListeners(),this.editor.commands.add("insertDrupalMedia",new c(this.editor))}upcastDrupalMediaIsImage(e){const{model:t,plugins:i}=this.editor;i.get("DrupalMediaMetadataRepository").getMetadata(e).then((i=>{e&&t.enqueueChange({isUndoable:!1},(t=>{t.setAttribute("drupalMediaIsImage",!!i.imageSourceMetadata,e)}))})).catch((i=>{e&&(console.warn(i.toString()),t.enqueueChange({isUndoable:!1},(t=>{t.setAttribute("drupalMediaIsImage",m,e)})))}))}upcastDrupalMediaType(e){this.editor.plugins.get("DrupalMediaMetadataRepository").getMetadata(e).then((t=>{e&&this.editor.model.enqueueChange({isUndoable:!1},(i=>{i.setAttribute("drupalMediaType",t.type,e)}))})).catch((t=>{e&&(console.warn(t.toString()),this.editor.model.enqueueChange({isUndoable:!1},(t=>{t.setAttribute("drupalMediaType",m,e)})))}))}async _fetchPreview(e){const t={text:this._renderElement(e),uuid:e.getAttribute("drupalMediaEntityUuid")},i=await fetch(`${this.previewUrl}?${new URLSearchParams(t)}`,{headers:{"X-Drupal-MediaPreview-CSRF-Token":this.editor.config.get("drupalMedia").previewCsrfToken}});if(i.ok){return{label:i.headers.get("drupal-media-label"),preview:await i.text()}}return{label:this.labelError,preview:this.themeError}}_defineSchema(){this.editor.model.schema.register("drupalMedia",{inheritAllFrom:"$blockObject",allowAttributes:Object.keys(this.attrs)}),this.editor.editing.view.domConverter.blockElements.push("drupal-media")}_defineConverters(){const e=this.editor.conversion,i=this.editor.plugins.get("DrupalMediaMetadataRepository");e.for("upcast").elementToElement({view:{name:"drupal-media"},model:"drupalMedia"}).add((e=>{e.on("element:drupal-media",((e,t)=>{const[n]=t.modelRange.getItems();i.getMetadata(n).then((e=>{n&&(this.upcastDrupalMediaIsImage(n),this.editor.model.enqueueChange({isUndoable:!1},(t=>{t.setAttribute("drupalMediaType",e.type,n)})))})).catch((e=>{console.warn(e.toString())}))}),{priority:"lowest"})})),e.for("dataDowncast").elementToElement({model:"drupalMedia",view:{name:"drupal-media"}}),e.for("editingDowncast").elementToElement({model:"drupalMedia",view:(e,{writer:i})=>{const n=i.createContainerElement("figure",{class:"drupal-media"});if(!this.previewUrl){const e=i.createRawElement("div",{"data-drupal-media-preview":"unavailable"});i.insert(i.createPositionAt(n,0),e)}return i.setCustomProperty("drupalMedia",!0,n),(0,t.toWidget)(n,i,{label:Drupal.t("Media widget")})}}).add((e=>{const t=(e,t,i)=>{const n=i.writer,a=t.item,r=i.mapper.toViewElement(t.item);let o=d(r.getChildren());if(o){if("ready"!==o.getAttribute("data-drupal-media-preview"))return;n.setAttribute("data-drupal-media-preview","loading",o)}else o=n.createRawElement("div",{"data-drupal-media-preview":"loading"}),n.insert(n.createPositionAt(r,0),o);this._fetchPreview(a).then((({label:e,preview:t})=>{o&&this.editor.editing.view.change((i=>{const n=i.createRawElement("div",{"data-drupal-media-preview":"ready","aria-label":e},(e=>{e.innerHTML=t}));i.insert(i.createPositionBefore(o),n),i.remove(o)}))}))};return this.converterAttributes.forEach((i=>{e.on(`attribute:${i}:drupalMedia`,t)})),e})),e.for("editingDowncast").add((e=>{e.on("attribute:drupalElementStyleAlign:drupalMedia",((e,t,i)=>{const n={left:"drupal-media-style-align-left",right:"drupal-media-style-align-right",center:"drupal-media-style-align-center"},a=i.mapper.toViewElement(t.item),r=i.writer;n[t.attributeOldValue]&&r.removeClass(n[t.attributeOldValue],a),n[t.attributeNewValue]&&i.consumable.consume(t.item,e.name)&&r.addClass(n[t.attributeNewValue],a)}))})),Object.keys(this.attrs).forEach((t=>{const i={model:{key:t,name:"drupalMedia"},view:{name:"drupal-media",key:this.attrs[t]}};e.for("dataDowncast").attributeToAttribute(i),e.for("upcast").attributeToAttribute(i)}))}_defineListeners(){this.editor.model.on("insertContent",((e,[t])=>{a(t)&&(this.upcastDrupalMediaIsImage(t),this.upcastDrupalMediaType(t))}))}_renderElement(e){const t=this.editor.model.change((t=>{const i=t.createDocumentFragment(),n=t.cloneElement(e,!1);return["linkHref"].forEach((e=>{t.removeAttribute(e,n)})),t.append(n,i),i}));return this.editor.data.stringify(t)}static get pluginName(){return"DrupalMediaEditing"}}var g=i("ckeditor5/src/ui.js");class h extends e.Plugin{init(){const e=this.editor,t=this.editor.config.get("drupalMedia");if(!t)return;const{libraryURL:i,openDialog:n,dialogSettings:a={}}=t;i&&"function"==typeof n&&e.ui.componentFactory.add("drupalMedia",(t=>{const r=e.commands.get("insertDrupalMedia"),o=new g.ButtonView(t);return o.set({label:Drupal.t("Insert Media"),icon:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M19.1873 4.86414L10.2509 6.86414V7.02335H10.2499V15.5091C9.70972 15.1961 9.01793 15.1048 8.34069 15.3136C7.12086 15.6896 6.41013 16.8967 6.75322 18.0096C7.09631 19.1226 8.3633 19.72 9.58313 19.344C10.6666 19.01 11.3484 18.0203 11.2469 17.0234H11.2499V9.80173L18.1803 8.25067V14.3868C17.6401 14.0739 16.9483 13.9825 16.2711 14.1913C15.0513 14.5674 14.3406 15.7744 14.6836 16.8875C15.0267 18.0004 16.2937 18.5978 17.5136 18.2218C18.597 17.8877 19.2788 16.8982 19.1773 15.9011H19.1803V8.02687L19.1873 8.0253V4.86414Z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M13.5039 0.743652H0.386932V12.1603H13.5039V0.743652ZM12.3379 1.75842H1.55289V11.1454H1.65715L4.00622 8.86353L6.06254 10.861L9.24985 5.91309L11.3812 9.22179L11.7761 8.6676L12.3379 9.45621V1.75842ZM6.22048 4.50869C6.22048 5.58193 5.35045 6.45196 4.27722 6.45196C3.20398 6.45196 2.33395 5.58193 2.33395 4.50869C2.33395 3.43546 3.20398 2.56543 4.27722 2.56543C5.35045 2.56543 6.22048 3.43546 6.22048 4.50869Z"/></svg>\n',tooltip:!0}),o.bind("isOn","isEnabled").to(r,"value","isEnabled"),this.listenTo(o,"execute",(()=>{n(i,(({attributes:t})=>{e.execute("insertDrupalMedia",t)}),a)})),o}))}}class f extends e.Plugin{static get requires(){return[t.WidgetToolbarRepository]}static get pluginName(){return"DrupalMediaToolbar"}afterInit(){const{editor:e}=this;var i;e.plugins.get(t.WidgetToolbarRepository).register("drupalMedia",{ariaLabel:Drupal.t("Drupal Media toolbar"),items:(i=e.config.get("drupalMedia.toolbar"),i.map((e=>l(e)?e.name:e))||[]),getRelatedElement:e=>s(e)})}}class b extends e.Command{refresh(){const e=o(this.editor.model.document.selection);this.isEnabled=!!e&&e.getAttribute("drupalMediaIsImage")&&e.getAttribute("drupalMediaIsImage")!==m,this.isEnabled?this.value=e.getAttribute("drupalMediaAlt"):this.value=!1}execute(e){const{model:t}=this.editor,i=o(t.document.selection);e.newValue=e.newValue.trim(),t.change((t=>{e.newValue.length>0?t.setAttribute("drupalMediaAlt",e.newValue,i):t.removeAttribute("drupalMediaAlt",i)}))}}class w extends e.Plugin{init(){this._data=new WeakMap}getMetadata(e){if(this._data.get(e))return new Promise((t=>{t(this._data.get(e))}));const t=this.editor.config.get("drupalMedia");if(!t)return new Promise(((e,t)=>{t(new Error("drupalMedia configuration is required for parsing metadata."))}));if(!e.hasAttribute("drupalMediaEntityUuid"))return new Promise(((e,t)=>{t(new Error("drupalMedia element must have drupalMediaEntityUuid attribute to retrieve metadata."))}));const{metadataUrl:i}=t;return(async e=>{const t=await fetch(e);if(t.ok)return JSON.parse(await t.text());throw new Error("Fetching media embed metadata from the server failed.")})(`${i}&${new URLSearchParams({uuid:e.getAttribute("drupalMediaEntityUuid")})}`).then((t=>(this._data.set(e,t),t)))}static get pluginName(){return"DrupalMediaMetadataRepository"}}class y extends e.Plugin{static get requires(){return[w]}static get pluginName(){return"MediaImageTextAlternativeEditing"}init(){const{editor:e,editor:{model:t,conversion:i}}=this;t.schema.extend("drupalMedia",{allowAttributes:["drupalMediaIsImage"]}),i.for("editingDowncast").add((e=>{e.on("attribute:drupalMediaIsImage",((e,t,i)=>{const{writer:n,mapper:a}=i,r=a.toViewElement(t.item);if(t.attributeNewValue!==m){const e=Array.from(r.getChildren()).find((e=>e.getCustomProperty("drupalMediaMetadataError")));return void(e&&(n.setCustomProperty("widgetLabel",e.getCustomProperty("drupalMediaOriginalWidgetLabel"),e),n.removeElement(e)))}const o=Drupal.t("Not all functionality may be available because some information could not be retrieved."),s=new g.Template({tag:"span",children:[{tag:"span",attributes:{class:"drupal-media__metadata-error-icon","data-cke-tooltip-text":o}}]}).render(),l=n.createRawElement("div",{class:"drupal-media__metadata-error"},((e,t)=>{t.setContentOf(e,s.outerHTML)}));n.setCustomProperty("drupalMediaMetadataError",!0,l);const d=r.getCustomProperty("widgetLabel");n.setCustomProperty("drupalMediaOriginalWidgetLabel",d,l),n.setCustomProperty("widgetLabel",`${d} (${o})`,r),n.insert(n.createPositionAt(r,0),l)}),{priority:"low"})})),e.commands.add("mediaImageTextAlternative",new b(this.editor))}}function v(e){const t=e.editing.view,i=g.BalloonPanelView.defaultPositions;return{target:t.domConverter.viewToDom(t.document.selection.getSelectedElement()),positions:[i.northArrowSouth,i.northArrowSouthWest,i.northArrowSouthEast,i.southArrowNorth,i.southArrowNorthWest,i.southArrowNorthEast]}}var E=i("ckeditor5/src/utils.js");class M extends g.View{constructor(t){super(t),this.focusTracker=new E.FocusTracker,this.keystrokes=new E.KeystrokeHandler,this.decorativeToggle=this._decorativeToggleView(),this.labeledInput=this._createLabeledInputView(),this.saveButtonView=this._createButton(Drupal.t("Save"),e.icons.check,"ck-button-save"),this.saveButtonView.type="submit",this.cancelButtonView=this._createButton(Drupal.t("Cancel"),e.icons.cancel,"ck-button-cancel","cancel"),this._focusables=new g.ViewCollection,this._focusCycler=new g.FocusCycler({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"form",attributes:{class:["ck","ck-media-alternative-text-form","ck-vertical-form"],tabindex:"-1"},children:[{tag:"div",children:[this.decorativeToggle]},this.labeledInput,this.saveButtonView,this.cancelButtonView]}),(0,g.injectCssTransitionDisabler)(this)}render(){super.render(),this.keystrokes.listenTo(this.element),(0,g.submitHandler)({view:this}),[this.decorativeToggle,this.labeledInput,this.saveButtonView,this.cancelButtonView].forEach((e=>{this._focusables.add(e),this.focusTracker.add(e.element)}))}_createButton(e,t,i,n){const a=new g.ButtonView(this.locale);return a.set({label:e,icon:t,tooltip:!0}),a.extendTemplate({attributes:{class:i}}),n&&a.delegate("execute").to(this,n),a}_createLabeledInputView(){const e=new g.LabeledFieldView(this.locale,g.createLabeledInputText);return e.bind("class").to(this.decorativeToggle,"isOn",(e=>e?"ck-hidden":"")),e.label=Drupal.t("Alternative text override"),e}_decorativeToggleView(){const e=new g.SwitchButtonView(this.locale);return e.set({withText:!0,label:Drupal.t("Decorative image")}),e.on("execute",(()=>{e.isOn&&(this.labeledInput.fieldView.element.value=""),e.set("isOn",!e.isOn)})),e}}class k extends e.Plugin{static get requires(){return[g.ContextualBalloon]}static get pluginName(){return"MediaImageTextAlternativeUi"}init(){this._createButton(),this._createForm()}destroy(){super.destroy(),this._form.destroy()}_createButton(){const t=this.editor;t.ui.componentFactory.add("mediaImageTextAlternative",(i=>{const n=t.commands.get("mediaImageTextAlternative"),a=new g.ButtonView(i);return a.set({label:Drupal.t("Override media image alternative text"),icon:e.icons.lowVision,tooltip:!0}),a.bind("isVisible").to(n,"isEnabled"),this.listenTo(a,"execute",(()=>{this._showForm()})),a}))}_createForm(){const e=this.editor,t=e.editing.view.document;this._balloon=this.editor.plugins.get("ContextualBalloon"),this._form=new M(e.locale),this._form.render(),this.listenTo(this._form,"submit",(()=>{e.execute("mediaImageTextAlternative",{newValue:this._form.decorativeToggle.isOn?'""':this._form.labeledInput.fieldView.element.value}),this._hideForm(!0)})),this.listenTo(this._form,"cancel",(()=>{this._hideForm(!0)})),this._form.keystrokes.set("Esc",((e,t)=>{this._hideForm(!0),t()})),this.listenTo(e.ui,"update",(()=>{s(t.selection)?this._isVisible&&function(e){const t=e.plugins.get("ContextualBalloon");if(s(e.editing.view.document.selection)){const i=v(e);t.updatePosition(i)}}(e):this._hideForm(!0)})),(0,g.clickOutsideHandler)({emitter:this._form,activator:()=>this._isVisible,contextElements:[this._balloon.view.element],callback:()=>this._hideForm()})}_showForm(){if(this._isVisible)return;const e=this.editor,t=e.commands.get("mediaImageTextAlternative"),i=this._form.decorativeToggle,n=e.plugins.get("DrupalMediaMetadataRepository"),r=this._form.labeledInput;this._form.disableCssTransitions(),this._isInBalloon||this._balloon.add({view:this._form,position:v(e)}),i.isOn='""'===t.value,r.fieldView.element.value=t.value||"",r.fieldView.value=r.fieldView.element.value,this._form.defaultAltText="";const o=e.model.document.selection.getSelectedElement();a(o)&&n.getMetadata(o).then((e=>{this._form.defaultAltText=e.imageSourceMetadata?e.imageSourceMetadata.alt:"",r.infoText=Drupal.t(`Leave blank to use the default alternative text: "${this._form.defaultAltText}".`)})).catch((e=>{console.warn(e.toString())})),this._form.enableCssTransitions()}_hideForm(e){this._isInBalloon&&(this._form.focusTracker.isFocused&&this._form.saveButtonView.focus(),this._balloon.remove(this._form),e&&this.editor.editing.view.focus())}get _isVisible(){return this._balloon.visibleView===this._form}get _isInBalloon(){return this._balloon.hasView(this._form)}}class D extends e.Plugin{static get requires(){return[y,k]}static get pluginName(){return"MediaImageTextAlternative"}}function C(e,t,i){if(t.attributes)for(const[n,a]of Object.entries(t.attributes))e.setAttribute(n,a,i);t.styles&&e.setStyle(t.styles,i),t.classes&&e.addClass(t.classes,i)}function A(e,t,i){if(!i.consumable.consume(t.item,e.name))return;const n=i.mapper.toViewElement(t.item);C(i.writer,t.attributeNewValue,n)}class _ extends e.Plugin{constructor(e){if(super(e),!e.plugins.has("GeneralHtmlSupport"))return;e.plugins.has("DataFilter")&&e.plugins.has("DataSchema")||console.error("DataFilter and DataSchema plugins are required for Drupal Media to integrate with General HTML Support plugin.");const{schema:t}=e.model,{conversion:i}=e,n=this.editor.plugins.get("DataFilter");this.editor.plugins.get("DataSchema").registerBlockElement({model:"drupalMedia",view:"drupal-media"}),n.on("register:drupal-media",((e,a)=>{"drupalMedia"===a.model&&(t.extend("drupalMedia",{allowAttributes:["htmlLinkAttributes","htmlAttributes"]}),i.for("upcast").add(function(e){return t=>{t.on("element:drupal-media",((t,i,n)=>{function a(t,a){const r=e.processViewAttributes(t,n);r&&n.writer.setAttribute(a,r,i.modelRange)}const r=i.viewItem,o=r.parent;a(r,"htmlAttributes"),o.is("element","a")&&a(o,"htmlLinkAttributes")}),{priority:"low"})}}(n)),i.for("editingDowncast").add((e=>{e.on("attribute:linkHref:drupalMedia",((e,t,i)=>{if(!i.consumable.consume(t.item,"attribute:htmlLinkAttributes:drupalMedia"))return;const n=i.mapper.toViewElement(t.item),a=function(e,t,i){const n=e.createRangeOn(t);for(const{item:e}of n.getWalker())if(e.is("element",i))return e}(i.writer,n,"a");C(i.writer,t.item.getAttribute("htmlLinkAttributes"),a)}),{priority:"low"})})),i.for("dataDowncast").add((e=>{e.on("attribute:linkHref:drupalMedia",((e,t,i)=>{if(!i.consumable.consume(t.item,"attribute:htmlLinkAttributes:drupalMedia"))return;const n=i.mapper.toViewElement(t.item).parent;C(i.writer,t.item.getAttribute("htmlLinkAttributes"),n)}),{priority:"low"}),e.on("attribute:htmlAttributes:drupalMedia",A,{priority:"low"})})),e.stop())}))}static get pluginName(){return"DrupalMediaGeneralHtmlSupport"}}class x extends e.Plugin{static get requires(){return[p,_,h,f,D]}static get pluginName(){return"DrupalMedia"}}var V=i("ckeditor5/src/engine.js");function S(e){return Array.from(e.getChildren()).find((e=>"drupal-media"===e.name))}function T(e){return t=>{t.on(`attribute:${e.id}:drupalMedia`,((t,i,n)=>{const a=n.mapper.toViewElement(i.item);let r=Array.from(a.getChildren()).find((e=>"a"===e.name));if(r=!r&&a.is("element","a")?a:Array.from(a.getAncestors()).find((e=>"a"===e.name)),r){for(const[t,i]of(0,E.toMap)(e.attributes))n.writer.setAttribute(t,i,r);e.classes&&n.writer.addClass(e.classes,r);for(const t in e.styles)Object.prototype.hasOwnProperty.call(e.styles,t)&&n.writer.setStyle(t,e.styles[t],r)}}))}}function I(e,t){return e=>{e.on("element:a",((e,i,n)=>{const a=i.viewItem;if(!S(a))return;const r=new V.Matcher(t._createPattern()).match(a);if(!r)return;if(!n.consumable.consume(a,r.match))return;const o=i.modelCursor.nodeBefore;n.writer.setAttribute(t.id,!0,o)}),{priority:"high"})}}class L extends e.Plugin{static get requires(){return["LinkEditing","DrupalMediaEditing"]}static get pluginName(){return"DrupalLinkMediaEditing"}init(){const{editor:e}=this;e.model.schema.extend("drupalMedia",{allowAttributes:["linkHref"]}),e.conversion.for("upcast").add((e=>{e.on("element:a",((e,t,i)=>{const n=t.viewItem,a=S(n);if(!a)return;if(!i.consumable.consume(n,{attributes:["href"],name:!0}))return;const r=n.getAttribute("href");if(null===r)return;const o=i.convertItem(a,t.modelCursor);t.modelRange=o.modelRange,t.modelCursor=o.modelCursor;const s=t.modelCursor.nodeBefore;s&&s.is("element","drupalMedia")&&i.writer.setAttribute("linkHref",r,s)}),{priority:"high"})})),e.conversion.for("editingDowncast").add((e=>{e.on("attribute:linkHref:drupalMedia",((e,t,i)=>{const{writer:n}=i;if(!i.consumable.consume(t.item,e.name))return;const a=i.mapper.toViewElement(t.item),r=Array.from(a.getChildren()).find((e=>"a"===e.name));if(r)t.attributeNewValue?n.setAttribute("href",t.attributeNewValue,r):(n.move(n.createRangeIn(r),n.createPositionAt(a,0)),n.remove(r));else{const e=Array.from(a.getChildren()).find((e=>e.getAttribute("data-drupal-media-preview"))),i=n.createContainerElement("a",{href:t.attributeNewValue});n.insert(n.createPositionAt(a,0),i),n.move(n.createRangeOn(e),n.createPositionAt(i,0))}}),{priority:"high"})})),e.conversion.for("dataDowncast").add((e=>{e.on("attribute:linkHref:drupalMedia",((e,t,i)=>{const{writer:n}=i;if(!i.consumable.consume(t.item,e.name))return;const a=i.mapper.toViewElement(t.item),r=n.createContainerElement("a",{href:t.attributeNewValue});n.insert(n.createPositionBefore(a),r),n.move(n.createRangeOn(a),n.createPositionAt(r,0))}),{priority:"high"})})),this._enableManualDecorators();if(e.commands.get("link").automaticDecorators.length>0)throw new Error("The Drupal Media plugin is not compatible with automatic link decorators. To use Drupal Media, disable any plugins providing automatic link decorators.")}_enableManualDecorators(){const e=this.editor,t=e.commands.get("link");for(const i of t.manualDecorators)e.model.schema.extend("drupalMedia",{allowAttributes:i.id}),e.conversion.for("downcast").add(T(i)),e.conversion.for("upcast").add(I(0,i))}}class O extends e.Plugin{static get requires(){return["LinkEditing","LinkUI","DrupalMediaEditing"]}static get pluginName(){return"DrupalLinkMediaUi"}init(){const{editor:e}=this,t=e.editing.view.document;this.listenTo(t,"click",((t,i)=>{this._isSelectedLinkedMedia(e.model.document.selection)&&(i.preventDefault(),t.stop())}),{priority:"high"}),this._createToolbarLinkMediaButton()}_createToolbarLinkMediaButton(){const{editor:e}=this;e.ui.componentFactory.add("drupalLinkMedia",(t=>{const i=new g.ButtonView(t),n=e.plugins.get("LinkUI"),a=e.commands.get("link");return i.set({isEnabled:!0,label:Drupal.t("Link media"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.077 15 .991-1.416a.75.75 0 1 1 1.229.86l-1.148 1.64a.748.748 0 0 1-.217.206 5.251 5.251 0 0 1-8.503-5.955.741.741 0 0 1 .12-.274l1.147-1.639a.75.75 0 1 1 1.228.86L4.933 10.7l.006.003a3.75 3.75 0 0 0 6.132 4.294l.006.004zm5.494-5.335a.748.748 0 0 1-.12.274l-1.147 1.639a.75.75 0 1 1-1.228-.86l.86-1.23a3.75 3.75 0 0 0-6.144-4.301l-.86 1.229a.75.75 0 0 1-1.229-.86l1.148-1.64a.748.748 0 0 1 .217-.206 5.251 5.251 0 0 1 8.503 5.955zm-4.563-2.532a.75.75 0 0 1 .184 1.045l-3.155 4.505a.75.75 0 1 1-1.229-.86l3.155-4.506a.75.75 0 0 1 1.045-.184z"/></svg>\n',keystroke:"Ctrl+K",tooltip:!0,isToggleable:!0}),i.bind("isEnabled").to(a,"isEnabled"),i.bind("isOn").to(a,"value",(e=>!!e)),this.listenTo(i,"execute",(()=>{this._isSelectedLinkedMedia(e.model.document.selection)?n._addActionsView():n._showUI(!0)})),i}))}_isSelectedLinkedMedia(e){const t=e.getSelectedElement();return!!t&&t.is("element","drupalMedia")&&t.hasAttribute("linkHref")}}class P extends e.Plugin{static get requires(){return[L,O]}static get pluginName(){return"DrupalLinkMedia"}}const B={get inline(){return{name:"inline",title:"In line",icon:e.icons.objectInline,modelElements:["imageInline"],isDefault:!0}},get alignLeft(){return{name:"alignLeft",title:"Left aligned image",icon:e.icons.objectLeft,modelElements:["imageBlock","imageInline"],className:"image-style-align-left"}},get alignBlockLeft(){return{name:"alignBlockLeft",title:"Left aligned image",icon:e.icons.objectBlockLeft,modelElements:["imageBlock"],className:"image-style-block-align-left"}},get alignCenter(){return{name:"alignCenter",title:"Centered image",icon:e.icons.objectCenter,modelElements:["imageBlock"],className:"image-style-align-center"}},get alignRight(){return{name:"alignRight",title:"Right aligned image",icon:e.icons.objectRight,modelElements:["imageBlock","imageInline"],className:"image-style-align-right"}},get alignBlockRight(){return{name:"alignBlockRight",title:"Right aligned image",icon:e.icons.objectBlockRight,modelElements:["imageBlock"],className:"image-style-block-align-right"}},get block(){return{name:"block",title:"Centered image",icon:e.icons.objectCenter,modelElements:["imageBlock"],isDefault:!0}},get side(){return{name:"side",title:"Side image",icon:e.icons.objectRight,modelElements:["imageBlock"],className:"image-style-side"}}},N=(()=>({full:e.icons.objectFullWidth,left:e.icons.objectBlockLeft,right:e.icons.objectBlockRight,center:e.icons.objectCenter,inlineLeft:e.icons.objectLeft,inlineRight:e.icons.objectRight,inline:e.icons.objectInline}))(),j=[{name:"imageStyle:wrapText",title:"Wrap text",defaultItem:"imageStyle:alignLeft",items:["imageStyle:alignLeft","imageStyle:alignRight"]},{name:"imageStyle:breakText",title:"Break text",defaultItem:"imageStyle:block",items:["imageStyle:alignBlockLeft","imageStyle:block","imageStyle:alignBlockRight"]}];function R(e){(0,E.logWarning)("image-style-configuration-definition-invalid",e)}const F={normalizeStyles:function(e){return(e.configuredStyles.options||[]).map((e=>function(e){e="string"==typeof e?B[e]?{...B[e]}:{name:e}:function(e,t){const i={...t};for(const n in e)Object.prototype.hasOwnProperty.call(t,n)||(i[n]=e[n]);return i}(B[e.name],e);"string"==typeof e.icon&&(e.icon=N[e.icon]||e.icon);return e}(e))).filter((t=>function(e,{isBlockPluginLoaded:t,isInlinePluginLoaded:i}){const{modelElements:n,name:a}=e;if(!(n&&n.length&&a))return R({style:e}),!1;{const a=[t?"imageBlock":null,i?"imageInline":null];if(!n.some((e=>a.includes(e))))return(0,E.logWarning)("image-style-missing-dependency",{style:e,missingPlugins:n.map((e=>"imageBlock"===e?"ImageBlockEditing":"ImageInlineEditing"))}),!1}return!0}(t,e)))},getDefaultStylesConfiguration:function(e,t){return e&&t?{options:["inline","alignLeft","alignRight","alignCenter","alignBlockLeft","alignBlockRight","block","side"]}:e?{options:["block","side"]}:t?{options:["inline","alignLeft","alignRight"]}:{}},getDefaultDropdownDefinitions:function(e){return e.has("ImageBlockEditing")&&e.has("ImageInlineEditing")?[...j]:[]},warnInvalidStyle:R,DEFAULT_OPTIONS:B,DEFAULT_ICONS:N,DEFAULT_DROPDOWN_DEFINITIONS:j};function U(e,t,i){for(const n of t)if(i.checkAttribute(e,n))return!0;return!1}function H(e,t,i){const n=e.getSelectedElement();if(n&&U(n,i,t))return n;let{parent:a}=e.getFirstPosition();for(;a;){if(a.is("element")&&U(a,i,t))return a;a=a.parent}return null}class $ extends e.Command{constructor(e,t){super(e),this.styles={},Object.keys(t).forEach((e=>{this.styles[e]=new Map(t[e].map((e=>[e.name,e])))})),this.modelAttributes=[];for(const e of Object.keys(t)){const t=u(e);this.modelAttributes.push(t)}}refresh(){const{editor:e}=this,t=H(e.model.document.selection,e.model.schema,this.modelAttributes);this.isEnabled=!!t,this.isEnabled?this.value=this.getValue(t):this.value=!1}getValue(e){const t={};return Object.keys(this.styles).forEach((i=>{const n=u(i);if(e.hasAttribute(n))t[i]=e.getAttribute(n);else for(const[,e]of this.styles[i])e.isDefault&&(t[i]=e.name)})),t}execute(e={}){const{editor:{model:t}}=this,{value:i,group:n}=e,a=u(n);t.change((e=>{const r=H(t.document.selection,t.schema,this.modelAttributes);!i||this.styles[n].get(i).isDefault?e.removeAttribute(a,r):e.setAttribute(a,i,r)}))}}function q(e,t){for(const i of t)if(i.name===e)return i}class W extends e.Plugin{init(){const{editor:t}=this,i=t.config.get("drupalElementStyles");this.normalizedStyles={},Object.keys(i).forEach((t=>{this.normalizedStyles[t]=i[t].map((t=>("string"==typeof t.icon&&e.icons[t.icon]&&(t.icon=e.icons[t.icon]),t.name&&(t.name=`${t.name}`),t))).filter((e=>e.isDefault||e.attributeName&&e.attributeValue?e.modelElements&&Array.isArray(e.modelElements)?!!e.name||(console.warn("drupalElementStyles options must include a name."),!1):(console.warn("drupalElementStyles options must include an array of supported modelElements."),!1):(console.warn(`${e.attributeValue} drupalElementStyles options must include attributeName and attributeValue.`),!1)))})),this._setupConversion(),t.commands.add("drupalElementStyle",new $(t,this.normalizedStyles))}_setupConversion(){const{editor:e}=this,{schema:t}=e.model;Object.keys(this.normalizedStyles).forEach((i=>{const n=u(i),a=(r=this.normalizedStyles[i],(e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const n=q(t.attributeNewValue,r),a=q(t.attributeOldValue,r),o=i.mapper.toViewElement(t.item),s=i.writer;a&&("class"===a.attributeName?s.removeClass(a.attributeValue,o):s.removeAttribute(a.attributeName,o)),n&&("class"===n.attributeName?s.addClass(n.attributeValue,o):n.isDefault||s.setAttribute(n.attributeName,n.attributeValue,o))});var r;const o=function(e,t){const i=e.filter((e=>!e.isDefault));return(e,n,a)=>{if(!n.modelRange)return;const r=n.viewItem,o=(0,E.first)(n.modelRange.getItems());if(o&&a.schema.checkAttribute(o,t))for(const e of i)if("class"===e.attributeName)a.consumable.consume(r,{classes:e.attributeValue})&&a.writer.setAttribute(t,e.name,o);else if(a.consumable.consume(r,{attributes:[e.attributeName]}))for(const e of i)e.attributeValue===r.getAttribute(e.attributeName)&&a.writer.setAttribute(t,e.name,o)}}(this.normalizedStyles[i],n);e.editing.downcastDispatcher.on(`attribute:${n}`,a),e.data.downcastDispatcher.on(`attribute:${n}`,a);[...new Set(this.normalizedStyles[i].map((e=>e.modelElements)).flat())].forEach((e=>{t.extend(e,{allowAttributes:n})})),e.data.upcastDispatcher.on("element",o,{priority:"low"})}))}static get pluginName(){return"DrupalElementStyleEditing"}}const K=e=>e,z=(e,t)=>(e?`${e}: `:"")+t;function Z(e,t){return`drupalElementStyle:${t}:${e}`}class G extends e.Plugin{static get requires(){return[W]}init(){const{plugins:e}=this.editor,t=this.editor.config.get("drupalMedia.toolbar")||[],i=e.get("DrupalElementStyleEditing").normalizedStyles;Object.keys(i).forEach((e=>{i[e].forEach((t=>{this._createButton(t,e,i[e])}))}));t.filter(l).filter((e=>{const t=[];if(!e.display)return console.warn("dropdown configuration must include a display key specifying either listDropdown or splitButton."),!1;e.items.includes(e.defaultItem)||console.warn("defaultItem must be part of items in the dropdown configuration.");for(const i of e.items){const e=i.split(":")[1];t.push(e)}return!!t.every((e=>e===t[0]))||(console.warn("dropdown configuration should only contain buttons from one group."),!1)})).forEach((e=>{if(e.items.length>=2){const t=e.name.split(":")[1];switch(e.display){case"splitButton":this._createDropdown(e,i[t]);break;case"listDropdown":this._createListDropdown(e,i[t])}}}))}updateOptionVisibility(e,t,i,n){const{selection:a}=this.editor.model.document,r={};r[n]=e;const o=a?a.getSelectedElement():H(a,this.editor.model.schema,r),s=e.filter((function(e){for(const[t,i]of(0,E.toMap)(e.modelAttributes))if(o&&o.hasAttribute(t))return i.includes(o.getAttribute(t));return!0}));i.hasOwnProperty("model")?s.includes(t)?i.model.set({class:""}):i.model.set({class:"ck-hidden"}):s.includes(t)?i.set({class:""}):i.set({class:"ck-hidden"})}_createDropdown(e,t){const i=this.editor.ui.componentFactory;i.add(e.name,(n=>{let a;const{defaultItem:r,items:o,title:s}=e,l=o.filter((e=>{const i=e.split(":")[1];return t.find((({name:t})=>Z(t,i)===e))})).map((e=>{const t=i.create(e);return e===r&&(a=t),t}));o.length!==l.length&&F.warnInvalidStyle({dropdown:e});const d=(0,g.createDropdown)(n,g.SplitButtonView),u=d.buttonView;return(0,g.addToolbarToDropdown)(d,l),u.set({label:z(s,a.label),class:null,tooltip:!0}),u.bind("icon").toMany(l,"isOn",((...e)=>{const t=e.findIndex(K);return t<0?a.icon:l[t].icon})),u.bind("label").toMany(l,"isOn",((...e)=>{const t=e.findIndex(K);return z(s,t<0?a.label:l[t].label)})),u.bind("isOn").toMany(l,"isOn",((...e)=>e.some(K))),u.bind("class").toMany(l,"isOn",((...e)=>e.some(K)?"ck-splitbutton_flatten":null)),u.on("execute",(()=>{l.some((({isOn:e})=>e))?d.isOpen=!d.isOpen:a.fire("execute")})),d.bind("isEnabled").toMany(l,"isEnabled",((...e)=>e.some(K))),d}))}_createButton(e,t,i){const n=e.name;this.editor.ui.componentFactory.add(Z(n,t),(a=>{const r=this.editor.commands.get("drupalElementStyle"),o=new g.ButtonView(a);return o.set({label:e.title,icon:e.icon,tooltip:!0,isToggleable:!0}),o.bind("isEnabled").to(r,"isEnabled"),o.bind("isOn").to(r,"value",(e=>e&&e[t]===n)),o.on("execute",this._executeCommand.bind(this,n,t)),this.listenTo(this.editor.ui,"update",(()=>{this.updateOptionVisibility(i,e,o,t)})),o}))}getDropdownListItemDefinitions(e,t,i){const n=new E.Collection;return e.forEach((t=>{const a={type:"button",model:new g.ViewModel({group:i,commandValue:t.name,label:t.title,withText:!0,class:""})};n.add(a),this.listenTo(this.editor.ui,"update",(()=>{this.updateOptionVisibility(e,t,a,i)}))})),n}_createListDropdown(e,t){const i=this.editor.ui.componentFactory;i.add(e.name,(n=>{let a;const{defaultItem:r,items:o,title:s,defaultText:l}=e,d=e.name.split(":")[1],u=o.filter((e=>t.find((({name:t})=>Z(t,d)===e)))).map((e=>{const t=i.create(e);return e===r&&(a=t),t}));o.length!==u.length&&F.warnInvalidStyle({dropdown:e});const c=(0,g.createDropdown)(n,g.DropdownButtonView),m=c.buttonView;m.set({label:z(s,a.label),class:null,tooltip:l,withText:!0});const p=this.editor.commands.get("drupalElementStyle");return m.bind("label").to(p,"value",(e=>{if(e?.[d])for(const i of t)if(i.name===e[d])return i.title;return l})),c.bind("isOn").to(p),c.bind("isEnabled").to(this),(0,g.addListToDropdown)(c,this.getDropdownListItemDefinitions(t,p,d)),this.listenTo(c,"execute",(e=>{this._executeCommand(e.source.commandValue,e.source.group)})),c}))}_executeCommand(e,t){this.editor.execute("drupalElementStyle",{value:e,group:t}),this.editor.editing.view.focus()}static get pluginName(){return"DrupalElementStyleUi"}}class J extends e.Plugin{static get requires(){return[W,G]}static get pluginName(){return"DrupalElementStyle"}}function X(e){const t=e.getFirstPosition().findAncestor("caption");return t&&a(t.parent)?t:null}function Q(e){for(const t of e.getChildren())if(t&&t.is("element","caption"))return t;return null}class Y extends e.Command{refresh(){const e=this.editor.model.document.selection,t=e.getSelectedElement();if(!t)return this.isEnabled=!!o(e),void(this.value=!!X(e));this.isEnabled=a(t),this.isEnabled?this.value=!!Q(t):this.value=!1}execute(e={}){const{focusCaptionOnShow:t}=e;this.editor.model.change((e=>{this.value?this._hideDrupalMediaCaption(e):this._showDrupalMediaCaption(e,t)}))}_showDrupalMediaCaption(e,t){const i=this.editor.model.document.selection,n=this.editor.plugins.get("DrupalMediaCaptionEditing"),a=o(i),r=n._getSavedCaption(a)||e.createElement("caption");e.append(r,a),t&&e.setSelection(r,"in")}_hideDrupalMediaCaption(e){const t=this.editor,i=t.model.document.selection,n=t.plugins.get("DrupalMediaCaptionEditing");let a,r=i.getSelectedElement();r?a=Q(r):(a=X(i),r=o(i)),n._saveCaption(r,a),e.setSelection(r,"on"),e.remove(a)}}class ee extends e.Plugin{static get requires(){return[]}static get pluginName(){return"DrupalMediaCaptionEditing"}constructor(e){super(e),this._savedCaptionsMap=new WeakMap}init(){const e=this.editor,t=e.model.schema;t.isRegistered("caption")?t.extend("caption",{allowIn:"drupalMedia"}):t.register("caption",{allowIn:"drupalMedia",allowContentOf:"$block",isLimit:!0}),e.commands.add("toggleMediaCaption",new Y(e)),this._setupConversion()}_setupConversion(){const e=this.editor,i=e.editing.view;var n;e.conversion.for("upcast").add(function(e){const t=(t,i,n)=>{const{viewItem:a}=i,{writer:r,consumable:o}=n;if(!i.modelRange||!o.consume(a,{attributes:["data-caption"]}))return;const s=r.createElement("caption"),l=i.modelRange.start.nodeAfter,d=e.data.processor.toView(a.getAttribute("data-caption"));n.consumable.constructor.createFrom(d,n.consumable),n.convertChildren(d,s),r.append(s,l)};return e=>{e.on("element:drupal-media",t,{priority:"low"})}}(e)),e.conversion.for("editingDowncast").elementToElement({model:"caption",view:(e,{writer:n})=>{if(!a(e.parent))return null;const r=n.createEditableElement("figcaption");return r.placeholder=Drupal.t("Enter media caption"),(0,V.enablePlaceholder)({view:i,element:r,keepOnFocus:!0}),(0,t.toWidgetEditable)(r,n)}}),e.editing.mapper.on("modelToViewPosition",(n=i,(e,t)=>{const i=t.modelPosition,r=i.parent;if(!a(r))return;const o=t.mapper.toViewElement(r);t.viewPosition=n.createPositionAt(o,i.offset+1)})),e.conversion.for("dataDowncast").add(function(e){return t=>{t.on("insert:caption",((t,i,n)=>{const{consumable:r,writer:o,mapper:s}=n;if(!a(i.item.parent)||!r.consume(i.item,"insert"))return;const l=e.model.createRangeIn(i.item),d=o.createDocumentFragment();s.bindElements(i.item,d);for(const{item:t}of Array.from(l)){const i={item:t,range:e.model.createRangeOn(t)},a=`insert:${t.name||"$text"}`;e.data.downcastDispatcher.fire(a,i,n);for(const a of t.getAttributeKeys())Object.assign(i,{attributeKey:a,attributeOldValue:null,attributeNewValue:i.item.getAttribute(a)}),e.data.downcastDispatcher.fire(`attribute:${a}`,i,n)}for(const e of o.createRangeIn(d).getItems())s.unbindViewElement(e);s.unbindViewElement(d);const u=e.data.processor.toData(d);if(u){const e=s.toViewElement(i.item.parent);o.setAttribute("data-caption",u,e)}}))}}(e))}_getSavedCaption(e){const t=this._savedCaptionsMap.get(e);return t?V.Element.fromJSON(t):null}_saveCaption(e,t){this._savedCaptionsMap.set(e,t.toJSON())}}class te extends e.Plugin{static get requires(){return[]}static get pluginName(){return"DrupalMediaCaptionUI"}init(){const{editor:t}=this,i=t.editing.view;t.ui.componentFactory.add("toggleDrupalMediaCaption",(n=>{const a=new g.ButtonView(n),r=t.commands.get("toggleMediaCaption");return a.set({label:Drupal.t("Caption media"),icon:e.icons.caption,tooltip:!0,isToggleable:!0}),a.bind("isOn","isEnabled").to(r,"value","isEnabled"),a.bind("label").to(r,"value",(e=>e?Drupal.t("Toggle caption off"):Drupal.t("Toggle caption on"))),this.listenTo(a,"execute",(()=>{t.execute("toggleMediaCaption",{focusCaptionOnShow:!0});const e=X(t.model.document.selection);if(e){const n=t.editing.mapper.toViewElement(e);i.scrollToTheSelection(),i.change((e=>{e.addClass("drupal-media__caption_highlighted",n)}))}t.editing.view.focus()})),a}))}}class ie extends e.Plugin{static get requires(){return[ee,te]}static get pluginName(){return"DrupalMediaCaption"}}const ne={DrupalMedia:x,MediaImageTextAlternative:D,MediaImageTextAlternativeEditing:y,MediaImageTextAlternativeUi:k,DrupalLinkMedia:P,DrupalMediaCaption:ie,DrupalElementStyle:J}})(),n=n.default})()));
\ No newline at end of file +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.CKEditor5=e():(t.CKEditor5=t.CKEditor5||{},t.CKEditor5.drupalMedia=e())}(globalThis,(()=>(()=>{var t={"ckeditor5/src/core.js":(t,e,a)=>{t.exports=a("dll-reference CKEditor5.dll")("./src/core.js")},"ckeditor5/src/engine.js":(t,e,a)=>{t.exports=a("dll-reference CKEditor5.dll")("./src/engine.js")},"ckeditor5/src/icons.js":(t,e,a)=>{t.exports=a("dll-reference CKEditor5.dll")("./src/icons.js")},"ckeditor5/src/ui.js":(t,e,a)=>{t.exports=a("dll-reference CKEditor5.dll")("./src/ui.js")},"ckeditor5/src/utils.js":(t,e,a)=>{t.exports=a("dll-reference CKEditor5.dll")("./src/utils.js")},"ckeditor5/src/widget.js":(t,e,a)=>{t.exports=a("dll-reference CKEditor5.dll")("./src/widget.js")},"dll-reference CKEditor5.dll":t=>{"use strict";t.exports=CKEditor5.dll}},e={};function a(i){var l=e[i];if(void 0!==l)return l.exports;var n=e[i]={exports:{}};return t[i](n,n.exports,a),n.exports}a.d=(t,e)=>{for(var i in e)a.o(e,i)&&!a.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:e[i]})},a.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),a.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var i={};return(()=>{"use strict";a.d(i,{default:()=>hi});var t={};a.r(t),a.d(t,{IconAccessibility:()=>V,IconAddComment:()=>f,IconAlignBottom:()=>x,IconAlignCenter:()=>Z,IconAlignJustify:()=>b,IconAlignLeft:()=>L,IconAlignMiddle:()=>C,IconAlignRight:()=>I,IconAlignTop:()=>y,IconArrowDown:()=>B,IconArrowUp:()=>A,IconBold:()=>E,IconBookmark:()=>D,IconBookmarkInline:()=>k,IconBookmarkMedium:()=>S,IconBookmarkSmall:()=>_,IconBrowseFiles:()=>T,IconBulletedList:()=>O,IconCancel:()=>P,IconCaption:()=>j,IconCaseChange:()=>R,IconCheck:()=>F,IconChevronDown:()=>N,IconChevronUp:()=>U,IconCkboxImageEdit:()=>W,IconCode:()=>q,IconCodeBlock:()=>$,IconCog:()=>K,IconColorPalette:()=>G,IconColorTileCheck:()=>J,IconCommentsArchive:()=>Q,IconContentLock:()=>X,IconContentUnlock:()=>Y,IconCopy:()=>tt,IconDragHandle:()=>et,IconDragIndicator:()=>at,IconDropbox:()=>it,IconDropdownArrow:()=>lt,IconEditComment:()=>nt,IconEmoji:()=>ot,IconEraser:()=>st,IconError:()=>ht,IconExportPdf:()=>rt,IconExportWord:()=>vt,IconFacebook:()=>ct,IconFindReplace:()=>dt,IconFontBackground:()=>mt,IconFontColor:()=>gt,IconFontFamily:()=>pt,IconFontSize:()=>wt,IconFullscreenEnter:()=>ut,IconFullscreenLeave:()=>Mt,IconGoogleDrive:()=>Ht,IconGooglePhotos:()=>zt,IconHeading1:()=>Vt,IconHeading2:()=>ft,IconHeading3:()=>xt,IconHeading4:()=>Zt,IconHeading5:()=>bt,IconHeading6:()=>Lt,IconHistory:()=>Ct,IconHorizontalLine:()=>It,IconHtml:()=>yt,IconImage:()=>At,IconImageAssetManager:()=>Bt,IconImageUpload:()=>Et,IconImageUrl:()=>kt,IconImportExport:()=>Dt,IconImportWord:()=>St,IconIndent:()=>_t,IconInsertMergeField:()=>Tt,IconItalic:()=>Ot,IconLegalStyleList:()=>Pt,IconLink:()=>jt,IconListStyleCircle:()=>Rt,IconListStyleDecimal:()=>Nt,IconListStyleDecimalLeadingZero:()=>Ft,IconListStyleDisc:()=>Ut,IconListStyleLowerLatin:()=>Wt,IconListStyleLowerRoman:()=>$t,IconListStyleSquare:()=>qt,IconListStyleUpperLatin:()=>Kt,IconListStyleUpperRoman:()=>Gt,IconLocal:()=>Jt,IconLoupe:()=>Qt,IconLowVision:()=>Xt,IconMagicWand:()=>Yt,IconMarker:()=>te,IconMedia:()=>ae,IconMediaPlaceholder:()=>ee,IconMultiLevelList:()=>ie,IconNextArrow:()=>le,IconNotification:()=>ne,IconNumberedList:()=>oe,IconObjectCenter:()=>se,IconObjectFullWidth:()=>he,IconObjectInline:()=>ce,IconObjectInlineLeft:()=>re,IconObjectInlineRight:()=>ve,IconObjectLeft:()=>de,IconObjectRight:()=>me,IconObjectSizeCustom:()=>ge,IconObjectSizeFull:()=>pe,IconObjectSizeLarge:()=>we,IconObjectSizeMedium:()=>ue,IconObjectSizeSmall:()=>Me,IconOneDrive:()=>He,IconOutdent:()=>ze,IconPageBreak:()=>Ve,IconPaginationExample:()=>fe,IconPaintRoller:()=>be,IconPaintRollerCursorDefault:()=>xe,IconPaintRollerCursorText:()=>Ze,IconParagraph:()=>Le,IconPen:()=>Ie,IconPencil:()=>Ce,IconPilcrow:()=>ye,IconPlay:()=>Be,IconPlus:()=>Ae,IconPreviewMergeFields:()=>Ee,IconPreviousArrow:()=>ke,IconPrint:()=>De,IconProjectLogo:()=>Se,IconQuote:()=>_e,IconRedo:()=>Te,IconRemove:()=>je,IconRemoveComment:()=>Oe,IconRemoveFormat:()=>Pe,IconReturnArrow:()=>Re,IconRevisionHistory:()=>Fe,IconRobotPencil:()=>Ne,IconSelectAll:()=>Ue,IconSettings:()=>We,IconShowBlocks:()=>$e,IconSource:()=>qe,IconSpecialCharacters:()=>Ke,IconStrikethrough:()=>Ge,IconSubmit:()=>Je,IconSubscript:()=>Qe,IconSuperscript:()=>Xe,IconTable:()=>na,IconTableCellProperties:()=>Ye,IconTableColumn:()=>ta,IconTableLayout:()=>oa,IconTableMergeCell:()=>ea,IconTableOfContents:()=>aa,IconTableProperties:()=>ia,IconTableRow:()=>la,IconTemplate:()=>ha,IconTemplateGeneric:()=>sa,IconText:()=>va,IconTextAlternative:()=>ra,IconThreeVerticalDots:()=>ca,IconTodoList:()=>da,IconTrackChanges:()=>pa,IconTrackChangesAccept:()=>ma,IconTrackChangesDiscard:()=>ga,IconUnderline:()=>wa,IconUndo:()=>ua,IconUnlink:()=>Ma,IconUploadcareImageEdit:()=>Ha,IconUploadcareImageUpload:()=>za,IconUploadcareLink:()=>Va,IconUser:()=>fa,IconWarning:()=>xa});var e=a("ckeditor5/src/core.js"),l=a("ckeditor5/src/widget.js");function n(t){return!!t&&t.is("element","drupalMedia")}function o(t){return(0,l.isWidget)(t)&&!!t.getCustomProperty("drupalMedia")}function s(t){const e=t.getSelectedElement();return n(e)?e:t.getFirstPosition().findAncestor("drupalMedia")}function h(t){const e=t.getSelectedElement();if(e&&o(e))return e;if(null===t.getFirstPosition())return null;let a=t.getFirstPosition().parent;for(;a;){if(a.is("element")&&o(a))return a;a=a.parent}return null}function r(t){const e=typeof t;return null!=t&&("object"===e||"function"===e)}function v(t){for(const e of t){if(e.hasAttribute("data-drupal-media-preview"))return e;if(e.childCount){const t=v(e.getChildren());if(t)return t}}return null}function c(t){return`drupalElementStyle${t[0].toUpperCase()+t.substring(1)}`}class d extends e.Command{execute(t){const e=this.editor.plugins.get("DrupalMediaEditing"),a=Object.entries(e.attrs).reduce(((t,[e,a])=>(t[a]=e,t)),{}),i=Object.keys(t).reduce(((e,i)=>(a[i]&&(e[a[i]]=t[i]),e)),{});if(this.editor.plugins.has("DrupalElementStyleEditing")){const e=this.editor.plugins.get("DrupalElementStyleEditing"),{normalizedStyles:a}=e;for(const l of Object.keys(a))for(const a of e.normalizedStyles[l])if(t[a.attributeName]&&a.attributeValue===t[a.attributeName]){const t=c(l);i[t]=a.name}}this.editor.model.change((t=>{this.editor.model.insertObject(function(t,e){return t.createElement("drupalMedia",e)}(t,i))}))}refresh(){const t=this.editor.model,e=t.document.selection,a=t.schema.findAllowedParent(e.getFirstPosition(),"drupalMedia");this.isEnabled=null!==a}}const m="METADATA_ERROR";class g extends e.Plugin{static get requires(){return[l.Widget]}constructor(t){super(t),this.attrs={drupalMediaAlt:"alt",drupalMediaEntityType:"data-entity-type",drupalMediaEntityUuid:"data-entity-uuid"},this.converterAttributes=["drupalMediaEntityUuid","drupalElementStyleViewMode","drupalMediaEntityType","drupalMediaAlt"]}init(){const t=this.editor.config.get("drupalMedia");if(!t)return;const{previewURL:e,themeError:a}=t;this.previewUrl=e,this.labelError=Drupal.t("Preview failed"),this.themeError=a||`\n <p>${Drupal.t("An error occurred while trying to preview the media. Save your work and reload this page.")}<p>\n `,this._defineSchema(),this._defineConverters(),this._defineListeners(),this.editor.commands.add("insertDrupalMedia",new d(this.editor))}upcastDrupalMediaIsImage(t){const{model:e,plugins:a}=this.editor;a.get("DrupalMediaMetadataRepository").getMetadata(t).then((a=>{t&&e.enqueueChange({isUndoable:!1},(e=>{e.setAttribute("drupalMediaIsImage",!!a.imageSourceMetadata,t)}))})).catch((a=>{t&&(console.warn(a.toString()),e.enqueueChange({isUndoable:!1},(e=>{e.setAttribute("drupalMediaIsImage",m,t)})))}))}upcastDrupalMediaType(t){this.editor.plugins.get("DrupalMediaMetadataRepository").getMetadata(t).then((e=>{t&&this.editor.model.enqueueChange({isUndoable:!1},(a=>{a.setAttribute("drupalMediaType",e.type,t)}))})).catch((e=>{t&&(console.warn(e.toString()),this.editor.model.enqueueChange({isUndoable:!1},(e=>{e.setAttribute("drupalMediaType",m,t)})))}))}async _fetchPreview(t){const e={text:this._renderElement(t),uuid:t.getAttribute("drupalMediaEntityUuid")},a=await fetch(`${this.previewUrl}?${new URLSearchParams(e)}`,{headers:{"X-Drupal-MediaPreview-CSRF-Token":this.editor.config.get("drupalMedia").previewCsrfToken}});if(a.ok){return{label:a.headers.get("drupal-media-label"),preview:await a.text()}}return{label:this.labelError,preview:this.themeError}}_defineSchema(){this.editor.model.schema.register("drupalMedia",{inheritAllFrom:"$blockObject",allowAttributes:Object.keys(this.attrs)}),this.editor.editing.view.domConverter.blockElements.push("drupal-media")}_defineConverters(){const t=this.editor.conversion,e=this.editor.plugins.get("DrupalMediaMetadataRepository");t.for("upcast").elementToElement({view:{name:"drupal-media"},model:"drupalMedia"}).add((t=>{t.on("element:drupal-media",((t,a)=>{const[i]=a.modelRange.getItems();e.getMetadata(i).then((t=>{i&&(this.upcastDrupalMediaIsImage(i),this.editor.model.enqueueChange({isUndoable:!1},(e=>{e.setAttribute("drupalMediaType",t.type,i)})))})).catch((t=>{console.warn(t.toString())}))}),{priority:"lowest"})})),t.for("dataDowncast").elementToElement({model:"drupalMedia",view:{name:"drupal-media"}}),t.for("editingDowncast").elementToElement({model:"drupalMedia",view:(t,{writer:e})=>{const a=e.createContainerElement("figure",{class:"drupal-media"});if(!this.previewUrl){const t=e.createRawElement("div",{"data-drupal-media-preview":"unavailable"});e.insert(e.createPositionAt(a,0),t)}return e.setCustomProperty("drupalMedia",!0,a),(0,l.toWidget)(a,e,{label:Drupal.t("Media widget")})}}).add((t=>{const e=(t,e,a)=>{const i=a.writer,l=e.item,n=a.mapper.toViewElement(e.item);let o=v(n.getChildren());if(o){if("ready"!==o.getAttribute("data-drupal-media-preview"))return;i.setAttribute("data-drupal-media-preview","loading",o)}else o=i.createRawElement("div",{"data-drupal-media-preview":"loading"}),i.insert(i.createPositionAt(n,0),o);this._fetchPreview(l).then((({label:t,preview:e})=>{o&&this.editor.editing.view.change((a=>{const i=a.createRawElement("div",{"data-drupal-media-preview":"ready","aria-label":t},(t=>{t.innerHTML=e}));a.insert(a.createPositionBefore(o),i),a.remove(o)}))}))};return this.converterAttributes.forEach((a=>{t.on(`attribute:${a}:drupalMedia`,e)})),t})),t.for("editingDowncast").add((t=>{t.on("attribute:drupalElementStyleAlign:drupalMedia",((t,e,a)=>{const i={left:"drupal-media-style-align-left",right:"drupal-media-style-align-right",center:"drupal-media-style-align-center"},l=a.mapper.toViewElement(e.item),n=a.writer;i[e.attributeOldValue]&&n.removeClass(i[e.attributeOldValue],l),i[e.attributeNewValue]&&a.consumable.consume(e.item,t.name)&&n.addClass(i[e.attributeNewValue],l)}))})),Object.keys(this.attrs).forEach((e=>{const a={model:{key:e,name:"drupalMedia"},view:{name:"drupal-media",key:this.attrs[e]}};t.for("dataDowncast").attributeToAttribute(a),t.for("upcast").attributeToAttribute(a)}))}_defineListeners(){this.editor.model.on("insertContent",((t,[e])=>{n(e)&&(this.upcastDrupalMediaIsImage(e),this.upcastDrupalMediaType(e))}))}_renderElement(t){const e=this.editor.model.change((e=>{const a=e.createDocumentFragment(),i=e.cloneElement(t,!1);return["linkHref"].forEach((t=>{e.removeAttribute(t,i)})),e.append(i,a),a}));return this.editor.data.stringify(e)}static get pluginName(){return"DrupalMediaEditing"}}var p=a("ckeditor5/src/ui.js");class w extends e.Plugin{init(){const t=this.editor,e=this.editor.config.get("drupalMedia");if(!e)return;const{libraryURL:a,openDialog:i,dialogSettings:l={}}=e;a&&"function"==typeof i&&t.ui.componentFactory.add("drupalMedia",(e=>{const n=t.commands.get("insertDrupalMedia"),o=new p.ButtonView(e);return o.set({label:Drupal.t("Insert Media"),icon:'<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M19.1873 4.86414L10.2509 6.86414V7.02335H10.2499V15.5091C9.70972 15.1961 9.01793 15.1048 8.34069 15.3136C7.12086 15.6896 6.41013 16.8967 6.75322 18.0096C7.09631 19.1226 8.3633 19.72 9.58313 19.344C10.6666 19.01 11.3484 18.0203 11.2469 17.0234H11.2499V9.80173L18.1803 8.25067V14.3868C17.6401 14.0739 16.9483 13.9825 16.2711 14.1913C15.0513 14.5674 14.3406 15.7744 14.6836 16.8875C15.0267 18.0004 16.2937 18.5978 17.5136 18.2218C18.597 17.8877 19.2788 16.8982 19.1773 15.9011H19.1803V8.02687L19.1873 8.0253V4.86414Z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M13.5039 0.743652H0.386932V12.1603H13.5039V0.743652ZM12.3379 1.75842H1.55289V11.1454H1.65715L4.00622 8.86353L6.06254 10.861L9.24985 5.91309L11.3812 9.22179L11.7761 8.6676L12.3379 9.45621V1.75842ZM6.22048 4.50869C6.22048 5.58193 5.35045 6.45196 4.27722 6.45196C3.20398 6.45196 2.33395 5.58193 2.33395 4.50869C2.33395 3.43546 3.20398 2.56543 4.27722 2.56543C5.35045 2.56543 6.22048 3.43546 6.22048 4.50869Z"/></svg>\n',tooltip:!0}),o.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(o,"execute",(()=>{i(a,(({attributes:e})=>{t.execute("insertDrupalMedia",e)}),l)})),o}))}}class u extends e.Plugin{static get requires(){return[l.WidgetToolbarRepository]}static get pluginName(){return"DrupalMediaToolbar"}afterInit(){const{editor:t}=this;var e;t.plugins.get(l.WidgetToolbarRepository).register("drupalMedia",{ariaLabel:Drupal.t("Drupal Media toolbar"),items:(e=t.config.get("drupalMedia.toolbar"),e.map((t=>r(t)?t.name:t))||[]),getRelatedElement:t=>h(t)})}}class M extends e.Command{refresh(){const t=s(this.editor.model.document.selection);this.isEnabled=t?.getAttribute("drupalMediaIsImage")&&t.getAttribute("drupalMediaIsImage")!==m,this.isEnabled?this.value=t.getAttribute("drupalMediaAlt"):this.value=!1}execute(t){const{model:e}=this.editor,a=s(e.document.selection);t.newValue=t.newValue.trim(),e.change((e=>{t.newValue.length>0?e.setAttribute("drupalMediaAlt",t.newValue,a):e.removeAttribute("drupalMediaAlt",a)}))}}class H extends e.Plugin{init(){this._data=new WeakMap}getMetadata(t){if(this._data.get(t))return new Promise((e=>{e(this._data.get(t))}));const e=this.editor.config.get("drupalMedia");if(!e)return new Promise(((t,e)=>{e(new Error("drupalMedia configuration is required for parsing metadata."))}));if(!t.hasAttribute("drupalMediaEntityUuid"))return new Promise(((t,e)=>{e(new Error("drupalMedia element must have drupalMediaEntityUuid attribute to retrieve metadata."))}));const{metadataUrl:a}=e;return(async t=>{const e=await fetch(t);if(e.ok)return JSON.parse(await e.text());throw new Error("Fetching media embed metadata from the server failed.")})(`${a}&${new URLSearchParams({uuid:t.getAttribute("drupalMediaEntityUuid")})}`).then((e=>(this._data.set(t,e),e)))}static get pluginName(){return"DrupalMediaMetadataRepository"}}class z extends e.Plugin{static get requires(){return[H]}static get pluginName(){return"MediaImageTextAlternativeEditing"}init(){const{editor:t,editor:{model:e,conversion:a}}=this;e.schema.extend("drupalMedia",{allowAttributes:["drupalMediaIsImage"]}),a.for("editingDowncast").add((t=>{t.on("attribute:drupalMediaIsImage",((t,e,a)=>{const{writer:i,mapper:l}=a,n=l.toViewElement(e.item);if(e.attributeNewValue!==m){const t=Array.from(n.getChildren()).find((t=>t.getCustomProperty("drupalMediaMetadataError")));return void(t&&(i.setCustomProperty("widgetLabel",t.getCustomProperty("drupalMediaOriginalWidgetLabel"),t),i.removeElement(t)))}const o=Drupal.t("Not all functionality may be available because some information could not be retrieved."),s=new p.Template({tag:"span",children:[{tag:"span",attributes:{class:"drupal-media__metadata-error-icon","data-cke-tooltip-text":o}}]}).render(),h=i.createRawElement("div",{class:"drupal-media__metadata-error"},((t,e)=>{e.setContentOf(t,s.outerHTML)}));i.setCustomProperty("drupalMediaMetadataError",!0,h);const r=n.getCustomProperty("widgetLabel");i.setCustomProperty("drupalMediaOriginalWidgetLabel",r,h),i.setCustomProperty("widgetLabel",`${r} (${o})`,n),i.insert(i.createPositionAt(n,0),h)}),{priority:"low"})})),t.commands.add("mediaImageTextAlternative",new M(this.editor))}}const V='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10 6.628a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"/><path d="M8.5 9.125a.3.3 0 0 0-.253-.296L5.11 8.327a.75.75 0 1 1 .388-1.449l4.04.716c.267.072.624.08.893.009l4.066-.724a.75.75 0 1 1 .388 1.45l-3.132.5a.3.3 0 0 0-.253.296v1.357a.3.3 0 0 0 .018.102l1.615 4.438a.75.75 0 0 1-1.41.513l-1.35-3.71a.3.3 0 0 0-.281-.197h-.209a.3.3 0 0 0-.282.198l-1.35 3.711a.75.75 0 0 1-1.41-.513l1.64-4.509a.3.3 0 0 0 .019-.103V9.125Z"/><path clip-rule="evenodd" d="M10 18.5a8.5 8.5 0 1 1 0-17 8.5 8.5 0 0 1 0 17Zm0 1.5c5.523 0 10-4.477 10-10S15.523 0 10 0 0 4.477 0 10s4.477 10 10 10Z"/></svg>',f='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M4 1.5h12A3.5 3.5 0 0 1 19.5 5v8l-.005.192a3.5 3.5 0 0 1-2.927 3.262l-.062.008v1.813a1.5 1.5 0 0 1-2.193 1.33l-.371-.193-.38-.212a13.452 13.452 0 0 1-3.271-2.63l-.062-.07H4A3.5 3.5 0 0 1 .5 13V5A3.5 3.5 0 0 1 4 1.5ZM4 3a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6.924a11.917 11.917 0 0 0 3.71 3.081l.372.194v-3.268L14.962 15H16a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H4Z"/><path d="M9.75 5a.75.75 0 0 0-.75.75v2.5H6.5a.75.75 0 0 0 0 1.5H9v2.5a.75.75 0 0 0 1.5 0v-2.5H13a.75.75 0 0 0 0-1.5h-2.5v-2.5A.75.75 0 0 0 9.75 5Z"/></svg>',x='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m9.239 13.938-2.88-1.663a.75.75 0 0 1 .75-1.3L9 12.067V4.75a.75.75 0 1 1 1.5 0v7.318l1.89-1.093a.75.75 0 0 1 .75 1.3l-2.879 1.663a.752.752 0 0 1-.511.187.752.752 0 0 1-.511-.187zM4.25 17a.75.75 0 1 1 0-1.5h10.5a.75.75 0 0 1 0 1.5H4.25z"/></svg>',Z='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm2.286 4c0 .414.336.75.75.75h9.928a.75.75 0 1 0 0-1.5H5.036a.75.75 0 0 0-.75.75zm0-8c0 .414.336.75.75.75h9.928a.75.75 0 1 0 0-1.5H5.036a.75.75 0 0 0-.75.75z"/></svg>',b='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 4c0 .414.336.75.75.75h9.929a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0-8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75z"/></svg>',L='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 4c0 .414.336.75.75.75h9.929a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0-8c0 .414.336.75.75.75h9.929a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75z"/></svg>',C='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M9.75 11.875a.752.752 0 0 1 .508.184l2.883 1.666a.75.75 0 0 1-.659 1.344l-.091-.044-1.892-1.093.001 4.318a.75.75 0 1 1-1.5 0v-4.317l-1.89 1.092a.75.75 0 0 1-.75-1.3l2.879-1.663a.752.752 0 0 1 .51-.187zM15.25 9a.75.75 0 1 1 0 1.5H4.75a.75.75 0 1 1 0-1.5h10.5zM9.75.375a.75.75 0 0 1 .75.75v4.318l1.89-1.093.092-.045a.75.75 0 0 1 .659 1.344l-2.883 1.667a.752.752 0 0 1-.508.184.752.752 0 0 1-.511-.187L6.359 5.65a.75.75 0 0 1 .75-1.299L9 5.442V1.125a.75.75 0 0 1 .75-.75z"/></svg>',I='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M18 3.75a.75.75 0 0 1-.75.75H2.75a.75.75 0 1 1 0-1.5h14.5a.75.75 0 0 1 .75.75zm0 8a.75.75 0 0 1-.75.75H2.75a.75.75 0 1 1 0-1.5h14.5a.75.75 0 0 1 .75.75zm0 4a.75.75 0 0 1-.75.75H7.321a.75.75 0 1 1 0-1.5h9.929a.75.75 0 0 1 .75.75zm0-8a.75.75 0 0 1-.75.75H7.321a.75.75 0 1 1 0-1.5h9.929a.75.75 0 0 1 .75.75z"/></svg>',y='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m10.261 7.062 2.88 1.663a.75.75 0 0 1-.75 1.3L10.5 8.933v7.317a.75.75 0 1 1-1.5 0V8.932l-1.89 1.093a.75.75 0 0 1-.75-1.3l2.879-1.663a.752.752 0 0 1 .511-.187.752.752 0 0 1 .511.187zM15.25 4a.75.75 0 1 1 0 1.5H4.75a.75.75 0 0 1 0-1.5h10.5z"/></svg>',B='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10 .75a9.25 9.25 0 1 1 0 18.5 9.25 9.25 0 0 1 0-18.5zm0 1.5a7.75 7.75 0 1 0 0 15.5 7.75 7.75 0 0 0 0-15.5zm0 2.022a.75.75 0 0 1 .743.649l.007.101v8.165l2.714-2.705a.75.75 0 0 1 .977-.07l.084.072a.75.75 0 0 1 .07.976l-.072.084-3.994 3.981a.75.75 0 0 1-.975.073l-.084-.073-3.99-3.98a.75.75 0 0 1 .975-1.135l.085.072 2.71 2.706V5.022a.75.75 0 0 1 .75-.75z"/></svg>',A='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10 19.25a9.25 9.25 0 1 0 0-18.5 9.25 9.25 0 0 0 0 18.5zm0-1.5a7.75 7.75 0 1 1 0-15.5 7.75 7.75 0 0 1 0 15.5zm0-2.022a.75.75 0 0 0 .743-.649l.007-.101V6.813l2.714 2.705a.75.75 0 0 0 .977.07l.084-.072a.75.75 0 0 0 .07-.976l-.072-.084-3.994-3.981a.75.75 0 0 0-.975-.073l-.084.073-3.99 3.98a.75.75 0 0 0 .975 1.135l.085-.072 2.71-2.706v8.166c0 .414.336.75.75.75z"/></svg>',E='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10.187 17H5.773c-.637 0-1.092-.138-1.364-.415-.273-.277-.409-.718-.409-1.323V4.738c0-.617.14-1.062.419-1.332.279-.27.73-.406 1.354-.406h4.68c.69 0 1.288.041 1.793.124.506.083.96.242 1.36.478.341.197.644.447.906.75a3.262 3.262 0 0 1 .808 2.162c0 1.401-.722 2.426-2.167 3.075C15.05 10.175 16 11.315 16 13.01a3.756 3.756 0 0 1-2.296 3.504 6.1 6.1 0 0 1-1.517.377c-.571.073-1.238.11-2 .11zm-.217-6.217H7v4.087h3.069c1.977 0 2.965-.69 2.965-2.072 0-.707-.256-1.22-.768-1.537-.512-.319-1.277-.478-2.296-.478zM7 5.13v3.619h2.606c.729 0 1.292-.067 1.69-.2a1.6 1.6 0 0 0 .91-.765c.165-.267.247-.566.247-.897 0-.707-.26-1.176-.778-1.409-.519-.232-1.31-.348-2.375-.348H7z"/></svg>',k='<svg viewBox="0 0 14 16" xmlns="http://www.w3.org/2000/svg"><path class="ck-icon__fill" d="M2 14.436V2a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1v12.436a.5.5 0 0 1-.819.385l-3.862-3.2a.5.5 0 0 0-.638 0l-3.862 3.2A.5.5 0 0 1 2 14.436Z"/></svg>',D='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M5.68 3.417a.238.238 0 0 0-.24.236v12.66l3.793-3.102a1.215 1.215 0 0 1 1.534 0l3.793 3.103V3.654a.238.238 0 0 0-.24-.237H5.68ZM4 3.653C4 2.74 4.752 2 5.68 2h8.64c.928 0 1.68.74 1.68 1.653v13.164c0 1-1.185 1.547-1.967.908L10 14.426l-4.033 3.299c-.782.64-1.967.092-1.967-.908V3.653Z"/></svg>',S='<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M4.4 2.24c-.11 0-.2.092-.2.207v11.077l3.16-2.714a.975.975 0 0 1 1.28 0l3.16 2.714V2.447a.203.203 0 0 0-.2-.207H4.4ZM3 2.447C3 1.647 3.627 1 4.4 1h7.2c.773 0 1.4.648 1.4 1.447v11.518c0 .875-.988 1.354-1.64.794L8 11.873 4.64 14.76c-.652.56-1.64.081-1.64-.794V2.447Z"/></svg>',_='<svg viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M4.216 2.031a.503.503 0 0 0-.489.516v9.42l2.648-2.324a.938.938 0 0 1 1.25 0l2.648 2.324v-9.42a.503.503 0 0 0-.489-.516H4.216Zm-1.466.516C2.75 1.693 3.406 1 4.216 1h5.568c.81 0 1.466.693 1.466 1.547v9.42c0 .873-.965 1.351-1.602.793L7 10.436 4.352 12.76c-.637.558-1.602.08-1.602-.793v-9.42Z"/></svg>',T='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11.627 16.5zm5.873-.196zm0-7.001V8h-13v8.5h4.341c.191.54.457 1.044.785 1.5H2a1.5 1.5 0 0 1-1.5-1.5v-13A1.5 1.5 0 0 1 2 2h4.5a1.5 1.5 0 0 1 1.06.44L9.122 4H16a1.5 1.5 0 0 1 1.5 1.5v1A1.5 1.5 0 0 1 19 8v2.531a6.027 6.027 0 0 0-1.5-1.228zM16 6.5v-1H8.5l-2-2H2v13h1V8a1.5 1.5 0 0 1 1.5-1.5H16z"/><path d="M14.5 19.5a5 5 0 1 1 0-10 5 5 0 0 1 0 10zM15 14v-2h-1v2h-2v1h2v2h1v-2h2v-1h-2z"/></svg>',O='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M7 5.75c0 .414.336.75.75.75h9.5a.75.75 0 1 0 0-1.5h-9.5a.75.75 0 0 0-.75.75zm-6 0C1 4.784 1.777 4 2.75 4c.966 0 1.75.777 1.75 1.75 0 .966-.777 1.75-1.75 1.75C1.784 7.5 1 6.723 1 5.75zm6 9c0 .414.336.75.75.75h9.5a.75.75 0 1 0 0-1.5h-9.5a.75.75 0 0 0-.75.75zm-6 0c0-.966.777-1.75 1.75-1.75.966 0 1.75.777 1.75 1.75 0 .966-.777 1.75-1.75 1.75-.966 0-1.75-.777-1.75-1.75z"/></svg>',P='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.591 10.177 4.243 4.242a1 1 0 0 1-1.415 1.415l-4.242-4.243-4.243 4.243a1 1 0 0 1-1.414-1.415l4.243-4.242L4.52 5.934A1 1 0 0 1 5.934 4.52l4.243 4.243 4.242-4.243a1 1 0 1 1 1.415 1.414l-4.243 4.243z"/></svg>',j='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 16h9a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2z"/><path d="M17 1a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h14zm0 1.5H3a.5.5 0 0 0-.492.41L2.5 3v9a.5.5 0 0 0 .41.492L3 12.5h14a.5.5 0 0 0 .492-.41L17.5 12V3a.5.5 0 0 0-.41-.492L17 2.5z" fill-opacity=".6"/></svg>',R='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M5.789 3 0 17h1.664l1.664-4.027h6.797l.227.548c.046-.172.112-.352.209-.545.217-.436.556-.609.898-.798L7.664 3H5.79Zm.938 1.758 2.777 6.715H3.949l2.778-6.715Z"/><path d="M15.956 7.5c-1.584-.02-3.226.824-3.843 2.882l1.495.106c.904-2.082 4.594-2.13 4.375.534-3.245 1.024-4.838.117-6.082 2.62-.208.418-.17 1.57.54 2.397.71.826 2.014 1.149 3.409.85 1.395-.299 2.24-1.386 2.24-1.386L18.205 17h1.493l-.059-1.72-.056-5.274C19.51 8.612 17.75 7.524 15.956 7.5Zm2.027 4.696s.641 2.453-1.528 3.27c-3.376 1.269-4.188-2.141-1.775-2.638 1.704-.352 1.873-.25 3.303-.632Z"/></svg>',F='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6.972 16.615a.997.997 0 0 1-.744-.292l-4.596-4.596a1 1 0 1 1 1.414-1.414l3.926 3.926 9.937-9.937a1 1 0 0 1 1.414 1.415L7.717 16.323a.997.997 0 0 1-.745.292z"/></svg>',N='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M16.435 5.506a.75.75 0 0 1 1.197.899l-.067.089-6.992 8a.75.75 0 0 1-1.05.078l-.079-.078-7.008-8a.75.75 0 0 1 1.049-1.066l.08.078 6.442 7.354 6.428-7.354z"/></svg>',U='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M16.435 14.494a.75.75 0 0 0 1.197-.899l-.067-.089-6.992-8a.75.75 0 0 0-1.05-.078l-.079.078-7.008 8a.75.75 0 0 0 1.049 1.066l.08-.078 6.442-7.354 6.428 7.354z"/></svg>',W='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M1.201 1C.538 1 0 1.47 0 2.1v14.363c0 .64.534 1.037 1.186 1.037H5.06l5.058-5.078L6.617 9.15a.696.696 0 0 0-.957-.033L1.5 13.6V2.5h15v4.354a3.478 3.478 0 0 1 1.5.049V2.1c0-.63-.547-1.1-1.2-1.1H1.202Zm11.713 2.803a2.147 2.147 0 0 0-2.049 1.992 2.14 2.14 0 0 0 1.28 2.096 2.13 2.13 0 0 0 2.642-3.11 2.129 2.129 0 0 0-1.873-.978ZM8.089 17.635v2.388h2.389l7.046-7.046-2.39-2.39-7.045 7.048Zm11.282-6.507a.637.637 0 0 0 .139-.692.603.603 0 0 0-.139-.205l-1.49-1.488a.63.63 0 0 0-.899 0l-1.166 1.163 2.39 2.39 1.165-1.168Z"/></svg>',$='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M12.87 12.61a.75.75 0 0 1-.089.976l-.085.07-3.154 2.254 3.412 2.414a.75.75 0 0 1 .237.95l-.057.095a.75.75 0 0 1-.95.237l-.096-.058-4.272-3.022-.003-1.223 4.01-2.867a.75.75 0 0 1 1.047.174zm2.795-.231.095.057 4.011 2.867-.003 1.223-4.272 3.022-.095.058a.75.75 0 0 1-.88-.151l-.07-.086-.058-.095a.75.75 0 0 1 .15-.88l.087-.07 3.412-2.414-3.154-2.253-.085-.071a.75.75 0 0 1 .862-1.207zM16 0a2 2 0 0 1 2 2v9.354l-.663-.492-.837-.001V2a.5.5 0 0 0-.5-.5H2a.5.5 0 0 0-.5.5v15a.5.5 0 0 0 .5.5h3.118L7.156 19H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h14zM5.009 15l.003 1H3v-1h2.009zm2.188-2-1.471 1H5v-1h2.197zM10 11v.095L8.668 12H7v-1h3zm4-2v1H7V9h7zm0-2v1H7V7h7zm-4-2v1H5V5h5zM6 3v1H3V3h3z"/></svg>',q='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m12.5 5.7 5.2 3.9v1.3l-5.6 4c-.1.2-.3.2-.5.2-.3-.1-.6-.7-.6-1l.3-.4 4.7-3.5L11.5 7l-.2-.2c-.1-.3-.1-.6 0-.8.2-.2.5-.4.8-.4a.8.8 0 0 1 .4.1zm-5.2 0L2 9.6v1.3l5.6 4c.1.2.3.2.5.2.3-.1.7-.7.6-1 0-.1 0-.3-.2-.4l-5-3.5L8.2 7l.2-.2c.1-.3.1-.6 0-.8-.2-.2-.5-.4-.8-.4a.8.8 0 0 0-.3.1z"/></svg>',K='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.333 2 .19 2.263a5.899 5.899 0 0 1 1.458.604L14.714 3.4 16.6 5.286l-1.467 1.733c.263.452.468.942.605 1.46L18 8.666v2.666l-2.263.19a5.899 5.899 0 0 1-.604 1.458l1.467 1.733-1.886 1.886-1.733-1.467a5.899 5.899 0 0 1-1.46.605L11.334 18H8.667l-.19-2.263a5.899 5.899 0 0 1-1.458-.604L5.286 16.6 3.4 14.714l1.467-1.733a5.899 5.899 0 0 1-.604-1.458L2 11.333V8.667l2.262-.189a5.899 5.899 0 0 1 .605-1.459L3.4 5.286 5.286 3.4l1.733 1.467a5.899 5.899 0 0 1 1.46-.605L8.666 2h2.666zM10 6.267a3.733 3.733 0 1 0 0 7.466 3.733 3.733 0 0 0 0-7.466z"/></svg>',G='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10.209 18.717A8.5 8.5 0 1 1 18.686 9.6h-.008l.002.12a3 3 0 0 1-2.866 2.997h-.268l-.046-.002v.002h-4.791a2 2 0 1 0 0 4 1 1 0 1 1-.128 1.992 8.665 8.665 0 0 1-.372.008Zm-3.918-7.01a1.25 1.25 0 1 0-2.415-.648 1.25 1.25 0 0 0 2.415.647ZM5.723 8.18a1.25 1.25 0 1 0 .647-2.414 1.25 1.25 0 0 0-.647 2.414ZM9.76 6.155a1.25 1.25 0 1 0 .647-2.415 1.25 1.25 0 0 0-.647 2.415Zm4.028 1.759a1.25 1.25 0 1 0 .647-2.415 1.25 1.25 0 0 0-.647 2.415Z"/></svg>',J='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path class="ck-icon__fill" d="M16.935 5.328a2 2 0 0 1 0 2.829l-7.778 7.778a2 2 0 0 1-2.829 0L3.5 13.107a1.999 1.999 0 1 1 2.828-2.829l.707.707a1 1 0 0 0 1.414 0l5.658-5.657a2 2 0 0 1 2.828 0z"/><path d="M14.814 6.035 8.448 12.4a1 1 0 0 1-1.414 0l-1.413-1.415A1 1 0 1 0 4.207 12.4l2.829 2.829a1 1 0 0 0 1.414 0l7.778-7.778a1 1 0 1 0-1.414-1.415z"/></svg>',Q='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M14 3.5A3.5 3.5 0 0 1 17.5 7v6l-.005.192a3.501 3.501 0 0 1-2.927 3.262l-.062.008v1.813a1.5 1.5 0 0 1-2.193 1.33l-.37-.193-.38-.212a13.452 13.452 0 0 1-3.272-2.63l-.062-.07-4.729-.046a3.5 3.5 0 0 1-3.5-3.5v-6a3.5 3.5 0 0 1 3.5-3.5L14 3.5ZM3.5 4.954a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2L8.924 15a11.917 11.917 0 0 0 3.71 3.081l.372.194v-3.268L12.962 15H14a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2L3.5 4.954Z"/><path d="M16.5.5h-10a3.5 3.5 0 0 0-3.162 2h1.84A2 2 0 0 1 6.5 2h10a2 2 0 0 1 2 2v8.873a3.502 3.502 0 0 0 1.495-2.681L20 10V4A3.5 3.5 0 0 0 16.5.5Z"/><path clip-rule="evenodd" d="M12.013 7.453a.75.75 0 0 1 .034 1.06l-3.75 4a.75.75 0 0 1-1.045.048l-2.25-2a.75.75 0 0 1 .996-1.122l1.704 1.515 3.25-3.467a.75.75 0 0 1 1.061-.034Z"/></svg>',X='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M15.5 6.5a3.5 3.5 0 0 1 3.495 3.308L19 10v2a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-7a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1v-2l.005-.192A3.5 3.5 0 0 1 15.5 6.5zm0 7.5a.5.5 0 0 0-.492.41L15 14.5v2a.5.5 0 0 0 .992.09L16 16.5v-2a.5.5 0 0 0-.5-.5zm0-6a2 2 0 0 0-2 2v2h4v-2a2 2 0 0 0-2-2zm-9.25 8a.75.75 0 1 1 0 1.5H.75a.75.75 0 1 1 0-1.5h5.5zm0-5a.75.75 0 1 1 0 1.5H.75a.75.75 0 1 1 0-1.5h5.5zm3-5a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1 0-1.5h8.5zm6-5a.75.75 0 1 1 0 1.5H.75a.75.75 0 0 1 0-1.5h14.5z"/></svg>',Y='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6.25 16a.75.75 0 1 1 0 1.5H.75a.75.75 0 1 1 0-1.5h5.5zm0-5a.75.75 0 1 1 0 1.5H.75a.75.75 0 1 1 0-1.5h5.5zm3-5a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1 0-1.5h8.5zm6-5a.75.75 0 1 1 0 1.5H.75a.75.75 0 0 1 0-1.5h14.5zm.25 5.5a3.5 3.5 0 0 1 3.143 1.959.75.75 0 0 1-1.36.636A2 2 0 0 0 13.5 10v2H19a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-7a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1v-2l.005-.192A3.5 3.5 0 0 1 15.5 6.5zm0 7.5a.5.5 0 0 0-.492.41L15 14.5v2a.5.5 0 0 0 .992.09L16 16.5v-2a.5.5 0 0 0-.5-.5z"/></svg>',tt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M5 2.801a.7.7 0 0 0-.7.7v11.5a.8.8 0 0 1-1.6 0v-11.5a2.3 2.3 0 0 1 2.3-2.3h6.5a.8.8 0 0 1 0 1.6H5Zm.7 3.7a2.3 2.3 0 0 1 2.3-2.3h7a2.3 2.3 0 0 1 2.3 2.3v10a2.3 2.3 0 0 1-2.3 2.3H8a2.3 2.3 0 0 1-2.3-2.3v-10Zm2.3-.7a.7.7 0 0 0-.7.7v10a.7.7 0 0 0 .7.7h7a.7.7 0 0 0 .7-.7v-10a.7.7 0 0 0-.7-.7H8Z"/></svg>',et='<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M4 0v1H1v3H0V.5A.5.5 0 0 1 .5 0H4zm8 0h3.5a.5.5 0 0 1 .5.5V4h-1V1h-3V0zM4 16H.5a.5.5 0 0 1-.5-.5V12h1v3h3v1zm8 0v-1h3v-3h1v3.5a.5.5 0 0 1-.5.5H12z"/><path fill-opacity=".256" d="M1 1h14v14H1z"/><g class="ck-icon__selected-indicator"><path d="M7 0h2v1H7V0zM0 7h1v2H0V7zm15 0h1v2h-1V7zm-8 8h2v1H7v-1z"/><path fill-opacity=".254" d="M1 1h14v14H1z"/></g></svg>',at='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M5 3.25a1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0-3 0"/><path d="M12 3.25a1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0-3 0"/><path d="M5 10a1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0-3 0"/><path d="M12 10a1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0-3 0"/><path d="M5 16.75a1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0-3 0"/><path d="M12 16.75a1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0-3 0"/></svg>',it='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M5.972 3.115A.746.746 0 0 1 6.374 3c.14 0 .28.037.402.115l3.229 2.059 3.228-2.057a.75.75 0 0 1 .805 0l3.629 2.31h.002a.757.757 0 0 1 0 1.264h-.002L15.034 8.37l2.633 1.678h.002a.756.756 0 0 1 0 1.262h-.002l-3.63 2.312a.746.746 0 0 1-.161.076c.234.08.409.275.482.5a.75.75 0 0 1-.322.854l-3.629 2.308a.75.75 0 0 1-.805 0l-3.63-2.31a.75.75 0 0 1-.229-1.031l.076-.122h.022a.746.746 0 0 1 .32-.189.75.75 0 0 1-.19-.086l-3.63-2.312a.756.756 0 0 1 0-1.264l2.632-1.678-2.632-1.676a.757.757 0 0 1 0-1.263l3.63-2.313Zm2.64 2.946L6.374 4.635 4.136 6.06l2.238 1.423L8.612 6.06Zm7.262 0-2.236-1.426-2.239 1.426 2.237 1.423 2.238-1.423Zm-3.637 2.306-2.232-1.422-2.233 1.422 2.235 1.422 2.23-1.422Zm-3.625 2.31L6.374 9.253l-2.238 1.426 2.238 1.424 2.238-1.424Zm7.262 0-2.236-1.425-2.239 1.426 2.237 1.424 2.238-1.424Zm-2.64 2.944-3.23-2.056-3.228 2.056a.75.75 0 0 1-.185.084.724.724 0 0 1 .185.08l3.229 2.057 3.226-2.055a.827.827 0 0 1 .18-.084.746.746 0 0 1-.178-.082Z"/></svg>',lt='<svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg"><path d="M.941 4.523a.75.75 0 1 1 1.06-1.06l3.006 3.005 3.005-3.005a.75.75 0 1 1 1.06 1.06l-3.549 3.55a.75.75 0 0 1-1.168-.136L.941 4.523z"/></svg>',nt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 13.598v2.777h2.778l8.194-8.193-2.78-2.78L3 13.6v-.001zm13.12-7.566a.735.735 0 0 0 0-1.044l-1.734-1.73a.735.735 0 0 0-1.044 0L11.985 4.61l2.78 2.78 1.354-1.358z"/></svg>',ot='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M8.5 8.25a1.25 1.25 0 1 1-2.499.001A1.25 1.25 0 0 1 8.5 8.25Z"/><path clip-rule="evenodd" d="M14 8.25a1.25 1.25 0 1 1-2.499.001A1.25 1.25 0 0 1 14 8.25Z"/><path clip-rule="evenodd" d="M7.127 12.088a.75.75 0 1 0-1.254.824C6.88 14.444 8.423 15.25 10 15.25c1.578 0 3.12-.805 4.127-2.338a.75.75 0 0 0-1.254-.824C12.13 13.221 11.048 13.75 10 13.75c-1.047 0-2.13-.529-2.873-1.662Z"/><path d="M10 19a9 9 0 1 0 0-18 9 9 0 0 0 0 18Zm0-1.5a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15Z"/></svg>',st='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m8.636 9.531-2.758 3.94a.5.5 0 0 0 .122.696l3.224 2.284h1.314l2.636-3.736L8.636 9.53zm.288 8.451L5.14 15.396a2 2 0 0 1-.491-2.786l6.673-9.53a2 2 0 0 1 2.785-.49l3.742 2.62a2 2 0 0 1 .491 2.785l-7.269 10.053-2.147-.066z"/><path d="M4 18h5.523v-1H4zm-2 0h1v-1H2z"/></svg>',ht='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M9.9 4.385a1.2 1.2 0 0 0-.44.44h.002l-5.284 9.15a1.2 1.2 0 0 0 1.04 1.8h10.564a1.2 1.2 0 0 0 1.04-1.8l-5.282-9.15a1.2 1.2 0 0 0-1.64-.44Zm.05 8.363a.301.301 0 0 1 .115-.023h.9a.301.301 0 0 1 .3.3v.9a.3.3 0 0 1-.3.3h-.9a.3.3 0 0 1-.3-.3v-.9a.3.3 0 0 1 .185-.277Zm-.185-4.723a.3.3 0 0 1 .3-.3h.9a.3.3 0 0 1 .3.3v3.4a.3.3 0 0 1-.3.3h-.9a.301.301 0 0 1-.3-.3v-3.4Z"/></svg>',rt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M19 4.5 14 0H3v6.5h1.5v-5h8v5h5V11H19V4.5ZM14 2l3.3 3H14V2Z"/><path d="m12.452 18.5 1.25 1.5H3v-3h1.5v1.5h7.952Z"/><path d="M19.826 16.843a.75.75 0 1 0-1.152-.96L17.5 17.29V13H16v4.29l-1.174-1.408a.75.75 0 1 0-1.152.96l2.346 2.816a.95.95 0 0 0 1.46 0l2.346-2.815Z"/><path d="M1.63 14.24V12.3h.88c.66 0 1.14-.15 1.46-.45.32-.3.48-.71.48-1.24 0-.52-.15-.91-.44-1.2C3.7 9.15 3.28 9 2.69 9H0v5.24h1.63Zm.4-3h-.4v-1.17h.46c.3 0 .5.05.62.17.1.11.16.25.16.42 0 .16-.06.3-.19.41-.13.11-.34.16-.66.16l.01.01Zm5.7 3c.28 0 .6-.05.96-.14.26-.07.5-.21.73-.42.22-.2.4-.47.53-.77.12-.31.19-.75.19-1.3 0-.37-.04-.7-.13-1.02a2.3 2.3 0 0 0-.42-.84c-.19-.24-.43-.43-.72-.56C8.57 9.06 8.2 9 7.72 9h-2.4v5.24h2.41Zm-.4-1.19h-.4v-2.86h.4c.43 0 .73.1.91.3.18.2.27.59.27 1.14 0 .42-.04.73-.12.91a.76.76 0 0 1-.34.4c-.14.07-.38.11-.72.11Zm5.3 1.2V12.1h2.02v-1.06h-2.03v-.91H15V9h-4v5.24h1.62l.01.01Z"/></svg>',vt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M17.826 16.843a.75.75 0 0 0-1.152-.96L15.5 17.29V12H14v5.29l-1.174-1.408a.75.75 0 0 0-1.152.96l2.346 2.816a.95.95 0 0 0 1.46 0l2.346-2.815Z"/><path d="m14 0 5 4.5v9.741a2.737 2.737 0 0 0-1.5-.617V6.5h-5v-5h-8v3H3V0h11Zm0 2v3h3.3L14 2Z"/><path d="M3 17.5h6.746c.1.22.23.429.391.623l.731.877H3v-1.5Z"/><path d="M8.5 6a1.5 1.5 0 0 1 1.493 1.356L10 7.5v7a1.5 1.5 0 0 1-1.356 1.493L8.5 16h-7a1.5 1.5 0 0 1-1.493-1.356L0 14.5v-7a1.5 1.5 0 0 1 1.356-1.493L1.5 6h7ZM7.483 8.795l-.042.088-.986 2.534-.947-2.528-.043-.092a.601.601 0 0 0-1.042.008l-.042.093-.883 2.465-.937-2.475-.042-.089a.6.6 0 0 0-1.107.42l.027.093 1.514 4 .044.092a.6.6 0 0 0 1.041-.01l.041-.092.88-2.458.925 2.467.046.096a.6.6 0 0 0 1.032 0l.043-.09 1.554-4 .028-.093a.6.6 0 0 0-1.104-.43v.001Z"/></svg>',ct='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10.01 2C5.59 2 2 5.59 2 10.01a8.011 8.011 0 0 0 6.775 7.914.754.754 0 0 0 .598-.17.75.75 0 0 0 .262-.565v-5.02a.745.745 0 0 0-.22-.524.745.745 0 0 0-.526-.221H7.77v-.627h1.12a.745.745 0 0 0 .525-.22c.14-.14.22-.329.22-.526V8.324c0-.466.122-1.083.524-1.48.33-.326 1.017-.6 2.332-.43v.408c-.152.012-.305.017-.457.04-.335.048-.662.136-.943.326-.313.21-.497.505-.59.804-.093.3-.107.602-.107.88v1.18a.746.746 0 0 0 .744.746h1.158l-.098.63h-1.06a.744.744 0 0 0-.744.744v5.017a.752.752 0 0 0 .26.567c.081.07.177.119.28.148a.75.75 0 0 0 .319.022A8.012 8.012 0 0 0 10.01 2Zm0 1.486a6.52 6.52 0 0 1 6.521 6.524c0 2.945-1.973 5.386-4.65 6.197v-3.291h.951a.749.749 0 0 0 .736-.63l.332-2.12a.742.742 0 0 0-.17-.6.745.745 0 0 0-.564-.26h-1.285V8.87c0-.252.024-.384.039-.433.003-.008.002-.012.002-.016.016-.011.104-.055.326-.088a7 7 0 0 1 .984-.05.746.746 0 0 0 .528-.218.743.743 0 0 0 .217-.527V5.76a.747.747 0 0 0-.586-.729c-2.04-.438-3.433-.083-4.278.75-.818.807-.968 1.884-.968 2.543v.983H7.027a.744.744 0 0 0-.525.22.743.743 0 0 0-.219.526v2.119c0 .197.08.386.219.525.14.14.328.221.525.221h1.118v3.291c-2.681-.809-4.659-3.25-4.659-6.197a6.523 6.523 0 0 1 6.524-6.526Z"/></svg>',dt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m12.87 13.786 1.532-1.286 3.857 4.596a1 1 0 1 1-1.532 1.286l-3.857-4.596z"/><path d="M16.004 8.5a6.5 6.5 0 0 1-9.216 5.905c-1.154-.53-.863-1.415-.663-1.615.194-.194.564-.592 1.635-.141a4.5 4.5 0 0 0 5.89-5.904l-.104-.227 1.332-1.331c.045-.046.196-.041.224.007a6.47 6.47 0 0 1 .902 3.306zm-3.4-5.715c.562.305.742 1.106.354 1.494-.388.388-.995.414-1.476.178a4.5 4.5 0 0 0-6.086 5.882l.114.236-1.348 1.349c-.038.037-.17.022-.198-.023a6.5 6.5 0 0 1 5.54-9.9 6.469 6.469 0 0 1 3.1.784z"/><path d="M4.001 11.93.948 8.877a.2.2 0 0 1 .141-.341h6.106a.2.2 0 0 1 .141.341L4.283 11.93a.2.2 0 0 1-.282 0zm11.083-6.789 3.053 3.053a.2.2 0 0 1-.14.342H11.89a.2.2 0 0 1-.14-.342l3.052-3.053a.2.2 0 0 1 .282 0z"/></svg>',mt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M4 2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2zm8.38 9.262H7.62L10 5.506l2.38 5.756zm.532 1.285L14.34 16h1.426L10.804 4H9.196L4.234 16H5.66l1.428-3.453h5.824z"/></svg>',gt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M12.4 10.3 10 4.5l-2.4 5.8h4.8zm.5 1.2H7.1L5.7 15H4.2l5-12h1.6l5 12h-1.5L13 11.5zm3.1 7H4a1 1 0 0 1 0-2h12a1 1 0 0 1 0 2z"/></svg>',pt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11.03 3h6.149a.75.75 0 1 1 0 1.5h-5.514L11.03 3zm1.27 3h4.879a.75.75 0 1 1 0 1.5h-4.244L12.3 6zm1.27 3h3.609a.75.75 0 1 1 0 1.5h-2.973L13.57 9zm-2.754 2.5L8.038 4.785 5.261 11.5h5.555zm.62 1.5H4.641l-1.666 4.028H1.312l5.789-14h1.875l5.789 14h-1.663L11.436 13z"/></svg>',wt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M9.816 11.5 7.038 4.785 4.261 11.5h5.555zm.62 1.5H3.641l-1.666 4.028H.312l5.789-14h1.875l5.789 14h-1.663L10.436 13zm7.55 2.279.779-.779.707.707-2.265 2.265-2.193-2.265.707-.707.765.765V4.825c0-.042 0-.083.002-.123l-.77.77-.707-.707L17.207 2.5l2.265 2.265-.707.707-.782-.782c.002.043.003.089.003.135v10.454z"/></svg>',ut='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11.5 5.75a.75.75 0 0 1 0-1.5H15a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0V6.81l-2.72 2.72a.75.75 0 0 1-1.06-1.06l2.72-2.72H11.5Z"/><path d="M9.53 10.47a.75.75 0 0 1 0 1.06l-2.72 2.72H8.5a.75.75 0 0 1 0 1.5H5a.75.75 0 0 1-.75-.75v-3.5a.75.75 0 0 1 1.5 0v1.69l2.72-2.72a.75.75 0 0 1 1.06 0Z"/><path d="M2 0h16a2 2 0 0 1 2 2v16a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2Zm16 1.5H2a.5.5 0 0 0-.5.5v16a.5.5 0 0 0 .5.5h16a.5.5 0 0 0 .5-.5V2a.5.5 0 0 0-.5-.5Z"/></svg>',Mt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M15.53 5.53a.75.75 0 0 0-1.06-1.06l-2.72 2.72V5.5a.75.75 0 0 0-1.5 0V9a.75.75 0 0 0 .75.75h3.5a.75.75 0 0 0 0-1.5h-1.69l2.72-2.72Z"/><path d="M5.5 10.25a.75.75 0 0 0 0 1.5h1.69l-2.72 2.72a.75.75 0 1 0 1.06 1.06l2.72-2.72v1.69a.75.75 0 0 0 1.5 0V11a.75.75 0 0 0-.75-.75H5.5Z"/><path d="M0 2a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v16a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2Zm18.5 0a.5.5 0 0 0-.5-.5H2a.5.5 0 0 0-.5.5v16a.5.5 0 0 0 .5.5h16a.5.5 0 0 0 .5-.5V2Z"/></svg>',Ht='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M7.666 3a.736.736 0 0 0-.371.1.748.748 0 0 0-.275.267l-4.918 8.397a.743.743 0 0 0-.006.744l2.46 4.318a.747.747 0 0 0 .65.377h9.606a.754.754 0 0 0 .65-.377l2.46-4.318a.74.74 0 0 0 .002-.735l-4.688-8.392a.754.754 0 0 0-.654-.38H7.666Zm1.285 1.492h3.195l3.854 6.9h-3.1l-3.949-6.9Zm-1.293.742L9.223 7.97l-4.016 6.988-1.6-2.813 4.051-6.91Zm2.424 4.237 1.098 1.922H8.977l1.105-1.922ZM8.12 12.885h7.87l-1.61 2.825H6.494l1.625-2.826Z"/></svg>',zt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M9.258 3.082c0-.594.486-1.082 1.08-1.082a4.38 4.38 0 0 1 4.239 5.489c-.18.688-.633 1.245-1.109 1.767h3.468c.595 0 1.082.488 1.082 1.082a4.382 4.382 0 0 1-5.49 4.24v-.001c-.689-.18-1.246-.633-1.768-1.109v3.468c0 .595-.487 1.082-1.082 1.082a4.384 4.384 0 0 1-4.111-2.866 4.382 4.382 0 0 1-.125-2.624c.18-.689.632-1.246 1.108-1.768H3.082A1.085 1.085 0 0 1 2 9.68a4.382 4.382 0 0 1 5.49-4.238c.69.18 1.246.632 1.768 1.108V3.082Zm3.164 1.32c-.435-.46-1.043-.667-1.662-.767v5.49c.619-.1 1.227-.307 1.662-.766a2.875 2.875 0 0 0 0-3.958ZM7.21 6.918a2.876 2.876 0 0 0-2.93.789c-.396.423-.569.983-.658 1.55h5.56c-.045-.295-.091-.59-.224-.859a2.879 2.879 0 0 0-1.748-1.48Zm9.254 3.841h-5.653l.013.1c.012.098.025.197.053.292a2.873 2.873 0 0 0 4.862 1.158 2.87 2.87 0 0 0 .398-.54v-.001c.111-.195.2-.403.263-.619.026-.092.038-.188.05-.283l.014-.107Zm-8.872 4.86c.437.459 1.045.666 1.665.766V10.89c-1.369.222-2.456 1.314-2.456 2.747 0 .738.283 1.447.791 1.981Z"/></svg>',Vt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M19 9v10h-2v-8h-2V9h4zM4 8.5h5V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v11.5a1 1 0 0 1-1 1H10a1 1 0 0 1-1-1V11H4v4.5a1 1 0 0 1-1 1h-.5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1H3a1 1 0 0 1 1 1v4.5z"/></svg>',ft='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 8.5h5V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v11.5a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1V11H3v4.5a1 1 0 0 1-1 1h-.5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1H2a1 1 0 0 1 1 1v4.5zm16.076 8.343V18.5h-6.252c.067-.626.27-1.22.61-1.78.338-.561 1.006-1.305 2.005-2.232.804-.749 1.297-1.257 1.479-1.523.245-.368.368-.732.368-1.092 0-.398-.107-.703-.32-.917-.214-.214-.51-.32-.886-.32-.372 0-.669.111-.889.336-.22.224-.347.596-.38 1.117l-1.778-.178c.106-.982.438-1.686.997-2.114.558-.427 1.257-.64 2.095-.64.918 0 1.64.247 2.164.742.525.495.787 1.11.787 1.847 0 .419-.075.818-.225 1.197-.15.378-.388.775-.714 1.19-.216.275-.605.67-1.168 1.187-.563.516-.92.859-1.07 1.028a3.11 3.11 0 0 0-.365.495h3.542z"/></svg>',xt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 8.5h5V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v11.5a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1V11H3v4.5a1 1 0 0 1-1 1h-.5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1H2a1 1 0 0 1 1 1v4.5zm9.989 7.53 1.726-.209c.055.44.203.777.445 1.01.24.232.533.349.876.349.368 0 .678-.14.93-.42.251-.279.377-.655.377-1.13 0-.448-.12-.803-.362-1.066a1.153 1.153 0 0 0-.882-.393c-.228 0-.501.044-.819.133l.197-1.453c.482.012.85-.092 1.105-.315.253-.222.38-.517.38-.885 0-.313-.093-.563-.279-.75-.186-.185-.434-.278-.743-.278a1.07 1.07 0 0 0-.78.317c-.216.212-.347.52-.394.927l-1.644-.28c.114-.562.287-1.012.517-1.348.231-.337.553-.601.965-.794a3.24 3.24 0 0 1 1.387-.289c.876 0 1.579.28 2.108.838.436.457.653.973.653 1.549 0 .817-.446 1.468-1.339 1.955.533.114.96.37 1.28.768.319.398.478.878.478 1.441 0 .817-.298 1.513-.895 2.088-.596.576-1.339.864-2.228.864-.842 0-1.54-.243-2.094-.727-.555-.485-.876-1.118-.965-1.901z"/></svg>',Zt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3.5 8.5h5V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v11.5a1 1 0 0 1-1 1h-.5a1 1 0 0 1-1-1V11h-5v4.5a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v4.5zm13.55 10v-1.873h-3.81v-1.561l4.037-5.91h1.498v5.904h1.156v1.567h-1.156V18.5H17.05zm0-3.44v-3.18l-2.14 3.18h2.14z"/></svg>',bt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3.5 8.5h5V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v11.5a1 1 0 0 1-1 1h-.5a1 1 0 0 1-1-1V11h-5v4.5a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v4.5zm9.578 7.607 1.777-.184c.05.402.201.72.45.955a1.223 1.223 0 0 0 1.81-.101c.258-.303.387-.759.387-1.368 0-.572-.128-1-.384-1.286-.256-.285-.59-.428-1-.428-.512 0-.971.226-1.377.679l-1.448-.21.915-4.843h4.716v1.67H15.56l-.28 1.58a2.697 2.697 0 0 1 1.219-.298 2.68 2.68 0 0 1 2.012.863c.55.576.825 1.323.825 2.241a3.36 3.36 0 0 1-.666 2.05c-.605.821-1.445 1.232-2.52 1.232-.86 0-1.56-.23-2.101-.692-.542-.461-.866-1.081-.971-1.86z"/></svg>',Lt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3.5 8.5h5V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v11.5a1 1 0 0 1-1 1h-.5a1 1 0 0 1-1-1V11h-5v4.5a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v4.5zm15.595 2.973-1.726.19c-.043-.355-.153-.617-.33-.787-.178-.169-.409-.253-.692-.253-.377 0-.695.169-.956.507-.26.339-.424 1.043-.492 2.114.445-.525.997-.787 1.657-.787.745 0 1.383.284 1.914.85.531.568.797 1.3.797 2.197 0 .952-.28 1.716-.838 2.291-.559.576-1.276.864-2.152.864-.94 0-1.712-.365-2.317-1.095-.605-.73-.908-1.927-.908-3.59 0-1.705.316-2.935.946-3.688.63-.753 1.45-1.13 2.457-1.13.706 0 1.291.198 1.755.594.463.395.758.97.885 1.723zm-4.043 3.891c0 .58.133 1.028.4 1.343.266.315.57.473.914.473.33 0 .605-.13.825-.388.22-.258.33-.68.33-1.27 0-.604-.118-1.047-.355-1.329a1.115 1.115 0 0 0-.89-.422c-.342 0-.632.134-.869.403s-.355.666-.355 1.19z"/></svg>',Ct='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11 1a9 9 0 1 1-8.027 13.075l1.128-1.129A7.502 7.502 0 0 0 18.5 10a7.5 7.5 0 1 0-14.962.759l-.745-.746-.76.76A9 9 0 0 1 11 1z"/><path d="M.475 8.17a.75.75 0 0 1 .978.047l.075.082 1.284 1.643 1.681-1.284a.75.75 0 0 1 .978.057l.073.083a.75.75 0 0 1-.057.978l-.083.073-2.27 1.737a.75.75 0 0 1-.973-.052l-.074-.082-1.741-2.23a.75.75 0 0 1 .13-1.052z"/><path d="M11.5 5v4.999l3.196 3.196-1.06 1.06L10.1 10.72l-.1-.113V5z"/></svg>',It='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 9h16v2H2z"/></svg>',yt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M17 0a2 2 0 0 1 2 2v7a1 1 0 0 1 1 1v5a1 1 0 0 1-.883.993l-.118.006L19 17a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2l-.001-1.001-.116-.006A1 1 0 0 1 0 15v-5a1 1 0 0 1 .999-1L1 2a2 2 0 0 1 2-2h14zm.499 15.999h-15L2.5 17a.5.5 0 0 0 .5.5h14a.5.5 0 0 0 .5-.5l-.001-1.001zm-3.478-6.013-.014.014H14v.007l-1.525 1.525-1.46-1.46-.015.013V10h-1v5h1v-3.53l1.428 1.43.048.043.131-.129L14 11.421V15h1v-5h-.965l-.014-.014zM2 10H1v5h1v-2h2v2h1v-5H4v2H2v-2zm7 0H6v1h1v4h1v-4h1v-1zm8 0h-1v5h3v-1h-2v-4zm0-8.5H3a.5.5 0 0 0-.5.5l-.001 6.999h15L17.5 2a.5.5 0 0 0-.5-.5zM10 7v1H4V7h6zm3-2v1H4V5h9zm-3-2v1H4V3h6z"/></svg>',Bt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M1.201 1c-.662 0-1.2.47-1.2 1.1v14.248c0 .64.533 1.152 1.185 1.152h6.623v-7.236L6.617 9.15a.694.694 0 0 0-.957-.033L1.602 13.55V2.553l14.798.003V9.7H18V2.1c0-.63-.547-1.1-1.2-1.1H1.202Zm11.723 2.805a2.094 2.094 0 0 0-1.621.832 2.127 2.127 0 0 0 1.136 3.357 2.13 2.13 0 0 0 2.611-1.506 2.133 2.133 0 0 0-.76-2.244 2.13 2.13 0 0 0-1.366-.44Z"/><path clip-rule="evenodd" d="M19.898 12.369v6.187a.844.844 0 0 1-.844.844h-8.719a.844.844 0 0 1-.843-.844v-7.312a.844.844 0 0 1 .843-.844h2.531a.843.843 0 0 1 .597.248l.838.852h4.75c.223 0 .441.114.6.272a.844.844 0 0 1 .247.597Zm-1.52.654-4.377.02-1.1-1.143H11v6h7.4l-.023-4.877Z"/></svg>',At='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6.66 9.118a.693.693 0 0 1 .956.032l3.65 3.411 2.422-2.238a.695.695 0 0 1 .945 0L17.5 13.6V2.5h-15v11.1l4.16-4.482ZM17.8 1c.652 0 1.2.47 1.2 1.1v14.362c0 .64-.532 1.038-1.184 1.038H2.184C1.532 17.5 1 17.103 1 16.462V2.1C1 1.47 1.537 1 2.2 1h15.6Zm-5.655 6a2.128 2.128 0 0 1 .157-2.364A2.133 2.133 0 1 1 12.145 7Z"/></svg>',Et='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M1.201 1C.538 1 0 1.47 0 2.1v14.363c0 .64.534 1.037 1.186 1.037h9.494a2.97 2.97 0 0 1-.414-.287 2.998 2.998 0 0 1-1.055-2.03 3.003 3.003 0 0 1 .693-2.185l.383-.455-.02.018-3.65-3.41a.695.695 0 0 0-.957-.034L1.5 13.6V2.5h15v5.535a2.97 2.97 0 0 1 1.412.932l.088.105V2.1c0-.63-.547-1.1-1.2-1.1H1.202Zm11.713 2.803a2.146 2.146 0 0 0-2.049 1.992 2.14 2.14 0 0 0 1.28 2.096 2.13 2.13 0 0 0 2.644-3.11 2.134 2.134 0 0 0-1.875-.978Z"/><path d="M15.522 19.1a.79.79 0 0 0 .79-.79v-5.373l2.059 2.455a.79.79 0 1 0 1.211-1.015l-3.352-3.995a.79.79 0 0 0-.995-.179.784.784 0 0 0-.299.221l-3.35 3.99a.79.79 0 1 0 1.21 1.017l1.936-2.306v5.185c0 .436.353.79.79.79Z"/><path d="M15.522 19.1a.79.79 0 0 0 .79-.79v-5.373l2.059 2.455a.79.79 0 1 0 1.211-1.015l-3.352-3.995a.79.79 0 0 0-.995-.179.784.784 0 0 0-.299.221l-3.35 3.99a.79.79 0 1 0 1.21 1.017l1.936-2.306v5.185c0 .436.353.79.79.79Z"/></svg>',kt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M1.201 1C.538 1 0 1.47 0 2.1v14.363c0 .64.534 1.037 1.186 1.037h7.029a5.401 5.401 0 0 1 .615-4.338l.762-1.232-2.975-2.78a.696.696 0 0 0-.957-.033L1.5 13.6V2.5h15v6.023c.449.131.887.32 1.307.573l.058.033c.046.028.09.057.135.086V2.1c0-.63-.547-1.1-1.2-1.1H1.202Zm11.713 2.803a2.15 2.15 0 0 0-1.611.834 2.118 2.118 0 0 0-.438 1.158 2.14 2.14 0 0 0 1.277 2.096 2.132 2.132 0 0 0 2.645-3.11 2.13 2.13 0 0 0-1.873-.978Z"/><path d="M16.63 10.294a3.003 3.003 0 0 0-4.142.887l-.117.177a.647.647 0 0 0-.096.492.664.664 0 0 0 .278.418.7.7 0 0 0 .944-.234 1.741 1.741 0 0 1 2.478-.463 1.869 1.869 0 0 1 .476 2.55.637.637 0 0 0-.071.5.646.646 0 0 0 .309.396.627.627 0 0 0 .869-.19l.027-.041a3.226 3.226 0 0 0-.956-4.492Zm-6.061 3.78-.044.066a3.228 3.228 0 0 0 .82 4.403 3.005 3.005 0 0 0 4.275-.798l.13-.197a.626.626 0 0 0 .092-.475.638.638 0 0 0-.268-.402.713.713 0 0 0-.99.26l-.018.029a1.741 1.741 0 0 1-2.477.461 1.87 1.87 0 0 1-.475-2.55l.029-.047a.647.647 0 0 0 .086-.485.66.66 0 0 0-.275-.408l-.04-.027a.609.609 0 0 0-.845.17Z"/><path d="M15.312 13.925c.24-.36.154-.838-.19-1.067-.346-.23-.82-.124-1.059.236l-1.268 1.907c-.239.36-.153.838.192 1.067.345.23.818.123 1.057-.236l1.268-1.907Z"/></svg>',Dt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M19 4.5 14 0H3v12.673l.868-1.041c.185-.222.4-.402.632-.54V1.5h8v5h5v7.626a2.24 2.24 0 0 1 1.5.822V4.5ZM14 5V2l3.3 3H14Zm-3.692 12.5c.062.105.133.206.213.303L11.52 19H8v-.876a2.243 2.243 0 0 0 1.82-.624h.488Zm7.518-.657a.75.75 0 0 0-1.152-.96L15.5 17.29V12H14v5.29l-1.174-1.408a.75.75 0 0 0-1.152.96l2.346 2.816a.95.95 0 0 0 1.46 0l2.346-2.815Zm-15.056-.38a.75.75 0 0 1-.096-1.056l2.346-2.815a.95.95 0 0 1 1.46 0l2.346 2.815a.75.75 0 1 1-1.152.96L6.5 14.96V20H5v-5.04l-1.174 1.408a.75.75 0 0 1-1.056.096Z"/></svg>',St='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m14 0 5 4.5v8.892l-1.5-1.8V6.5h-5v-5h-8v3H3V0h11Zm0 2v3h3.3L14 2Z"/><path d="M10.74 18a2.76 2.76 0 0 1-.469-.5H3V19h9.25v-.374A2.737 2.737 0 0 1 10.74 18Z"/><path d="M8.5 6a1.5 1.5 0 0 1 1.493 1.356L10 7.5v7a1.5 1.5 0 0 1-1.356 1.493L8.5 16h-7a1.5 1.5 0 0 1-1.493-1.356L0 14.5v-7a1.5 1.5 0 0 1 1.356-1.493L1.5 6h7ZM7.483 8.795l-.042.088-.986 2.534-.947-2.528-.043-.092a.601.601 0 0 0-1.042.008l-.042.093-.883 2.465-.937-2.475-.042-.089a.6.6 0 0 0-1.107.42l.027.093 1.514 4 .044.092a.6.6 0 0 0 1.041-.01l.041-.092.88-2.458.925 2.467.046.096a.602.602 0 0 0 1.032 0l.043-.09 1.554-4 .028-.093a.6.6 0 0 0-1.104-.43v.001Zm4.191 6.612a.75.75 0 1 0 1.152.96L14 14.96V20h1.5v-5.04l1.174 1.408a.75.75 0 1 0 1.152-.96l-2.346-2.816a.95.95 0 0 0-1.46 0l-2.346 2.815Z"/></svg>',_t='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm5 6c0 .414.336.75.75.75h9.5a.75.75 0 1 0 0-1.5h-9.5a.75.75 0 0 0-.75.75zM2.75 16.5h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 1 0 0 1.5zM1.632 6.95 5.02 9.358a.4.4 0 0 1-.013.661l-3.39 2.207A.4.4 0 0 1 1 11.892V7.275a.4.4 0 0 1 .632-.326z"/></svg>',Tt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle cx="10.0001" cy="9.79993" r="1.5"/><path d="M13.25 2.75V2h.035a6.272 6.272 0 0 1 .363.014c.21.013.517.041.785.109.397.1.738.281 1.007.55.268.269.429.587.524.907.182.608.15 1.314.108 1.913l-.03.408c-.038.487-.073.93-.053 1.353.026.527.136.879.333 1.112.223.263.494.428.72.528a2.077 2.077 0 0 0 .335.117l.01.002.613.109v.628h-2.402a3.34 3.34 0 0 1-.42-.415c-.509-.601-.655-1.345-.687-2.009-.025-.527.02-1.094.059-1.592.01-.12.018-.236.026-.347.044-.621.044-1.067-.049-1.377a.63.63 0 0 0-.148-.276.642.642 0 0 0-.313-.157 3.134 3.134 0 0 0-.512-.066 6.026 6.026 0 0 0-.286-.01h-.016L13.25 3.5h-.75V2h.75v.75Z"/><path d="M13.25 16.75v.75h.035a6.852 6.852 0 0 0 .363-.014 4.55 4.55 0 0 0 .785-.109c.397-.1.738-.28 1.007-.55.268-.269.429-.587.524-.907.182-.608.15-1.314.108-1.912l-.03-.41c-.038-.486-.073-.93-.053-1.352.026-.527.136-.879.333-1.112.223-.263.494-.428.72-.528a2.08 2.08 0 0 1 .335-.117l.01-.002.613-.109V9.75h-2.402a3.341 3.341 0 0 0-.42.416c-.509.6-.655 1.344-.687 2.008-.025.527.02 1.095.059 1.592.01.12.018.236.026.347.044.621.044 1.067-.049 1.378a.63.63 0 0 1-.148.275.643.643 0 0 1-.313.157 3.213 3.213 0 0 1-.512.066 6.178 6.178 0 0 1-.286.01l-.016.001H12.5v1.5h.75v-.75Z"/><path d="M6.75 2.75V2h-.035a6.278 6.278 0 0 0-.363.014 4.55 4.55 0 0 0-.785.109 2.13 2.13 0 0 0-1.008.55 2.119 2.119 0 0 0-.524.907c-.181.608-.15 1.314-.108 1.913l.031.408c.038.487.073.93.052 1.353-.025.527-.136.879-.333 1.112a2.013 2.013 0 0 1-.718.528 2.072 2.072 0 0 1-.337.117l-.01.002L2 9.122v.628h2.402a3.28 3.28 0 0 0 .42-.415c.509-.601.654-1.345.686-2.009.026-.527-.019-1.094-.058-1.592-.01-.12-.019-.236-.026-.347-.044-.621-.044-1.067.048-1.377a.63.63 0 0 1 .149-.276.642.642 0 0 1 .312-.157c.13-.032.323-.054.513-.066a6.027 6.027 0 0 1 .286-.01h.015L6.75 3.5h.75V2h-.75v.75Z"/><path d="M6.75 16.75v.75h-.035a6.86 6.86 0 0 1-.363-.014 4.549 4.549 0 0 1-.785-.109 2.131 2.131 0 0 1-1.008-.55 2.119 2.119 0 0 1-.524-.907c-.181-.608-.15-1.314-.108-1.912l.031-.41c.038-.486.073-.93.052-1.352-.025-.527-.136-.879-.333-1.112a2.013 2.013 0 0 0-.718-.528 2.075 2.075 0 0 0-.337-.117l-.01-.002L2 10.378V9.75h2.402c.144.119.286.257.42.416.509.6.654 1.344.686 2.008.026.527-.019 1.095-.058 1.592-.01.12-.019.236-.026.347-.044.621-.044 1.067.048 1.378a.63.63 0 0 0 .149.275.64.64 0 0 0 .312.157c.13.032.323.054.513.066a6.18 6.18 0 0 0 .286.01l.015.001H7.5v1.5h-.75v-.75Z"/></svg>',Ot='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m9.586 14.633.021.004c-.036.335.095.655.393.962.082.083.173.15.274.201h1.474a.6.6 0 1 1 0 1.2H5.304a.6.6 0 0 1 0-1.2h1.15c.474-.07.809-.182 1.005-.334.157-.122.291-.32.404-.597l2.416-9.55a1.053 1.053 0 0 0-.281-.823 1.12 1.12 0 0 0-.442-.296H8.15a.6.6 0 0 1 0-1.2h6.443a.6.6 0 1 1 0 1.2h-1.195c-.376.056-.65.155-.823.296-.215.175-.423.439-.623.79l-2.366 9.347z"/></svg>',Pt='<svg viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg"><path d="M35 20a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1h-8a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h8Zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H15.5a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1H35Z" fill-opacity="0.16"/><path d="M8.508 9.561c.378-.294.638-.637.778-1.03h1.004V15H9.053v-4.654a4.257 4.257 0 0 1-1.595.936v-1.121c.322-.105.672-.305 1.05-.6Z"/><path d="M13.033 13.765V15h-1.235v-1.235h1.235Z"/><path d="M14.332 23.969v-6.47h-1.004c-.14.394-.4.737-.778 1.03-.378.296-.728.496-1.05.6v1.122a4.257 4.257 0 0 0 1.595-.936v4.654h1.237Z"/><path d="M17.075 23.969v-1.235H15.84v1.235h1.235Z"/><path d="M21.174 23.969v-6.47H20.17c-.14.394-.4.737-.778 1.03-.378.296-.728.496-1.05.6v1.122a4.258 4.258 0 0 0 1.595-.936v4.654h1.237Z"/><path d="M23.917 23.969v-1.235h-1.235v1.235h1.235Z"/><path d="M19.032 27.5v6.469h-1.237v-4.654a4.257 4.257 0 0 1-1.595.936V29.13c.322-.105.672-.305 1.05-.6.378-.294.638-.637.778-1.03h1.004Z"/><path d="M21.775 32.734v1.235H20.54v-1.235h1.235Z"/><path d="M26.132 34.069v-6.47h-1.004c-.14.394-.4.737-.778 1.03-.378.296-.728.496-1.05.6v1.122a4.257 4.257 0 0 0 1.595-.936v4.654h1.237Z"/><path d="M28.875 34.069v-1.235H27.64v1.235h1.235Z"/><path d="M33.232 34.069v-6.47h-1.004c-.14.394-.4.737-.778 1.03-.378.296-.728.496-1.05.6v1.122a4.257 4.257 0 0 0 1.595-.936v4.654h1.237Z"/><path d="M35.975 34.069v-1.235H34.74v1.235h1.235Z"/></svg>',jt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.077 15 .991-1.416a.75.75 0 1 1 1.229.86l-1.148 1.64a.748.748 0 0 1-.217.206 5.251 5.251 0 0 1-8.503-5.955.741.741 0 0 1 .12-.274l1.147-1.639a.75.75 0 1 1 1.228.86L4.933 10.7l.006.003a3.75 3.75 0 0 0 6.132 4.294l.006.004zm5.494-5.335a.748.748 0 0 1-.12.274l-1.147 1.639a.75.75 0 1 1-1.228-.86l.86-1.23a3.75 3.75 0 0 0-6.144-4.301l-.86 1.229a.75.75 0 0 1-1.229-.86l1.148-1.64a.748.748 0 0 1 .217-.206 5.251 5.251 0 0 1 8.503 5.955zm-4.563-2.532a.75.75 0 0 1 .184 1.045l-3.155 4.505a.75.75 0 1 1-1.229-.86l3.155-4.506a.75.75 0 0 1 1.045-.184z"/></svg>',Rt='<svg viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg"><path d="M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z" fill-opacity=".163"/><path d="M11 27a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm0 1a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm0-10a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm0 1a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm0-10a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm0 1a2 2 0 1 0 0 4 2 2 0 0 0 0-4z"/></svg>',Ft='<svg viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg"><path d="M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z" fill-opacity=".163"/><path d="M5.714 15.11c.624 0 1.11-.22 1.46-.66.421-.533.632-1.408.632-2.627 0-1.222-.21-2.096-.629-2.624-.351-.445-.839-.668-1.463-.668-.624 0-1.11.22-1.459.66-.422.533-.633 1.406-.633 2.619 0 1.236.192 2.095.576 2.577.384.482.89.723 1.516.723zm0-1.024a.614.614 0 0 1-.398-.14c-.115-.094-.211-.283-.287-.565-.077-.283-.115-.802-.115-1.558s.043-1.294.128-1.613c.064-.246.155-.417.272-.512a.617.617 0 0 1 .4-.143.61.61 0 0 1 .398.143c.116.095.211.284.288.567.076.283.114.802.114 1.558s-.043 1.292-.128 1.608c-.064.246-.155.417-.272.512a.617.617 0 0 1-.4.143zm6.078.914V8.531H10.79c-.14.393-.4.736-.778 1.03-.378.295-.728.495-1.05.6v1.121a4.257 4.257 0 0 0 1.595-.936V15h1.235zm3.344 0v-1.235h-1.235V15h1.235zm-9.422 9.11c.624 0 1.11-.22 1.46-.66.421-.533.632-1.408.632-2.627 0-1.222-.21-2.096-.629-2.624-.351-.445-.839-.668-1.463-.668-.624 0-1.11.22-1.459.66-.422.533-.633 1.406-.633 2.619 0 1.236.192 2.095.576 2.577.384.482.89.723 1.516.723zm0-1.024a.614.614 0 0 1-.398-.14c-.115-.094-.211-.283-.287-.565-.077-.283-.115-.802-.115-1.558s.043-1.294.128-1.613c.064-.246.155-.417.272-.512a.617.617 0 0 1 .4-.143.61.61 0 0 1 .398.143c.116.095.211.284.288.567.076.283.114.802.114 1.558s-.043 1.292-.128 1.608c-.064.246-.155.417-.272.512a.617.617 0 0 1-.4.143zm7.088.914v-1.147H10.35c.065-.111.149-.226.253-.343.104-.117.35-.354.74-.712.39-.357.66-.631.81-.821.225-.288.39-.562.493-.824.104-.263.156-.539.156-.829 0-.51-.181-.936-.544-1.279-.364-.342-.863-.514-1.499-.514-.58 0-1.063.148-1.45.444-.387.296-.617.784-.69 1.463l1.23.124c.024-.36.112-.619.264-.774.152-.155.357-.233.615-.233.261 0 .465.074.613.222.148.148.222.36.222.635 0 .25-.085.501-.255.756-.126.185-.467.536-1.024 1.055-.691.641-1.154 1.156-1.388 1.544-.235.389-.375.8-.422 1.233h4.328zm2.334 0v-1.235h-1.235V24h1.235zM5.714 34.11c.624 0 1.11-.22 1.46-.66.421-.533.632-1.408.632-2.627 0-1.222-.21-2.096-.629-2.624-.351-.445-.839-.668-1.463-.668-.624 0-1.11.22-1.459.66-.422.533-.633 1.406-.633 2.619 0 1.236.192 2.095.576 2.577.384.482.89.723 1.516.723zm0-1.024a.614.614 0 0 1-.398-.14c-.115-.094-.211-.283-.287-.565-.077-.283-.115-.802-.115-1.558s.043-1.294.128-1.613c.064-.246.155-.417.272-.512a.617.617 0 0 1 .4-.143.61.61 0 0 1 .398.143c.116.095.211.284.288.567.076.283.114.802.114 1.558s-.043 1.292-.128 1.608c-.064.246-.155.417-.272.512a.617.617 0 0 1-.4.143zm4.992 1.024c.616 0 1.13-.2 1.543-.598.413-.398.62-.88.62-1.446 0-.39-.111-.722-.332-.997a1.5 1.5 0 0 0-.886-.532c.618-.337.927-.788.927-1.353 0-.399-.15-.756-.452-1.073-.366-.386-.853-.58-1.46-.58a2.25 2.25 0 0 0-.96.2 1.617 1.617 0 0 0-.667.55c-.16.232-.28.544-.359.933l1.139.194c.032-.282.123-.495.272-.642.15-.146.33-.22.54-.22.214 0 .386.065.515.194s.193.302.193.518c0 .255-.088.46-.264.613-.175.154-.43.227-.764.218l-.136 1.006c.22-.061.408-.092.566-.092.24 0 .444.09.611.272.167.182.25.428.25.739 0 .328-.086.589-.26.782a.833.833 0 0 1-.644.29.841.841 0 0 1-.607-.242c-.167-.16-.27-.394-.308-.698l-1.195.145c.062.542.284.98.668 1.316.384.335.867.503 1.45.503zm4.43-.11v-1.235h-1.235V34h1.235z"/></svg>',Nt='<svg viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg"><path d="M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z" fill-opacity=".163"/><path d="M10.29 15V8.531H9.286c-.14.393-.4.736-.778 1.03-.378.295-.728.495-1.05.6v1.121a4.257 4.257 0 0 0 1.595-.936V15h1.235zm3.343 0v-1.235h-1.235V15h1.235zM11.3 24v-1.147H8.848c.064-.111.148-.226.252-.343.104-.117.351-.354.74-.712.39-.357.66-.631.81-.821.225-.288.39-.562.494-.824.104-.263.156-.539.156-.829 0-.51-.182-.936-.545-1.279-.363-.342-.863-.514-1.499-.514-.58 0-1.063.148-1.45.444-.387.296-.617.784-.69 1.463l1.23.124c.024-.36.112-.619.264-.774.153-.155.358-.233.616-.233.26 0 .465.074.613.222.148.148.222.36.222.635 0 .25-.085.501-.255.756-.126.185-.468.536-1.024 1.055-.692.641-1.155 1.156-1.389 1.544-.234.389-.375.8-.422 1.233H11.3zm2.333 0v-1.235h-1.235V24h1.235zM9.204 34.11c.615 0 1.129-.2 1.542-.598.413-.398.62-.88.62-1.446 0-.39-.11-.722-.332-.997a1.5 1.5 0 0 0-.886-.532c.619-.337.928-.788.928-1.353 0-.399-.151-.756-.453-1.073-.366-.386-.852-.58-1.459-.58a2.25 2.25 0 0 0-.96.2 1.617 1.617 0 0 0-.668.55c-.16.232-.28.544-.358.933l1.138.194c.032-.282.123-.495.272-.642.15-.146.33-.22.54-.22.215 0 .386.065.515.194s.193.302.193.518c0 .255-.087.46-.263.613-.176.154-.43.227-.765.218l-.136 1.006c.22-.061.409-.092.567-.092.24 0 .444.09.61.272.168.182.251.428.251.739 0 .328-.087.589-.261.782a.833.833 0 0 1-.644.29.841.841 0 0 1-.607-.242c-.167-.16-.27-.394-.307-.698l-1.196.145c.062.542.285.98.668 1.316.384.335.868.503 1.45.503zm4.43-.11v-1.235h-1.236V34h1.235z"/></svg>',Ut='<svg viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg"><path d="M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z" fill-opacity=".163"/><path d="M11 27a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm0-9a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm0-9a3 3 0 1 1 0 6 3 3 0 0 1 0-6z"/></svg>',Wt='<svg viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg"><path d="M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z" fill-opacity=".163"/><path d="M9.62 14.105c.272 0 .528-.05.768-.153s.466-.257.677-.462c.009.024.023.072.044.145.047.161.086.283.119.365h1.221a2.649 2.649 0 0 1-.222-.626c-.04-.195-.059-.498-.059-.908l.013-1.441c0-.536-.055-.905-.165-1.105-.11-.201-.3-.367-.569-.497-.27-.13-.68-.195-1.23-.195-.607 0-1.064.108-1.371.325-.308.217-.525.55-.65 1.002l1.12.202c.076-.217.176-.369.299-.455.123-.086.294-.13.514-.13.325 0 .546.05.663.152.118.101.176.27.176.508v.123c-.222.093-.622.194-1.2.303-.427.082-.755.178-.982.288-.227.11-.403.268-.53.474a1.327 1.327 0 0 0-.188.706c0 .398.138.728.415.988.277.261.656.391 1.136.391zm.368-.87a.675.675 0 0 1-.492-.189.606.606 0 0 1-.193-.448c0-.176.08-.32.241-.435.106-.07.33-.142.673-.215a7.19 7.19 0 0 0 .751-.19v.247c0 .296-.016.496-.048.602a.773.773 0 0 1-.295.409 1.07 1.07 0 0 1-.637.22zm4.645.765v-1.235h-1.235V14h1.235zM10.2 25.105c.542 0 1.003-.215 1.382-.646.38-.43.57-1.044.57-1.84 0-.771-.187-1.362-.559-1.774a1.82 1.82 0 0 0-1.41-.617c-.522 0-.973.216-1.354.65v-2.32H7.594V25h1.147v-.686a1.9 1.9 0 0 0 .67.592c.26.133.523.2.79.2zm-.299-.975c-.354 0-.638-.164-.852-.492-.153-.232-.229-.59-.229-1.073 0-.468.098-.818.295-1.048a.93.93 0 0 1 .738-.345c.302 0 .55.118.743.354.193.236.29.62.29 1.154 0 .5-.096.868-.288 1.1-.192.233-.424.35-.697.35zm4.478.87v-1.235h-1.234V25h1.234zm-4.017 9.105c.6 0 1.08-.142 1.437-.426.357-.284.599-.704.725-1.261l-1.213-.207c-.061.326-.167.555-.316.688a.832.832 0 0 1-.576.2.916.916 0 0 1-.75-.343c-.185-.228-.278-.62-.278-1.173 0-.498.091-.853.274-1.066.183-.212.429-.318.736-.318.232 0 .42.061.565.184.145.123.238.306.28.55l1.216-.22c-.146-.501-.387-.874-.722-1.119-.336-.244-.788-.366-1.356-.366-.695 0-1.245.214-1.653.643-.407.43-.61 1.03-.61 1.8 0 .762.202 1.358.608 1.788.406.431.95.646 1.633.646zM14.633 34v-1.235h-1.235V34h1.235z"/></svg>',$t='<svg viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg"><path d="M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z" fill-opacity=".163"/><path d="M11.88 8.7V7.558h-1.234V8.7h1.234zm0 5.3V9.333h-1.234V14h1.234zm2.5 0v-1.235h-1.234V14h1.235zm-4.75 4.7v-1.142H8.395V18.7H9.63zm0 5.3v-4.667H8.395V24H9.63zm2.5-5.3v-1.142h-1.234V18.7h1.235zm0 5.3v-4.667h-1.234V24h1.235zm2.501 0v-1.235h-1.235V24h1.235zM7.38 28.7v-1.142H6.145V28.7H7.38zm0 5.3v-4.667H6.145V34H7.38zm2.5-5.3v-1.142H8.646V28.7H9.88zm0 5.3v-4.667H8.646V34H9.88zm2.5-5.3v-1.142h-1.234V28.7h1.235zm0 5.3v-4.667h-1.234V34h1.235zm2.501 0v-1.235h-1.235V34h1.235z"/></svg>',qt='<svg viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg"><path d="M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z" fill-opacity=".163"/><path d="M14 27v6H8v-6h6zm0-9v6H8v-6h6zm0-9v6H8V9h6z"/></svg>',Kt='<svg viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg"><path d="M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z" fill-opacity=".163"/><path d="m7.88 15 .532-1.463h2.575L11.549 15h1.415l-2.58-6.442H9.01L6.5 15h1.38zm2.69-2.549H8.811l.87-2.39.887 2.39zM14.88 15v-1.235h-1.234V15h1.234zM9.352 25c.83-.006 1.352-.02 1.569-.044.346-.038.636-.14.872-.305.236-.166.422-.387.558-.664.137-.277.205-.562.205-.855 0-.372-.106-.695-.317-.97-.21-.276-.512-.471-.905-.585a1.51 1.51 0 0 0 .661-.567 1.5 1.5 0 0 0 .244-.83c0-.28-.066-.53-.197-.754a1.654 1.654 0 0 0-.495-.539 1.676 1.676 0 0 0-.672-.266c-.25-.042-.63-.063-1.14-.063H7.158V25h2.193zm.142-3.88H8.46v-1.49h.747c.612 0 .983.007 1.112.022.217.026.38.102.49.226.11.125.165.287.165.486a.68.68 0 0 1-.192.503.86.86 0 0 1-.525.23 11.47 11.47 0 0 1-.944.023h.18zm.17 2.795H8.46v-1.723h1.05c.592 0 .977.03 1.154.092.177.062.313.16.406.295a.84.84 0 0 1 .14.492c0 .228-.06.41-.181.547a.806.806 0 0 1-.473.257c-.126.026-.423.04-.892.04zM14.88 25v-1.235h-1.234V25h1.234zm-5.018 9.11c.691 0 1.262-.17 1.711-.512.45-.341.772-.864.965-1.567l-1.261-.4c-.109.472-.287.818-.536 1.037-.25.22-.547.33-.892.33-.47 0-.85-.173-1.143-.519-.293-.345-.44-.925-.44-1.74 0-.767.15-1.322.447-1.665.297-.343.684-.514 1.162-.514.346 0 .64.096.881.29.242.193.4.457.477.79l1.288-.307c-.147-.516-.367-.911-.66-1.187-.492-.465-1.132-.698-1.92-.698-.902 0-1.63.296-2.184.89-.554.593-.83 1.426-.83 2.498 0 1.014.275 1.813.825 2.397.551.585 1.254.877 2.11.877zM14.88 34v-1.235h-1.234V34h1.234z"/></svg>',Gt='<svg viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg"><path d="M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z" fill-opacity=".163"/><path d="M11.916 15V8.558h-1.301V15h1.3zm2.465 0v-1.235h-1.235V15h1.235zM9.665 25v-6.442h-1.3V25h1.3zm2.5 0v-6.442h-1.3V25h1.3zm2.466 0v-1.235h-1.235V25h1.235zm-7.216 9v-6.442h-1.3V34h1.3zm2.5 0v-6.442h-1.3V34h1.3zm2.501 0v-6.442h-1.3V34h1.3zm2.465 0v-1.235h-1.235V34h1.235z"/></svg>',Jt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M4.2 3c-.584 0-1.145.23-1.557.643A2.203 2.203 0 0 0 2 5.199v8.719a2.194 2.194 0 0 0 2.2 2.195h11.624a2.194 2.194 0 0 0 2.196-2.195V7.621a2.194 2.194 0 0 0-2.195-2.2h-5.393l-1.237-2.06A.752.752 0 0 0 8.56 3H4.2Zm0 1.488h3.935l1.236 2.06a.75.75 0 0 0 .64.362h5.813a.712.712 0 0 1 .707.71v6.298a.707.707 0 0 1-.707.707H4.2a.71.71 0 0 1-.71-.707V5.199a.711.711 0 0 1 .71-.71Z"/></svg>',Qt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M12.68 13.74h-.001l4.209 4.208a1 1 0 1 0 1.414-1.414l-4.267-4.268a6 6 0 1 0-1.355 1.474ZM13 9a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z"/></svg>',Xt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M5.085 6.22 2.943 4.078a.75.75 0 1 1 1.06-1.06l2.592 2.59A11.094 11.094 0 0 1 10 5.068c4.738 0 8.578 3.101 8.578 5.083 0 1.197-1.401 2.803-3.555 3.887l1.714 1.713a.75.75 0 0 1-.09 1.138.488.488 0 0 1-.15.084.75.75 0 0 1-.821-.16L6.17 7.304c-.258.11-.51.233-.757.365l6.239 6.24-.006.005.78.78c-.388.094-.78.166-1.174.215l-1.11-1.11h.011L4.55 8.197a7.2 7.2 0 0 0-.665.514l-.112.098 4.897 4.897-.005.006 1.276 1.276a10.164 10.164 0 0 1-1.477-.117l-.479-.479-.009.009-4.863-4.863-.022.031a2.563 2.563 0 0 0-.124.2c-.043.077-.08.158-.108.241a.534.534 0 0 0-.028.133.29.29 0 0 0 .008.072.927.927 0 0 0 .082.226c.067.133.145.26.234.379l3.242 3.365.025.01.59.623c-3.265-.918-5.59-3.155-5.59-4.668 0-1.194 1.448-2.838 3.663-3.93zm7.07.531a4.632 4.632 0 0 1 1.108 5.992l.345.344.046-.018a9.313 9.313 0 0 0 2-1.112c.256-.187.5-.392.727-.613.137-.134.27-.277.392-.431.072-.091.141-.185.203-.286.057-.093.107-.19.148-.292a.72.72 0 0 0 .036-.12.29.29 0 0 0 .008-.072.492.492 0 0 0-.028-.133.999.999 0 0 0-.036-.096 2.165 2.165 0 0 0-.071-.145 2.917 2.917 0 0 0-.125-.2 3.592 3.592 0 0 0-.263-.335 5.444 5.444 0 0 0-.53-.523 7.955 7.955 0 0 0-1.054-.768 9.766 9.766 0 0 0-1.879-.891c-.337-.118-.68-.219-1.027-.301zm-2.85.21-.069.002a.508.508 0 0 0-.254.097.496.496 0 0 0-.104.679.498.498 0 0 0 .326.199l.045.005c.091.003.181.003.272.012a2.45 2.45 0 0 1 2.017 1.513c.024.061.043.125.069.185a.494.494 0 0 0 .45.287h.008a.496.496 0 0 0 .35-.158.482.482 0 0 0 .13-.335.638.638 0 0 0-.048-.219 3.379 3.379 0 0 0-.36-.723 3.438 3.438 0 0 0-2.791-1.543l-.028-.001h-.013z"/></svg>',Yt='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M15.346 9.422a.151.151 0 0 1 .284 0l.548 1.484a.152.152 0 0 0 .09.089l1.483.549a.151.151 0 0 1 0 .284l-1.483.548a.151.151 0 0 0-.09.09l-.548 1.483a.152.152 0 0 1-.142.1.151.151 0 0 1-.142-.1l-.549-1.483a.15.15 0 0 0-.09-.09l-1.483-.548a.15.15 0 0 1 0-.284l1.484-.549a.152.152 0 0 0 .089-.09l.549-1.483Z"/><path d="M16.306 1.742a.151.151 0 0 1 .284 0l.549 1.483a.15.15 0 0 0 .089.09l1.483.548a.151.151 0 0 1 .072.229.151.151 0 0 1-.072.055l-1.483.549a.15.15 0 0 0-.09.09l-.548 1.482a.151.151 0 0 1-.284 0l-.549-1.483a.15.15 0 0 0-.09-.09l-1.483-.548a.151.151 0 0 1 0-.284l1.484-.549a.152.152 0 0 0 .09-.089l.548-1.483Z"/><path d="M7.665 1.742a.151.151 0 0 1 .284 0l.549 1.483a.151.151 0 0 0 .09.09l1.482.548a.151.151 0 0 1 .072.229.151.151 0 0 1-.072.055l-1.483.549a.151.151 0 0 0-.09.09L7.95 6.267a.151.151 0 0 1-.284 0l-.549-1.483a.151.151 0 0 0-.089-.09l-1.483-.548a.151.151 0 0 1 0-.284l1.483-.549a.151.151 0 0 0 .09-.089l.548-1.483-.001.001Z"/><path d="M14.72 7.946a.848.848 0 0 0 .25-.591.824.824 0 0 0-.241-.588l-1.943-1.938a.812.812 0 0 0-.588-.241.838.838 0 0 0-.591.25l-1.545 1.539 3.115 3.115 1.542-1.546h.001Z"/><path clip-rule="evenodd" d="M1.19 15.636a.96.96 0 0 1 .281-.679l7.835-7.834 3.121 3.12-7.834 7.835a.959.959 0 0 1-1.358 0l-1.764-1.764a.96.96 0 0 1-.28-.678Zm9.22-5.391-1.121-1.12-6.479 6.478 1.121 1.121 6.479-6.479Z"/></svg>',te='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path class="ck-icon__fill" d="M10.798 1.59 3.002 12.875l1.895 1.852 2.521 1.402 6.997-12.194z"/><path d="m2.556 16.727.234-.348c-.297-.151-.462-.293-.498-.426-.036-.137.002-.416.115-.837.094-.25.15-.449.169-.595a4.495 4.495 0 0 0 0-.725c-.209-.621-.303-1.041-.284-1.26.02-.218.178-.506.475-.862l6.77-9.414c.539-.91 1.605-.85 3.199.18 1.594 1.032 2.188 1.928 1.784 2.686l-5.877 10.36c-.158.412-.333.673-.526.782-.193.108-.604.179-1.232.21-.362.131-.608.237-.738.318-.13.081-.305.238-.526.47-.293.265-.504.397-.632.397-.096 0-.27-.075-.524-.226l-.31.41-1.6-1.12zm-.279.415 1.575 1.103-.392.515H1.19l1.087-1.618zm8.1-13.656-4.953 6.9L8.75 12.57l4.247-7.574c.175-.25-.188-.647-1.092-1.192-.903-.546-1.412-.652-1.528-.32zM8.244 18.5 9.59 17h9.406v1.5H8.245z"/></svg>',ee='<svg viewBox="0 0 64 42" xmlns="http://www.w3.org/2000/svg"><path d="M47.426 17V3.713L63.102 0v19.389h-.001l.001.272c0 1.595-2.032 3.43-4.538 4.098-2.506.668-4.538-.083-4.538-1.678 0-1.594 2.032-3.43 4.538-4.098.914-.244 2.032-.565 2.888-.603V4.516L49.076 7.447v9.556A1.014 1.014 0 0 0 49 17h-1.574zM29.5 17h-8.343a7.073 7.073 0 1 0-4.657 4.06v3.781H3.3a2.803 2.803 0 0 1-2.8-2.804V8.63a2.803 2.803 0 0 1 2.8-2.805h4.082L8.58 2.768A1.994 1.994 0 0 1 10.435 1.5h8.985c.773 0 1.477.448 1.805 1.149l1.488 3.177H26.7c1.546 0 2.8 1.256 2.8 2.805V17zm-11.637 0H17.5a1 1 0 0 0-1 1v.05A4.244 4.244 0 1 1 17.863 17zm29.684 2c.97 0 .953-.048.953.889v20.743c0 .953.016.905-.953.905H19.453c-.97 0-.953.048-.953-.905V19.89c0-.937-.016-.889.97-.889h28.077zm-4.701 19.338V22.183H24.154v16.155h18.692zM20.6 21.375v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616V37.53H20.6zm24.233-16.155v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615V37.53h-1.615zM29.485 25.283a.4.4 0 0 1 .593-.35l9.05 4.977a.4.4 0 0 1 0 .701l-9.05 4.978a.4.4 0 0 1-.593-.35v-9.956z"/></svg>',ae='<svg viewBox="0 0 22 20" xmlns="http://www.w3.org/2000/svg"><path d="M1.587 1.5c-.612 0-.601-.029-.601.551v14.84c0 .59-.01.559.591.559h18.846c.602 0 .591.03.591-.56V2.052c0-.58.01-.55-.591-.55H1.587Zm.701.971h1.003v1H2.288v-1Zm16.448 0h1.003v1h-1.003v-1Zm-14.24 1h13.008v12H4.467l.029-12Zm-2.208 1h1.003v1H2.288v-1Zm16.448 0h1.003v1h-1.003v-1Zm-16.448 2h1.003v1H2.288v-1Zm16.448 0h1.003v1h-1.003v-1Zm-16.448 2h1.003v1H2.288v-1Zm16.448 0h1.003v1h-1.003v-1Zm-16.448 2h1.003v1H2.288v-1Zm16.448 0h1.003v1h-1.003v-1Zm-16.448 2h1.003l-.029 1h-.974v-1Zm16.448 0h1.003v1h-1.003v-1Zm-16.448 2h.974v1h-.974v-1Zm16.448 0h1.003v1h-1.003v-1Z"/><path d="M8.374 6.648a.399.399 0 0 1 .395-.4.402.402 0 0 1 .2.049l5.148 2.824a.4.4 0 0 1 0 .7l-5.148 2.824a.403.403 0 0 1-.595-.35V6.648Z"/></svg>',ie='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M7.85 6.5a.75.75 0 0 1 0-1.5h9.5a.75.75 0 1 1 0 1.5h-9.5Z"/><path d="M3 8V2.7H.5v1h1V8H3Z"/><path d="M13.42 14.185a.75.75 0 0 0 .53 1.28h3.4a.75.75 0 1 0 0-1.5h-3.4a.75.75 0 0 0-.53.22Z"/><path d="M5.636 8.035V6.8H4.4v1.235h1.236Z"/><path d="M9 17.865v-5.3H6.5v1h1v4.3H9Z"/><path d="M11.636 17.9v-1.235H10.4V17.9h1.236Z"/><path d="M3.2 17.865v-5.3H.7v1h1v4.3h1.5Z"/><path d="M5.836 17.9v-1.235H4.6V17.9h1.236Z"/></svg>',le='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M8.537 14.813a.888.888 0 1 1-1.254-1.255L10.84 10 7.283 6.442a.888.888 0 1 1 1.254-1.255L12.74 9.39a.888.888 0 0 1-.16 1.382l-4.043 4.042z"/></svg>',ne='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10 0C4.48 0 0 4.48 0 10s4.48 10 10 10 10-4.48 10-10S15.52 0 10 0zm1 15H9v-2h2v2zm0-4H9V5h2v6z"/></svg>',oe='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M7 5.75c0 .414.336.75.75.75h9.5a.75.75 0 1 0 0-1.5h-9.5a.75.75 0 0 0-.75.75zM3.5 3v5H2V3.7H1v-1h2.5V3zM.343 17.857l2.59-3.257H2.92a.6.6 0 1 0-1.04 0H.302a2 2 0 1 1 3.995 0h-.001c-.048.405-.16.734-.333.988-.175.254-.59.692-1.244 1.312H4.3v1h-4l.043-.043zM7 14.75a.75.75 0 0 1 .75-.75h9.5a.75.75 0 1 1 0 1.5h-9.5a.75.75 0 0 1-.75-.75z"/></svg>',se='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm0 12h16v1.5H2z"/><path d="M15.003 7v5.5a1 1 0 0 1-1 1H5.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H6.5V12h6.997V7.5z"/></svg>',he='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm0 12h16v1.5H2z"/><path d="M18 7v5.5a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1zm-1.505.5H3.504V12h12.991V7.5z"/></svg>',re='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm11.5 9H18v1.5h-4.5zm0-3H18v1.5h-4.5zm0-3H18v1.5h-4.5zM2 15h16v1.5H2z"/><path d="M12.003 7v5.5a1 1 0 0 1-1 1H2.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H3.5V12h6.997V7.5z"/></svg>',ve='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm0 12h16v1.5H2zm0-9h5v1.5H2zm0 3h5v1.5H2zm0 3h5v1.5H2z"/><path d="M18.003 7v5.5a1 1 0 0 1-1 1H8.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H9.5V12h6.997V7.5z"/></svg>',ce='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm11.5 9H18v1.5h-4.5zM2 15h16v1.5H2z"/><path d="M12.003 7v5.5a1 1 0 0 1-1 1H2.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H3.5V12h6.997V7.5z"/></svg>',de='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm0 12h16v1.5H2z"/><path d="M12.003 7v5.5a1 1 0 0 1-1 1H2.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H3.5V12h6.997V7.5z"/></svg>',me='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm0 12h16v1.5H2z"/><path d="M18.003 7v5.5a1 1 0 0 1-1 1H8.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H9.5V12h6.997V7.5z"/></svg>',ge='<svg xmlns="http://www.w3.org/2000/svg" xmlns:v="https://vecta.io/nano" viewBox="0 0 20 20"><path d="M.95 1.43a.95.95 0 0 0-.95.95v3.1a.95.95 0 0 0 .95.95h.75v6.3H.95a.95.95 0 0 0-.95.95v3.1a.95.95 0 0 0 .95.95h3.1a.95.95 0 0 0 .95-.95v-.65h1.932l1.539-1.5H5v-.95a.95.95 0 0 0-.95-.95H3.2v-6.3h.85A.95.95 0 0 0 5 5.48v-.55h10v.55a.95.95 0 0 0 .95.95h3.1a.95.95 0 0 0 .95-.95v-3.1a.95.95 0 0 0-.95-.95h-3.1a.95.95 0 0 0-.95.95v1.05H5V2.38a.95.95 0 0 0-.95-.95H.95zm.55 3.5v-2h2v2h-2zm0 9.3v2h2v-2h-2zm15-11.3v2h2v-2h-2z"/><path d="M8.139 20.004v-2.388l7.045-7.048 2.391 2.391-7.046 7.046h-2.39zm11.421-9.101a.64.64 0 0 1-.138.206l-1.165 1.168-2.391-2.391 1.167-1.163a.63.63 0 0 1 .206-.138.635.635 0 0 1 .243-.049.63.63 0 0 1 .449.187l1.491 1.488c.059.059.108.129.138.206s.049.16.049.243a.6.6 0 0 1-.049.243z"/></svg>',pe='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M2.5 17v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zM1 15.5v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm0-2v1h-1v-1h1zm-19 0v1H0v-1h1zM14.5 2v1h-1V2h1zm2 0v1h-1V2h1zm2 0v1h-1V2h1zm-8 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm8 0v1h-1V2h1zm-10 0v1h-1V2h1z"/><path d="M18.095 2H1.905C.853 2 0 2.895 0 4v12c0 1.105.853 2 1.905 2h16.19C19.147 18 20 17.105 20 16V4c0-1.105-.853-2-1.905-2zm0 1.5c.263 0 .476.224.476.5v12c0 .276-.213.5-.476.5H1.905a.489.489 0 0 1-.476-.5V4c0-.276.213-.5.476-.5h16.19z"/></svg>',we='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2.5 16.5v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1ZM1 15v1H0v-1h1Zm19 0v1h-1v-1h1ZM1 13v1H0v-1h1Zm19 0v1h-1v-1h1ZM1 11v1H0v-1h1Zm19 0v1h-1v-1h1ZM1 9v1H0V9h1Zm19 0v1h-1V9h1ZM1 7v1H0V7h1Zm19 0v1h-1V7h1ZM1 5v1H0V5h1Zm19 0v1h-1V5h1Zm0-2v1h-1V3h1ZM1 3v1H0V3h1Zm13.5-1.5v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm-8 0v1h-1v-1h1Zm-2 0v1h-1v-1h1Zm-2 0v1h-1v-1h1Zm-2 0v1h-1v-1h1Zm8 0v1h-1v-1h1Zm-10 0v1h-1v-1h1Z"/><path d="M13 5.5H2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2v-8a2 2 0 0 0-2-2ZM13 7a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-.5.5H2a.5.5 0 0 1-.5-.5v-8A.5.5 0 0 1 2 7h11Z"/></svg>',ue='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2.5 16.5v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1ZM1 15v1H0v-1h1Zm19 0v1h-1v-1h1ZM1 13v1H0v-1h1Zm19 0v1h-1v-1h1ZM1 11v1H0v-1h1Zm19 0v1h-1v-1h1ZM1 9v1H0V9h1Zm19 0v1h-1V9h1ZM1 7v1H0V7h1Zm19 0v1h-1V7h1ZM1 5v1H0V5h1Zm19 0v1h-1V5h1Zm0-2v1h-1V3h1ZM1 3v1H0V3h1Zm13.5-1.5v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm-8 0v1h-1v-1h1Zm-2 0v1h-1v-1h1Zm-2 0v1h-1v-1h1Zm-2 0v1h-1v-1h1Zm8 0v1h-1v-1h1Zm-10 0v1h-1v-1h1Z"/><path d="M10 7.5H2a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2v-6a2 2 0 0 0-2-2ZM10 9a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-.5.5H2a.5.5 0 0 1-.5-.5v-6A.5.5 0 0 1 2 9h8Z"/></svg>',Me='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2.5 16.5v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1ZM1 15v1H0v-1h1Zm19 0v1h-1v-1h1ZM1 13v1H0v-1h1Zm19 0v1h-1v-1h1ZM1 11v1H0v-1h1Zm19 0v1h-1v-1h1ZM1 9v1H0V9h1Zm19 0v1h-1V9h1ZM1 7v1H0V7h1Zm19 0v1h-1V7h1ZM1 5v1H0V5h1Zm19 0v1h-1V5h1Zm0-2v1h-1V3h1ZM1 3v1H0V3h1Zm13.5-1.5v1h-1v-1h1Zm2 0v1h-1v-1h1Zm2 0v1h-1v-1h1Zm-8 0v1h-1v-1h1Zm-2 0v1h-1v-1h1Zm-2 0v1h-1v-1h1Zm-2 0v1h-1v-1h1Zm8 0v1h-1v-1h1Zm-10 0v1h-1v-1h1Z"/><path d="M7 9.5H2a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h5a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2ZM7 11a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-.5.5H2a.5.5 0 0 1-.5-.5v-4A.5.5 0 0 1 2 11h5Z"/></svg>',He='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10.223 5.001a5.277 5.277 0 0 0-4.408 2.258c-3.224.423-4.908 4.123-3.032 6.814l.004.008.002.004c.48.627 1.712 1.84 3.588 1.84h7.936c.667 0 1.32-.179 1.894-.522a3.838 3.838 0 0 0 1.381-1.46v-.005c1.13-2.16-.133-4.777-2.488-5.298-.617-1.853-2.177-3.242-4.111-3.565a5.273 5.273 0 0 0-.766-.074Zm-.092 1.5a2.5 2.5 0 0 1 .23.008c.077.004.154.014.231.021l.226.035a5.203 5.203 0 0 1 .45.116 3.31 3.31 0 0 1 .433.166 4.079 4.079 0 0 1 .606.348 4.195 4.195 0 0 1 .37.293 3.54 3.54 0 0 1 .33.348 3.517 3.517 0 0 1 .505.778 3.182 3.182 0 0 0-.42.117c-.082.03-.164.06-.244.094l-1.49.627-2.686-1.61a4.39 4.39 0 0 0-1.002-.445c.015-.01.032-.026.047-.039a3.744 3.744 0 0 1 .4-.289 3.713 3.713 0 0 1 .424-.23 3.02 3.02 0 0 1 .219-.094c.074-.03.15-.053.225-.076a3.77 3.77 0 0 1 .222-.06c.077-.02.157-.035.233-.05.075-.015.15-.025.228-.033.077-.007.154-.015.233-.02.078-.003.154-.005.23-.005Zm-3.8 2.193h.003c.54.001 1.111.156 1.551.428l1.783 1.07-5.867 2.471c-.535-1.29-.15-2.788 1.059-3.537l.007-.004a2.88 2.88 0 0 1 1.463-.428Zm7.974 1.33.152.008c.086.008.173.018.258.033a1.956 1.956 0 0 1 .477.145 2.179 2.179 0 0 1 .918.756c.046.066.09.133.127.2a2.284 2.284 0 0 1 .269.919c.004.081.008.165.002.248-.003.055-.012.111-.02.166l-3.507-2.102.459-.193.015-.008a2.118 2.118 0 0 1 .41-.125 2.297 2.297 0 0 1 .44-.047Zm-3.008 1.112 4.506 2.699a2.217 2.217 0 0 1-.338.26 2.228 2.228 0 0 1-.668.275c-.078.019-.157.03-.24.04-.081.007-.164.015-.246.015H6.373a3.09 3.09 0 0 1-.168-.004 1.904 1.904 0 0 1-.164-.016l-.154-.023c-.051-.008-.102-.014-.15-.026a2.942 2.942 0 0 1-.77-.3 2.889 2.889 0 0 1-.21-.133c-.012-.008-.019-.016-.03-.024l6.57-2.763Z"/></svg>',ze='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm5 6c0 .414.336.75.75.75h9.5a.75.75 0 1 0 0-1.5h-9.5a.75.75 0 0 0-.75.75zM2.75 16.5h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 1 0 0 1.5zm1.618-9.55L.98 9.358a.4.4 0 0 0 .013.661l3.39 2.207A.4.4 0 0 0 5 11.892V7.275a.4.4 0 0 0-.632-.326z"/></svg>',Ve='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3.598.687h1.5v5h-1.5zm14.5 0h1.5v5h-1.5z"/><path d="M19.598 4.187v1.5h-16v-1.5zm-16 14.569h1.5v-5h-1.5zm14.5 0h1.5v-5h-1.5z"/><path d="M19.598 15.256v-1.5h-16v1.5zM5.081 9h6v2h-6zm8 0h6v2h-6zm-9.483 1L0 12.5v-5z"/></svg>',fe='<svg viewBox="2 2 56 18" xmlns="http://www.w3.org/2000/svg"><path d="m12.527 14.733-.514.022-.057-.057-.058-.058.006-2.44.007-2.44-.834-.023-.833-.022.023-.406.024-.405.536-.1.536-.098.25-.145.25-.145.17-.429.172-.428.399-.024.398-.023v7.08l.02.059.02.059zm17.894.016h-.457l.043-.138.043-.137.635-2.004.636-2.004.437-1.375.436-1.375.055-.196.054-.197.38-.024.378-.024.07.069.07.07-1.162 3.667-1.16 3.667h-.458zm11.733 0h-.55V9.72h-1.65v-.864h.385l.4-.086.398-.086.233-.195.232-.196.138-.386.137-.387h.827v7.229zm6.404 0h-.51V13.02h-3.143v-1.01l1.044-1.44 1.045-1.44.59-.824.592-.825h.854l.02 2.298.021 2.298h1.02v.943H49.07v1.729zM47 12.06l1.008-.022.022-1.4.021-1.401-.07.044-.07.043-.901 1.279-.901 1.278-.058.1-.059.101z"/><path d="m12.256 22.893-10.53.01-.157-.038-.157-.038-.255-.12L.9 22.59v-.19l.228-.218.228-.218.16.086.16.085h20.922l.16-.085.16-.086.228.218.227.218v.189l-.294.146-.295.147z"/></svg>',xe='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 31 20"><mask id="a" maskUnits="userSpaceOnUse" x="13" y="1" width="17" height="18"><rect x="13" y="1" width="17" height="18"/><path d="M14 3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H15a1 1 0 0 1-1-1V3Z"/><path d="M27 3.25a1.5 1.5 0 0 1 1.5 1.5v1.7a2.25 2.25 0 0 1-1.932 2.226l-4.424.632a.75.75 0 0 0-.644.743V11a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H20a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1v-.95a2.25 2.25 0 0 1 1.932-2.226l4.424-.632A.75.75 0 0 0 27 6.449V3.25Z"/></mask><path d="M14 3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H15a1 1 0 0 1-1-1V3Z"/><path d="M27 3.25a1.5 1.5 0 0 1 1.5 1.5v1.7a2.25 2.25 0 0 1-1.932 2.226l-4.424.632a.75.75 0 0 0-.644.743V11a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H20a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1v-.95a2.25 2.25 0 0 1 1.932-2.226l4.424-.632A.75.75 0 0 0 27 6.449V3.25Z"/><path d="M14 3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H15a1 1 0 0 1-1-1V3Z" stroke-width="2" mask="url(#a)"/><path d="M27 3.25a1.5 1.5 0 0 1 1.5 1.5v1.7a2.25 2.25 0 0 1-1.932 2.226l-4.424.632a.75.75 0 0 0-.644.743V11a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H20a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1v-.95a2.25 2.25 0 0 1 1.932-2.226l4.424-.632A.75.75 0 0 0 27 6.449V3.25Z" stroke-width="2" mask="url(#a)"/><mask id="b" maskUnits="userSpaceOnUse" x="1.75" y="1.165" width="12" height="17"><rect x="1.75" y="1.165" width="12" height="17"/><path d="m12.25 9.96-9.5-7.795 2 12.124 2.384-2.53 2.75 4.762 1.732-1-2.75-4.763 3.384-.799Z"/></mask><path d="m12.25 9.96-9.5-7.795 2 12.124 2.384-2.53 2.75 4.762 1.732-1-2.75-4.763 3.384-.799Z"/><path d="m12.25 9.96-9.5-7.795 2 12.124 2.384-2.53 2.75 4.762 1.732-1-2.75-4.763 3.384-.799Z" stroke-width="2" stroke-linejoin="round" mask="url(#b)"/></svg>',Ze='<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 31 20" width="30" height="20">\n <path d="M14 3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H15a1 1 0 0 1-1-1V3Z" fill="#000"/>\n <path d="M27 3.25a1.5 1.5 0 0 1 1.5 1.5v1.7a2.25 2.25 0 0 1-1.932 2.226l-4.424.632a.75.75 0 0 0-.644.743V11a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H20a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1v-.95a2.25 2.25 0 0 1 1.932-2.226l4.424-.632A.75.75 0 0 0 27 6.449V3.25Z" fill="#000"/>\n <path fill-rule="evenodd" clip-rule="evenodd" d="M26.855 2.25H27a2.5 2.5 0 0 1 2.5 2.5v1.7a3.25 3.25 0 0 1-2.79 3.216l-4.21.602a2 2 0 0 1 1 1.732v5a2 2 0 0 1-2 2H20a2 2 0 0 1-2-2v-5a2 2 0 0 1 1-1.732v-.217A3.25 3.25 0 0 1 21.129 7H15a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h10a2 2 0 0 1 1.855 1.25ZM20 10.05V11a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h1.5a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1v-.95c0-.016 0-.033.002-.05a.75.75 0 0 1 .642-.692l4.424-.632A2.25 2.25 0 0 0 28.5 6.45V4.75a1.496 1.496 0 0 0-1.5-1.5v3.2a.75.75 0 0 1-.644.742l-4.424.632A2.25 2.25 0 0 0 20 10.05ZM15 2a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H15Z" fill="#fff"/>\n <path d="M2.5 2.5A.5.5 0 0 1 3 2h2.5a.5.5 0 0 1 .354.146l.646.647.646-.647A.5.5 0 0 1 7.5 2H10a.5.5 0 0 1 0 1H7.707L7 3.707V10h.5a.5.5 0 0 1 0 1H7v4.793l.707.707H10a.5.5 0 0 1 0 1H7.5a.5.5 0 0 1-.354-.146l-.646-.647-.646.647a.5.5 0 0 1-.354.146H3a.5.5 0 0 1 0-1h2.293L6 15.793V11h-.5a.5.5 0 0 1 0-1H6V3.707L5.293 3H3a.5.5 0 0 1-.5-.5Z" fill="#000"/>\n <path fill-rule="evenodd" clip-rule="evenodd" d="m5.793 3.5-.5-.5H3a.5.5 0 0 1 0-1h2.5a.5.5 0 0 1 .354.146l.145.146.501.5.646-.646A.5.5 0 0 1 7.5 2H10a.5.5 0 0 1 0 1H7.707L7 3.707V10h.5a.5.5 0 0 1 0 1H7v4.793l.707.707H10a.5.5 0 0 1 0 1H7.5a.5.5 0 0 1-.354-.146l-.646-.647-.5.5-.146.147a.5.5 0 0 1-.354.146H3a.5.5 0 0 1 0-1h2.293L6 15.793V11h-.5a.5.5 0 0 1 0-1H6V3.707L5.793 3.5Zm-.914.5L5 4.121v4.964a1.5 1.5 0 0 0 0 2.83v3.464l-.121.121H3a1.5 1.5 0 0 0 0 3h2.5a1.5 1.5 0 0 0 1-.382 1.5 1.5 0 0 0 1 .382H10a1.5 1.5 0 0 0 0-3H8.121L8 15.379v-3.464a1.5 1.5 0 0 0 0-2.83V4.121L8.121 4H10a1.5 1.5 0 0 0 0-3H7.5a1.5 1.5 0 0 0-1 .382A1.5 1.5 0 0 0 5.5 1H3a1.5 1.5 0 1 0 0 3h1.879Z" fill="#fff"/>\n</svg>\n',be='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V3Z"/><path d="M16 3.25a1.5 1.5 0 0 1 1.5 1.5v1.7a2.25 2.25 0 0 1-1.932 2.226l-4.424.632a.75.75 0 0 0-.644.743V11a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1v-.95a2.25 2.25 0 0 1 1.932-2.226l4.424-.632A.75.75 0 0 0 16 6.449V3.25Z"/></svg>',Le='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10.5 5.5H7v5h3.5a2.5 2.5 0 1 0 0-5zM5 3h6.5v.025a5 5 0 0 1 0 9.95V13H7v4a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z"/></svg>',Ce='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m7.3 17.37-.061.088a1.518 1.518 0 0 1-.934.535l-4.178.663-.806-4.153a1.495 1.495 0 0 1 .187-1.058l.056-.086L8.77 2.639c.958-1.351 2.803-1.076 4.296-.03 1.497 1.047 2.387 2.693 1.433 4.055L7.3 17.37zM9.14 4.728l-5.545 8.346 3.277 2.294 5.544-8.346L9.14 4.728zM6.07 16.512l-3.276-2.295.53 2.73 2.746-.435zM9.994 3.506 13.271 5.8c.316-.452-.16-1.333-1.065-1.966-.905-.634-1.895-.78-2.212-.328zM8 18.5 9.375 17H19v1.5H8z"/></svg>',Ie='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path class="ck-icon__fill" d="M10.126 2.268 2.002 13.874l1.895 1.852 2.521 1.402L14.47 5.481l-1.543-2.568-2.801-.645z"/><path d="m4.5 18.088-2.645-1.852-.04-2.95-.006-.005.006-.008v-.025l.011.008L8.73 2.97c.165-.233.356-.417.567-.557l-1.212.308L4.604 7.9l-.83-.558 3.694-5.495 2.708-.69 1.65 1.145.046.018.85-1.216 2.16 1.512-.856 1.222c.828.967 1.144 2.141.432 3.158L7.55 17.286l.006.005-3.055.797H4.5zm-.634.166-1.976.516-.026-1.918 2.002 1.402zM9.968 3.817l-.006-.004-6.123 9.184 3.277 2.294 6.108-9.162.005.003c.317-.452-.16-1.332-1.064-1.966-.891-.624-1.865-.776-2.197-.349zM8.245 18.5 9.59 17h9.406v1.5H8.245z"/></svg>',ye='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6.999 2H15a1 1 0 0 1 0 2h-1.004v13a1 1 0 1 1-2 0V4H8.999v13a1 1 0 1 1-2 0v-7A4 4 0 0 1 3 6a4 4 0 0 1 3.999-4z"/></svg>',Be='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M10 19a9 9 0 1 0 0-18 9 9 0 0 0 0 18Zm3.45-9.872a1 1 0 0 1 0 1.744l-4.96 2.79A1 1 0 0 1 7 12.79V7.21a1 1 0 0 1 1.49-.872l4.96 2.79Z"/></svg>',Ae='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10 2a1 1 0 0 0-1 1v6H3a1 1 0 1 0 0 2h6v6a1 1 0 1 0 2 0v-6h6a1 1 0 1 0 0-2h-6V3a1 1 0 0 0-1-1Z"/></svg>',Ee='<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">\n<circle cx="9.00037" cy="9.79993" r="1.5"/>\n<path d="M5.75024 2.75005C5.75019 2.00005 5.75006 2.00005 5.75006 2.00005L5.74877 2.00005L5.74647 2.00006L5.73927 2.00009L5.71503 2.0003C5.6947 2.00053 5.66619 2.00098 5.63111 2.00185C5.56123 2.0036 5.46388 2.00707 5.35241 2.01402C5.14095 2.02722 4.83482 2.05536 4.56712 2.12276C4.1703 2.22267 3.82938 2.40399 3.55967 2.67392C3.29221 2.94161 3.1311 3.26001 3.03544 3.5803C2.85401 4.18776 2.8854 4.89393 2.92747 5.49256C2.9373 5.6324 2.94792 5.76849 2.95828 5.90131C2.99629 6.38849 3.03087 6.83163 3.01038 7.25369C2.98475 7.78147 2.87469 8.13279 2.6777 8.3656C2.45517 8.6286 2.1841 8.79405 1.95875 8.89436C1.84756 8.94386 1.75282 8.97509 1.68956 8.99319C1.65813 9.00219 1.63513 9.00776 1.62253 9.01062L1.61304 9.01269L1.00024 9.12173V9.75005H3.4023C3.54579 9.63123 3.68814 9.49364 3.82278 9.33451C4.33087 8.73405 4.47638 7.99036 4.50861 7.32643C4.5342 6.79933 4.48942 6.23163 4.4502 5.73429C4.44071 5.61404 4.43155 5.49785 4.42378 5.3874C4.38011 4.76596 4.37986 4.32043 4.4727 4.00956C4.51418 3.87069 4.56668 3.78828 4.62078 3.73414C4.67264 3.68223 4.76124 3.6207 4.93336 3.57736C5.06269 3.5448 5.25656 3.52293 5.44585 3.51111C5.53475 3.50556 5.61296 3.50277 5.66854 3.50139C5.6962 3.5007 5.71789 3.50036 5.73209 3.5002L5.74748 3.50007L5.75054 3.50005L6.5003 3.5L6.50019 2L5.75006 2.00005L5.75024 2.75005Z"/>\n<path d="M5.75024 16.7501C5.75019 17.5001 5.75006 17.5001 5.75006 17.5001L5.74877 17.5001L5.74647 17.5001L5.73927 17.5L5.71503 17.4998C5.6947 17.4996 5.66619 17.4991 5.63111 17.4983C5.56123 17.4965 5.46388 17.493 5.35241 17.4861C5.14095 17.4729 4.83482 17.4448 4.56712 17.3774C4.1703 17.2774 3.82938 17.0961 3.55967 16.8262C3.29221 16.5585 3.1311 16.2401 3.03544 15.9198C2.85401 15.3124 2.8854 14.6062 2.92747 14.0076C2.9373 13.8677 2.94792 13.7316 2.95828 13.5988C2.99629 13.1116 3.03087 12.6685 3.01038 12.2464C2.98475 11.7186 2.87469 11.3673 2.6777 11.1345C2.45517 10.8715 2.1841 10.7061 1.95875 10.6058C1.84756 10.5563 1.75282 10.525 1.68956 10.5069C1.65813 10.4979 1.63513 10.4924 1.62253 10.4895L1.61304 10.4874L1.00024 10.3784V9.75005H3.4023C3.54579 9.86887 3.68814 10.0065 3.82278 10.1656C4.33087 10.7661 4.47638 11.5098 4.50861 12.1737C4.5342 12.7008 4.48942 13.2685 4.4502 13.7658C4.44071 13.8861 4.43155 14.0023 4.42378 14.1127C4.38011 14.7341 4.37986 15.1797 4.4727 15.4906C4.51418 15.6294 4.56668 15.7118 4.62078 15.766C4.67264 15.8179 4.76124 15.8794 4.93336 15.9228C5.06269 15.9553 5.25656 15.9772 5.44585 15.989C5.53475 15.9945 5.61296 15.9973 5.66854 15.9987C5.6962 15.9994 5.71789 15.9998 5.73209 15.9999L5.74748 16L5.75054 16.0001L6.5003 16.0001L6.50019 17.5001L5.75006 17.5001L5.75024 16.7501Z"/>\n<path fill-rule="evenodd" clip-rule="evenodd" d="M12.2514 2.00005L12.2501 2.00005L11.5 2L11.4999 3.5L12.2496 3.50005L12.2527 3.50007L12.2681 3.5002C12.2823 3.50036 12.304 3.5007 12.3316 3.50139C12.3872 3.50277 12.4654 3.50556 12.5543 3.51111C12.7436 3.52293 12.9375 3.5448 13.0668 3.57736C13.2389 3.6207 13.3275 3.68223 13.3794 3.73414C13.4335 3.78828 13.486 3.87069 13.5275 4.00956C13.6203 4.32043 13.6201 4.76596 13.5764 5.3874C13.5686 5.49785 13.5595 5.61404 13.55 5.73429C13.5108 6.23163 13.466 6.79933 13.4916 7.32643C13.5238 7.99036 13.6693 8.73405 14.1774 9.33451C14.312 9.49364 14.4544 9.63123 14.5979 9.75005C14.4544 9.86887 14.312 10.0065 14.1774 10.1656C13.7121 10.7154 13.5509 11.3854 13.5023 12.0042C13.6011 12.0012 13.7003 11.9997 13.7999 11.9997C14.208 11.9997 14.6093 12.0247 15.0018 12.0729C15.0416 11.6402 15.1479 11.3408 15.3225 11.1345C15.545 10.8715 15.8161 10.7061 16.0414 10.6058C16.1526 10.5563 16.2474 10.525 16.3106 10.5069C16.342 10.4979 16.365 10.4924 16.3776 10.4895L16.3871 10.4874L16.9999 10.3784V9.75005V9.12173L16.3871 9.01269L16.3776 9.01062C16.365 9.00776 16.342 9.00219 16.3106 8.99319C16.2474 8.97509 16.1526 8.94386 16.0414 8.89436C15.8161 8.79405 15.545 8.6286 15.3225 8.3656C15.1255 8.13279 15.0154 7.78147 14.9898 7.25369C14.9693 6.83163 15.0039 6.38849 15.0419 5.90131C15.0523 5.76849 15.0629 5.6324 15.0727 5.49256C15.1148 4.89393 15.1462 4.18776 14.9647 3.5803C14.8691 3.26001 14.708 2.94161 14.4405 2.67392C14.1708 2.40399 13.8299 2.22267 13.433 2.12276C13.1654 2.05536 12.8592 2.02722 12.6478 2.01402C12.5363 2.00707 12.4389 2.0036 12.3691 2.00185C12.334 2.00098 12.3055 2.00053 12.2851 2.0003L12.2609 2.00009L12.2537 2.00006L12.2514 2.00005Z"/>\n<path fill-rule="evenodd" clip-rule="evenodd" d="M9.00335 17.2062L9.00308 17.2065C8.7234 17.5118 8.24919 17.5327 7.94372 17.2532C7.63816 16.9735 7.61716 16.4991 7.89681 16.1935L8.45008 16.6999C7.89681 16.1935 7.89697 16.1934 7.89713 16.1932L7.89751 16.1928L7.89844 16.1918L7.90098 16.189L7.90879 16.1806L7.93517 16.1526C7.95746 16.1292 7.98914 16.0963 8.02971 16.0555C8.11079 15.9738 8.22768 15.8597 8.37644 15.724C8.6732 15.4532 9.10079 15.0927 9.62744 14.7314C10.6647 14.0198 12.1659 13.2499 13.8501 13.2499C15.5343 13.2499 17.0355 14.0198 18.0727 14.7314C18.5994 15.0927 19.027 15.4532 19.3237 15.724C19.4725 15.8597 19.5894 15.9738 19.6705 16.0555C19.711 16.0963 19.7427 16.1292 19.765 16.1526L19.7914 16.1806L19.7992 16.189L19.8017 16.1918L19.8027 16.1928L19.803 16.1932C19.8032 16.1934 19.8034 16.1935 19.2501 16.6999L19.8034 16.1935C20.083 16.4991 20.062 16.9735 19.7565 17.2532C19.4511 17.5326 18.9772 17.5118 18.6975 17.207L18.6971 17.2065L18.6968 17.2062L18.6945 17.2037L18.6783 17.1865C18.6629 17.1704 18.6386 17.1452 18.6059 17.1123C18.5404 17.0463 18.4414 16.9494 18.3127 16.8321C18.0546 16.5966 17.6814 16.282 17.2242 15.9683C16.9805 15.8012 16.7185 15.6381 16.4421 15.4883C16.7016 15.9322 16.8502 16.4487 16.8502 16.9999C16.8502 18.6567 15.5071 19.9999 13.8502 19.9999C12.1934 19.9999 10.8502 18.6567 10.8502 16.9999C10.8502 16.4486 10.9989 15.932 11.2584 15.4881C10.9819 15.6379 10.7198 15.8011 10.476 15.9683C10.0188 16.282 9.64555 16.5966 9.38746 16.8321C9.25879 16.9494 9.15975 17.0463 9.09425 17.1123C9.06153 17.1452 9.03726 17.1704 9.02192 17.1865L9.00572 17.2037L9.00335 17.2062Z"/>\n<circle cx="14.8253" cy="16.1749" r="1.125" fill="white"/>\n</svg>\n',ke='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11.463 5.187a.888.888 0 1 1 1.254 1.255L9.16 10l3.557 3.557a.888.888 0 1 1-1.254 1.255L7.26 10.61a.888.888 0 0 1 .16-1.382l4.043-4.042z"/></svg>',De='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M15 2.5H5v4h10v-4zm-1 1v2H6v-2h8z"/><path d="M16 5.5a2.5 2.5 0 0 1 2.495 2.336L18.5 8v5a2.5 2.5 0 0 1-2.336 2.495L16 15.5h-1V14h1a1 1 0 0 0 .993-.883L17 13V8a1 1 0 0 0-.883-.993L16 7H4a1 1 0 0 0-.993.883L3 8v5a1 1 0 0 0 .883.993L4 14h1v1.5H4a2.5 2.5 0 0 1-2.495-2.336L1.5 13V8a2.5 2.5 0 0 1 2.336-2.495L4 5.5h12zM6.5 8a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1h2z"/><path d="M15 12H5v7h10v-7zm-1 1v5H6v-5h8z"/><path d="M7 14h6v1H7zm0 2h6v1H7z"/></svg>',Se='<svg xmlns="http://www.w3.org/2000/svg" width="53" height="10" viewBox="0 0 53 10"><path fill="#1C2331" d="M31.724 1.492a15.139 15.139 0 0 0 .045 1.16 2.434 2.434 0 0 0-.687-.34 3.68 3.68 0 0 0-1.103-.166 2.332 2.332 0 0 0-1.14.255 1.549 1.549 0 0 0-.686.87c-.15.41-.225.98-.225 1.712 0 .939.148 1.659.444 2.161.297.503.792.754 1.487.754.452.015.9-.094 1.294-.316.296-.174.557-.4.771-.669l.14.852h1.282V.007h-1.623v1.485ZM31 6.496a1.77 1.77 0 0 1-.494.061.964.964 0 0 1-.521-.127.758.758 0 0 1-.296-.466 3.984 3.984 0 0 1-.093-.992 4.208 4.208 0 0 1 .098-1.052.753.753 0 0 1 .307-.477 1.08 1.08 0 0 1 .55-.122c.233-.004.466.026.69.089l.483.144v2.553c-.11.076-.213.143-.307.2a1.73 1.73 0 0 1-.417.189ZM35.68 0l-.702.004c-.322.002-.482.168-.48.497l.004.581c.002.33.164.493.486.49l.702-.004c.322-.002.481-.167.48-.496L36.165.49c-.002-.33-.164-.493-.486-.491ZM36.145 2.313l-1.612.01.034 5.482 1.613-.01-.035-5.482ZM39.623.79 37.989.8 38 2.306l-.946.056.006 1.009.949-.006.024 2.983c.003.476.143.844.419 1.106.275.26.658.39 1.148.387.132 0 .293-.01.483-.03.19-.02.38-.046.57-.08.163-.028.324-.068.482-.119l-.183-1.095-.702.004a.664.664 0 0 1-.456-.123.553.553 0 0 1-.14-.422l-.016-2.621 1.513-.01-.006-1.064-1.514.01-.01-1.503ZM46.226 2.388c-.41-.184-.956-.274-1.636-.27-.673.004-1.215.101-1.627.29-.402.179-.72.505-.888.91-.18.419-.268.979-.264 1.68.004.688.1 1.24.285 1.655.172.404.495.724.9.894.414.18.957.268 1.63.264.68-.004 1.224-.099 1.632-.284.4-.176.714-.501.878-.905.176-.418.263-.971.258-1.658-.004-.702-.097-1.261-.28-1.677a1.696 1.696 0 0 0-.888-.9Zm-.613 3.607a.77.77 0 0 1-.337.501 1.649 1.649 0 0 1-1.317.009.776.776 0 0 1-.343-.497 4.066 4.066 0 0 1-.105-1.02 4.136 4.136 0 0 1 .092-1.03.786.786 0 0 1 .337-.507 1.59 1.59 0 0 1 1.316-.008.79.79 0 0 1 .344.502c.078.337.113.683.105 1.03.012.343-.019.685-.092 1.02ZM52.114 2.07a2.67 2.67 0 0 0-1.128.278c-.39.191-.752.437-1.072.73l-.157-.846-1.273.008.036 5.572 1.623-.01-.024-3.78c.35-.124.646-.22.887-.286.26-.075.53-.114.8-.118l.45-.003.144-1.546-.286.001ZM22.083 7.426l-1.576-2.532a2.137 2.137 0 0 0-.172-.253 1.95 1.95 0 0 0-.304-.29.138.138 0 0 1 .042-.04 1.7 1.7 0 0 0 .328-.374l1.75-2.71c.01-.015.025-.028.024-.048-.01-.01-.021-.007-.031-.007L20.49 1.17a.078.078 0 0 0-.075.045l-.868 1.384c-.23.366-.46.732-.688 1.099a.108.108 0 0 1-.112.06c-.098-.005-.196-.001-.294-.002-.018 0-.038.006-.055-.007.002-.02.002-.039.005-.058a4.6 4.6 0 0 0 .046-.701V1.203c0-.02-.009-.032-.03-.03h-.033L16.93 1.17c-.084 0-.073-.01-.073.076v6.491c-.001.018.006.028.025.027h1.494c.083 0 .072.007.072-.071v-2.19c0-.055-.003-.11-.004-.166a3.366 3.366 0 0 0-.05-.417h.06c.104 0 .209.002.313-.002a.082.082 0 0 1 .084.05c.535.913 1.07 1.824 1.607 2.736a.104.104 0 0 0 .103.062c.554-.003 1.107-.002 1.66-.002l.069-.003-.019-.032-.188-.304ZM27.112 6.555c-.005-.08-.004-.08-.082-.08h-2.414c-.053 0-.106-.003-.159-.011a.279.279 0 0 1-.246-.209.558.558 0 0 1-.022-.15c0-.382 0-.762-.002-1.143 0-.032.007-.049.042-.044h2.504c.029.003.037-.012.034-.038V3.814c0-.089.013-.078-.076-.078h-2.44c-.07 0-.062.003-.062-.06v-.837c0-.047.004-.093.013-.14a.283.283 0 0 1 .241-.246.717.717 0 0 1 .146-.011h2.484c.024.002.035-.009.036-.033l.003-.038.03-.496c.01-.183.024-.365.034-.548.005-.085.003-.087-.082-.094-.218-.018-.437-.038-.655-.05a17.845 17.845 0 0 0-.657-.026 72.994 72.994 0 0 0-1.756-.016 1.7 1.7 0 0 0-.471.064 1.286 1.286 0 0 0-.817.655c-.099.196-.149.413-.145.633v3.875c0 .072.003.144.011.216a1.27 1.27 0 0 0 .711 1.029c.228.113.48.167.734.158.757-.005 1.515.002 2.272-.042.274-.016.548-.034.82-.053.03-.002.043-.008.04-.041-.008-.104-.012-.208-.019-.312a69.964 69.964 0 0 1-.05-.768ZM16.14 7.415l-.127-1.075c-.004-.03-.014-.04-.044-.037a13.125 13.125 0 0 1-.998.073c-.336.01-.672.02-1.008.016-.116-.001-.233-.014-.347-.039a.746.746 0 0 1-.45-.262c-.075-.1-.132-.211-.167-.33a3.324 3.324 0 0 1-.126-.773 9.113 9.113 0 0 1-.015-.749c0-.285.022-.57.065-.852.023-.158.066-.312.127-.46a.728.728 0 0 1 .518-.443 1.64 1.64 0 0 1 .397-.048c.628-.001 1.255.003 1.882.05.022.001.033-.006.036-.026l.003-.031.06-.55c.019-.177.036-.355.057-.532.004-.034-.005-.046-.04-.056a5.595 5.595 0 0 0-1.213-.21 10.783 10.783 0 0 0-.708-.02c-.24-.003-.48.01-.719.041a3.477 3.477 0 0 0-.625.14 1.912 1.912 0 0 0-.807.497c-.185.2-.33.433-.424.688a4.311 4.311 0 0 0-.24 1.096c-.031.286-.045.572-.042.86-.006.43.024.86.091 1.286.04.25.104.497.193.734.098.279.26.53.473.734.214.205.473.358.756.446.344.11.702.17 1.063.177a8.505 8.505 0 0 0 1.578-.083 6.11 6.11 0 0 0 .766-.18c.03-.008.047-.023.037-.057a.157.157 0 0 1-.003-.025Z"/><path fill="#AFE229" d="M6.016 6.69a1.592 1.592 0 0 0-.614.21c-.23.132-.422.32-.56.546-.044.072-.287.539-.287.539l-.836 1.528.009.006c.038.025.08.046.123.063.127.046.26.07.395.073.505.023 1.011-.007 1.517-.003.29.009.58.002.869-.022a.886.886 0 0 0 .395-.116.962.962 0 0 0 .312-.286c.056-.083.114-.163.164-.249.24-.408.48-.816.718-1.226.075-.128.148-.257.222-.386l.112-.192a1.07 1.07 0 0 0 .153-.518l-1.304.023s-1.258-.005-1.388.01Z"/><path fill="#771BFF" d="m2.848 9.044.76-1.39.184-.352c-.124-.067-.245-.14-.367-.21-.346-.204-.706-.384-1.045-.6a.984.984 0 0 1-.244-.207c-.108-.134-.136-.294-.144-.46-.021-.409-.002-.818-.009-1.227-.003-.195 0-.39.003-.585.004-.322.153-.553.427-.713l.833-.488c.22-.13.44-.257.662-.385.05-.029.105-.052.158-.077.272-.128.519-.047.76.085l.044.028c.123.06.242.125.358.196.318.178.635.357.952.537.095.056.187.117.275.184.194.144.254.35.266.578.016.284.007.569.006.853-.001.28.004.558 0 .838.592-.003 1.259 0 1.259 0l.723-.013c-.003-.292-.007-.584-.007-.876 0-.524.015-1.048-.016-1.571-.024-.42-.135-.8-.492-1.067a5.02 5.02 0 0 0-.506-.339A400.52 400.52 0 0 0 5.94.787C5.722.664 5.513.524 5.282.423 5.255.406 5.228.388 5.2.373 4.758.126 4.305-.026 3.807.21c-.097.046-.197.087-.29.14A699.896 699.896 0 0 0 .783 1.948c-.501.294-.773.717-.778 1.31-.004.36-.009.718-.001 1.077.016.754-.017 1.508.024 2.261.016.304.07.6.269.848.127.15.279.28.448.382.622.4 1.283.734 1.92 1.11l.183.109Z"/></svg>\n',_e='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 10.423a6.5 6.5 0 0 1 6.056-6.408l.038.67C6.448 5.423 5.354 7.663 5.22 10H9c.552 0 .5.432.5.986v4.511c0 .554-.448.503-1 .503h-5c-.552 0-.5-.449-.5-1.003v-4.574zm8 0a6.5 6.5 0 0 1 6.056-6.408l.038.67c-2.646.739-3.74 2.979-3.873 5.315H17c.552 0 .5.432.5.986v4.511c0 .554-.448.503-1 .503h-5c-.552 0-.5-.449-.5-1.003v-4.574z"/></svg>',Te='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m14.958 9.367-2.189 1.837a.75.75 0 0 0 .965 1.149l3.788-3.18a.747.747 0 0 0 .21-.284.75.75 0 0 0-.17-.945L13.77 4.762a.75.75 0 1 0-.964 1.15l2.331 1.955H6.22A.75.75 0 0 0 6 7.9a4 4 0 1 0 1.477 7.718l-.344-1.489A2.5 2.5 0 1 1 6.039 9.4l-.008-.032h8.927z"/></svg>',Oe='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M5.2 7h9.2c.6 0 1 .4 1 1v9.9c0 .5-.4 1-1 1H5.2a1 1 0 0 1-1-1V8c0-.6.4-1 1-1zm1 1.5c-.3 0-.5.2-.5.5v8c0 .3.2.5.5.5h.5c.2 0 .5-.2.5-.5V9c0-.3-.3-.5-.5-.5h-.5zm3.2 0c-.2 0-.5.2-.5.5v8c0 .3.3.5.5.5h.5c.3 0 .5-.2.5-.5V9c0-.3-.2-.5-.5-.5h-.4zm3.5 0c-.2 0-.5.2-.5.5v8c0 .3.3.5.5.5h.5c.3 0 .5-.2.5-.5V9c0-.3-.2-.5-.5-.5h-.5zm-1.4-7.1H8.3L6.5 3.6H3.8c-.5 0-.7.3-.7.8s.2.7.7.7h12c.6 0 .9-.2.9-.7 0-.5-.3-.8-1-.8h-2.4l-1.8-2.2z"/></svg>',Pe='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M8.69 14.915c.053.052.173.083.36.093a.366.366 0 0 1 .345.485l-.003.01a.738.738 0 0 1-.697.497h-2.67a.374.374 0 0 1-.353-.496l.013-.038a.681.681 0 0 1 .644-.458c.197-.012.325-.043.386-.093a.28.28 0 0 0 .072-.11L9.592 4.5H6.269c-.359-.017-.609.013-.75.09-.142.078-.289.265-.442.563-.192.29-.516.464-.864.464H4.17a.43.43 0 0 1-.407-.569L4.46 3h13.08l-.62 2.043a.81.81 0 0 1-.775.574h-.114a.486.486 0 0 1-.486-.486c.001-.284-.054-.464-.167-.54-.112-.076-.367-.106-.766-.091h-3.28l-2.68 10.257c-.006.074.007.127.038.158zM3 17h8a.5.5 0 1 1 0 1H3a.5.5 0 1 1 0-1zm11.299 1.17a.75.75 0 1 1-1.06-1.06l1.414-1.415-1.415-1.414a.75.75 0 0 1 1.06-1.06l1.415 1.414 1.414-1.415a.75.75 0 1 1 1.06 1.06l-1.413 1.415 1.414 1.415a.75.75 0 0 1-1.06 1.06l-1.415-1.414-1.414 1.414z"/></svg>',je='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M5.2 7h9.2c.6 0 1 .4 1 1v9.9c0 .5-.4 1-1 1H5.2a1 1 0 0 1-1-1V8c0-.6.4-1 1-1Zm1 1.5c-.3 0-.5.2-.5.5v8c0 .3.2.5.5.5h.5c.2 0 .5-.2.5-.5V9c0-.3-.3-.5-.5-.5h-.5Zm3.2 0c-.2 0-.5.2-.5.5v8c0 .3.3.5.5.5h.5c.3 0 .5-.2.5-.5V9c0-.3-.2-.5-.5-.5h-.5Zm3.5 0c-.2 0-.5.2-.5.5v8c0 .3.3.5.5.5h.5c.3 0 .5-.2.5-.5V9c0-.3-.2-.5-.5-.5h-.5Zm-1.4-7.1H8.3L6.5 3.6H3.8c-.5 0-.7.3-.7.8s.2.7.7.7h12c.6 0 .9-.2.9-.7 0-.5-.3-.8-1-.8h-2.4l-1.8-2.2Z"/></svg>',Re='<svg viewBox="0 0 10 8" xmlns="http://www.w3.org/2000/svg"><path d="M9.055.263v3.972h-6.77M1 4.216l2-2.038m-2 2 2 2.038"/></svg>',Fe='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11 1a9 9 0 1 1-8.027 13.075l1.128-1.129A7.502 7.502 0 0 0 18.5 10a7.5 7.5 0 1 0-14.962.759l-.745-.746-.76.76A9 9 0 0 1 11 1z"/><path d="M.475 8.17a.75.75 0 0 1 .978.047l.075.082 1.284 1.643 1.681-1.284a.75.75 0 0 1 .978.057l.073.083a.75.75 0 0 1-.057.978l-.083.073-2.27 1.737a.75.75 0 0 1-.973-.052l-.074-.082-1.741-2.23a.75.75 0 0 1 .13-1.052z"/><path d="M11.5 5v4.999l3.196 3.196-1.06 1.06L10.1 10.72l-.1-.113V5z"/></svg>',Ne='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M9.61 2.66a1.406 1.406 0 1 0-1.407 0v.891H3.28a2.11 2.11 0 0 0-2.11 2.11v10.312a2.11 2.11 0 0 0 2.11 2.109h5.684l-.054-1.157.18-.25H3.28a.703.703 0 0 1-.703-.702V5.66c0-.389.315-.704.703-.704h11.25c.388 0 .703.315.703.704v2.484l.358-.497a2.492 2.492 0 0 1 1.048-.84V5.66a2.11 2.11 0 0 0-2.11-2.11H9.61v-.89Z"/><path d="M5.625 10.817c.518 0 .937-.63.937-1.407 0-.776-.42-1.406-.937-1.406-.518 0-.938.63-.938 1.406 0 .777.42 1.407.938 1.407Z"/><path d="M13.125 9.41c0 .777-.42 1.407-.938 1.407s-.937-.63-.937-1.407c0-.776.42-1.406.937-1.406.518 0 .938.63.938 1.406Z"/><path d="M.937 8.004A.937.937 0 0 0 0 8.942v1.875c0 .517.42.937.937.937v-3.75Z"/><path d="M6.128 12.51a.782.782 0 0 1 1.085.216c.272.408.907.707 1.693.707s1.421-.3 1.693-.707a.782.782 0 0 1 1.302.868c-.666 1-1.906 1.403-2.995 1.403-1.089 0-2.329-.404-2.995-1.403a.782.782 0 0 1 .217-1.085Z"/><path d="m16.987 8.91-.622.864 2.879 2.074.622-.864a.71.71 0 0 0-.161-.99l-1.728-1.245a.71.71 0 0 0-.99.161Z"/><path d="M11.635 19.951a.355.355 0 0 1-.449-.31l-.214-2.38 4.978-6.911 2.88 2.074-4.978 6.91-2.217.617Z"/></svg>',Ue='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M.75 15.5a.75.75 0 0 1 .75.75V18l.008.09A.5.5 0 0 0 2 18.5h1.75a.75.75 0 1 1 0 1.5H1.5l-.144-.007a1.5 1.5 0 0 1-1.35-1.349L0 18.5v-2.25a.75.75 0 0 1 .75-.75zm18.5 0a.75.75 0 0 1 .75.75v2.25l-.007.144a1.5 1.5 0 0 1-1.349 1.35L18.5 20h-2.25a.75.75 0 1 1 0-1.5H18a.5.5 0 0 0 .492-.41L18.5 18v-1.75a.75.75 0 0 1 .75-.75zm-10.45 3c.11 0 .2.09.2.2v1.1a.2.2 0 0 1-.2.2H7.2a.2.2 0 0 1-.2-.2v-1.1c0-.11.09-.2.2-.2h1.6zm4 0c.11 0 .2.09.2.2v1.1a.2.2 0 0 1-.2.2h-1.6a.2.2 0 0 1-.2-.2v-1.1c0-.11.09-.2.2-.2h1.6zm.45-5.5a.75.75 0 1 1 0 1.5h-8.5a.75.75 0 1 1 0-1.5h8.5zM1.3 11c.11 0 .2.09.2.2v1.6a.2.2 0 0 1-.2.2H.2a.2.2 0 0 1-.2-.2v-1.6c0-.11.09-.2.2-.2h1.1zm18.5 0c.11 0 .2.09.2.2v1.6a.2.2 0 0 1-.2.2h-1.1a.2.2 0 0 1-.2-.2v-1.6c0-.11.09-.2.2-.2h1.1zm-4.55-2a.75.75 0 1 1 0 1.5H4.75a.75.75 0 1 1 0-1.5h10.5zM1.3 7c.11 0 .2.09.2.2v1.6a.2.2 0 0 1-.2.2H.2a.2.2 0 0 1-.2-.2V7.2c0-.11.09-.2.2-.2h1.1zm18.5 0c.11 0 .2.09.2.2v1.6a.2.2 0 0 1-.2.2h-1.1a.2.2 0 0 1-.2-.2V7.2c0-.11.09-.2.2-.2h1.1zm-4.55-2a.75.75 0 1 1 0 1.5h-2.5a.75.75 0 1 1 0-1.5h2.5zm-5 0a.75.75 0 1 1 0 1.5h-5.5a.75.75 0 0 1 0-1.5h5.5zm-6.5-5a.75.75 0 0 1 0 1.5H2a.5.5 0 0 0-.492.41L1.5 2v1.75a.75.75 0 0 1-1.5 0V1.5l.007-.144A1.5 1.5 0 0 1 1.356.006L1.5 0h2.25zM18.5 0l.144.007a1.5 1.5 0 0 1 1.35 1.349L20 1.5v2.25a.75.75 0 1 1-1.5 0V2l-.008-.09A.5.5 0 0 0 18 1.5h-1.75a.75.75 0 1 1 0-1.5h2.25zM8.8 0c.11 0 .2.09.2.2v1.1a.2.2 0 0 1-.2.2H7.2a.2.2 0 0 1-.2-.2V.2c0-.11.09-.2.2-.2h1.6zm4 0c.11 0 .2.09.2.2v1.1a.2.2 0 0 1-.2.2h-1.6a.2.2 0 0 1-.2-.2V.2c0-.11.09-.2.2-.2h1.6z"/></svg>',We='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M3.734 6.375H1.75a.75.75 0 0 1 0-1.5h1.984a2.626 2.626 0 0 1 5.032 0h9.48a.75.75 0 0 1 0 1.5h-9.48a2.626 2.626 0 0 1-5.032 0Zm1.141-.75a1.375 1.375 0 1 1 2.75 0 1.375 1.375 0 0 1-2.75 0ZM16.263 14.625h1.983a.75.75 0 0 1 0 1.5h-1.983a2.626 2.626 0 0 1-5.033 0H1.75a.75.75 0 0 1 0-1.5h9.48a2.626 2.626 0 0 1 5.033 0Zm-1.142.75a1.375 1.375 0 1 1-2.75 0 1.375 1.375 0 0 1 2.75 0Z"/></svg>\n',$e='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m6.395 9.196 2.545-.007V6.498a.598.598 0 0 1 .598-.598h.299a.598.598 0 0 1 .598.598v6.877a.598.598 0 0 1-.598.598h-.299a.598.598 0 0 1-.598-.598v-2.691l-2.545.007v2.691a.598.598 0 0 1-.598.598h-.299a.598.598 0 0 1-.598-.598V6.505a.598.598 0 0 1 .598-.598h.299a.598.598 0 0 1 .598.598v2.691Z"/><path d="M15.094 13.417V6.462a.562.562 0 0 0-.562-.562h-.782a1 1 0 0 0-.39.08l-1.017.43a.562.562 0 0 0-.343.517v.197c0 .4.406.67.775.519l.819-.337v6.111c0 .31.251.562.561.562h.377c.31 0 .562-.251.562-.562Z"/><path d="M0 15.417v1.5h1.5v-1.5H0Z"/><path d="M18.5 15.417v1.5H20v-1.5h-1.5Z"/><path d="M18.5 12.333v1.5H20v-1.5h-1.5Z"/><path d="M18.5 9.25v1.5H20v-1.5h-1.5Z"/><path d="M18.5 6.167v1.5H20v-1.5h-1.5Z"/><path d="M0 18.5v.5a1 1 0 0 0 1 1h.5v-1.5H0Z"/><path d="M3.083 18.5V20h1.5v-1.5h-1.5Z"/><path d="M6.167 18.5V20h1.5v-1.5h-1.5Z"/><path d="M9.25 18.5V20h1.5v-1.5h-1.5Z"/><path d="M12.333 18.5V20h1.5v-1.5h-1.5Z"/><path d="M15.417 18.5V20h1.5v-1.5h-1.5Z"/><path d="M18.5 18.5V20h.5a1 1 0 0 0 1-1v-.5h-1.5Z"/><path clip-rule="evenodd" d="M0 1a1 1 0 0 1 1-1h18a1 1 0 0 1 1 1v3.583h-1.5V1.5h-17v12.333H0V1Z"/></svg>',qe='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m12.5 0 5 4.5v15.003h-16V0h11zM3 1.5v3.25l-1.497 1-.003 8 1.5 1v3.254L7.685 18l-.001 1.504H17.5V8.002L16 9.428l-.004-4.22-4.222-3.692L3 1.5z"/><path d="M4.06 6.64a.75.75 0 0 1 .958 1.15l-.085.07L2.29 9.75l2.646 1.89c.302.216.4.62.232.951l-.058.095a.75.75 0 0 1-.951.232l-.095-.058-3.5-2.5V9.14l3.496-2.5zm4.194 6.22a.75.75 0 0 1-.958-1.149l.085-.07 2.643-1.89-2.646-1.89a.75.75 0 0 1-.232-.952l.058-.095a.75.75 0 0 1 .95-.232l.096.058 3.5 2.5v1.22l-3.496 2.5zm7.644-.836 2.122 2.122-5.825 5.809-2.125-.005.003-2.116zm2.539-1.847 1.414 1.414a.5.5 0 0 1 0 .707l-1.06 1.06-2.122-2.12 1.061-1.061a.5.5 0 0 1 .707 0z"/></svg>',Ke='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10 2.5a7.47 7.47 0 0 1 4.231 1.31 7.268 7.268 0 0 1 2.703 3.454 7.128 7.128 0 0 1 .199 4.353c-.39 1.436-1.475 2.72-2.633 3.677h2.013c0-.226.092-.443.254-.603a.876.876 0 0 1 1.229 0c.163.16.254.377.254.603v.853c0 .209-.078.41-.22.567a.873.873 0 0 1-.547.28l-.101.006h-4.695a.517.517 0 0 1-.516-.518v-1.265c0-.21.128-.398.317-.489a5.601 5.601 0 0 0 2.492-2.371 5.459 5.459 0 0 0 .552-3.693 5.53 5.53 0 0 0-1.955-3.2A5.71 5.71 0 0 0 10 4.206 5.708 5.708 0 0 0 6.419 5.46 5.527 5.527 0 0 0 4.46 8.663a5.457 5.457 0 0 0 .554 3.695 5.6 5.6 0 0 0 2.497 2.37.55.55 0 0 1 .317.49v1.264c0 .286-.23.518-.516.518H2.618a.877.877 0 0 1-.614-.25.845.845 0 0 1-.254-.603v-.853c0-.226.091-.443.254-.603a.876.876 0 0 1 1.228 0c.163.16.255.377.255.603h1.925c-1.158-.958-2.155-2.241-2.545-3.678a7.128 7.128 0 0 1 .199-4.352 7.268 7.268 0 0 1 2.703-3.455A7.475 7.475 0 0 1 10 2.5z"/></svg>',Ge='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M7 16.4c-.8-.4-1.5-.9-2.2-1.5a.6.6 0 0 1-.2-.5l.3-.6h1c1 1.2 2.1 1.7 3.7 1.7 1 0 1.8-.3 2.3-.6.6-.4.6-1.2.6-1.3.2-1.2-.9-2.1-.9-2.1h2.1c.3.7.4 1.2.4 1.7v.8l-.6 1.2c-.6.8-1.1 1-1.6 1.2a6 6 0 0 1-2.4.6c-1 0-1.8-.3-2.5-.6zM6.8 9 6 8.3c-.4-.5-.5-.8-.5-1.6 0-.7.1-1.3.5-1.8.4-.6 1-1 1.6-1.3a6.3 6.3 0 0 1 4.7 0 4 4 0 0 1 1.7 1l.3.7c0 .1.2.4-.2.7-.4.2-.9.1-1 0a3 3 0 0 0-1.2-1c-.4-.2-1-.3-2-.4-.7 0-1.4.2-2 .6-.8.6-1 .8-1 1.5 0 .8.5 1 1.2 1.5.6.4 1.1.7 1.9 1H6.8z"/><path d="M3 10.5V9h14v1.5z"/></svg>',Je='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M15.875 4.419a.75.75 0 0 0-1.5 0v7.25H6.818l2.33-1.955a.75.75 0 0 0-.963-1.15l-3.792 3.182a.75.75 0 0 0-.17.945c.046.11.118.208.21.284l3.788 3.18a.75.75 0 1 0 .965-1.149l-2.19-1.837h7.629c.69 0 1.25-.56 1.25-1.25v-7.5Z"/></svg>',Qe='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m7.03 10.349 3.818-3.819a.8.8 0 1 1 1.132 1.132L8.16 11.48l3.819 3.818a.8.8 0 1 1-1.132 1.132L7.03 12.61l-3.818 3.82a.8.8 0 1 1-1.132-1.132L5.9 11.48 2.08 7.662A.8.8 0 1 1 3.212 6.53l3.818 3.82zm8.147 7.829h2.549c.254 0 .447.05.58.152a.49.49 0 0 1 .201.413.54.54 0 0 1-.159.393c-.105.108-.266.162-.48.162h-3.594c-.245 0-.435-.066-.572-.197a.621.621 0 0 1-.205-.463c0-.114.044-.265.132-.453a1.62 1.62 0 0 1 .288-.444c.433-.436.824-.81 1.172-1.122.348-.312.597-.517.747-.615.267-.183.49-.368.667-.553.177-.185.312-.375.405-.57.093-.194.139-.384.139-.57a1.008 1.008 0 0 0-.554-.917 1.197 1.197 0 0 0-.56-.133c-.426 0-.761.182-1.005.546a2.332 2.332 0 0 0-.164.39 1.609 1.609 0 0 1-.258.488c-.096.114-.237.17-.423.17a.558.558 0 0 1-.405-.156.568.568 0 0 1-.161-.427c0-.218.05-.446.151-.683.101-.238.252-.453.452-.646s.454-.349.762-.467a2.998 2.998 0 0 1 1.081-.178c.498 0 .923.076 1.274.228a1.916 1.916 0 0 1 1.004 1.032 1.984 1.984 0 0 1-.156 1.794c-.2.32-.405.572-.613.754-.208.182-.558.468-1.048.857-.49.39-.826.691-1.008.906a2.703 2.703 0 0 0-.24.309z"/></svg>',Xe='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M15.677 8.678h2.549c.254 0 .447.05.58.152a.49.49 0 0 1 .201.413.54.54 0 0 1-.159.393c-.105.108-.266.162-.48.162h-3.594c-.245 0-.435-.066-.572-.197a.621.621 0 0 1-.205-.463c0-.114.044-.265.132-.453a1.62 1.62 0 0 1 .288-.444c.433-.436.824-.81 1.172-1.122.348-.312.597-.517.747-.615.267-.183.49-.368.667-.553.177-.185.312-.375.405-.57.093-.194.139-.384.139-.57a1.008 1.008 0 0 0-.554-.917 1.197 1.197 0 0 0-.56-.133c-.426 0-.761.182-1.005.546a2.332 2.332 0 0 0-.164.39 1.609 1.609 0 0 1-.258.488c-.096.114-.237.17-.423.17a.558.558 0 0 1-.405-.156.568.568 0 0 1-.161-.427c0-.218.05-.446.151-.683.101-.238.252-.453.452-.646s.454-.349.762-.467a2.998 2.998 0 0 1 1.081-.178c.498 0 .923.076 1.274.228a1.916 1.916 0 0 1 1.004 1.032 1.984 1.984 0 0 1-.156 1.794c-.2.32-.405.572-.613.754-.208.182-.558.468-1.048.857-.49.39-.826.691-1.008.906a2.703 2.703 0 0 0-.24.309zM7.03 10.349l3.818-3.819a.8.8 0 1 1 1.132 1.132L8.16 11.48l3.819 3.818a.8.8 0 1 1-1.132 1.132L7.03 12.61l-3.818 3.82a.8.8 0 1 1-1.132-1.132L5.9 11.48 2.08 7.662A.8.8 0 1 1 3.212 6.53l3.818 3.82z"/></svg>',Ye='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.105 18-.17 1H2.5A1.5 1.5 0 0 1 1 17.5v-15A1.5 1.5 0 0 1 2.5 1h15A1.5 1.5 0 0 1 19 2.5v9.975l-.85-.124-.15-.302V8h-5v4h.021l-.172.351-1.916.28-.151.027c-.287.063-.54.182-.755.341L8 13v5h3.105zM2 12h5V8H2v4zm10-4H8v4h4V8zM2 2v5h5V2H2zm0 16h5v-5H2v5zM13 7h5V2h-5v5zM8 2v5h4V2H8z" opacity=".6"/><path d="m15.5 11.5 1.323 2.68 2.957.43-2.14 2.085.505 2.946L15.5 18.25l-2.645 1.39.505-2.945-2.14-2.086 2.957-.43L15.5 11.5zM13 6a1 1 0 0 1 1 1v3.172a2.047 2.047 0 0 0-.293.443l-.858 1.736-1.916.28-.151.027A1.976 1.976 0 0 0 9.315 14H7a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h6zm-1 2H8v4h4V8z"/></svg>',ta='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2.5 1h15A1.5 1.5 0 0 1 19 2.5v15a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 1 17.5v-15A1.5 1.5 0 0 1 2.5 1zM2 2v16h16V2H2z" opacity=".6"/><path d="M18 7v1H2V7h16zm0 5v1H2v-1h16z" opacity=".6"/><path d="M14 1v18a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1zm-2 1H8v4h4V2zm0 6H8v4h4V8zm0 6H8v4h4v-4z"/></svg>',ea='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2.5 1h15A1.5 1.5 0 0 1 19 2.5v15a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 1 17.5v-15A1.5 1.5 0 0 1 2.5 1zM2 2v16h16V2H2z" opacity=".6"/><path d="M7 2h1v16H7V2zm5 0h1v7h-1V2zm6 5v1H2V7h16zM8 12v1H2v-1h6z" opacity=".6"/><path d="M7 7h12a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1zm1 2v9h10V9H8z"/></svg>',aa='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 19a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v8.022a6.47 6.47 0 0 0-1.5-.709V2a.5.5 0 0 0-.5-.5H3a.5.5 0 0 0-.5.5v15a.5.5 0 0 0 .5.5h6.313c.173.534.412 1.037.709 1.5H3Z"/><path d="M9.174 14a6.489 6.489 0 0 0-.155 1H6v-1h3.174Z"/><path d="M10.022 12a6.51 6.51 0 0 0-.524 1H4v-1h6.022Z"/><path d="M12.034 10c-.448.283-.86.62-1.224 1H6v-1h6.034Z"/><path d="M12 4v1H4V4h8Z"/><path d="M14 7V6H6v1h8Z"/><path d="M15 9V8H7v1h8Z"/><path clip-rule="evenodd" d="M20 15.5a4.5 4.5 0 1 1-9 0 4.5 4.5 0 0 1 9 0ZM15.5 13a.5.5 0 0 0-.5.5V15h-1.5a.5.5 0 0 0 0 1H15v1.5a.5.5 0 0 0 1 0V16h1.5a.5.5 0 0 0 0-1H16v-1.5a.5.5 0 0 0-.5-.5Z"/></svg>',ia='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M8 2v5h4V2h1v5h5v1h-5v4h.021l-.172.351-1.916.28-.151.027c-.287.063-.54.182-.755.341L8 13v5H7v-5H2v-1h5V8H2V7h5V2h1zm4 6H8v4h4V8z" opacity=".6"/><path d="m15.5 11.5 1.323 2.68 2.957.43-2.14 2.085.505 2.946L15.5 18.25l-2.645 1.39.505-2.945-2.14-2.086 2.957-.43L15.5 11.5zM17 1a2 2 0 0 1 2 2v9.475l-.85-.124-.857-1.736a2.048 2.048 0 0 0-.292-.44L17 3H3v14h7.808l.402.392L10.935 19H3a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h14z"/></svg>',la='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2.5 1h15A1.5 1.5 0 0 1 19 2.5v15a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 1 17.5v-15A1.5 1.5 0 0 1 2.5 1zM2 2v16h16V2H2z" opacity=".6"/><path d="M7 2h1v16H7V2zm5 0h1v16h-1V2z" opacity=".6"/><path d="M1 6h18a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm1 2v4h4V8H2zm6 0v4h4V8H8zm6 0v4h4V8h-4z"/></svg>',na='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 5.5v3h4v-3H3Zm0 4v3h4v-3H3Zm0 4v3h4v-3H3Zm5 3h4v-3H8v3Zm5 0h4v-3h-4v3Zm4-4v-3h-4v3h4Zm0-4v-3h-4v3h4Zm1.5 8A1.5 1.5 0 0 1 17 18H3a1.5 1.5 0 0 1-1.5-1.5V3c.222-.863 1.068-1.5 2-1.5h13c.932 0 1.778.637 2 1.5v13.5Zm-6.5-4v-3H8v3h4Zm0-4v-3H8v3h4Z"/></svg>',oa='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M1.5 4.121C1.5 2.95 2.426 2 3.568 2h12.864c1.142 0 2.068.95 2.068 2.121V16.38c0 1.171-.926 2.121-2.068 2.121H3.568c-1.142 0-2.068-.95-2.068-2.121V4.12Zm2.068-.707a.699.699 0 0 0-.69.707V6.38h14.244V4.12a.698.698 0 0 0-.69-.707H3.568Zm13.554 4.38h-4.968v3.939h4.968V7.794Zm0 5.353h-4.968v3.939h4.278c.381 0 .69-.317.69-.707v-3.232Zm-6.347 3.939V7.794H2.878v8.585c0 .39.309.707.69.707h7.207Z"/></svg>',sa='<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 45">\n <path fill="#F0F0F0" d="M2 0h41s2 0 2 2v41s0 2 -2 2h-41s-2 0 -2 -2v-41s0 -2 2 -2" />\n <path fill="#D5D5D5" d="M11 10h10s1 0 1 1v24s0 1 -1 1h-10s-1 0 -1 -1v-24s0 -1 1 -1" />\n <path fill="#D5D5D5" d="M25 10h10s1 0 1 1v10s0 1 -1 1h-10s-1 0 -1 -1v-10s0 -1 1 -1" />\n <path fill="#D5D5D5" d="M25 24h10s1 0 1 1v10s0 1 -1 1h-10s-1 0 -1 -1v-10s0 -1 1 -1" />\n</svg>\n',ha='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M8 0H3a2 2 0 0 0-2 2v15a2 2 0 0 0 2 2h5a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2ZM2.5 2a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 .5.5v15a.5.5 0 0 1-.5.5H3a.5.5 0 0 1-.5-.5V2Z"/><path clip-rule="evenodd" d="M13 0h5a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-5a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2Zm0 1.5a.5.5 0 0 0-.5.5v5a.5.5 0 0 0 .5.5h5a.5.5 0 0 0 .5-.5V2a.5.5 0 0 0-.5-.5h-5Z"/><path clip-rule="evenodd" d="M13 10h5a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-5a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2Zm0 1.5a.5.5 0 0 0-.5.5v5a.5.5 0 0 0 .5.5h5a.5.5 0 0 0 .5-.5v-5a.5.5 0 0 0-.5-.5h-5Z"/></svg>',ra='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3.035 1C2.446 1 2 1.54 2 2.098V10.5h1.5v-8h13v8H18V2.098C18 1.539 17.48 1 16.9 1H3.035Zm10.453 2.61a1.885 1.885 0 0 0-1.442.736 1.89 1.89 0 0 0 1.011 2.976 1.903 1.903 0 0 0 2.253-1.114 1.887 1.887 0 0 0-1.822-2.598ZM7.463 8.163a.611.611 0 0 0-.432.154L5.071 10.5h5.119L7.88 8.348a.628.628 0 0 0-.417-.185Zm6.236 1.059a.62.62 0 0 0-.42.164L12.07 10.5h2.969l-.92-1.113a.618.618 0 0 0-.42-.165ZM.91 11.5a.91.91 0 0 0-.91.912v6.877c0 .505.405.91.91.91h18.178a.91.91 0 0 0 .912-.91v-6.877a.908.908 0 0 0-.912-.912H.91ZM3.668 13h1.947l2.135 5.7H5.898l-.28-.946H3.601l-.278.945H1.516L3.668 13Zm4.947 0h1.801v4.3h2.7v1.4h-4.5V13h-.001Zm4.5 0h5.4v1.4h-1.798v4.3h-1.701v-4.3h-1.9V13h-.001Zm-8.517 1.457-.614 2.059h1.262l-.648-2.059Z"/></svg>',va='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M9.816 11.5 7.038 4.785 4.261 11.5h5.555Zm.62 1.5H3.641l-1.666 4.028H.312l5.789-14h1.875l5.789 14h-1.663L10.436 13Z"/><path d="m12.09 17-.534-1.292.848-1.971.545 1.319L12.113 17h-.023Zm1.142-5.187.545 1.319L15.5 9.13l1.858 4.316h-3.45l.398.965h3.467L18.887 17H20l-3.873-9h-1.254l-1.641 3.813Z"/></svg>',ca='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle cx="9.5" cy="4.5" r="1.5"/><circle cx="9.5" cy="10.5" r="1.5"/><circle cx="9.5" cy="16.5" r="1.5"/></svg>',da='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m2.315 14.705 2.224-2.24a.689.689 0 0 1 .963 0 .664.664 0 0 1 0 .949L2.865 16.07a.682.682 0 0 1-.112.089.647.647 0 0 1-.852-.051L.688 14.886a.635.635 0 0 1 0-.903.647.647 0 0 1 .91 0l.717.722zm5.185.045a.75.75 0 0 1 .75-.75h9.5a.75.75 0 1 1 0 1.5h-9.5a.75.75 0 0 1-.75-.75zM2.329 5.745l2.21-2.226a.689.689 0 0 1 .963 0 .664.664 0 0 1 0 .95L2.865 7.125a.685.685 0 0 1-.496.196.644.644 0 0 1-.468-.187L.688 5.912a.635.635 0 0 1 0-.903.647.647 0 0 1 .91 0l.73.736zM7.5 5.75A.75.75 0 0 1 8.25 5h9.5a.75.75 0 1 1 0 1.5h-9.5a.75.75 0 0 1-.75-.75z"/></svg>',ma='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 2.28C2 1.574 2.574 1 3.272 1l11.456.001c.703 0 1.272.573 1.272 1.28v8.453l-1.5 1.464V2.465c0-.003-11-.005-11-.005V16.5h2.356c.124.225.28.434.462.62l.868.88-3.914-.001A1.274 1.274 0 0 1 2 16.719V2.28Z"/><path d="M14.525 18H9.293l-1.48-1.5h3.75l.332.336.344-.336H14.5v-2.207L16 12.83v3.73L14.525 18Z"/><path d="M9.706 12.638a2.838 2.838 0 0 0-1.38-.36 2.817 2.817 0 0 0-1.602.5H6.18a.635.635 0 0 1-.633-.639.64.64 0 0 1 .633-.639h3.133a.639.639 0 0 1 .393 1.138Z"/><path d="M5.546 6.154c0-.353.292-.64.636-.64h5.682a.637.637 0 0 1 .449 1.09.641.641 0 0 1-.449.188H6.182a.636.636 0 0 1-.635-.639l-.001.001Z"/><path d="M5.546 9.138c0-.352.292-.638.636-.638h5.682a.635.635 0 0 1 .45 1.088.641.641 0 0 1-.45.189H6.182a.636.636 0 0 1-.636-.639Z"/><path d="m13.117 19.374 6.192-6.044a1.316 1.316 0 0 0 0-1.876 1.354 1.354 0 0 0-1.899 0l-5.515 5.382-2.63-2.666a1.312 1.312 0 0 0-.938-.393 1.315 1.315 0 0 0-.939.394 1.354 1.354 0 0 0 0 1.898l3.49 3.538a1.317 1.317 0 0 0 1.447.29 2.74 2.74 0 0 0 .792-.523Z" style="fill:#1FB11F"/></svg>',ga='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 2.28C2 1.574 2.574 1 3.272 1l11.456.001c.703 0 1.272.573 1.272 1.28v8.106l-.889.899-.611-.619V2.465c0-.003-11-.005-11-.005V16.5h6.458l-.136.138-.003.003c-.372.378-.628.85-.745 1.359l-5.802-.001A1.274 1.274 0 0 1 2 16.719V2.28Z"/><path d="M14.338 18h-3.676c.06-.112.136-.216.227-.308l1.178-1.192H14.5v-3.699l.61.618.89-.899v4.199c0 .383-.168.726-.431.96l-.457-.462-.774.783Z"/><path d="M9.043 11.5a2.853 2.853 0 0 0 .066 1.278H6.18a.635.635 0 0 1-.632-.639.64.64 0 0 1 .633-.639h2.863Z"/><path d="M12.493 9.233a2.816 2.816 0 0 0-2.434.544H6.182a.636.636 0 0 1-.636-.639c0-.352.292-.638.636-.638h5.682a.635.635 0 0 1 .629.733Z"/><path d="M5.546 6.154c0-.353.292-.64.636-.64h5.682a.637.637 0 0 1 .449 1.09.641.641 0 0 1-.449.188H6.182a.636.636 0 0 1-.635-.639l-.001.001Z"/><path d="m15.11 13.42 2.348-2.374a1.318 1.318 0 0 1 1.877 0 1.354 1.354 0 0 1 0 1.9l-2.346 2.372 2.346 2.374a1.354 1.354 0 0 1 0 1.898 1.316 1.316 0 0 1-1.877 0l-2.346-2.373-2.346 2.373a1.316 1.316 0 0 1-1.877 0 1.354 1.354 0 0 1 0-1.898l2.346-2.374-2.346-2.373a1.354 1.354 0 0 1 0-1.899 1.318 1.318 0 0 1 1.877 0l2.346 2.374h-.001Z" style="fill:#DA2020"/></svg>',pa='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6.182 5.514a.643.643 0 0 0-.636.64v-.001a.636.636 0 0 0 .636.639h5.682a.641.641 0 0 0 .636-.638.637.637 0 0 0-.636-.64H6.182Z"/><path d="M6.182 8.5a.642.642 0 0 0-.588.882.636.636 0 0 0 .588.395h5.682a.641.641 0 0 0 .636-.639.635.635 0 0 0-.636-.638H6.182Z"/><path d="M6.18 11.5a.64.64 0 0 0 0 1.278h3.133a.64.64 0 0 0 0-1.278H6.18Z"/><path d="m11.772 18.308.154-.23c-.195-.098-.304-.192-.328-.28-.024-.09 0-.274.076-.551.062-.166.099-.296.11-.393a2.934 2.934 0 0 0 0-.479c-.137-.41-.2-.685-.186-.83.013-.145.117-.335.313-.57l4.465-6.207c.356-.6 1.059-.56 2.11.118 1.05.68 1.443 1.272 1.177 1.772l-3.876 6.833c-.105.27-.22.444-.347.515-.128.07-.4.119-.813.139a2.954 2.954 0 0 0-.487.21c-.127.09-.244.193-.347.31-.193.174-.332.262-.416.262-.064 0-.178-.05-.346-.15l-.204.27-1.056-.739Zm-.184.274 1.039.727-.26.34h-1.496l.717-1.067Z"/><path clip-rule="evenodd" d="M3.272 1A1.28 1.28 0 0 0 2 2.28v14.439a1.276 1.276 0 0 0 1.272 1.28h6.838a2.13 2.13 0 0 1 .003-.61 4.08 4.08 0 0 1 .156-.67c.011-.029.02-.052.025-.069v-.008a7.395 7.395 0 0 1-.042-.142H3.5V2.46s11 .002 11 .005v6.341l.627-.872c.204-.32.49-.614.873-.819V2.281c0-.707-.569-1.28-1.272-1.28L3.272 1ZM16 9.29l-1.5 2.085V16.5h-2.708c.005.118.002.236-.007.354a.904.904 0 0 1-.013.075l-.001.005a3.108 3.108 0 0 1-.097.312c-.027.101-.048.19-.062.266a.734.734 0 0 0-.014.287.25.25 0 0 0 .068.105.65.65 0 0 0 .088.074l.017.011.016.01h.175L14.73 18c.697 0 1.271-.573 1.271-1.281v-7.43Z"/></svg>',wa='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 18v-1.5h14V18zm2.2-8V3.6c0-.4.4-.6.8-.6.3 0 .7.2.7.6v6.2c0 2 1.3 2.8 3.2 2.8 1.9 0 3.4-.9 3.4-2.9V3.6c0-.3.4-.5.8-.5.3 0 .7.2.7.5V10c0 2.7-2.2 4-4.9 4-2.6 0-4.7-1.2-4.7-4z"/></svg>',ua='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m5.042 9.367 2.189 1.837a.75.75 0 0 1-.965 1.149l-3.788-3.18a.747.747 0 0 1-.21-.284.75.75 0 0 1 .17-.945L6.23 4.762a.75.75 0 1 1 .964 1.15L4.863 7.866h8.917A.75.75 0 0 1 14 7.9a4 4 0 1 1-1.477 7.718l.344-1.489a2.5 2.5 0 1 0 1.094-4.73l.008-.032H5.042z"/></svg>',Ma='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.077 15 .991-1.416a.75.75 0 1 1 1.229.86l-1.148 1.64a.748.748 0 0 1-.217.206 5.251 5.251 0 0 1-8.503-5.955.741.741 0 0 1 .12-.274l1.147-1.639a.75.75 0 1 1 1.228.86L4.933 10.7l.006.003a3.75 3.75 0 0 0 6.132 4.294l.006.004zm5.494-5.335a.748.748 0 0 1-.12.274l-1.147 1.639a.75.75 0 1 1-1.228-.86l.86-1.23a3.75 3.75 0 0 0-6.144-4.301l-.86 1.229a.75.75 0 0 1-1.229-.86l1.148-1.64a.748.748 0 0 1 .217-.206 5.251 5.251 0 0 1 8.503 5.955zm-4.563-2.532a.75.75 0 0 1 .184 1.045l-3.155 4.505a.75.75 0 1 1-1.229-.86l3.155-4.506a.75.75 0 0 1 1.045-.184zm4.919 10.562-1.414 1.414a.75.75 0 1 1-1.06-1.06l1.414-1.415-1.415-1.414a.75.75 0 0 1 1.061-1.06l1.414 1.414 1.414-1.415a.75.75 0 0 1 1.061 1.061l-1.414 1.414 1.414 1.415a.75.75 0 0 1-1.06 1.06l-1.415-1.414z"/></svg>',Ha='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M1.201 1C.538 1 0 1.47 0 2.1v14.363c0 .64.534 1.037 1.186 1.037H5.06l5.058-5.078L6.617 9.15a.696.696 0 0 0-.957-.033L1.5 13.6V2.5h15v4.354a3.478 3.478 0 0 1 1.5.049V2.1c0-.63-.547-1.1-1.2-1.1H1.202Zm11.713 2.803a2.147 2.147 0 0 0-2.049 1.992 2.14 2.14 0 0 0 1.28 2.096 2.13 2.13 0 0 0 2.642-3.11 2.129 2.129 0 0 0-1.873-.978ZM8.089 17.635v2.388h2.389l7.046-7.046-2.39-2.39-7.045 7.048Zm11.282-6.507a.637.637 0 0 0 .139-.692.603.603 0 0 0-.139-.205l-1.49-1.488a.63.63 0 0 0-.899 0l-1.166 1.163 2.39 2.39 1.165-1.168Z"/></svg>',za='<svg viewBox="0 0 21 21" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0_146_268)"><path d="M1.801 1.4C1.138 1.4.6 1.87.6 2.5v14.363c0 .64.534 1.037 1.186 1.037h9.494a2.97 2.97 0 0 1-.414-.287A2.998 2.998 0 0 1 9.81 15.59v-.007a3.003 3.003 0 0 1 .693-2.186l.383-.455-.02.018-3.65-3.41a.695.695 0 0 0-.957-.034L2.1 14V2.9h15v5.535a2.97 2.97 0 0 1 1.412.932l.088.105V2.5c0-.63-.547-1.1-1.2-1.1H1.802Zm11.713 2.803a2.146 2.146 0 0 0-2.049 1.992 2.14 2.14 0 0 0 1.28 2.096 2.13 2.13 0 0 0 2.644-3.11 2.134 2.134 0 0 0-1.875-.978Z"/><path d="M16.122 19.5a.79.79 0 0 0 .79-.79v-5.373l2.059 2.455a.79.79 0 0 0 1.211-1.015l-3.351-3.995a.79.79 0 0 0-.996-.179.786.786 0 0 0-.299.221l-3.35 3.99a.79.79 0 1 0 1.21 1.017l1.936-2.306v5.185c0 .436.353.79.79.79Z"/><path d="M16.122 19.5a.79.79 0 0 0 .79-.79v-5.373l2.059 2.455a.79.79 0 0 0 1.211-1.015l-3.351-3.995a.79.79 0 0 0-.996-.179.786.786 0 0 0-.299.221l-3.35 3.99a.79.79 0 1 0 1.21 1.017l1.936-2.306v5.185c0 .436.353.79.79.79Z"/></g><defs><clipPath id="clip0_146_268"><rect width="20" height="20" transform="translate(0.599976 0.399963)"/></clipPath></defs></svg>',Va='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M12.748 2a4.622 4.622 0 0 0-3.174 1.362L8.02 4.915a.783.783 0 0 0 .002 1.11.786.786 0 0 0 1.11 0l1.55-1.553c1.185-1.185 3.024-1.195 4.116-.104l.851.854c1.092 1.091 1.083 2.927-.101 4.11l-1.555 1.554a.787.787 0 0 0 .557 1.34.78.78 0 0 0 .553-.23l1.554-1.552c1.758-1.757 1.838-4.597.102-6.332l-.854-.853A4.31 4.31 0 0 0 12.748 2Zm-.488 4.973a.78.78 0 0 0-.553.23L7.2 11.71l-.004.002a.784.784 0 0 0 1.11 1.107l.003-.002 4.504-4.505a.785.785 0 0 0-.554-1.339Zm-6.79.815a.791.791 0 0 0-.554.234L3.36 9.573c-1.757 1.758-1.836 4.597-.101 6.332l.853.852c1.736 1.734 4.572 1.655 6.33-.102l1.547-1.547.006-.008a.777.777 0 0 0 .244-.554.782.782 0 0 0-.799-.797.774.774 0 0 0-.56.248l-1.545 1.547c-1.184 1.184-3.021 1.195-4.113.104l-.854-.854c-1.091-1.091-1.083-2.927.102-4.111l1.552-1.555a.787.787 0 0 0 .233-.555.79.79 0 0 0-.06-.3.793.793 0 0 0-.173-.253s-.104-.14-.183-.185c-.051-.03-.133-.047-.37-.047Z"/></svg>',fa='<svg viewBox="0 0 11 10" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M5.5 5C8.538 5 11 7.015 11 9.5c0 .17-.011.336-.034.5H.034A3.732 3.732 0 0 1 0 9.5C0 7.015 2.462 5 5.5 5zm0-5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5z"/></svg>',xa='<svg width="12" height="12" viewBox="0 0 13 13" xmlns="http://www.w3.org/2000/svg">\n<path fill-rule="evenodd" clip-rule="evenodd" d="M12 6C12 9.31371 9.31371 12 6 12C2.68629 12 0 9.31371 0 6C0 2.68629 2.68629 0 6 0C9.31371 0 12 2.68629 12 6ZM5.27988 2.40003H6.71988V6.72003H5.27988V2.40003ZM6.72009 8.16003H5.28009V9.60003H6.72009V8.16003Z" fill="#DB3700"/>\n</svg>\n';function Za(t){const e=t.editing.view,a=p.BalloonPanelView.defaultPositions;return{target:e.domConverter.viewToDom(e.document.selection.getSelectedElement()),positions:[a.northArrowSouth,a.northArrowSouthWest,a.northArrowSouthEast,a.southArrowNorth,a.southArrowNorthWest,a.southArrowNorthEast]}}var ba=a("ckeditor5/src/utils.js");class La extends p.View{constructor(t){super(t),this.focusTracker=new ba.FocusTracker,this.keystrokes=new ba.KeystrokeHandler,this.decorativeToggle=this._decorativeToggleView(),this.labeledInput=this._createLabeledInputView(),this.saveButtonView=this._createButton(Drupal.t("Save"),F,"ck-button-save"),this.saveButtonView.type="submit",this.cancelButtonView=this._createButton(Drupal.t("Cancel"),P,"ck-button-cancel","cancel"),this._focusables=new p.ViewCollection,this._focusCycler=new p.FocusCycler({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"form",attributes:{class:["ck","ck-media-alternative-text-form","ck-vertical-form"],tabindex:"-1"},children:[{tag:"div",children:[this.decorativeToggle]},this.labeledInput,this.saveButtonView,this.cancelButtonView]}),(0,p.injectCssTransitionDisabler)(this)}render(){super.render(),this.keystrokes.listenTo(this.element),(0,p.submitHandler)({view:this}),[this.decorativeToggle,this.labeledInput,this.saveButtonView,this.cancelButtonView].forEach((t=>{this._focusables.add(t),this.focusTracker.add(t.element)}))}_createButton(t,e,a,i){const l=new p.ButtonView(this.locale);return l.set({label:t,icon:e,tooltip:!0}),l.extendTemplate({attributes:{class:a}}),i&&l.delegate("execute").to(this,i),l}_createLabeledInputView(){const t=new p.LabeledFieldView(this.locale,p.createLabeledInputText);return t.bind("class").to(this.decorativeToggle,"isOn",(t=>t?"ck-hidden":"")),t.label=Drupal.t("Alternative text override"),t}_decorativeToggleView(){const t=new p.SwitchButtonView(this.locale);return t.set({withText:!0,label:Drupal.t("Decorative image")}),t.on("execute",(()=>{t.isOn&&(this.labeledInput.fieldView.element.value=""),t.set("isOn",!t.isOn)})),t}}class Ca extends e.Plugin{static get requires(){return[p.ContextualBalloon]}static get pluginName(){return"MediaImageTextAlternativeUi"}init(){this._createButton(),this._createForm()}destroy(){super.destroy(),this._form.destroy()}_createButton(){const t=this.editor;t.ui.componentFactory.add("mediaImageTextAlternative",(e=>{const a=t.commands.get("mediaImageTextAlternative"),i=new p.ButtonView(e);return i.set({label:Drupal.t("Override media image alternative text"),icon:Xt,tooltip:!0}),i.bind("isVisible").to(a,"isEnabled"),this.listenTo(i,"execute",(()=>{this._showForm()})),i}))}_createForm(){const t=this.editor,e=t.editing.view.document;this._balloon=this.editor.plugins.get("ContextualBalloon"),this._form=new La(t.locale),this._form.render(),this.listenTo(this._form,"submit",(()=>{t.execute("mediaImageTextAlternative",{newValue:this._form.decorativeToggle.isOn?'""':this._form.labeledInput.fieldView.element.value}),this._hideForm(!0)})),this.listenTo(this._form,"cancel",(()=>{this._hideForm(!0)})),this._form.keystrokes.set("Esc",((t,e)=>{this._hideForm(!0),e()})),this.listenTo(t.ui,"update",(()=>{h(e.selection)?this._isVisible&&function(t){const e=t.plugins.get("ContextualBalloon");if(h(t.editing.view.document.selection)){const a=Za(t);e.updatePosition(a)}}(t):this._hideForm(!0)})),(0,p.clickOutsideHandler)({emitter:this._form,activator:()=>this._isVisible,contextElements:[this._balloon.view.element],callback:()=>this._hideForm()})}_showForm(){if(this._isVisible)return;const t=this.editor,e=t.commands.get("mediaImageTextAlternative"),a=this._form.decorativeToggle,i=t.plugins.get("DrupalMediaMetadataRepository"),l=this._form.labeledInput;this._form.disableCssTransitions(),this._isInBalloon||this._balloon.add({view:this._form,position:Za(t)}),a.isOn='""'===e.value,l.fieldView.element.value=e.value||"",l.fieldView.value=l.fieldView.element.value,this._form.defaultAltText="";const o=t.model.document.selection.getSelectedElement();n(o)&&i.getMetadata(o).then((t=>{this._form.defaultAltText=t.imageSourceMetadata?t.imageSourceMetadata.alt:"",l.infoText=Drupal.t(`Leave blank to use the default alternative text: "${this._form.defaultAltText}".`)})).catch((t=>{console.warn(t.toString())})),this._form.enableCssTransitions()}_hideForm(t){this._isInBalloon&&(this._form.focusTracker.isFocused&&this._form.saveButtonView.focus(),this._balloon.remove(this._form),t&&this.editor.editing.view.focus())}get _isVisible(){return this._balloon.visibleView===this._form}get _isInBalloon(){return this._balloon.hasView(this._form)}}class Ia extends e.Plugin{static get requires(){return[z,Ca]}static get pluginName(){return"MediaImageTextAlternative"}}function ya(t,e,a){if(e.attributes)for(const[i,l]of Object.entries(e.attributes))t.setAttribute(i,l,a);e.styles&&t.setStyle(e.styles,a),e.classes&&t.addClass(e.classes,a)}function Ba(t,e,a){if(!a.consumable.consume(e.item,t.name))return;const i=a.mapper.toViewElement(e.item);ya(a.writer,e.attributeNewValue,i)}class Aa extends e.Plugin{constructor(t){if(super(t),!t.plugins.has("GeneralHtmlSupport"))return;t.plugins.has("DataFilter")&&t.plugins.has("DataSchema")||console.error("DataFilter and DataSchema plugins are required for Drupal Media to integrate with General HTML Support plugin.");const{schema:e}=t.model,{conversion:a}=t,i=this.editor.plugins.get("DataFilter");this.editor.plugins.get("DataSchema").registerBlockElement({model:"drupalMedia",view:"drupal-media"}),i.on("register:drupal-media",((t,l)=>{"drupalMedia"===l.model&&(e.extend("drupalMedia",{allowAttributes:["htmlLinkAttributes","htmlAttributes"]}),a.for("upcast").add(function(t){return e=>{e.on("element:drupal-media",((e,a,i)=>{function l(e,l){const n=t.processViewAttributes(e,i);n&&i.writer.setAttribute(l,n,a.modelRange)}const n=a.viewItem,o=n.parent;l(n,"htmlAttributes"),o.is("element","a")&&l(o,"htmlLinkAttributes")}),{priority:"low"})}}(i)),a.for("editingDowncast").add((t=>{t.on("attribute:linkHref:drupalMedia",((t,e,a)=>{if(!a.consumable.consume(e.item,"attribute:htmlLinkAttributes:drupalMedia"))return;const i=a.mapper.toViewElement(e.item),l=function(t,e,a){const i=t.createRangeOn(e);for(const{item:t}of i.getWalker())if(t.is("element",a))return t}(a.writer,i,"a");ya(a.writer,e.item.getAttribute("htmlLinkAttributes"),l)}),{priority:"low"})})),a.for("dataDowncast").add((t=>{t.on("attribute:linkHref:drupalMedia",((t,e,a)=>{if(!a.consumable.consume(e.item,"attribute:htmlLinkAttributes:drupalMedia"))return;const i=a.mapper.toViewElement(e.item).parent;ya(a.writer,e.item.getAttribute("htmlLinkAttributes"),i)}),{priority:"low"}),t.on("attribute:htmlAttributes:drupalMedia",Ba,{priority:"low"})})),t.stop())}))}static get pluginName(){return"DrupalMediaGeneralHtmlSupport"}}class Ea extends e.Plugin{static get requires(){return[g,Aa,w,u,Ia]}static get pluginName(){return"DrupalMedia"}}var ka=a("ckeditor5/src/engine.js");function Da(t){return Array.from(t.getChildren()).find((t=>"drupal-media"===t.name))}function Sa(t){return e=>{e.on(`attribute:${t.id}:drupalMedia`,((e,a,i)=>{const l=i.mapper.toViewElement(a.item);let n=Array.from(l.getChildren()).find((t=>"a"===t.name));if(n=!n&&l.is("element","a")?l:Array.from(l.getAncestors()).find((t=>"a"===t.name)),n){for(const[e,a]of(0,ba.toMap)(t.attributes))i.writer.setAttribute(e,a,n);t.classes&&i.writer.addClass(t.classes,n);for(const e in t.styles)Object.prototype.hasOwnProperty.call(t.styles,e)&&i.writer.setStyle(e,t.styles[e],n)}}))}}function _a(t,e){return t=>{t.on("element:a",((t,a,i)=>{const l=a.viewItem;if(!Da(l))return;const n=new ka.Matcher(e._createPattern()).match(l);if(!n)return;if(!i.consumable.consume(l,n.match))return;const o=a.modelCursor.nodeBefore;i.writer.setAttribute(e.id,!0,o)}),{priority:"high"})}}class Ta extends e.Plugin{static get requires(){return["LinkEditing","DrupalMediaEditing"]}static get pluginName(){return"DrupalLinkMediaEditing"}init(){const{editor:t}=this;t.model.schema.extend("drupalMedia",{allowAttributes:["linkHref"]}),t.conversion.for("upcast").add((t=>{t.on("element:a",((t,e,a)=>{const i=e.viewItem,l=Da(i);if(!l)return;if(!a.consumable.consume(i,{attributes:["href"],name:!0}))return;const n=i.getAttribute("href");if(null===n)return;const o=a.convertItem(l,e.modelCursor);e.modelRange=o.modelRange,e.modelCursor=o.modelCursor;const s=e.modelCursor.nodeBefore;s&&s.is("element","drupalMedia")&&a.writer.setAttribute("linkHref",n,s)}),{priority:"high"})})),t.conversion.for("editingDowncast").add((t=>{t.on("attribute:linkHref:drupalMedia",((t,e,a)=>{const{writer:i}=a;if(!a.consumable.consume(e.item,t.name))return;const l=a.mapper.toViewElement(e.item),n=Array.from(l.getChildren()).find((t=>"a"===t.name));if(n)e.attributeNewValue?i.setAttribute("href",e.attributeNewValue,n):(i.move(i.createRangeIn(n),i.createPositionAt(l,0)),i.remove(n));else{const t=Array.from(l.getChildren()).find((t=>t.getAttribute("data-drupal-media-preview"))),a=i.createContainerElement("a",{href:e.attributeNewValue});i.insert(i.createPositionAt(l,0),a),i.move(i.createRangeOn(t),i.createPositionAt(a,0))}}),{priority:"high"})})),t.conversion.for("dataDowncast").add((t=>{t.on("attribute:linkHref:drupalMedia",((t,e,a)=>{const{writer:i}=a;if(!a.consumable.consume(e.item,t.name))return;const l=a.mapper.toViewElement(e.item),n=i.createContainerElement("a",{href:e.attributeNewValue});i.insert(i.createPositionBefore(l),n),i.move(i.createRangeOn(l),i.createPositionAt(n,0))}),{priority:"high"})})),this._enableManualDecorators();if(t.commands.get("link").automaticDecorators.length>0)throw new Error("The Drupal Media plugin is not compatible with automatic link decorators. To use Drupal Media, disable any plugins providing automatic link decorators.")}_enableManualDecorators(){const t=this.editor,e=t.commands.get("link");for(const a of e.manualDecorators)t.model.schema.extend("drupalMedia",{allowAttributes:a.id}),t.conversion.for("downcast").add(Sa(a)),t.conversion.for("upcast").add(_a(0,a))}}class Oa extends e.Plugin{static get requires(){return["LinkEditing","LinkUI","DrupalMediaEditing"]}static get pluginName(){return"DrupalLinkMediaUi"}init(){const{editor:t}=this,e=t.editing.view.document;this.listenTo(e,"click",((e,a)=>{this._isSelectedLinkedMedia(t.model.document.selection)&&(a.preventDefault(),e.stop())}),{priority:"high"}),this._createToolbarLinkMediaButton()}_createToolbarLinkMediaButton(){const{editor:t}=this;t.ui.componentFactory.add("drupalLinkMedia",(e=>{const a=new p.ButtonView(e),i=t.plugins.get("LinkUI"),l=t.commands.get("link");return a.set({isEnabled:!0,label:Drupal.t("Link media"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.077 15 .991-1.416a.75.75 0 1 1 1.229.86l-1.148 1.64a.748.748 0 0 1-.217.206 5.251 5.251 0 0 1-8.503-5.955.741.741 0 0 1 .12-.274l1.147-1.639a.75.75 0 1 1 1.228.86L4.933 10.7l.006.003a3.75 3.75 0 0 0 6.132 4.294l.006.004zm5.494-5.335a.748.748 0 0 1-.12.274l-1.147 1.639a.75.75 0 1 1-1.228-.86l.86-1.23a3.75 3.75 0 0 0-6.144-4.301l-.86 1.229a.75.75 0 0 1-1.229-.86l1.148-1.64a.748.748 0 0 1 .217-.206 5.251 5.251 0 0 1 8.503 5.955zm-4.563-2.532a.75.75 0 0 1 .184 1.045l-3.155 4.505a.75.75 0 1 1-1.229-.86l3.155-4.506a.75.75 0 0 1 1.045-.184z"/></svg>\n',keystroke:"Ctrl+K",tooltip:!0,isToggleable:!0}),a.bind("isEnabled").to(l,"isEnabled"),a.bind("isOn").to(l,"value",(t=>!!t)),this.listenTo(a,"execute",(()=>{this._isSelectedLinkedMedia(t.model.document.selection)?i._addToolbarView():i._showUI(!0)})),a}))}_isSelectedLinkedMedia(t){const e=t.getSelectedElement();return e?.is("element","drupalMedia")&&e.hasAttribute("linkHref")}}class Pa extends e.Plugin{static get requires(){return[Ta,Oa]}static get pluginName(){return"DrupalLinkMedia"}}var ja=a("ckeditor5/src/icons.js");const Ra={get inline(){return{name:"inline",title:"In line",icon:ja.IconObjectInline,modelElements:["imageInline"],isDefault:!0}},get alignLeft(){return{name:"alignLeft",title:"Left aligned image",icon:ja.IconObjectInlineLeft,modelElements:["imageBlock","imageInline"],className:"image-style-align-left"}},get alignBlockLeft(){return{name:"alignBlockLeft",title:"Left aligned image",icon:ja.IconObjectLeft,modelElements:["imageBlock"],className:"image-style-block-align-left"}},get alignCenter(){return{name:"alignCenter",title:"Centered image",icon:ja.IconObjectCenter,modelElements:["imageBlock"],className:"image-style-align-center"}},get alignRight(){return{name:"alignRight",title:"Right aligned image",icon:ja.IconObjectInlineRight,modelElements:["imageBlock","imageInline"],className:"image-style-align-right"}},get alignBlockRight(){return{name:"alignBlockRight",title:"Right aligned image",icon:ja.IconObjectRight,modelElements:["imageBlock"],className:"image-style-block-align-right"}},get block(){return{name:"block",title:"Centered image",icon:ja.IconObjectCenter,modelElements:["imageBlock"],isDefault:!0}},get side(){return{name:"side",title:"Side image",icon:ja.IconObjectInlineRight,modelElements:["imageBlock"],className:"image-style-side"}}},Fa=(()=>({full:ja.IconObjectFullWidth,left:ja.IconObjectLeft,right:ja.IconObjectRight,center:ja.IconObjectCenter,inlineLeft:ja.IconObjectInlineLeft,inlineRight:ja.IconObjectInlineRight,inline:ja.IconObjectInline}))(),Na=[{name:"imageStyle:wrapText",title:"Wrap text",defaultItem:"imageStyle:alignLeft",items:["imageStyle:alignLeft","imageStyle:alignRight"]},{name:"imageStyle:breakText",title:"Break text",defaultItem:"imageStyle:block",items:["imageStyle:alignBlockLeft","imageStyle:block","imageStyle:alignBlockRight"]}];function Ua(t){(0,ba.logWarning)("image-style-configuration-definition-invalid",t)}const Wa={normalizeStyles:function(t){return(t.configuredStyles.options||[]).map((t=>function(t){t="string"==typeof t?Ra[t]?{...Ra[t]}:{name:t}:function(t,e){const a={...e};for(const i in t)Object.prototype.hasOwnProperty.call(e,i)||(a[i]=t[i]);return a}(Ra[t.name],t);"string"==typeof t.icon&&(t.icon=Fa[t.icon]||t.icon);return t}(t))).filter((e=>function(t,{isBlockPluginLoaded:e,isInlinePluginLoaded:a}){const{modelElements:i,name:l}=t;if(!(i&&i.length&&l))return Ua({style:t}),!1;{const l=[e?"imageBlock":null,a?"imageInline":null];if(!i.some((t=>l.includes(t))))return(0,ba.logWarning)("image-style-missing-dependency",{style:t,missingPlugins:i.map((t=>"imageBlock"===t?"ImageBlockEditing":"ImageInlineEditing"))}),!1}return!0}(e,t)))},getDefaultStylesConfiguration:function(t,e){return t&&e?{options:["inline","alignLeft","alignRight","alignCenter","alignBlockLeft","alignBlockRight","block","side"]}:t?{options:["block","side"]}:e?{options:["inline","alignLeft","alignRight"]}:{}},getDefaultDropdownDefinitions:function(t){return t.has("ImageBlockEditing")&&t.has("ImageInlineEditing")?[...Na]:[]},warnInvalidStyle:Ua,DEFAULT_OPTIONS:Ra,DEFAULT_ICONS:Fa,DEFAULT_DROPDOWN_DEFINITIONS:Na};function $a(t,e,a){for(const i of e)if(a.checkAttribute(t,i))return!0;return!1}function qa(t,e,a){const i=t.getSelectedElement();if(i&&$a(i,a,e))return i;let{parent:l}=t.getFirstPosition();for(;l;){if(l.is("element")&&$a(l,a,e))return l;l=l.parent}return null}class Ka extends e.Command{constructor(t,e){super(t),this.styles={},Object.keys(e).forEach((t=>{this.styles[t]=new Map(e[t].map((t=>[t.name,t])))})),this.modelAttributes=[];for(const t of Object.keys(e)){const e=c(t);this.modelAttributes.push(e)}}refresh(){const{editor:t}=this,e=qa(t.model.document.selection,t.model.schema,this.modelAttributes);this.isEnabled=!!e,this.isEnabled?this.value=this.getValue(e):this.value=!1}getValue(t){const e={};return Object.keys(this.styles).forEach((a=>{const i=c(a);if(t.hasAttribute(i))e[a]=t.getAttribute(i);else for(const[,t]of this.styles[a])t.isDefault&&(e[a]=t.name)})),e}execute(t={}){const{editor:{model:e}}=this,{value:a,group:i}=t,l=c(i);e.change((t=>{const n=qa(e.document.selection,e.schema,this.modelAttributes);!a||this.styles[i].get(a).isDefault?t.removeAttribute(l,n):t.setAttribute(l,a,n)}))}}function Ga(t,e){for(const a of e)if(a.name===t)return a}class Ja extends e.Plugin{init(){const{editor:e}=this,a=e.config.get("drupalElementStyles");this.normalizedStyles={},Object.keys(a).forEach((e=>{this.normalizedStyles[e]=a[e].map((e=>("string"==typeof e.icon&&t[e.icon]&&(e.icon=t[e.icon]),e.name&&(e.name=`${e.name}`),e))).filter((t=>t.isDefault||t.attributeName&&t.attributeValue?t.modelElements&&Array.isArray(t.modelElements)?!!t.name||(console.warn("drupalElementStyles options must include a name."),!1):(console.warn("drupalElementStyles options must include an array of supported modelElements."),!1):(console.warn(`${t.attributeValue} drupalElementStyles options must include attributeName and attributeValue.`),!1)))})),this._setupConversion(),e.commands.add("drupalElementStyle",new Ka(e,this.normalizedStyles))}_setupConversion(){const{editor:t}=this,{schema:e}=t.model;Object.keys(this.normalizedStyles).forEach((a=>{const i=c(a),l=(n=this.normalizedStyles[a],(t,e,a)=>{if(!a.consumable.consume(e.item,t.name))return;const i=Ga(e.attributeNewValue,n),l=Ga(e.attributeOldValue,n),o=a.mapper.toViewElement(e.item),s=a.writer;l&&("class"===l.attributeName?s.removeClass(l.attributeValue,o):s.removeAttribute(l.attributeName,o)),i&&("class"===i.attributeName?s.addClass(i.attributeValue,o):i.isDefault||s.setAttribute(i.attributeName,i.attributeValue,o))});var n;const o=function(t,e){const a=t.filter((t=>!t.isDefault));return(t,i,l)=>{if(!i.modelRange)return;const n=i.viewItem,o=(0,ba.first)(i.modelRange.getItems());if(o&&l.schema.checkAttribute(o,e))for(const t of a)if("class"===t.attributeName)l.consumable.consume(n,{classes:t.attributeValue})&&l.writer.setAttribute(e,t.name,o);else if(l.consumable.consume(n,{attributes:[t.attributeName]}))for(const t of a)t.attributeValue===n.getAttribute(t.attributeName)&&l.writer.setAttribute(e,t.name,o)}}(this.normalizedStyles[a],i);t.editing.downcastDispatcher.on(`attribute:${i}`,l),t.data.downcastDispatcher.on(`attribute:${i}`,l);[...new Set(this.normalizedStyles[a].map((t=>t.modelElements)).flat())].forEach((t=>{e.extend(t,{allowAttributes:i})})),t.data.upcastDispatcher.on("element",o,{priority:"low"})}))}static get pluginName(){return"DrupalElementStyleEditing"}}const Qa=t=>t,Xa=(t,e)=>(t?`${t}: `:"")+e;function Ya(t,e){return`drupalElementStyle:${e}:${t}`}class ti extends e.Plugin{static get requires(){return[Ja]}init(){const{plugins:t}=this.editor,e=this.editor.config.get("drupalMedia.toolbar")||[],a=t.get("DrupalElementStyleEditing").normalizedStyles;Object.keys(a).forEach((t=>{a[t].forEach((e=>{this._createButton(e,t,a[t])}))}));e.filter(r).filter((t=>{const e=[];if(!t.display)return console.warn("dropdown configuration must include a display key specifying either listDropdown or splitButton."),!1;t.items.includes(t.defaultItem)||console.warn("defaultItem must be part of items in the dropdown configuration.");for(const a of t.items){const t=a.split(":")[1];e.push(t)}return!!e.every((t=>t===e[0]))||(console.warn("dropdown configuration should only contain buttons from one group."),!1)})).forEach((t=>{if(t.items.length>=2){const e=t.name.split(":")[1];switch(t.display){case"splitButton":this._createDropdown(t,a[e]);break;case"listDropdown":this._createListDropdown(t,a[e])}}}))}updateOptionVisibility(t,e,a,i){const{selection:l}=this.editor.model.document,n={};n[i]=t;const o=l?l.getSelectedElement():qa(l,this.editor.model.schema,n),s=t.filter((function(t){for(const[e,a]of(0,ba.toMap)(t.modelAttributes))if(o&&o.hasAttribute(e))return a.includes(o.getAttribute(e));return!0}));a.hasOwnProperty("model")?s.includes(e)?a.model.set({class:""}):a.model.set({class:"ck-hidden"}):s.includes(e)?a.set({class:""}):a.set({class:"ck-hidden"})}_createDropdown(t,e){const a=this.editor.ui.componentFactory;a.add(t.name,(i=>{let l;const{defaultItem:n,items:o,title:s}=t,h=o.filter((t=>{const a=t.split(":")[1];return e.find((({name:e})=>Ya(e,a)===t))})).map((t=>{const e=a.create(t);return t===n&&(l=e),e}));o.length!==h.length&&Wa.warnInvalidStyle({dropdown:t});const r=(0,p.createDropdown)(i,p.SplitButtonView),v=r.buttonView;return(0,p.addToolbarToDropdown)(r,h),v.set({label:Xa(s,l.label),class:null,tooltip:!0}),v.bind("icon").toMany(h,"isOn",((...t)=>{const e=t.findIndex(Qa);return e<0?l.icon:h[e].icon})),v.bind("label").toMany(h,"isOn",((...t)=>{const e=t.findIndex(Qa);return Xa(s,e<0?l.label:h[e].label)})),v.bind("isOn").toMany(h,"isOn",((...t)=>t.some(Qa))),v.bind("class").toMany(h,"isOn",((...t)=>t.some(Qa)?"ck-splitbutton_flatten":null)),v.on("execute",(()=>{h.some((({isOn:t})=>t))?r.isOpen=!r.isOpen:l.fire("execute")})),r.bind("isEnabled").toMany(h,"isEnabled",((...t)=>t.some(Qa))),r}))}_createButton(t,e,a){const i=t.name;this.editor.ui.componentFactory.add(Ya(i,e),(l=>{const n=this.editor.commands.get("drupalElementStyle"),o=new p.ButtonView(l);return o.set({label:t.title,icon:t.icon,tooltip:!0,isToggleable:!0}),o.bind("isEnabled").to(n,"isEnabled"),o.bind("isOn").to(n,"value",(t=>t&&t[e]===i)),o.on("execute",this._executeCommand.bind(this,i,e)),this.listenTo(this.editor.ui,"update",(()=>{this.updateOptionVisibility(a,t,o,e)})),o}))}getDropdownListItemDefinitions(t,e,a){const i=new ba.Collection;return t.forEach((e=>{const l={type:"button",model:new p.ViewModel({group:a,commandValue:e.name,label:e.title,withText:!0,class:""})};i.add(l),this.listenTo(this.editor.ui,"update",(()=>{this.updateOptionVisibility(t,e,l,a)}))})),i}_createListDropdown(t,e){const a=this.editor.ui.componentFactory;a.add(t.name,(i=>{let l;const{defaultItem:n,items:o,title:s,defaultText:h}=t,r=t.name.split(":")[1],v=o.filter((t=>e.find((({name:e})=>Ya(e,r)===t)))).map((t=>{const e=a.create(t);return t===n&&(l=e),e}));o.length!==v.length&&Wa.warnInvalidStyle({dropdown:t});const c=(0,p.createDropdown)(i,p.DropdownButtonView),d=c.buttonView;d.set({label:Xa(s,l.label),class:null,tooltip:h,withText:!0});const m=this.editor.commands.get("drupalElementStyle");return d.bind("label").to(m,"value",(t=>{if(t?.[r])for(const a of e)if(a.name===t[r])return a.title;return h})),c.bind("isOn").to(m),c.bind("isEnabled").to(this),(0,p.addListToDropdown)(c,this.getDropdownListItemDefinitions(e,m,r)),this.listenTo(c,"execute",(t=>{this._executeCommand(t.source.commandValue,t.source.group)})),c}))}_executeCommand(t,e){this.editor.execute("drupalElementStyle",{value:t,group:e}),this.editor.editing.view.focus()}static get pluginName(){return"DrupalElementStyleUi"}}class ei extends e.Plugin{static get requires(){return[Ja,ti]}static get pluginName(){return"DrupalElementStyle"}}function ai(t){const e=t.getFirstPosition().findAncestor("caption");return e&&n(e.parent)?e:null}function ii(t){for(const e of t.getChildren())if(e&&e.is("element","caption"))return e;return null}class li extends e.Command{refresh(){const t=this.editor.model.document.selection,e=t.getSelectedElement();if(!e)return this.isEnabled=!!s(t),void(this.value=!!ai(t));this.isEnabled=n(e),this.isEnabled?this.value=!!ii(e):this.value=!1}execute(t={}){const{focusCaptionOnShow:e}=t;this.editor.model.change((t=>{this.value?this._hideDrupalMediaCaption(t):this._showDrupalMediaCaption(t,e)}))}_showDrupalMediaCaption(t,e){const a=this.editor.model.document.selection,i=this.editor.plugins.get("DrupalMediaCaptionEditing"),l=s(a),n=i._getSavedCaption(l)||t.createElement("caption");t.append(n,l),e&&t.setSelection(n,"in")}_hideDrupalMediaCaption(t){const e=this.editor,a=e.model.document.selection,i=e.plugins.get("DrupalMediaCaptionEditing");let l,n=a.getSelectedElement();n?l=ii(n):(l=ai(a),n=s(a)),i._saveCaption(n,l),t.setSelection(n,"on"),t.remove(l)}}class ni extends e.Plugin{static get requires(){return[]}static get pluginName(){return"DrupalMediaCaptionEditing"}constructor(t){super(t),this._savedCaptionsMap=new WeakMap}init(){const t=this.editor,e=t.model.schema;e.isRegistered("caption")?e.extend("caption",{allowIn:"drupalMedia"}):e.register("caption",{allowIn:"drupalMedia",allowContentOf:"$block",isLimit:!0}),t.commands.add("toggleMediaCaption",new li(t)),this._setupConversion()}_setupConversion(){const t=this.editor,e=t.editing.view;var a;t.conversion.for("upcast").add(function(t){const e=(e,a,i)=>{const{viewItem:l}=a,{writer:n,consumable:o}=i;if(!a.modelRange||!o.consume(l,{attributes:["data-caption"]}))return;const s=n.createElement("caption"),h=a.modelRange.start.nodeAfter,r=t.data.processor.toView(l.getAttribute("data-caption"));i.consumable.constructor.createFrom(r,i.consumable),i.convertChildren(r,s),n.append(s,h)};return t=>{t.on("element:drupal-media",e,{priority:"low"})}}(t)),t.conversion.for("editingDowncast").elementToElement({model:"caption",view:(t,{writer:a})=>{if(!n(t.parent))return null;const i=a.createEditableElement("figcaption");return i.placeholder=Drupal.t("Enter media caption"),(0,ka.enablePlaceholder)({view:e,element:i,keepOnFocus:!0}),(0,l.toWidgetEditable)(i,a)}}),t.editing.mapper.on("modelToViewPosition",(a=e,(t,e)=>{const i=e.modelPosition,l=i.parent;if(!n(l))return;const o=e.mapper.toViewElement(l);e.viewPosition=a.createPositionAt(o,i.offset+1)})),t.conversion.for("dataDowncast").add(function(t){return e=>{e.on("insert:caption",((e,a,i)=>{const{consumable:l,writer:o,mapper:s}=i;if(!n(a.item.parent)||!l.consume(a.item,"insert"))return;const h=t.model.createRangeIn(a.item),r=o.createDocumentFragment();s.bindElements(a.item,r);for(const{item:e}of Array.from(h)){const a={item:e,range:t.model.createRangeOn(e)},l=`insert:${e.name||"$text"}`;t.data.downcastDispatcher.fire(l,a,i);for(const l of e.getAttributeKeys())Object.assign(a,{attributeKey:l,attributeOldValue:null,attributeNewValue:a.item.getAttribute(l)}),t.data.downcastDispatcher.fire(`attribute:${l}`,a,i)}for(const t of o.createRangeIn(r).getItems())s.unbindViewElement(t);s.unbindViewElement(r);const v=t.data.processor.toData(r);if(v){const t=s.toViewElement(a.item.parent);o.setAttribute("data-caption",v,t)}}))}}(t))}_getSavedCaption(t){const e=this._savedCaptionsMap.get(t);return e?ka.Element.fromJSON(e):null}_saveCaption(t,e){this._savedCaptionsMap.set(t,e.toJSON())}}class oi extends e.Plugin{static get requires(){return[]}static get pluginName(){return"DrupalMediaCaptionUI"}init(){const{editor:t}=this,e=t.editing.view;t.ui.componentFactory.add("toggleDrupalMediaCaption",(a=>{const i=new p.ButtonView(a),l=t.commands.get("toggleMediaCaption");return i.set({label:Drupal.t("Caption media"),icon:j,tooltip:!0,isToggleable:!0}),i.bind("isOn","isEnabled").to(l,"value","isEnabled"),i.bind("label").to(l,"value",(t=>t?Drupal.t("Toggle caption off"):Drupal.t("Toggle caption on"))),this.listenTo(i,"execute",(()=>{t.execute("toggleMediaCaption",{focusCaptionOnShow:!0});const a=ai(t.model.document.selection);if(a){const i=t.editing.mapper.toViewElement(a);e.scrollToTheSelection(),e.change((t=>{t.addClass("drupal-media__caption_highlighted",i)}))}t.editing.view.focus()})),i}))}}class si extends e.Plugin{static get requires(){return[ni,oi]}static get pluginName(){return"DrupalMediaCaption"}}const hi={DrupalMedia:Ea,MediaImageTextAlternative:Ia,MediaImageTextAlternativeEditing:z,MediaImageTextAlternativeUi:Ca,DrupalLinkMedia:Pa,DrupalMediaCaption:si,DrupalElementStyle:ei}})(),i=i.default})()));
\ No newline at end of file diff --git a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalImage/src/imagealternativetext/drupalimagealternativetextui.js b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalImage/src/imagealternativetext/drupalimagealternativetextui.js index 50abc4fe3b82..dedcf00f63ba 100644 --- a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalImage/src/imagealternativetext/drupalimagealternativetextui.js +++ b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalImage/src/imagealternativetext/drupalimagealternativetextui.js @@ -8,7 +8,8 @@ * @module drupalImage/imagealternativetext/drupalimagealternativetextui */ -import { Plugin, icons } from 'ckeditor5/src/core'; +import { Plugin } from 'ckeditor5/src/core'; +import { IconLowVision } from '@ckeditor/ckeditor5-icons'; import { ButtonView, ContextualBalloon, @@ -147,7 +148,7 @@ export default class DrupalImageAlternativeTextUi extends Plugin { view.set({ label: Drupal.t('Change image alternative text'), - icon: icons.lowVision, + icon: IconLowVision, tooltip: true, }); diff --git a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalImage/src/imagealternativetext/ui/imagealternativetextformview.js b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalImage/src/imagealternativetext/ui/imagealternativetextformview.js index 8c6ceadd4a13..8bfd9e47fbdd 100644 --- a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalImage/src/imagealternativetext/ui/imagealternativetextformview.js +++ b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalImage/src/imagealternativetext/ui/imagealternativetextformview.js @@ -17,7 +17,7 @@ import { submitHandler, } from 'ckeditor5/src/ui'; import { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils'; -import { icons } from 'ckeditor5/src/core'; +import { IconCheck, IconCancel } from '@ckeditor/ckeditor5-icons'; /** * A class rendering alternative text form view. @@ -70,7 +70,7 @@ export default class ImageAlternativeTextFormView extends View { */ this.saveButtonView = this._createButton( Drupal.t('Save'), - icons.check, + IconCheck, 'ck-button-save', ); this.saveButtonView.type = 'submit'; @@ -94,7 +94,7 @@ export default class ImageAlternativeTextFormView extends View { */ this.cancelButtonView = this._createButton( Drupal.t('Cancel'), - icons.cancel, + IconCancel, 'ck-button-cancel', 'cancel', ); diff --git a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/drupalelementstyle/drupalelementstyleediting.js b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/drupalelementstyle/drupalelementstyleediting.js index 6b717b1ad0b4..677b7b18a23e 100644 --- a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/drupalelementstyle/drupalelementstyleediting.js +++ b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/drupalelementstyle/drupalelementstyleediting.js @@ -1,7 +1,8 @@ /* eslint-disable import/no-extraneous-dependencies */ /* cspell:ignore drupalelementstyle drupalelementstylecommand */ /* cspell:ignore drupalelementstyleediting */ -import { Plugin, icons } from 'ckeditor5/src/core'; +import { Plugin } from 'ckeditor5/src/core'; +import * as icons from '@ckeditor/ckeditor5-icons'; import { first } from 'ckeditor5/src/utils'; import DrupalElementStyleCommand from './drupalelementstylecommand'; import { groupNameToModelAttributeKey } from '../utils'; @@ -163,7 +164,7 @@ function viewToModelStyleAttribute(styles, modelAttribute) { * drupalElementStyles: * side: * - name: 'side' - * icon: 'objectBlockRight' + * icon: 'IconObjectRight' * title: 'Side image' * attributeName: 'class' * attributeValue: 'image-side' @@ -171,12 +172,12 @@ function viewToModelStyleAttribute(styles, modelAttribute) { * align: * - name: 'right' * title: 'Right aligned media' - * icon: 'objectRight' + * icon: 'IconObjectInlineRight' * attributeName: 'data-align' * modelElements: [ 'drupalMedia' ] * - name: 'left' * title: 'Left aligned media' - * icon: 'objectLeft' + * icon: 'IconObjectInlineLeft' * attributeName: 'data-align' * attributeValue: 'left' * modelElements: [ 'drupalMedia' ] diff --git a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/drupallinkmedia/drupallinkmediaui.js b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/drupallinkmedia/drupallinkmediaui.js index cb4685e49f23..3148fc0b944c 100644 --- a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/drupallinkmedia/drupallinkmediaui.js +++ b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/drupallinkmedia/drupallinkmediaui.js @@ -83,7 +83,7 @@ export default class DrupalLinkMediaUI extends Plugin { // depending on whether the media is already linked. this.listenTo(button, 'execute', () => { if (this._isSelectedLinkedMedia(editor.model.document.selection)) { - plugin._addActionsView(); + plugin._addToolbarView(); } else { plugin._showUI(true); } @@ -103,8 +103,7 @@ export default class DrupalLinkMediaUI extends Plugin { _isSelectedLinkedMedia(selection) { const selectedModelElement = selection.getSelectedElement(); return ( - !!selectedModelElement && - selectedModelElement.is('element', 'drupalMedia') && + selectedModelElement?.is('element', 'drupalMedia') && selectedModelElement.hasAttribute('linkHref') ); } diff --git a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/drupalmediacaption/drupalmediacaptionui.js b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/drupalmediacaption/drupalmediacaptionui.js index c5f89893c8ec..5c1afcf987b3 100644 --- a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/drupalmediacaption/drupalmediacaptionui.js +++ b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/drupalmediacaption/drupalmediacaptionui.js @@ -1,5 +1,6 @@ /* eslint-disable import/no-extraneous-dependencies */ -import { Plugin, icons } from 'ckeditor5/src/core'; +import { Plugin } from 'ckeditor5/src/core'; +import { IconCaption } from '@ckeditor/ckeditor5-icons'; import { ButtonView } from 'ckeditor5/src/ui'; import { getMediaCaptionFromModelSelection } from './utils'; @@ -34,7 +35,7 @@ export default class DrupalMediaCaptionUI extends Plugin { const captionCommand = editor.commands.get('toggleMediaCaption'); button.set({ label: Drupal.t('Caption media'), - icon: icons.caption, + icon: IconCaption, tooltip: true, isToggleable: true, }); diff --git a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/mediaimagetextalternative/mediaimagetextalternativecommand.js b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/mediaimagetextalternative/mediaimagetextalternativecommand.js index b4623eee7728..2ae8ca9d809d 100644 --- a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/mediaimagetextalternative/mediaimagetextalternativecommand.js +++ b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/mediaimagetextalternative/mediaimagetextalternativecommand.js @@ -22,8 +22,7 @@ export default class MediaImageTextAlternativeCommand extends Command { this.editor.model.document.selection, ); this.isEnabled = - !!drupalMediaElement && - drupalMediaElement.getAttribute('drupalMediaIsImage') && + drupalMediaElement?.getAttribute('drupalMediaIsImage') && drupalMediaElement.getAttribute('drupalMediaIsImage') !== METADATA_ERROR; if (this.isEnabled) { diff --git a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/mediaimagetextalternative/mediaimagetextalternativeui.js b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/mediaimagetextalternative/mediaimagetextalternativeui.js index 151fb2a30293..6ab77c7b60fe 100644 --- a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/mediaimagetextalternative/mediaimagetextalternativeui.js +++ b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/mediaimagetextalternative/mediaimagetextalternativeui.js @@ -2,7 +2,8 @@ /* cspell:ignore imagetextalternative mediaimagetextalternative */ /* cspell:ignore mediaimagetextalternativeediting textalternativeformview */ -import { Plugin, icons } from 'ckeditor5/src/core'; +import { Plugin } from 'ckeditor5/src/core'; +import { IconLowVision } from '@ckeditor/ckeditor5-icons'; import { ButtonView, ContextualBalloon, @@ -66,7 +67,7 @@ export default class MediaImageTextAlternativeUi extends Plugin { view.set({ label: Drupal.t('Override media image alternative text'), - icon: icons.lowVision, + icon: IconLowVision, tooltip: true, }); diff --git a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/mediaimagetextalternative/ui/textalternativeformview.js b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/mediaimagetextalternative/ui/textalternativeformview.js index 4ba0020a2e1e..b6702acbab90 100644 --- a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/mediaimagetextalternative/ui/textalternativeformview.js +++ b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalMedia/src/mediaimagetextalternative/ui/textalternativeformview.js @@ -14,7 +14,7 @@ import { Template, } from 'ckeditor5/src/ui'; import { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils'; -import { icons } from 'ckeditor5/src/core'; +import { IconCheck, IconCancel } from '@ckeditor/ckeditor5-icons'; export default class TextAlternativeFormView extends View { /** @@ -50,7 +50,7 @@ export default class TextAlternativeFormView extends View { */ this.saveButtonView = this._createButton( Drupal.t('Save'), - icons.check, + IconCheck, 'ck-button-save', ); this.saveButtonView.type = 'submit'; @@ -60,7 +60,7 @@ export default class TextAlternativeFormView extends View { */ this.cancelButtonView = this._createButton( Drupal.t('Cancel'), - icons.cancel, + IconCancel, 'ck-button-cancel', 'cancel', ); diff --git a/core/modules/ckeditor5/src/Plugin/CKEditor5Plugin/Alignment.php b/core/modules/ckeditor5/src/Plugin/CKEditor5Plugin/Alignment.php index b74b08fb347d..c1eb1eebfeb2 100644 --- a/core/modules/ckeditor5/src/Plugin/CKEditor5Plugin/Alignment.php +++ b/core/modules/ckeditor5/src/Plugin/CKEditor5Plugin/Alignment.php @@ -117,7 +117,7 @@ class Alignment extends CKEditor5PluginDefault implements CKEditor5PluginConfigu $subset = HTMLRestrictions::fromString(implode($all_elements)); foreach ($plugin_definition->getCKEditor5Config()['alignment']['options'] as $configured_alignment) { if (!in_array($configured_alignment['name'], $enabled_alignments, TRUE)) { - $element_string = '<$text-container class=' . '"' . $configured_alignment["className"] . '"' . '>'; + $element_string = '<$text-container class="' . $configured_alignment["className"] . '">'; $subset = $subset->diff(HTMLRestrictions::fromString($element_string)); } } diff --git a/core/modules/ckeditor5/src/Plugin/CKEditor5PluginDefinition.php b/core/modules/ckeditor5/src/Plugin/CKEditor5PluginDefinition.php index 8ef1e8aea449..8723ae266ca8 100644 --- a/core/modules/ckeditor5/src/Plugin/CKEditor5PluginDefinition.php +++ b/core/modules/ckeditor5/src/Plugin/CKEditor5PluginDefinition.php @@ -52,6 +52,36 @@ final class CKEditor5PluginDefinition extends PluginDefinition implements Plugin throw new \InvalidArgumentException(sprintf('Property %s with value %s does not exist on %s.', $property, $value, __CLASS__)); } } + + // In version CKEditor5 45.0.0, the icons were renamed, so if any + // drupalElementStyles are specifying icons, deprecate use of the old names + // and provide a mapping for backwards compatibility. + // @see https://ckeditor.com/docs/ckeditor5/latest/updating/guides/changelog.html#new-installation-methods-improvements-icons-replacement + // @see https://github.com/ckeditor/ckeditor5/blob/v44.3.0/packages/ckeditor5-core/src/index.ts + // @see https://github.com/ckeditor/ckeditor5/blob/v45.0.0/packages/ckeditor5-icons/src/index.ts + if (!isset($this->ckeditor5) || !isset($this->ckeditor5['config']['drupalElementStyles']) || !is_array($this->ckeditor5['config']['drupalElementStyles'])) { + return; + } + + foreach ($this->ckeditor5['config']['drupalElementStyles'] as $group_id => &$groups) { + if (!is_array($groups)) { + continue; + } + + foreach ($groups as &$style) { + if (is_array($style) && isset($style['icon']) && is_string($style['icon']) && !preg_match('/^(<svg)|(Icon)/', $style['icon'])) { + $deprecated_icon = $style['icon']; + $style['icon'] = match ($deprecated_icon) { + 'objectLeft' => 'IconObjectInlineLeft', + 'objectRight' => 'IconObjectInlineRight', + 'objectBlockLeft' => 'IconObjectLeft', + 'objectBlockRight' => 'IconObjectRight', + default => 'Icon' . ucfirst($style['icon']) + }; + @trigger_error(sprintf('The icon configuration value "%s" in drupalElementStyles group %s for CKEditor5 plugin %s is deprecated in drupal:11.2.0 and will be removed in drupal:12.0.0. Try using "%s" instead. See https://www.drupal.org/node/3528806', $deprecated_icon, $group_id, $this->id(), $style['icon']), E_USER_DEPRECATED); + } + } + } } /** diff --git a/core/modules/ckeditor5/tests/modules/ckeditor5_icon_deprecation_test/ckeditor5_icon_deprecation_test.ckeditor5.yml b/core/modules/ckeditor5/tests/modules/ckeditor5_icon_deprecation_test/ckeditor5_icon_deprecation_test.ckeditor5.yml new file mode 100644 index 000000000000..8ee35f2a3e9d --- /dev/null +++ b/core/modules/ckeditor5/tests/modules/ckeditor5_icon_deprecation_test/ckeditor5_icon_deprecation_test.ckeditor5.yml @@ -0,0 +1,46 @@ +# This plugin is for testing deprecation of CKEditor 5 icon names before version 45. +ckeditor5_icon_deprecation_test_plugin: + ckeditor5: + plugins: [] + config: + drupalElementStyles: + align: + # This is a valid icon name. + - name: 'IconObjectCenter' + title: 'Icon object center' + icon: IconObjectCenter + modelElements: ['drupalMedia'] + # The next four are deprecated icon names with specifically mapped to v45 icon names. + - name: 'objectBlockLeft' + title: 'Object block left' + icon: objectBlockLeft + modelElements: ['drupalMedia'] + - name: 'objectBlockRight' + title: 'Object block right' + icon: objectBlockRight + modelElements: [ 'drupalMedia' ] + - name: 'objectLeft' + title: 'Object left' + icon: objectLeft + modelElements: [ 'drupalMedia' ] + - name: 'objectRight' + title: 'Object right' + icon: objectRight + modelElements: [ 'drupalMedia' ] + svg: + # Icon set as SVG XML. + - name: 'svg' + title: 'SVG' + icon: '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm0 12h16v1.5H2z"/><path d="M18.003 7v5.5a1 1 0 0 1-1 1H8.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H9.5V12h6.997V7.5z"/></svg>' + modelElements: [ 'drupalMedia' ] + threeVerticalDots: + # This is a deprecated icon name mapped with general rule 'exampleName' -> 'IconExampleName'. + - name: 'threeVerticalDots' + title: 'Three vertical dots' + icon: threeVerticalDots + modelElements: [ 'drupalMedia' ] + + drupal: + label: Deprecated icons + elements: + - <drupal-media> diff --git a/core/modules/ckeditor5/tests/modules/ckeditor5_icon_deprecation_test/ckeditor5_icon_deprecation_test.info.yml b/core/modules/ckeditor5/tests/modules/ckeditor5_icon_deprecation_test/ckeditor5_icon_deprecation_test.info.yml new file mode 100644 index 000000000000..d9ebea174b67 --- /dev/null +++ b/core/modules/ckeditor5/tests/modules/ckeditor5_icon_deprecation_test/ckeditor5_icon_deprecation_test.info.yml @@ -0,0 +1,7 @@ +name: CKEditor icon deprecation test +type: module +description: "Provides test CKEditor5 plugin with deprecated Drupal element styles icon config" +package: Testing +version: VERSION +dependencies: + - ckeditor5:ckeditor5 diff --git a/core/modules/ckeditor5/tests/src/FunctionalJavascript/CKEditor5DialogTest.php b/core/modules/ckeditor5/tests/src/FunctionalJavascript/CKEditor5DialogTest.php index 734bc3b430c2..9ed2be2d85ba 100644 --- a/core/modules/ckeditor5/tests/src/FunctionalJavascript/CKEditor5DialogTest.php +++ b/core/modules/ckeditor5/tests/src/FunctionalJavascript/CKEditor5DialogTest.php @@ -81,7 +81,7 @@ class CKEditor5DialogTest extends CKEditor5TestBase { // Make sure the input field can have focus and we can type into it. $input->setValue($link_url); // Save the new link. - $page->find('css', '.ck-balloon-panel .ck-button-save')->click(); + $page->find('xpath', "//button[span[text()='Insert']]")->click(); // Make sure something was added to the text. $this->assertNotEmpty($content_area->getText()); } diff --git a/core/modules/ckeditor5/tests/src/FunctionalJavascript/CKEditor5HeightTest.php b/core/modules/ckeditor5/tests/src/FunctionalJavascript/CKEditor5HeightTest.php new file mode 100644 index 000000000000..81928b1642b9 --- /dev/null +++ b/core/modules/ckeditor5/tests/src/FunctionalJavascript/CKEditor5HeightTest.php @@ -0,0 +1,137 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\ckeditor5\FunctionalJavascript; + +use Drupal\editor\Entity\Editor; +use Drupal\Tests\ckeditor5\Traits\CKEditor5TestTrait; + +/** + * Tests ckeditor height respects field rows config. + * + * @group ckeditor5 + * @internal + */ +class CKEditor5HeightTest extends CKEditor5TestBase { + + use CKEditor5TestTrait; + + /** + * Tests editor height respects rows config. + */ + public function testCKEditor5Height(): void { + $this->addNewTextFormat(); + /** @var \Drupal\editor\Entity\Editor $editor */ + $editor = Editor::load('ckeditor5'); + $editor->setSettings([ + 'toolbar' => [ + 'items' => [ + 'sourceEditing', + ], + ], + 'plugins' => [ + 'ckeditor5_sourceEditing' => [ + 'allowed_tags' => [], + ], + ], + ])->save(); + $this->drupalGet('/node/add/page'); + $this->waitForEditor(); + + // We expect height to be 320, but test to ensure that it's greater + // than 300. We want to ensure that we don't hard code a very specific + // value because tests might break if styles change (line-height, etc). + // Note that the default height for CKEditor5 is 47px. + $this->assertGreaterThan(300, $this->getEditorHeight()); + // Check source editing height. + $this->pressEditorButton('Source'); + $assert = $this->assertSession(); + $this->assertNotNull($assert->waitForElementVisible('css', '.ck-source-editing-area')); + $this->assertGreaterThan(300, $this->getEditorHeight(TRUE)); + + // Test the max height of the editor is less that the window height. + $body = \str_repeat('<p>Llamas are cute.</p>', 100); + $node = $this->drupalCreateNode([ + 'body' => $body, + ]); + $this->drupalGet($node->toUrl('edit-form')); + $this->assertLessThan($this->getWindowHeight(), $this->getEditorHeight()); + + // Check source editing has a scroll bar. + $this->pressEditorButton('Source'); + $this->assertNotNull($assert->waitForElementVisible('css', '.ck-source-editing-area')); + $this->assertTrue($this->isSourceEditingScrollable()); + + // Double the editor row count. + \Drupal::service('entity_display.repository')->getFormDisplay('node', 'page') + ->setComponent('body', [ + 'type' => 'text_textarea_with_summary', + 'settings' => [ + 'rows' => 18, + ], + ]) + ->save(); + // Check the height of the editor again. + $this->drupalGet('/node/add/page'); + $this->waitForEditor(); + // We expect height to be 640, but test to ensure that it's greater + // than 600. We want to ensure that we don't hard code a very specific + // value because tests might break if styles change (line-height, etc). + // Note that the default height for CKEditor5 is 47px. + $this->assertGreaterThan(600, $this->getEditorHeight()); + } + + /** + * Gets the height of ckeditor. + */ + private function getEditorHeight(bool $sourceEditing = FALSE): int { + $selector = $sourceEditing ? '.ck-source-editing-area' : '.ck-editor__editable'; + $javascript = <<<JS + return document.querySelector('$selector').clientHeight; + JS; + return $this->getSession()->evaluateScript($javascript); + } + + /** + * Gets the window height. + */ + private function getWindowHeight(): int { + $javascript = <<<JS + return window.innerHeight; + JS; + return $this->getSession()->evaluateScript($javascript); + } + + /** + * Checks that the source editing element is scrollable. + */ + private function isSourceEditingScrollable(): bool { + $javascript = <<<JS + (function () { + const element = document.querySelector('.ck-source-editing-area textarea'); + const style = window.getComputedStyle(element); + if ( + element.scrollHeight > element.clientHeight && + style.overflow !== 'hidden' && + style['overflow-y'] !== 'hidden' && + style.overflow !== 'clip' && + style['overflow-y'] !== 'clip' + ) { + if ( + element === document.scrollingElement || + (style.overflow !== 'visible' && + style['overflow-y'] !== 'visible') + ) { + return true; + } + } + + return false; + })(); + JS; + $evaluateScript = $this->getSession()->evaluateScript($javascript); + return $evaluateScript; + } + +} diff --git a/core/modules/ckeditor5/tests/src/FunctionalJavascript/ImageTestBase.php b/core/modules/ckeditor5/tests/src/FunctionalJavascript/ImageTestBase.php index 427a74a7054c..8efebd4de818 100644 --- a/core/modules/ckeditor5/tests/src/FunctionalJavascript/ImageTestBase.php +++ b/core/modules/ckeditor5/tests/src/FunctionalJavascript/ImageTestBase.php @@ -92,7 +92,7 @@ abstract class ImageTestBase extends CKEditor5TestBase { $dialog = $page->find('css', '.ck-dialog'); $src_input = $dialog->find('css', '.ck-image-insert-url input[type=text]'); $src_input->setValue($src); - $dialog->find('xpath', "//button[span[text()='Accept']]")->click(); + $dialog->find('xpath', "//button[span[text()='Insert']]")->click(); // Wait for the image to be uploaded and rendered by CKEditor 5. $this->assertNotEmpty($this->assertSession()->waitForElementVisible('css', '.ck-widget.image > img[src="' . $src . '"]')); } diff --git a/core/modules/ckeditor5/tests/src/FunctionalJavascript/ImageTestBaselineTrait.php b/core/modules/ckeditor5/tests/src/FunctionalJavascript/ImageTestBaselineTrait.php index 2e0d3e6e3ceb..4cc94a97cded 100644 --- a/core/modules/ckeditor5/tests/src/FunctionalJavascript/ImageTestBaselineTrait.php +++ b/core/modules/ckeditor5/tests/src/FunctionalJavascript/ImageTestBaselineTrait.php @@ -186,10 +186,10 @@ trait ImageTestBaselineTrait { $link_image_button->press(); // Assert structure of link form balloon. $balloon = $this->assertVisibleBalloon('.ck-link-form'); - $url_input = $balloon->find('css', '.ck-labeled-field-view__input-wrapper .ck-input-text'); - // Fill in link form balloon's <input> and hit "Save". + $url_input = $balloon->find('css', '.ck-labeled-field-view__input-wrapper .ck-input-text[inputmode=url]'); + // Fill in link form balloon's <input> and hit "Insert". $url_input->setValue('http://www.drupal.org/association'); - $balloon->pressButton('Save'); + $balloon->pressButton('Insert'); // Assert the "editingDowncast" HTML after making changes. First assert // the link exists, then assert the expected DOM structure in detail. diff --git a/core/modules/ckeditor5/tests/src/FunctionalJavascript/ImageUrlTest.php b/core/modules/ckeditor5/tests/src/FunctionalJavascript/ImageUrlTest.php index 949b4d04ed23..d2ed0f991e85 100644 --- a/core/modules/ckeditor5/tests/src/FunctionalJavascript/ImageUrlTest.php +++ b/core/modules/ckeditor5/tests/src/FunctionalJavascript/ImageUrlTest.php @@ -30,7 +30,7 @@ class ImageUrlTest extends ImageUrlTestBase { $dialog = $page->find('css', '.ck-dialog'); $src_input = $dialog->find('css', '.ck-image-insert-url input[type=text]'); $src_input->setValue($src); - $dialog->find('xpath', "//button[span[text()='Accept']]")->click(); + $dialog->find('xpath', "//button[span[text()='Insert']]")->click(); $this->assertNotEmpty($assert_session->waitForElementVisible('css', $image_selector)); $this->click($image_selector); diff --git a/core/modules/ckeditor5/tests/src/FunctionalJavascript/MediaLinkabilityTest.php b/core/modules/ckeditor5/tests/src/FunctionalJavascript/MediaLinkabilityTest.php index f7580f8847ac..2d581b36ee5c 100644 --- a/core/modules/ckeditor5/tests/src/FunctionalJavascript/MediaLinkabilityTest.php +++ b/core/modules/ckeditor5/tests/src/FunctionalJavascript/MediaLinkabilityTest.php @@ -134,10 +134,10 @@ class MediaLinkabilityTest extends MediaTestBase { $link_media_button->press(); // Assert structure of link form balloon. $balloon = $this->assertVisibleBalloon('.ck-link-form'); - $url_input = $balloon->find('css', '.ck-labeled-field-view__input-wrapper .ck-input-text'); - // Fill in link form balloon's <input> and hit "Save". + $url_input = $balloon->find('css', '.ck-labeled-field-view__input-wrapper .ck-input-text[inputmode=url]'); + // Fill in link form balloon's <input> and hit "Insert". $url_input->setValue('http://linking-embedded-media.com'); - $balloon->pressButton('Save'); + $balloon->pressButton('Insert'); // Assert the "editingDowncast" HTML after making changes. Assert the link // exists, then assert the link exists. Then assert the expected DOM @@ -272,13 +272,15 @@ class MediaLinkabilityTest extends MediaTestBase { $this->getBalloonButton('Link media')->click(); $balloon = $this->assertVisibleBalloon('.ck-link-form'); - $url_input = $balloon->find('css', '.ck-labeled-field-view__input-wrapper .ck-input-text'); + $url_input = $balloon->find('css', '.ck-labeled-field-view__input-wrapper .ck-input-text[inputmode=url]'); $url_input->setValue('http://linking-embedded-media.com'); + $balloon->pressButton('Insert'); + $this->getBalloonButton('Link properties')->click(); $this->getBalloonButton($decorator)->click(); - $balloon->pressButton('Save'); + $this->getBalloonButton('Back')->click(); $this->assertNotEmpty($assert_session->waitForElementVisible('css', '.drupal-media a')); - $this->assertVisibleBalloon('.ck-link-actions'); + $this->assertVisibleBalloon('.ck-link-toolbar'); $xpath = new \DOMXPath($this->getEditorDataAsDom()); $this->assertNotEmpty($xpath->query("//a[@href='http://linking-embedded-media.com']$decorator_attributes")); @@ -296,7 +298,7 @@ class MediaLinkabilityTest extends MediaTestBase { $drupalmedia->click(); $this->assertVisibleBalloon('.ck-toolbar[aria-label="Drupal Media toolbar"]'); $this->getBalloonButton('Link media')->click(); - $this->assertVisibleBalloon('.ck-link-actions'); + $this->assertVisibleBalloon('.ck-link-toolbar'); $this->getBalloonButton('Unlink')->click(); $this->assertTrue($assert_session->waitForElementRemoved('css', '.drupal-media a')); diff --git a/core/modules/ckeditor5/tests/src/FunctionalJavascript/MediaTest.php b/core/modules/ckeditor5/tests/src/FunctionalJavascript/MediaTest.php index 114704afb7f8..5ba284497086 100644 --- a/core/modules/ckeditor5/tests/src/FunctionalJavascript/MediaTest.php +++ b/core/modules/ckeditor5/tests/src/FunctionalJavascript/MediaTest.php @@ -332,7 +332,7 @@ class MediaTest extends MediaTestBase { $this->assertNotEmpty($assert_session->waitForElement('css', '.drupal-media figcaption.ck-editor__nested-editable')); $this->pressEditorButton('Link'); $this->assertVisibleBalloon('.ck-link-form'); - $link_input = $page->find('css', '.ck-balloon-panel .ck-link-form input[type=text]'); + $link_input = $page->find('css', '.ck-balloon-panel .ck-link-form input[type=text][inputmode=url]'); $link_input->setValue('https://example.com'); $page->find('css', '.ck-balloon-panel .ck-link-form button[type=submit]')->click(); $this->assertNotEmpty($assert_session->waitForElement('css', '.drupal-media figcaption > a')); diff --git a/core/modules/ckeditor5/tests/src/FunctionalJavascript/StyleTest.php b/core/modules/ckeditor5/tests/src/FunctionalJavascript/StyleTest.php index e295090d7c18..2de2d3201dc9 100644 --- a/core/modules/ckeditor5/tests/src/FunctionalJavascript/StyleTest.php +++ b/core/modules/ckeditor5/tests/src/FunctionalJavascript/StyleTest.php @@ -658,7 +658,7 @@ JS; // 6. the `reliable` class has been added to the `<a>` // 7. The `deep-dive` class has been added to the `<div>` // 8. The `caution` class has been added to the `<caption>` - $this->assertSame('<h2 class="red-heading">Upgrades</h2><p>Drupal has historically been difficult to upgrade from one major version to the next.</p><p class="highlighted interesting">This changed with Drupal 8.</p><blockquote class="famous"><p>Updating from Drupal 8\'s latest version to Drupal 9.0.0 should be as easy as updating between minor versions of Drupal 8.</p></blockquote><p>— <a class="reliable" href="https://dri.es/making-drupal-upgrades-easy-forever">Dries</a></p><div class="deep-dive"><ul class="items"><li>Update Drupal core using Composer</li><li>Update Drupal core manually</li><li>Update Drupal core using Drush</li></ul><ol class="steps"><li>Back up your files and database</li><li>Put your site into maintenance mode</li><li>Update the code and apply changes</li><li>Deactivate maintenance mode</li></ol><table class="data-analysis"><caption class="caution">Drupal upgrades are now easy, with a few caveats.</caption><tbody><tr><td>First</td><td>Second</td></tr><tr><td>Data value 1</td><td>Data value 2</td></tr></tbody></table></div>', $this->getEditorDataAsHtmlString()); + $this->assertSame('<h2 class="red-heading">Upgrades</h2><p>Drupal has historically been difficult to upgrade from one major version to the next.</p><p class="highlighted interesting">This changed with Drupal 8.</p><blockquote class="famous"><p>Updating from Drupal 8\'s latest version to Drupal 9.0.0 should be as easy as updating between minor versions of Drupal 8.</p></blockquote><p>— <a class="reliable" href="https://dri.es/making-drupal-upgrades-easy-forever">Dries</a></p><div class="deep-dive"><ul class="items"><li>Update Drupal core using Composer</li><li>Update Drupal core manually</li><li>Update Drupal core using Drush</li></ul><ol class="steps"><li>Back up your files and database</li><li>Put your site into maintenance mode</li><li>Update the code and apply changes</li><li>Deactivate maintenance mode</li></ol><table class="table data-analysis"><caption class="caution">Drupal upgrades are now easy, with a few caveats.</caption><tbody><tr><td>First</td><td>Second</td></tr><tr><td>Data value 1</td><td>Data value 2</td></tr></tbody></table></div>', $this->getEditorDataAsHtmlString()); } } diff --git a/core/modules/ckeditor5/tests/src/Kernel/CKEditor5PluginManagerTest.php b/core/modules/ckeditor5/tests/src/Kernel/CKEditor5PluginManagerTest.php index 84e26e783882..731e777749eb 100644 --- a/core/modules/ckeditor5/tests/src/Kernel/CKEditor5PluginManagerTest.php +++ b/core/modules/ckeditor5/tests/src/Kernel/CKEditor5PluginManagerTest.php @@ -18,6 +18,7 @@ use Drupal\filter\Entity\FilterFormat; use Drupal\Tests\SchemaCheckTestTrait; use Drupal\TestTools\Random; use org\bovigo\vfs\vfsStream; +use PHPUnit\Framework\Attributes\IgnoreDeprecations; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag; use Symfony\Component\Yaml\Yaml; @@ -2053,4 +2054,26 @@ PHP, ]; } + /** + * Tests deprecation and backwards compatibility of icon names. + */ + #[IgnoreDeprecations] + public function testDeprecatedIcons(): void { + $this->expectDeprecation('The icon configuration value "objectBlockLeft" in drupalElementStyles group align for CKEditor5 plugin ckeditor5_icon_deprecation_test_plugin is deprecated in drupal:11.2.0 and will be removed in drupal:12.0.0. Try using "IconObjectLeft" instead. See https://www.drupal.org/node/3528806'); + $this->expectDeprecation('The icon configuration value "objectBlockRight" in drupalElementStyles group align for CKEditor5 plugin ckeditor5_icon_deprecation_test_plugin is deprecated in drupal:11.2.0 and will be removed in drupal:12.0.0. Try using "IconObjectRight" instead. See https://www.drupal.org/node/3528806'); + $this->expectDeprecation('The icon configuration value "objectLeft" in drupalElementStyles group align for CKEditor5 plugin ckeditor5_icon_deprecation_test_plugin is deprecated in drupal:11.2.0 and will be removed in drupal:12.0.0. Try using "IconObjectInlineLeft" instead. See https://www.drupal.org/node/3528806'); + $this->expectDeprecation('The icon configuration value "objectRight" in drupalElementStyles group align for CKEditor5 plugin ckeditor5_icon_deprecation_test_plugin is deprecated in drupal:11.2.0 and will be removed in drupal:12.0.0. Try using "IconObjectInlineRight" instead. See https://www.drupal.org/node/3528806'); + $this->expectDeprecation('The icon configuration value "threeVerticalDots" in drupalElementStyles group threeVerticalDots for CKEditor5 plugin ckeditor5_icon_deprecation_test_plugin is deprecated in drupal:11.2.0 and will be removed in drupal:12.0.0. Try using "IconThreeVerticalDots" instead. See https://www.drupal.org/node/3528806'); + \Drupal::service('module_installer')->install(['ckeditor5_icon_deprecation_test']); + $definitions = \Drupal::service('plugin.manager.ckeditor5.plugin')->getDefinitions(); + $config = $definitions['ckeditor5_icon_deprecation_test_plugin']->toArray()['ckeditor5']['config']['drupalElementStyles']; + $this->assertSame('IconObjectCenter', $config['align'][0]['icon']); + $this->assertSame('IconObjectLeft', $config['align'][1]['icon']); + $this->assertSame('IconObjectRight', $config['align'][2]['icon']); + $this->assertSame('IconObjectInlineLeft', $config['align'][3]['icon']); + $this->assertSame('IconObjectInlineRight', $config['align'][4]['icon']); + $this->assertStringContainsString('<svg viewBox="0 0 20 20"', $config['svg'][0]['icon']); + $this->assertSame('IconThreeVerticalDots', $config['threeVerticalDots'][0]['icon']); + } + } diff --git a/core/modules/ckeditor5/tests/src/Kernel/ValidatorsTest.php b/core/modules/ckeditor5/tests/src/Kernel/ValidatorsTest.php index 8c87a78752ed..75735a0cc513 100644 --- a/core/modules/ckeditor5/tests/src/Kernel/ValidatorsTest.php +++ b/core/modules/ckeditor5/tests/src/Kernel/ValidatorsTest.php @@ -965,7 +965,7 @@ class ValidatorsTest extends KernelTestBase { 'status' => TRUE, 'weight' => 0, 'settings' => [ - 'allowed_html' => "<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type='1 A I'> <li> <dl> <dt> <dd> <h2 id='jump-*'> <h3 id> <h4 id> <h5 id> <h6 id>" . "<p> <br>", + 'allowed_html' => "<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type='1 A I'> <li> <dl> <dt> <dd> <h2 id='jump-*'> <h3 id> <h4 id> <h5 id> <h6 id> <p> <br>", 'filter_html_help' => TRUE, 'filter_html_nofollow' => TRUE, ], diff --git a/core/modules/ckeditor5/tests/src/Nightwatch/Tests/ckEditor5EditorHeightTest.js b/core/modules/ckeditor5/tests/src/Nightwatch/Tests/ckEditor5EditorHeightTest.js deleted file mode 100644 index a1b76110eb7a..000000000000 --- a/core/modules/ckeditor5/tests/src/Nightwatch/Tests/ckEditor5EditorHeightTest.js +++ /dev/null @@ -1,241 +0,0 @@ -// cspell:ignore sourceediting - -module.exports = { - '@tags': ['core', 'ckeditor5'], - before(browser) { - browser - .drupalInstall({ installProfile: 'testing' }) - .drupalInstallModule('ckeditor5', true) - .drupalInstallModule('field_ui') - .drupalInstallModule('node', true); - - // Set fixed (desktop-ish) size to ensure a maximum viewport. - browser.window.resize(1920, 1080); - }, - after(browser) { - browser.drupalUninstall(); - }, - 'Ensure CKEditor respects field widget row value': (browser) => { - browser.drupalLoginAsAdmin(() => { - browser - // Create new input format. - .drupalRelativeURL('/admin/config/content/formats/add') - .waitForElementVisible('[data-drupal-selector="edit-name"]') - .updateValue('[data-drupal-selector="edit-name"]', 'test') - .waitForElementVisible('#edit-name-machine-name-suffix') - .click( - '[data-drupal-selector="edit-editor-editor"] option[value=ckeditor5]', - ) - // Wait for CKEditor 5 settings to be visible. - .waitForElementVisible( - '[data-drupal-selector="edit-editor-settings-toolbar"]', - ) - .click('.ckeditor5-toolbar-button-sourceEditing') // Select the Source Editing button. - // Hit the down arrow key to move it to the toolbar. - .perform(function () { - return this.actions().sendKeys(browser.Keys.ARROW_DOWN); - }) - // Wait for new source editing vertical tab to be present before continuing. - .waitForElementVisible( - '[href*=edit-editor-settings-plugins-ckeditor5-sourceediting]', - ) - .submitForm('input[type="submit"]') - .waitForElementVisible('[data-drupal-messages]') - .assert.textContains('[data-drupal-messages]', 'Added text format') - // Create new content type. - .drupalRelativeURL('/admin/structure/types/add') - .waitForElementVisible('[data-drupal-selector="edit-name"]') - .updateValue('[data-drupal-selector="edit-name"]', 'test') - .waitForElementVisible('#edit-name-machine-name-suffix') // Wait for machine name to update. - .submitForm('input[type="submit"]') - .waitForElementVisible('[data-drupal-messages]') - .assert.textContains( - '[data-drupal-messages]', - 'The content type test has been added', - ) - // Navigate to the create content page and measure height of the editor. - .drupalRelativeURL('/node/add/test') - .waitForElementVisible('.ck-editor__editable') - .execute( - // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow - function () { - const height = document.querySelector( - '.ck-editor__editable', - ).clientHeight; - - // We expect height to be 320, but test to ensure that it's greater - // than 300. We want to ensure that we don't hard code a very specific - // value because tests might break if styles change (line-height, etc). - // Note that the default height for CKEditor5 is 47px. - return height > 300; - }, - [], - (result) => { - browser.assert.ok( - result.value, - 'Editor height is set to 9 rows (default).', - ); - }, - ) - .click('.ck-source-editing-button') - .waitForElementVisible('.ck-source-editing-area') - .execute( - // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow - function () { - const height = document.querySelector( - '.ck-source-editing-area', - ).clientHeight; - - // We expect height to be 320, but test to ensure that it's greater - // than 300. We want to ensure that we don't hard code a very specific - // value because tests might break if styles change (line-height, etc). - // Note that the default height for CKEditor5 is 47px. - return height > 300; - }, - [], - (result) => { - browser.assert.ok( - result.value, - 'Source editing height is set to 9 rows (default).', - ); - }, - ) - - // Navigate to the create content page and measure max-height of the editor. - .drupalRelativeURL('/node/add/test') - .execute( - // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow - function () { - window.Drupal.CKEditor5Instances.forEach((instance) => { - instance.setData('<p>Llamas are cute.</p>'.repeat(100)); - }); - - const height = document.querySelector( - '.ck-editor__editable', - ).clientHeight; - - return height < window.innerHeight; - }, - [], - (result) => { - browser.assert.ok( - result.value, - 'Editor area should never exceed full viewport.', - ); - }, - ) - // Source Editor textarea should have vertical scrollbar when needed. - .click('.ck-source-editing-button') - .waitForElementVisible('.ck-source-editing-area') - .execute( - // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow - function () { - function isScrollableY(element) { - const style = window.getComputedStyle(element); - - if ( - element.scrollHeight > element.clientHeight && - style.overflow !== 'hidden' && - style['overflow-y'] !== 'hidden' && - style.overflow !== 'clip' && - style['overflow-y'] !== 'clip' - ) { - if ( - element === document.scrollingElement || - (style.overflow !== 'visible' && - style['overflow-y'] !== 'visible') - ) { - return true; - } - } - - return false; - } - - return isScrollableY( - document.querySelector('.ck-source-editing-area textarea'), - ); - }, - [], - (result) => { - browser.assert.strictEqual( - result.value, - true, - 'Source Editor textarea should have vertical scrollbar when needed.', - ); - }, - ) - - // Double the editor row count. - .drupalRelativeURL('/admin/structure/types/manage/test/form-display') - .waitForElementVisible( - '[data-drupal-selector="edit-fields-body-settings-edit"]', - ) - .click('[data-drupal-selector="edit-fields-body-settings-edit"]') - .waitForElementVisible( - '[data-drupal-selector="edit-fields-body-settings-edit-form-settings-rows"]', - ) - .updateValue( - '[data-drupal-selector="edit-fields-body-settings-edit-form-settings-rows"]', - '18', - ) - // Save field settings. - .click( - '[data-drupal-selector="edit-fields-body-settings-edit-form-actions-save-settings"]', - ) - .waitForElementVisible( - '[data-drupal-selector="edit-fields-body"] .field-plugin-summary', - ) - .click('[data-drupal-selector="edit-submit"]') - .waitForElementVisible('[data-drupal-messages]') - .assert.textContains( - '[data-drupal-messages]', - 'Your settings have been saved', - ) - - // Navigate to the create content page and measure height of the editor. - .drupalRelativeURL('/node/add/test') - .execute( - // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow - function () { - const height = document.querySelector( - '.ck-editor__editable', - ).clientHeight; - - // We expect height to be 640, but test to ensure that it's greater - // than 600. We want to ensure that we don't hard code a very specific - // value because tests might break if styles change (line-height, etc). - // Note that the default height for CKEditor5 is 47px. - return height > 600; - }, - [], - (result) => { - browser.assert.ok(result.value, 'Editor height is set to 18 rows.'); - }, - ) - .click('.ck-source-editing-button') - .waitForElementVisible('.ck-source-editing-area') - .execute( - // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow - function () { - const height = document.querySelector( - '.ck-source-editing-area', - ).clientHeight; - - // We expect height to be 640, but test to ensure that it's greater - // than 600. We want to ensure that we don't hard code a very specific - // value because tests might break if styles change (line-height, etc). - // Note that the default height for CKEditor5 is 47px. - return height > 600; - }, - [], - (result) => { - browser.assert.ok( - result.value, - 'Source editing height is set to 18 rows (default).', - ); - }, - ); - }); - }, -}; diff --git a/core/modules/config/tests/src/Functional/ConfigExportUITest.php b/core/modules/config/tests/src/Functional/ConfigExportUITest.php index 8cf7e858b738..d54e4d3c8156 100644 --- a/core/modules/config/tests/src/Functional/ConfigExportUITest.php +++ b/core/modules/config/tests/src/Functional/ConfigExportUITest.php @@ -84,7 +84,7 @@ class ConfigExportUITest extends BrowserTestBase { // Ensure the test configuration override is in effect but was not exported. $this->assertSame('Foo', \Drupal::config('system.maintenance')->get('message')); $archiver->extract($temp_directory, ['system.maintenance.yml']); - $file_contents = file_get_contents($temp_directory . '/' . 'system.maintenance.yml'); + $file_contents = file_get_contents($temp_directory . '/system.maintenance.yml'); $exported = Yaml::decode($file_contents); $this->assertNotSame('Foo', $exported['message']); diff --git a/core/modules/config_translation/src/ConfigMapperManager.php b/core/modules/config_translation/src/ConfigMapperManager.php index 6ce0054a3d8e..6edbdf3561ed 100644 --- a/core/modules/config_translation/src/ConfigMapperManager.php +++ b/core/modules/config_translation/src/ConfigMapperManager.php @@ -79,7 +79,7 @@ class ConfigMapperManager extends DefaultPluginManager implements ConfigMapperMa $this->alterInfo('config_translation_info'); // Config translation only uses an info hook discovery, cache by language. - $cache_key = 'config_translation_info_plugins' . ':' . $language_manager->getCurrentLanguage()->getId(); + $cache_key = 'config_translation_info_plugins:' . $language_manager->getCurrentLanguage()->getId(); $this->setCacheBackend($cache_backend, $cache_key); } diff --git a/core/modules/content_moderation/tests/src/Functional/WorkspaceContentModerationIntegrationTest.php b/core/modules/content_moderation/tests/src/Functional/WorkspaceContentModerationIntegrationTest.php index 4b4fbe2c7905..2462173f970b 100644 --- a/core/modules/content_moderation/tests/src/Functional/WorkspaceContentModerationIntegrationTest.php +++ b/core/modules/content_moderation/tests/src/Functional/WorkspaceContentModerationIntegrationTest.php @@ -33,7 +33,7 @@ class WorkspaceContentModerationIntegrationTest extends ModerationStateTestBase protected function getAdministratorPermissions(): array { return array_merge($this->permissions, [ 'bypass node access', - 'view any workspace', + 'administer workspaces', ]); } @@ -50,6 +50,7 @@ class WorkspaceContentModerationIntegrationTest extends ModerationStateTestBase $this->createContentTypeFromUi('Article', 'article', TRUE); $this->setupWorkspaceSwitcherBlock(); + $this->createWorkspaceThroughUi('Stage', 'stage'); } /** diff --git a/core/modules/contextual/contextual.libraries.yml b/core/modules/contextual/contextual.libraries.yml index 6798d02d9070..0e80f3aed427 100644 --- a/core/modules/contextual/contextual.libraries.yml +++ b/core/modules/contextual/contextual.libraries.yml @@ -1,7 +1,6 @@ drupal.contextual-links: version: VERSION js: - js/contextualModelView.js: {} # Ensure to run before contextual/drupal.context-toolbar. js/contextual.js: { weight: -2 } css: diff --git a/core/modules/contextual/js/contextual.js b/core/modules/contextual/js/contextual.js index f1008eabe07b..5a852e28fbac 100644 --- a/core/modules/contextual/js/contextual.js +++ b/core/modules/contextual/js/contextual.js @@ -256,7 +256,259 @@ } }, }), - ContextualModelView: {}, + + /** + * Models the state of a contextual link's trigger, list & region. + */ + ContextualModelView: class { + constructor($contextual, $region, options) { + this.title = options.title || ''; + this.regionIsHovered = false; + this._hasFocus = false; + this._isOpen = false; + this._isLocked = false; + this.strings = options.strings; + this.timer = NaN; + this.modelId = btoa(Math.random()).substring(0, 12); + this.$region = $region; + this.$contextual = $contextual; + + if (!document.body.classList.contains('touchevents')) { + this.$region.on({ + mouseenter: () => { + this.regionIsHovered = true; + }, + mouseleave: () => { + this.close().blur(); + this.regionIsHovered = false; + }, + 'mouseleave mouseenter': () => this.render(), + }); + this.$contextual.on('mouseenter', () => { + this.focus(); + this.render(); + }); + } + + this.$contextual.on( + { + click: () => { + this.toggleOpen(); + }, + touchend: () => { + Drupal.contextual.ContextualModelView.touchEndToClick(); + }, + focus: () => { + this.focus(); + }, + blur: () => { + this.blur(); + }, + 'click blur touchend focus': () => this.render(), + }, + '.trigger', + ); + + this.$contextual.on( + { + click: () => { + this.close().blur(); + }, + touchend: (event) => { + Drupal.contextual.ContextualModelView.touchEndToClick(event); + }, + focus: () => { + this.focus(); + }, + blur: () => { + this.waitCloseThenBlur(); + }, + 'click blur touchend focus': () => this.render(), + }, + '.contextual-links a', + ); + + this.render(); + + // Let other JavaScript react to the adding of a new contextual link. + $(document).trigger('drupalContextualLinkAdded', { + $el: $contextual, + $region, + model: this, + }); + } + + /** + * Updates the rendered representation of the current contextual links. + */ + render() { + const { isOpen } = this; + const isVisible = this.isLocked || this.regionIsHovered || isOpen; + this.$region.toggleClass('focus', this.hasFocus); + this.$contextual + .toggleClass('open', isOpen) + // Update the visibility of the trigger. + .find('.trigger') + .toggleClass('visually-hidden', !isVisible); + + this.$contextual.find('.contextual-links').prop('hidden', !isOpen); + const trigger = this.$contextual.find('.trigger').get(0); + trigger.textContent = Drupal.t('@action @title configuration options', { + '@action': !isOpen ? this.strings.open : this.strings.close, + '@title': this.title, + }); + trigger.setAttribute('aria-pressed', isOpen); + } + + /** + * Prevents delay and simulated mouse events. + * + * @param {jQuery.Event} event the touch end event. + */ + static touchEndToClick(event) { + event.preventDefault(); + event.target.click(); + } + + /** + * Set up a timeout to allow a user to tab between the trigger and the + * contextual links without the menu dismissing. + */ + waitCloseThenBlur() { + this.timer = window.setTimeout(() => { + this.isOpen = false; + this.hasFocus = false; + this.render(); + }, 150); + } + + /** + * Opens or closes the contextual link. + * + * If it is opened, then also give focus. + * + * @return {Drupal.contextual.ContextualModelView} + * The current contextual model view. + */ + toggleOpen() { + const newIsOpen = !this.isOpen; + this.isOpen = newIsOpen; + if (newIsOpen) { + this.focus(); + } + return this; + } + + /** + * Gives focus to this contextual link. + * + * Also closes + removes focus from every other contextual link. + * + * @return {Drupal.contextual.ContextualModelView} + * The current contextual model view. + */ + focus() { + const { modelId } = this; + Drupal.contextual.instances.forEach((model) => { + if (model.modelId !== modelId) { + model.close().blur(); + } + }); + window.clearTimeout(this.timer); + this.hasFocus = true; + return this; + } + + /** + * Removes focus from this contextual link, unless it is open. + * + * @return {Drupal.contextual.ContextualModelView} + * The current contextual model view. + */ + blur() { + if (!this.isOpen) { + this.hasFocus = false; + } + return this; + } + + /** + * Closes this contextual link. + * + * Does not call blur() because we want to allow a contextual link to have + * focus, yet be closed for example when hovering. + * + * @return {Drupal.contextual.ContextualModelView} + * The current contextual model view. + */ + close() { + this.isOpen = false; + return this; + } + + /** + * Gets the current focus state. + * + * @return {boolean} the focus state. + */ + get hasFocus() { + return this._hasFocus; + } + + /** + * Sets the current focus state. + * + * @param {boolean} value - new focus state + */ + set hasFocus(value) { + this._hasFocus = value; + this.$region.toggleClass('focus', this._hasFocus); + } + + /** + * Gets the current open state. + * + * @return {boolean} the open state. + */ + get isOpen() { + return this._isOpen; + } + + /** + * Sets the current open state. + * + * @param {boolean} value - new open state + */ + set isOpen(value) { + this._isOpen = value; + // Nested contextual region handling: hide any nested contextual triggers. + this.$region + .closest('.contextual-region') + .find('.contextual .trigger:not(:first)') + .toggle(!this.isOpen); + } + + /** + * Gets the current locked state. + * + * @return {boolean} the locked state. + */ + get isLocked() { + return this._isLocked; + } + + /** + * Sets the current locked state. + * + * @param {boolean} value - new locked state + */ + set isLocked(value) { + if (value !== this._isLocked) { + this._isLocked = value; + this.render(); + } + } + }, }; /** diff --git a/core/modules/contextual/js/contextualModelView.js b/core/modules/contextual/js/contextualModelView.js deleted file mode 100644 index 4488045e2236..000000000000 --- a/core/modules/contextual/js/contextualModelView.js +++ /dev/null @@ -1,254 +0,0 @@ -(($, Drupal) => { - /** - * Models the state of a contextual link's trigger, list & region. - */ - Drupal.contextual.ContextualModelView = class { - constructor($contextual, $region, options) { - this.title = options.title || ''; - this.regionIsHovered = false; - this._hasFocus = false; - this._isOpen = false; - this._isLocked = false; - this.strings = options.strings; - this.timer = NaN; - this.modelId = btoa(Math.random()).substring(0, 12); - this.$region = $region; - this.$contextual = $contextual; - - if (!document.body.classList.contains('touchevents')) { - this.$region.on({ - mouseenter: () => { - this.regionIsHovered = true; - }, - mouseleave: () => { - this.close().blur(); - this.regionIsHovered = false; - }, - 'mouseleave mouseenter': () => this.render(), - }); - this.$contextual.on('mouseenter', () => { - this.focus(); - this.render(); - }); - } - - this.$contextual.on( - { - click: () => { - this.toggleOpen(); - }, - touchend: () => { - Drupal.contextual.ContextualModelView.touchEndToClick(); - }, - focus: () => { - this.focus(); - }, - blur: () => { - this.blur(); - }, - 'click blur touchend focus': () => this.render(), - }, - '.trigger', - ); - - this.$contextual.on( - { - click: () => { - this.close().blur(); - }, - touchend: (event) => { - Drupal.contextual.ContextualModelView.touchEndToClick(event); - }, - focus: () => { - this.focus(); - }, - blur: () => { - this.waitCloseThenBlur(); - }, - 'click blur touchend focus': () => this.render(), - }, - '.contextual-links a', - ); - - this.render(); - - // Let other JavaScript react to the adding of a new contextual link. - $(document).trigger('drupalContextualLinkAdded', { - $el: $contextual, - $region, - model: this, - }); - } - - /** - * Updates the rendered representation of the current contextual links. - */ - render() { - const { isOpen } = this; - const isVisible = this.isLocked || this.regionIsHovered || isOpen; - this.$region.toggleClass('focus', this.hasFocus); - this.$contextual - .toggleClass('open', isOpen) - // Update the visibility of the trigger. - .find('.trigger') - .toggleClass('visually-hidden', !isVisible); - - this.$contextual.find('.contextual-links').prop('hidden', !isOpen); - const trigger = this.$contextual.find('.trigger').get(0); - trigger.textContent = Drupal.t('@action @title configuration options', { - '@action': !isOpen ? this.strings.open : this.strings.close, - '@title': this.title, - }); - trigger.setAttribute('aria-pressed', isOpen); - } - - /** - * Prevents delay and simulated mouse events. - * - * @param {jQuery.Event} event the touch end event. - */ - static touchEndToClick(event) { - event.preventDefault(); - event.target.click(); - } - - /** - * Set up a timeout to allow a user to tab between the trigger and the - * contextual links without the menu dismissing. - */ - waitCloseThenBlur() { - this.timer = window.setTimeout(() => { - this.isOpen = false; - this.hasFocus = false; - this.render(); - }, 150); - } - - /** - * Opens or closes the contextual link. - * - * If it is opened, then also give focus. - * - * @return {Drupal.contextual.ContextualModelView} - * The current contextual model view. - */ - toggleOpen() { - const newIsOpen = !this.isOpen; - this.isOpen = newIsOpen; - if (newIsOpen) { - this.focus(); - } - return this; - } - - /** - * Gives focus to this contextual link. - * - * Also closes + removes focus from every other contextual link. - * - * @return {Drupal.contextual.ContextualModelView} - * The current contextual model view. - */ - focus() { - const { modelId } = this; - Drupal.contextual.instances.forEach((model) => { - if (model.modelId !== modelId) { - model.close().blur(); - } - }); - window.clearTimeout(this.timer); - this.hasFocus = true; - return this; - } - - /** - * Removes focus from this contextual link, unless it is open. - * - * @return {Drupal.contextual.ContextualModelView} - * The current contextual model view. - */ - blur() { - if (!this.isOpen) { - this.hasFocus = false; - } - return this; - } - - /** - * Closes this contextual link. - * - * Does not call blur() because we want to allow a contextual link to have - * focus, yet be closed for example when hovering. - * - * @return {Drupal.contextual.ContextualModelView} - * The current contextual model view. - */ - close() { - this.isOpen = false; - return this; - } - - /** - * Gets the current focus state. - * - * @return {boolean} the focus state. - */ - get hasFocus() { - return this._hasFocus; - } - - /** - * Sets the current focus state. - * - * @param {boolean} value - new focus state - */ - set hasFocus(value) { - this._hasFocus = value; - this.$region.toggleClass('focus', this._hasFocus); - } - - /** - * Gets the current open state. - * - * @return {boolean} the open state. - */ - get isOpen() { - return this._isOpen; - } - - /** - * Sets the current open state. - * - * @param {boolean} value - new open state - */ - set isOpen(value) { - this._isOpen = value; - // Nested contextual region handling: hide any nested contextual triggers. - this.$region - .closest('.contextual-region') - .find('.contextual .trigger:not(:first)') - .toggle(!this.isOpen); - } - - /** - * Gets the current locked state. - * - * @return {boolean} the locked state. - */ - get isLocked() { - return this._isLocked; - } - - /** - * Sets the current locked state. - * - * @param {boolean} value - new locked state - */ - set isLocked(value) { - if (value !== this._isLocked) { - this._isLocked = value; - this.render(); - } - } - }; -})(jQuery, Drupal); diff --git a/core/modules/field/field.module b/core/modules/field/field.module index 1819df65669d..ee5db3615262 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -16,10 +16,6 @@ use Drupal\Core\Form\FormStateInterface; require_once __DIR__ . '/field.purge.inc'; /** - * @} End of "defgroup field". - */ - -/** * Assembles a partial entity structure with initial IDs. * * @param object $ids diff --git a/core/modules/field/src/Hook/FieldHooks.php b/core/modules/field/src/Hook/FieldHooks.php index 274482f9ada6..e94e084ea3e3 100644 --- a/core/modules/field/src/Hook/FieldHooks.php +++ b/core/modules/field/src/Hook/FieldHooks.php @@ -257,6 +257,10 @@ class FieldHooks { } /** + * @} End of "defgroup field". + */ + + /** * Implements hook_config_import_steps_alter(). */ #[Hook('config_import_steps_alter')] diff --git a/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceAdminTest.php b/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceAdminTest.php index d8496e30e99b..407fdd794a45 100644 --- a/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceAdminTest.php +++ b/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceAdminTest.php @@ -192,7 +192,7 @@ class EntityReferenceAdminTest extends BrowserTestBase { $this->assertSession()->pageTextContains('Multiple content items match this reference;'); $this->assertSession()->pageTextContains($node1->getTitle() . ' (' . $node1->id() . ')'); $this->assertSession()->pageTextContains($node2->getTitle() . ' (' . $node2->id() . ')'); - $this->assertSession()->pageTextContains('Specify the one you want by appending the id in parentheses, like "' . $node2->getTitle() . ' (' . $node2->id() . ')' . '".'); + $this->assertSession()->pageTextContains('Specify the one you want by appending the id in parentheses, like "' . $node2->getTitle() . ' (' . $node2->id() . ')".'); $edit = [ 'title[0][value]' => 'Test', diff --git a/core/modules/field/tests/src/Kernel/FieldCrudTest.php b/core/modules/field/tests/src/Kernel/FieldCrudTest.php index 278f8dbc87c3..bf1e0cf5c575 100644 --- a/core/modules/field/tests/src/Kernel/FieldCrudTest.php +++ b/core/modules/field/tests/src/Kernel/FieldCrudTest.php @@ -313,7 +313,7 @@ class FieldCrudTest extends FieldKernelTestBase { $this->assertCount(0, $fields, 'A deleted field is marked for deletion.'); // Try to load the field normally and make sure it does not show up. - $field = FieldConfig::load('entity_test.' . '.' . $this->fieldDefinition['bundle'] . '.' . $this->fieldDefinition['field_name']); + $field = FieldConfig::load('entity_test.' . $this->fieldDefinition['bundle'] . '.' . $this->fieldDefinition['field_name']); $this->assertTrue(empty($field), 'Field was deleted'); // Make sure the other field is not deleted. diff --git a/core/modules/field/tests/src/Kernel/FieldStorageCrudTest.php b/core/modules/field/tests/src/Kernel/FieldStorageCrudTest.php index f845abeba457..849dd2402125 100644 --- a/core/modules/field/tests/src/Kernel/FieldStorageCrudTest.php +++ b/core/modules/field/tests/src/Kernel/FieldStorageCrudTest.php @@ -357,7 +357,7 @@ class FieldStorageCrudTest extends FieldKernelTestBase { $this->assertEmpty($field_storage, 'Field storage was deleted'); // Try to load the field normally and make sure it does not show up. - $field = FieldConfig::load('entity_test.' . '.' . $field_definition['bundle'] . '.' . $field_definition['field_name']); + $field = FieldConfig::load('entity_test.' . $field_definition['bundle'] . '.' . $field_definition['field_name']); $this->assertEmpty($field, 'Field was deleted'); // Make sure the other field and its storage are not deleted. diff --git a/core/modules/field_ui/css/field_ui_add_field.module.css b/core/modules/field_ui/css/field_ui_add_field.module.css index d12e6cc8a302..5b84207b5f0c 100644 --- a/core/modules/field_ui/css/field_ui_add_field.module.css +++ b/core/modules/field_ui/css/field_ui_add_field.module.css @@ -16,7 +16,7 @@ --input-fg-color: var(--color-gray); --color-blue: #003ecc; --color-red: #dc2323; - --details-box-shadow: 0 2px 0.25rem rgba(0, 0, 0, 0.1); + --details-box-shadow: 0 2px 0.25rem rgb(0, 0, 0, 0.1); } .field-ui-new-storage-wrapper { diff --git a/core/modules/field_ui/css/field_ui_add_field.module.pcss.css b/core/modules/field_ui/css/field_ui_add_field.module.pcss.css index b136e0f4b3cc..fc27ca1a253e 100644 --- a/core/modules/field_ui/css/field_ui_add_field.module.pcss.css +++ b/core/modules/field_ui/css/field_ui_add_field.module.pcss.css @@ -9,7 +9,7 @@ --input-fg-color: var(--color-gray); --color-blue: #003ecc; --color-red: #dc2323; - --details-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + --details-box-shadow: 0 2px 4px rgb(0, 0, 0, 0.1); } .field-ui-new-storage-wrapper { diff --git a/core/modules/file/tests/src/Functional/SaveUploadFormTest.php b/core/modules/file/tests/src/Functional/SaveUploadFormTest.php index 7830090636c4..3db3b0b06d66 100644 --- a/core/modules/file/tests/src/Functional/SaveUploadFormTest.php +++ b/core/modules/file/tests/src/Functional/SaveUploadFormTest.php @@ -245,7 +245,7 @@ class SaveUploadFormTest extends FileManagedTestBase { $this->drupalGet('file-test/save_upload_from_form_test'); $this->submitForm($edit, 'Submit'); $this->assertSession()->statusCodeEquals(200); - $this->assertSession()->responseContains('For security reasons, your upload has been renamed to <em class="placeholder">' . $this->phpFile->filename . '_.txt' . '</em>'); + $this->assertSession()->responseContains('For security reasons, your upload has been renamed to <em class="placeholder">' . $this->phpFile->filename . '_.txt</em>'); $this->assertSession()->pageTextContains('File MIME type is text/plain.'); $this->assertSession()->pageTextContains("You WIN!"); diff --git a/core/modules/file/tests/src/Functional/SaveUploadTest.php b/core/modules/file/tests/src/Functional/SaveUploadTest.php index 14509ea426c9..cb5bf4f09b00 100644 --- a/core/modules/file/tests/src/Functional/SaveUploadTest.php +++ b/core/modules/file/tests/src/Functional/SaveUploadTest.php @@ -278,7 +278,7 @@ class SaveUploadTest extends FileManagedTestBase { $this->drupalGet('file-test/upload'); $this->submitForm($edit, 'Submit'); $this->assertSession()->statusCodeEquals(200); - $this->assertSession()->responseContains('For security reasons, your upload has been renamed to <em class="placeholder">' . $this->phpFile->filename . '_.txt' . '</em>'); + $this->assertSession()->responseContains('For security reasons, your upload has been renamed to <em class="placeholder">' . $this->phpFile->filename . '_.txt</em>'); $this->assertSession()->pageTextContains('File name is php-2.php_.txt.'); $this->assertSession()->pageTextContains('File MIME type is text/plain.'); $this->assertSession()->pageTextContains("You WIN!"); @@ -303,7 +303,7 @@ class SaveUploadTest extends FileManagedTestBase { $this->drupalGet('file-test/upload'); $this->submitForm($edit, 'Submit'); $this->assertSession()->statusCodeEquals(200); - $this->assertSession()->responseContains('For security reasons, your upload has been renamed to <em class="placeholder">' . $this->phpFile->filename . '_.txt' . '</em>'); + $this->assertSession()->responseContains('For security reasons, your upload has been renamed to <em class="placeholder">' . $this->phpFile->filename . '_.txt</em>'); $this->assertSession()->pageTextContains('File name is php-2.php_.txt.'); $this->assertSession()->pageTextContains('File MIME type is text/plain.'); $this->assertSession()->pageTextContains("You WIN!"); diff --git a/core/modules/filter/tests/filter_test/src/Plugin/Filter/FilterTestPlaceholders.php b/core/modules/filter/tests/filter_test/src/Plugin/Filter/FilterTestPlaceholders.php index e1ddf5521877..862239599b0e 100644 --- a/core/modules/filter/tests/filter_test/src/Plugin/Filter/FilterTestPlaceholders.php +++ b/core/modules/filter/tests/filter_test/src/Plugin/Filter/FilterTestPlaceholders.php @@ -30,7 +30,7 @@ class FilterTestPlaceholders extends FilterBase implements TrustedCallbackInterf $result = new FilterProcessResult($text); $placeholder_with_argument = $result->createPlaceholder('\Drupal\filter_test\Plugin\Filter\FilterTestPlaceholders::renderDynamicThing', ['llama']); $placeholder_without_arguments = $result->createPlaceholder('\Drupal\filter_test\Plugin\Filter\FilterTestPlaceholders::renderStaticThing', []); - $result->setProcessedText($text . '<p>' . $placeholder_with_argument . '</p>' . '<p>' . $placeholder_without_arguments . '</p>'); + $result->setProcessedText($text . '<p>' . $placeholder_with_argument . '</p><p>' . $placeholder_without_arguments . '</p>'); return $result; } diff --git a/core/modules/image/src/ImageEffectBase.php b/core/modules/image/src/ImageEffectBase.php index 58be370c1e6e..745976133be7 100644 --- a/core/modules/image/src/ImageEffectBase.php +++ b/core/modules/image/src/ImageEffectBase.php @@ -3,7 +3,7 @@ namespace Drupal\image; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; -use Drupal\Core\Plugin\PluginBase; +use Drupal\Core\Plugin\ConfigurablePluginBase; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -17,7 +17,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; * @see \Drupal\image\ImageEffectManager * @see plugin_api */ -abstract class ImageEffectBase extends PluginBase implements ImageEffectInterface, ContainerFactoryPluginInterface { +abstract class ImageEffectBase extends ConfigurablePluginBase implements ImageEffectInterface, ContainerFactoryPluginInterface { /** * The image effect ID. @@ -46,7 +46,6 @@ abstract class ImageEffectBase extends PluginBase implements ImageEffectInterfac public function __construct(array $configuration, $plugin_id, $plugin_definition, LoggerInterface $logger) { parent::__construct($configuration, $plugin_id, $plugin_definition); - $this->setConfiguration($configuration); $this->logger = $logger; } @@ -154,13 +153,6 @@ abstract class ImageEffectBase extends PluginBase implements ImageEffectInterfac /** * {@inheritdoc} */ - public function defaultConfiguration() { - return []; - } - - /** - * {@inheritdoc} - */ public function calculateDependencies() { return []; } diff --git a/core/modules/image/tests/src/Unit/ImageStyleTest.php b/core/modules/image/tests/src/Unit/ImageStyleTest.php index d247642b3cd4..8b877753fefd 100644 --- a/core/modules/image/tests/src/Unit/ImageStyleTest.php +++ b/core/modules/image/tests/src/Unit/ImageStyleTest.php @@ -174,8 +174,8 @@ class ImageStyleTest extends UnitTestCase { // Assert the extension has been added to the URI before creating the token. $this->assertEquals($image_style->getPathToken('public://test.jpeg.png'), $image_style->getPathToken('public://test.jpeg')); - $this->assertEquals(substr(Crypt::hmacBase64($image_style->id() . ':' . 'public://test.jpeg.png', $private_key . $hash_salt), 0, 8), $image_style->getPathToken('public://test.jpeg')); - $this->assertNotEquals(substr(Crypt::hmacBase64($image_style->id() . ':' . 'public://test.jpeg', $private_key . $hash_salt), 0, 8), $image_style->getPathToken('public://test.jpeg')); + $this->assertEquals(substr(Crypt::hmacBase64($image_style->id() . ':public://test.jpeg.png', $private_key . $hash_salt), 0, 8), $image_style->getPathToken('public://test.jpeg')); + $this->assertNotEquals(substr(Crypt::hmacBase64($image_style->id() . ':public://test.jpeg', $private_key . $hash_salt), 0, 8), $image_style->getPathToken('public://test.jpeg')); // Image style that doesn't change the extension. $image_effect_id = $this->randomMachineName(); @@ -195,8 +195,8 @@ class ImageStyleTest extends UnitTestCase { ->willReturn($hash_salt); // Assert no extension has been added to the uri before creating the token. $this->assertNotEquals($image_style->getPathToken('public://test.jpeg.png'), $image_style->getPathToken('public://test.jpeg')); - $this->assertNotEquals(substr(Crypt::hmacBase64($image_style->id() . ':' . 'public://test.jpeg.png', $private_key . $hash_salt), 0, 8), $image_style->getPathToken('public://test.jpeg')); - $this->assertEquals(substr(Crypt::hmacBase64($image_style->id() . ':' . 'public://test.jpeg', $private_key . $hash_salt), 0, 8), $image_style->getPathToken('public://test.jpeg')); + $this->assertNotEquals(substr(Crypt::hmacBase64($image_style->id() . ':public://test.jpeg.png', $private_key . $hash_salt), 0, 8), $image_style->getPathToken('public://test.jpeg')); + $this->assertEquals(substr(Crypt::hmacBase64($image_style->id() . ':public://test.jpeg', $private_key . $hash_salt), 0, 8), $image_style->getPathToken('public://test.jpeg')); } /** diff --git a/core/modules/jsonapi/src/Controller/EntityResource.php b/core/modules/jsonapi/src/Controller/EntityResource.php index 6416d6cb27ac..53822cdf1f1f 100644 --- a/core/modules/jsonapi/src/Controller/EntityResource.php +++ b/core/modules/jsonapi/src/Controller/EntityResource.php @@ -672,9 +672,10 @@ class EntityResource { return $this->getRelationship($resource_type, $entity, $related, $request, $status); } - $main_property_name = $field_definition->getItemDefinition()->getMainPropertyName(); foreach ($new_resource_identifiers as $new_resource_identifier) { - $new_field_value = [$main_property_name => $this->getEntityFromResourceIdentifier($new_resource_identifier)->id()]; + // We assume all entity reference fields have an 'entity' computed + // property that can be used to assign the needed values. + $new_field_value = ['entity' => $this->getEntityFromResourceIdentifier($new_resource_identifier)]; // Remove `arity` from the received extra properties, otherwise this // will fail field validation. $new_field_value += array_diff_key($new_resource_identifier->getMeta(), array_flip([ResourceIdentifier::ARITY_KEY])); @@ -760,9 +761,10 @@ class EntityResource { * The field definition of the entity field to be updated. */ protected function doPatchMultipleRelationship(EntityInterface $entity, array $resource_identifiers, FieldDefinitionInterface $field_definition) { - $main_property_name = $field_definition->getItemDefinition()->getMainPropertyName(); - $entity->{$field_definition->getName()} = array_map(function (ResourceIdentifier $resource_identifier) use ($main_property_name) { - $field_properties = [$main_property_name => $this->getEntityFromResourceIdentifier($resource_identifier)->id()]; + $entity->{$field_definition->getName()} = array_map(function (ResourceIdentifier $resource_identifier) { + // We assume all entity reference fields have an 'entity' computed + // property that can be used to assign the needed values. + $field_properties = ['entity' => $this->getEntityFromResourceIdentifier($resource_identifier)]; // Remove `arity` from the received extra properties, otherwise this // will fail field validation. $field_properties += array_diff_key($resource_identifier->getMeta(), array_flip([ResourceIdentifier::ARITY_KEY])); diff --git a/core/modules/jsonapi/tests/modules/jsonapi_test_field_type/config/schema/jsonapi_test_field_type.schema.yml b/core/modules/jsonapi/tests/modules/jsonapi_test_field_type/config/schema/jsonapi_test_field_type.schema.yml new file mode 100644 index 000000000000..9d082c7649c3 --- /dev/null +++ b/core/modules/jsonapi/tests/modules/jsonapi_test_field_type/config/schema/jsonapi_test_field_type.schema.yml @@ -0,0 +1,11 @@ +field.storage_settings.jsonapi_test_field_type_entity_reference_uuid: + type: field.storage_settings.entity_reference + label: 'Entity reference field storage settings' + +field.field_settings.jsonapi_test_field_type_entity_reference_uuid: + type: field.field_settings.entity_reference + label: 'Entity reference field settings' + +field.value.jsonapi_test_field_type_entity_reference_uuid: + type: field.value.entity_reference + label: 'Default value' diff --git a/core/modules/jsonapi/tests/modules/jsonapi_test_field_type/src/Plugin/Field/FieldType/EntityReferenceUuidItem.php b/core/modules/jsonapi/tests/modules/jsonapi_test_field_type/src/Plugin/Field/FieldType/EntityReferenceUuidItem.php new file mode 100644 index 000000000000..f9aa3e77bbe9 --- /dev/null +++ b/core/modules/jsonapi/tests/modules/jsonapi_test_field_type/src/Plugin/Field/FieldType/EntityReferenceUuidItem.php @@ -0,0 +1,241 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\jsonapi_test_field_type\Plugin\Field\FieldType; + +use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\TypedData\EntityDataDefinition; +use Drupal\Core\Field\Attribute\FieldType; +use Drupal\Core\Field\EntityReferenceFieldItemList; +use Drupal\Core\Field\FieldDefinitionInterface; +use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem; +use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\Core\TypedData\DataReferenceDefinition; +use Drupal\Core\TypedData\DataReferenceTargetDefinition; + +/** + * Defines the 'entity_reference_uuid' entity field type. + * + * Supported settings (below the definition's 'settings' key) are: + * - target_type: The entity type to reference. Required. + * + * @property string $target_uuid + */ +#[FieldType( + id: 'jsonapi_test_field_type_entity_reference_uuid', + label: new TranslatableMarkup('Entity reference UUID'), + description: new TranslatableMarkup('An entity field containing an entity reference by UUID.'), + category: 'reference', + default_widget: 'entity_reference_autocomplete', + default_formatter: 'entity_reference_label', + list_class: EntityReferenceFieldItemList::class, +)] +class EntityReferenceUuidItem extends EntityReferenceItem { + + /** + * {@inheritdoc} + */ + public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) { + $settings = $field_definition->getSettings(); + $target_type_info = \Drupal::entityTypeManager()->getDefinition($settings['target_type']); + + $properties = parent::propertyDefinitions($field_definition); + + $target_uuid_definition = DataReferenceTargetDefinition::create('string') + ->setLabel(new TranslatableMarkup('@label UUID', ['@label' => $target_type_info->getLabel()])); + + $target_uuid_definition->setRequired(TRUE); + $properties['target_uuid'] = $target_uuid_definition; + + $properties['entity'] = DataReferenceDefinition::create('entity') + ->setLabel($target_type_info->getLabel()) + ->setDescription(new TranslatableMarkup('The referenced entity by UUID')) + // The entity object is computed out of the entity ID. + ->setComputed(TRUE) + ->setReadOnly(FALSE) + ->setTargetDefinition(EntityDataDefinition::create($settings['target_type'])) + // We can add a constraint for the target entity type. The list of + // referenceable bundles is a field setting, so the corresponding + // constraint is added dynamically in ::getConstraints(). + ->addConstraint('EntityType', $settings['target_type']); + + return $properties; + } + + /** + * {@inheritdoc} + */ + public static function mainPropertyName() { + return 'target_uuid'; + } + + /** + * {@inheritdoc} + */ + public static function schema(FieldStorageDefinitionInterface $field_definition) { + $columns = [ + 'target_uuid' => [ + 'description' => 'The UUID of the target entity.', + 'type' => 'varchar_ascii', + 'length' => 128, + ], + ]; + + return [ + 'columns' => $columns, + 'indexes' => [ + 'target_uuid' => ['target_uuid'], + ], + ]; + } + + /** + * {@inheritdoc} + */ + public function setValue($values, $notify = TRUE): void { + if (isset($values) && !is_array($values)) { + // If either a scalar or an object was passed as the value for the item, + // assign it to the 'entity' or 'target_uuid' depending on values type. + if (is_object($values)) { + $this->set('entity', $values, $notify); + } + else { + $this->set('target_uuid', $values, $notify); + } + } + else { + parent::setValue($values, FALSE); + // Support setting the field item with only one property, but make sure + // values stay in sync if only property is passed. + // NULL is a valid value, so we use array_key_exists(). + if (is_array($values) && array_key_exists('target_uuid', $values) && !isset($values['entity'])) { + $this->onChange('target_uuid', FALSE); + } + elseif (is_array($values) && !array_key_exists('target_uuid', $values) && isset($values['entity'])) { + $this->onChange('entity', FALSE); + } + elseif (is_array($values) && array_key_exists('target_uuid', $values) && isset($values['entity'])) { + // If both properties are passed, verify the passed values match. The + // only exception we allow is when we have a new entity: in this case + // its actual id and target_uuid will be different, due to the new + // entity marker. + $entity_uuid = $this->get('entity')->get('uuid'); + // If the entity has been saved and we're trying to set both the + // target_uuid and the entity values with a non-null target UUID, then + // the value for target_uuid should match the UUID of the entity value. + if (!$this->entity->isNew() && $values['target_uuid'] !== NULL && ($entity_uuid !== $values['target_uuid'])) { + throw new \InvalidArgumentException('The target UUID and entity passed to the entity reference item do not match.'); + } + } + // Notify the parent if necessary. + if ($notify && $this->parent) { + $this->parent->onChange($this->getName()); + } + } + + } + + /** + * {@inheritdoc} + */ + public function onChange($property_name, $notify = TRUE): void { + // Make sure that the target UUID and the target property stay in sync. + if ($property_name === 'entity') { + $property = $this->get('entity'); + if ($target_uuid = $property->isTargetNew() ? NULL : $property->getValue()->uuid()) { + $this->writePropertyValue('target_uuid', $target_uuid); + } + } + elseif ($property_name === 'target_uuid') { + $property = $this->get('entity'); + $entity_type = $property->getDataDefinition()->getConstraint('EntityType'); + $entities = \Drupal::entityTypeManager()->getStorage($entity_type)->loadByProperties(['uuid' => $this->get('target_uuid')->getValue()]); + if ($entity = array_shift($entities)) { + assert($entity instanceof EntityInterface); + $this->writePropertyValue('target_uuid', $entity->uuid()); + $this->writePropertyValue('entity', $entity); + } + } + parent::onChange($property_name, $notify); + } + + /** + * {@inheritdoc} + */ + public function isEmpty() { + // Avoid loading the entity by first checking the 'target_uuid'. + if ($this->target_uuid !== NULL) { + return FALSE; + } + if ($this->entity && $this->entity instanceof EntityInterface) { + return FALSE; + } + return TRUE; + } + + /** + * {@inheritdoc} + */ + public function preSave(): void { + if ($this->hasNewEntity()) { + // Save the entity if it has not already been saved by some other code. + if ($this->entity->isNew()) { + $this->entity->save(); + } + // Make sure the parent knows we are updating this property so it can + // react properly. + $this->target_uuid = $this->entity->uuid(); + } + if (!$this->isEmpty() && $this->target_uuid === NULL) { + $this->target_uuid = $this->entity->uuid(); + } + } + + /** + * {@inheritdoc} + */ + public static function generateSampleValue(FieldDefinitionInterface $field_definition): array { + $manager = \Drupal::service('plugin.manager.entity_reference_selection'); + + // Instead of calling $manager->getSelectionHandler($field_definition) + // replicate the behavior to be able to override the sorting settings. + $options = [ + 'target_type' => $field_definition->getFieldStorageDefinition()->getSetting('target_type'), + 'handler' => $field_definition->getSetting('handler'), + 'handler_settings' => $field_definition->getSetting('handler_settings') ?: [], + 'entity' => NULL, + ]; + + $entity_type = \Drupal::entityTypeManager()->getDefinition($options['target_type']); + $options['handler_settings']['sort'] = [ + 'field' => $entity_type->getKey('uuid'), + 'direction' => 'DESC', + ]; + $selection_handler = $manager->getInstance($options); + + // Select a random number of references between the last 50 referenceable + // entities created. + if ($referenceable = $selection_handler->getReferenceableEntities(NULL, 'CONTAINS', 50)) { + $group = array_rand($referenceable); + return ['target_uuid' => array_rand($referenceable[$group])]; + } + return []; + } + + /** + * Determines whether the item holds an unsaved entity. + * + * This is notably used for "autocreate" widgets, and more generally to + * support referencing freshly created entities (they will get saved + * automatically as the hosting entity gets saved). + * + * @return bool + * TRUE if the item holds an unsaved entity. + */ + public function hasNewEntity() { + return !$this->isEmpty() && $this->target_uuid === NULL && $this->entity->isNew(); + } + +} diff --git a/core/modules/jsonapi/tests/src/Functional/FileUploadTest.php b/core/modules/jsonapi/tests/src/Functional/FileUploadTest.php index 22f8f7f57d1b..7539670e1555 100644 --- a/core/modules/jsonapi/tests/src/Functional/FileUploadTest.php +++ b/core/modules/jsonapi/tests/src/Functional/FileUploadTest.php @@ -265,7 +265,7 @@ class FileUploadTest extends ResourceTestBase { ->set('field_rest_file_test', ['target_id' => $existing_file->id()]) ->save(); - $uri = Url::fromUri('base:' . '/jsonapi/entity_test/entity_test/' . $this->entity->uuid() . '/field_rest_file_test'); + $uri = Url::fromUri('base:/jsonapi/entity_test/entity_test/' . $this->entity->uuid() . '/field_rest_file_test'); // DX: 405 when read-only mode is enabled. $response = $this->fileRequest($uri, $this->testFileData); diff --git a/core/modules/jsonapi/tests/src/Functional/JsonApiRelationshipTest.php b/core/modules/jsonapi/tests/src/Functional/JsonApiRelationshipTest.php new file mode 100644 index 000000000000..110e1a6840b3 --- /dev/null +++ b/core/modules/jsonapi/tests/src/Functional/JsonApiRelationshipTest.php @@ -0,0 +1,157 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\jsonapi\Functional; + +use Drupal\Core\Url; +use Drupal\entity_test\EntityTestHelper; +use Drupal\field\Entity\FieldConfig; +use Drupal\field\Entity\FieldStorageConfig; +use GuzzleHttp\RequestOptions; + +/** + * JSON:API resource tests. + * + * @group jsonapi + * + * @internal + */ +class JsonApiRelationshipTest extends JsonApiFunctionalTestBase { + + /** + * {@inheritdoc} + */ + protected static $modules = [ + 'basic_auth', + 'entity_test', + 'jsonapi_test_field_type', + ]; + + /** + * The entity type ID. + */ + protected string $entityTypeId = 'entity_test'; + + /** + * The entity bundle. + */ + protected string $bundle = 'entity_test'; + + /** + * The field name. + */ + protected string $fieldName = 'field_child'; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + + EntityTestHelper::createBundle($this->bundle, 'Parent', $this->entityTypeId); + + FieldStorageConfig::create([ + 'field_name' => $this->fieldName, + 'type' => 'jsonapi_test_field_type_entity_reference_uuid', + 'entity_type' => $this->entityTypeId, + 'cardinality' => 1, + 'settings' => [ + 'target_type' => $this->entityTypeId, + ], + ])->save(); + FieldConfig::create([ + 'field_name' => $this->fieldName, + 'entity_type' => $this->entityTypeId, + 'bundle' => $this->bundle, + 'label' => $this->randomString(), + 'settings' => [ + 'handler' => 'default', + 'handler_settings' => [], + ], + ])->save(); + + \Drupal::service('router.builder')->rebuild(); + } + + /** + * Test relationships without target_id as main property. + * + * @see https://www.drupal.org/project/drupal/issues/3476224 + */ + public function testPatchHandleUUIDPropertyReferenceFieldIssue3127883(): void { + $this->config('jsonapi.settings')->set('read_only', FALSE)->save(TRUE); + $user = $this->drupalCreateUser([ + 'administer entity_test content', + 'view test entity', + ]); + + // Create parent and child entities. + $storage = $this->container->get('entity_type.manager') + ->getStorage($this->entityTypeId); + $parentEntity = $storage + ->create([ + 'type' => $this->bundle, + ]); + $parentEntity->save(); + $childUuid = $this->container->get('uuid')->generate(); + $childEntity = $storage + ->create([ + 'type' => $this->bundle, + 'uuid' => $childUuid, + ]); + $childEntity->save(); + $uuid = $childEntity->uuid(); + $this->assertEquals($childUuid, $uuid); + + // 1. Successful PATCH to the related endpoint. + $url = Url::fromUri(sprintf('internal:/jsonapi/%s/%s/%s/relationships/%s', $this->entityTypeId, $this->bundle, $parentEntity->uuid(), $this->fieldName)); + $request_options = [ + RequestOptions::HEADERS => [ + 'Content-Type' => 'application/vnd.api+json', + 'Accept' => 'application/vnd.api+json', + ], + RequestOptions::AUTH => [$user->getAccountName(), $user->pass_raw], + RequestOptions::JSON => [ + 'data' => [ + 'id' => $childUuid, + 'type' => sprintf('%s--%s', $this->entityTypeId, $this->bundle), + ], + ], + ]; + $response = $this->request('PATCH', $url, $request_options); + $this->assertSame(204, $response->getStatusCode(), (string) $response->getBody()); + $parentEntity = $storage->loadUnchanged($parentEntity->id()); + $this->assertEquals($childEntity->uuid(), $parentEntity->get($this->fieldName)->target_uuid); + + // Reset the relationship. + $parentEntity->set($this->fieldName, NULL) + ->save(); + $parentEntity = $storage->loadUnchanged($parentEntity->id()); + $this->assertTrue($parentEntity->get($this->fieldName)->isEmpty()); + + // 2. Successful PATCH to individual endpoint. + $url = Url::fromUri(sprintf('internal:/jsonapi/%s/%s/%s', $this->entityTypeId, $this->bundle, $parentEntity->uuid())); + $request_options[RequestOptions::JSON] = [ + 'data' => [ + 'id' => $parentEntity->uuid(), + 'type' => sprintf('%s--%s', $this->entityTypeId, $this->bundle), + 'relationships' => [ + $this->fieldName => [ + 'data' => [ + [ + 'id' => $childUuid, + 'type' => sprintf('%s--%s', $this->entityTypeId, $this->bundle), + ], + ], + ], + ], + ], + ]; + $response = $this->request('PATCH', $url, $request_options); + $this->assertSame(200, $response->getStatusCode(), (string) $response->getBody()); + $parentEntity = $storage->loadUnchanged($parentEntity->id()); + $this->assertEquals($childEntity->uuid(), $parentEntity->get($this->fieldName)->target_uuid); + } + +} diff --git a/core/modules/jsonapi/tests/src/Functional/WorkspaceTest.php b/core/modules/jsonapi/tests/src/Functional/WorkspaceTest.php index 97eec557d22d..48cbc20067a9 100644 --- a/core/modules/jsonapi/tests/src/Functional/WorkspaceTest.php +++ b/core/modules/jsonapi/tests/src/Functional/WorkspaceTest.php @@ -15,6 +15,7 @@ use Drupal\workspaces\Entity\Workspace; * JSON:API integration test for the "Workspace" content entity type. * * @group jsonapi + * @group workspaces */ class WorkspaceTest extends ResourceTestBase { @@ -142,7 +143,7 @@ class WorkspaceTest extends ResourceTestBase { 'changed' => (new \DateTime())->setTimestamp($this->entity->getChangedTime())->setTimezone(new \DateTimeZone('UTC'))->format(\DateTime::RFC3339), 'label' => 'Campaign', 'drupal_internal__id' => 'campaign', - 'drupal_internal__revision_id' => 2, + 'drupal_internal__revision_id' => 1, ], 'relationships' => [ 'parent' => [ diff --git a/core/modules/layout_builder/css/layout-builder.pcss.css b/core/modules/layout_builder/css/layout-builder.pcss.css index 7ddb9543e007..06b73b42992d 100644 --- a/core/modules/layout_builder/css/layout-builder.pcss.css +++ b/core/modules/layout_builder/css/layout-builder.pcss.css @@ -91,7 +91,7 @@ pointer-events: none; } - @nest .layout-builder--content-preview-disabled & { + .layout-builder--content-preview-disabled & { margin: 0; border-bottom: 2px dashed #979797; } diff --git a/core/modules/layout_builder/css/off-canvas.css b/core/modules/layout_builder/css/off-canvas.css index 1caa028602f5..0b90c63ce615 100644 --- a/core/modules/layout_builder/css/off-canvas.css +++ b/core/modules/layout_builder/css/off-canvas.css @@ -95,7 +95,7 @@ #drupal-off-canvas-wrapper .inline-block-create-button:hover, #drupal-off-canvas-wrapper .inline-block-list__item:hover { - background-color: rgba(255, 255, 255, 0.05); + background-color: rgb(255, 255, 255, 0.05); } #drupal-off-canvas-wrapper .inline-block-create-button:focus, diff --git a/core/modules/layout_builder/css/off-canvas.pcss.css b/core/modules/layout_builder/css/off-canvas.pcss.css index a63de90a0dd6..55083338bded 100644 --- a/core/modules/layout_builder/css/off-canvas.pcss.css +++ b/core/modules/layout_builder/css/off-canvas.pcss.css @@ -80,7 +80,7 @@ color: var(--off-canvas-text-color); &:hover { - background-color: rgba(255, 255, 255, 0.05); + background-color: rgb(255, 255, 255, 0.05); } &:focus { diff --git a/core/modules/layout_builder/src/EventSubscriber/BlockComponentRenderArray.php b/core/modules/layout_builder/src/EventSubscriber/BlockComponentRenderArray.php index 786fa3d786af..162928bb0918 100644 --- a/core/modules/layout_builder/src/EventSubscriber/BlockComponentRenderArray.php +++ b/core/modules/layout_builder/src/EventSubscriber/BlockComponentRenderArray.php @@ -2,8 +2,8 @@ namespace Drupal\layout_builder\EventSubscriber; -use Drupal\block_content\Access\RefinableDependentAccessInterface; use Drupal\Core\Access\AccessResult; +use Drupal\Core\Access\RefinableDependentAccessInterface; use Drupal\Core\Block\BlockPluginInterface; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Render\Element; diff --git a/core/modules/layout_builder/src/Plugin/Block/InlineBlock.php b/core/modules/layout_builder/src/Plugin/Block/InlineBlock.php index 2c66d43b8200..14686b9f532b 100644 --- a/core/modules/layout_builder/src/Plugin/Block/InlineBlock.php +++ b/core/modules/layout_builder/src/Plugin/Block/InlineBlock.php @@ -2,10 +2,10 @@ namespace Drupal\layout_builder\Plugin\Block; -use Drupal\block_content\Access\RefinableDependentAccessInterface; -use Drupal\block_content\Access\RefinableDependentAccessTrait; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Access\AccessResult; +use Drupal\Core\Access\RefinableDependentAccessInterface; +use Drupal\Core\Access\RefinableDependentAccessTrait; use Drupal\Core\Block\Attribute\Block; use Drupal\Core\Block\BlockBase; use Drupal\Core\Entity\Entity\EntityFormDisplay; diff --git a/core/modules/layout_builder/tests/modules/layout_builder_block_content_dependency_test/layout_builder_block_content_dependency_test.info.yml b/core/modules/layout_builder/tests/modules/layout_builder_block_content_dependency_test/layout_builder_block_content_dependency_test.info.yml new file mode 100644 index 000000000000..691e00a80c5a --- /dev/null +++ b/core/modules/layout_builder/tests/modules/layout_builder_block_content_dependency_test/layout_builder_block_content_dependency_test.info.yml @@ -0,0 +1,5 @@ +name: 'Layout Builder BLock Content dependency test' +type: module +description: 'Support module for testing Layout Builder''s implicit dependencies on Block Content' +package: Testing +version: VERSION diff --git a/core/modules/layout_builder/tests/modules/layout_builder_block_content_dependency_test/layout_builder_block_content_dependency_test.module b/core/modules/layout_builder/tests/modules/layout_builder_block_content_dependency_test/layout_builder_block_content_dependency_test.module new file mode 100644 index 000000000000..93bb03de4048 --- /dev/null +++ b/core/modules/layout_builder/tests/modules/layout_builder_block_content_dependency_test/layout_builder_block_content_dependency_test.module @@ -0,0 +1,19 @@ +<?php + +/** + * @file + * Provides hook implementations for testing Layout Builder with Block Content. + */ + +declare(strict_types=1); + +/** + * Implements hook_modules_installed(). + */ +function layout_builder_block_content_dependency_test_modules_installed(array $modules, bool $is_syncing): void { + // @see Drupal\Tests\layout_builder\Kernel\LayoutBuilderBlockContentDependencyTest + if (in_array('layout_builder', $modules)) { + \Drupal::service('plugin.manager.block')->getDefinitions(); + \Drupal::service('module_installer')->install(['block_content']); + } +} diff --git a/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderBlockContentDependencyTest.php b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderBlockContentDependencyTest.php new file mode 100644 index 000000000000..faa5d26bec92 --- /dev/null +++ b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderBlockContentDependencyTest.php @@ -0,0 +1,51 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\layout_builder\Kernel; + +use Drupal\KernelTests\KernelTestBase; + +/** + * Test for installing Layout Builder before Block Content in the same request. + * + * @group layout_builder + */ +class LayoutBuilderBlockContentDependencyTest extends KernelTestBase { + + /** + * Test that block_content can be successfully installed after layout_builder. + * + * The InlineBlock plugin class in layout_builder uses + * RefinableDependentAccessTrait, which used to live in block_content, though + * block_content is not a layout_builder dependency. Since the BlockContent + * entity type class also uses the same trait, if, in order and in the same + * request: + * 1. layout_builder is installed first without block_content + * 2. block plugins are discovered + * 3. block_content is installed, + * a fatal error can occur, because the trait was missing before block_content + * is installed and gets aliased to an empty trait. When the installation of + * the block_content module installs the BlockContent entity type, the empty + * trait is missing the methods that need to be implemented from the + * interface. + * + * @see \Drupal\Component\Plugin\Discovery\AttributeClassDiscovery + * @see \Drupal\Component\Discovery\MissingClassDetectionClassLoader + */ + public function testInstallLayoutBuilderAndBlockContent(): void { + $this->assertFalse(\Drupal::moduleHandler()->moduleExists('block_content')); + // Prevent classes in the block_content modules from being loaded before the + // module is installed. + $this->classLoader->setPsr4("Drupal\\block_content\\", ''); + + // Install test module that will act on layout_builder being installed and + // at that time does block plugin discovery first, then installs + // block_content. + \Drupal::service('module_installer')->install(['layout_builder_block_content_dependency_test']); + + \Drupal::service('module_installer')->install(['layout_builder']); + $this->assertTrue(\Drupal::moduleHandler()->moduleExists('block_content')); + } + +} diff --git a/core/modules/layout_builder/tests/src/Unit/BlockComponentRenderArrayTest.php b/core/modules/layout_builder/tests/src/Unit/BlockComponentRenderArrayTest.php index 530feea461da..baa6a080aa5a 100644 --- a/core/modules/layout_builder/tests/src/Unit/BlockComponentRenderArrayTest.php +++ b/core/modules/layout_builder/tests/src/Unit/BlockComponentRenderArrayTest.php @@ -4,9 +4,9 @@ declare(strict_types=1); namespace Drupal\Tests\layout_builder\Unit; -use Drupal\block_content\Access\RefinableDependentAccessInterface; use Drupal\Component\Plugin\Context\ContextInterface; use Drupal\Core\Access\AccessResult; +use Drupal\Core\Access\RefinableDependentAccessInterface; use Drupal\Core\Block\BlockManagerInterface; use Drupal\Core\Block\BlockPluginInterface; use Drupal\Core\Cache\Cache; diff --git a/core/modules/locale/src/PoDatabaseWriter.php b/core/modules/locale/src/PoDatabaseWriter.php index 7e7340cf1070..436d710d7bad 100644 --- a/core/modules/locale/src/PoDatabaseWriter.php +++ b/core/modules/locale/src/PoDatabaseWriter.php @@ -198,10 +198,15 @@ class PoDatabaseWriter implements PoWriterInterface { * {@inheritdoc} */ public function writeItems(PoReaderInterface $reader, $count = -1) { + // Processing multiple writes in a transaction is quicker than committing + // each individual write. + $transaction = \Drupal::database()->startTransaction(); $forever = $count == -1; while (($count-- > 0 || $forever) && ($item = $reader->readItem())) { $this->writeItem($item); } + // Commit the transaction. + unset($transaction); } /** diff --git a/core/modules/migrate/src/Plugin/Migration.php b/core/modules/migrate/src/Plugin/Migration.php index 961d7edd76b1..20c99bbd3e00 100644 --- a/core/modules/migrate/src/Plugin/Migration.php +++ b/core/modules/migrate/src/Plugin/Migration.php @@ -226,6 +226,8 @@ class Migration extends PluginBase implements MigrationInterface, RequirementsIn * These are different from the configuration dependencies. Migration * dependencies are only used to store relationships between migrations. * + * @var array + * * The migration_dependencies value is structured like this: * @code * [ @@ -238,10 +240,8 @@ class Migration extends PluginBase implements MigrationInterface, RequirementsIn * ], * ]; * @endcode - * - * @var array */ - // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName, Drupal.Commenting.VariableComment.Missing + // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName protected $migration_dependencies = []; /** diff --git a/core/modules/navigation/components/badge/badge.component.yml b/core/modules/navigation/components/badge/badge.component.yml index a7bb04f963eb..a7940d1efa54 100644 --- a/core/modules/navigation/components/badge/badge.component.yml +++ b/core/modules/navigation/components/badge/badge.component.yml @@ -21,6 +21,9 @@ props: enum: - info - success + meta:enum: + info: Information + success: Success slots: label: type: string diff --git a/core/modules/navigation/components/title/title.component.yml b/core/modules/navigation/components/title/title.component.yml index 696960d455f5..1001c42c109f 100644 --- a/core/modules/navigation/components/title/title.component.yml +++ b/core/modules/navigation/components/title/title.component.yml @@ -23,6 +23,9 @@ props: enum: - ellipsis - xs + meta:enum: + ellipsis: Ellipsis + xs: 'Extra-small' extra_classes: type: array title: Extra classes. @@ -43,6 +46,15 @@ props: - h5 - h6 - span + meta:enum: + h1: Heading 1 + h2: Heading 2 + h3: Heading 3 + h4: Heading 4 + h5: Heading 5 + h6: Heading 6 + span: Inline + x-translation-context: HTML tag # Provide a default value default: h2 icon: diff --git a/core/modules/navigation/components/toolbar-button/toolbar-button.component.yml b/core/modules/navigation/components/toolbar-button/toolbar-button.component.yml index 87e29a14bf44..130cca22e1cb 100644 --- a/core/modules/navigation/components/toolbar-button/toolbar-button.component.yml +++ b/core/modules/navigation/components/toolbar-button/toolbar-button.component.yml @@ -37,6 +37,17 @@ props: - primary - small-offset - weight--400 + meta:enum: + collapsible: Collapsible + dark: Dark + expand--down: Expands down + expand--side: Expands to the side + large: Large + non-interactive: Non-Interactive + primary: Primary + small-offset: Small offset + weight--400: Weight 400 + x-translation-context: Toolbar button modifiers extra_classes: type: array title: Extra classes. @@ -53,6 +64,11 @@ props: - a - button - span + meta:enum: + a: Link + button: Button + span: Inline + x-translation-context: HTML tag # Provide a default value default: button icon: diff --git a/core/modules/navigation/components/toolbar-button/toolbar-button.css b/core/modules/navigation/components/toolbar-button/toolbar-button.css index 3af3cbfdd39d..85bfb00883cf 100644 --- a/core/modules/navigation/components/toolbar-button/toolbar-button.css +++ b/core/modules/navigation/components/toolbar-button/toolbar-button.css @@ -36,7 +36,7 @@ text-align: start; -webkit-text-decoration: none; text-decoration: none; - word-break: break-word; + overflow-wrap: break-word; color: var(--toolbar-button-color); border: 0; border-radius: var(--admin-toolbar-space-8); diff --git a/core/modules/navigation/components/toolbar-button/toolbar-button.pcss.css b/core/modules/navigation/components/toolbar-button/toolbar-button.pcss.css index 9b40b8fcb460..0e1d5f3bdd57 100644 --- a/core/modules/navigation/components/toolbar-button/toolbar-button.pcss.css +++ b/core/modules/navigation/components/toolbar-button/toolbar-button.pcss.css @@ -33,7 +33,7 @@ cursor: pointer; text-align: start; text-decoration: none; - word-break: break-word; + overflow-wrap: break-word; color: var(--toolbar-button-color); border: 0; border-radius: var(--admin-toolbar-space-8); diff --git a/core/modules/navigation/css/base/variables.css b/core/modules/navigation/css/base/variables.css index 91063f3f09d9..c56c7322b6f4 100644 --- a/core/modules/navigation/css/base/variables.css +++ b/core/modules/navigation/css/base/variables.css @@ -74,14 +74,14 @@ We need it root to calculate the size of the displace in .dialog-off-canvas-main /* White. */ --admin-toolbar-color-white: var(--drupal-admin-color-white, #fff); /* Expanded background color. */ - --admin-toolbar-color-expanded: rgba(231, 234, 243, 0.5); /* --admin-toolbar-color-gray-050 */ + --admin-toolbar-color-expanded: rgb(231, 234, 243, 0.5); /* --admin-toolbar-color-gray-050 */ /* Fonts. */ --admin-toolbar-font-family: inter, sans-serif; /* Shadows. */ - --admin-toolbar-color-shadow-0: rgba(0, 0, 0, 0); - --admin-toolbar-color-shadow-6: rgba(0, 0, 0, 0.06); - --admin-toolbar-color-shadow-8: rgba(0, 0, 0, 0.08); - --admin-toolbar-color-shadow-15: rgba(0, 0, 0, 0.15); + --admin-toolbar-color-shadow-0: rgb(0, 0, 0, 0); + --admin-toolbar-color-shadow-6: rgb(0, 0, 0, 0.06); + --admin-toolbar-color-shadow-8: rgb(0, 0, 0, 0.08); + --admin-toolbar-color-shadow-15: rgb(0, 0, 0, 0.15); /** * Spaces. diff --git a/core/modules/navigation/css/base/variables.pcss.css b/core/modules/navigation/css/base/variables.pcss.css index ae9655a7ad0e..844e0ba048a7 100644 --- a/core/modules/navigation/css/base/variables.pcss.css +++ b/core/modules/navigation/css/base/variables.pcss.css @@ -71,14 +71,14 @@ We need it root to calculate the size of the displace in .dialog-off-canvas-main /* White. */ --admin-toolbar-color-white: var(--drupal-admin-color-white, #fff); /* Expanded background color. */ - --admin-toolbar-color-expanded: rgba(231, 234, 243, 0.5); /* --admin-toolbar-color-gray-050 */ + --admin-toolbar-color-expanded: rgb(231, 234, 243, 0.5); /* --admin-toolbar-color-gray-050 */ /* Fonts. */ --admin-toolbar-font-family: inter, sans-serif; /* Shadows. */ - --admin-toolbar-color-shadow-0: rgba(0, 0, 0, 0); - --admin-toolbar-color-shadow-6: rgba(0, 0, 0, 0.06); - --admin-toolbar-color-shadow-8: rgba(0, 0, 0, 0.08); - --admin-toolbar-color-shadow-15: rgba(0, 0, 0, 0.15); + --admin-toolbar-color-shadow-0: rgb(0, 0, 0, 0); + --admin-toolbar-color-shadow-6: rgb(0, 0, 0, 0.06); + --admin-toolbar-color-shadow-8: rgb(0, 0, 0, 0.08); + --admin-toolbar-color-shadow-15: rgb(0, 0, 0, 0.15); /** * Spaces. diff --git a/core/modules/navigation/css/components/admin-toolbar.css b/core/modules/navigation/css/components/admin-toolbar.css index 25fd9ca1cc02..8e8636d8a855 100644 --- a/core/modules/navigation/css/components/admin-toolbar.css +++ b/core/modules/navigation/css/components/admin-toolbar.css @@ -94,7 +94,7 @@ body { .admin-toolbar { block-size: calc(100vh - var(--drupal-displace-offset-top, 0px)); transform: none; - inset-block-start: var(--drupal-displace-offset-top, 0); + inset-block-start: 0; } } @media only screen and (max-height: 18.75rem) { @@ -333,7 +333,7 @@ body { display: none; width: 100vw; height: 100vh; - background-color: rgba(0, 0, 0, 0.14); + background-color: rgb(0, 0, 0, 0.14); } :where([data-admin-toolbar="expanded"]) .admin-toolbar-overlay { display: block; diff --git a/core/modules/navigation/css/components/admin-toolbar.pcss.css b/core/modules/navigation/css/components/admin-toolbar.pcss.css index 0b13b08252e1..55ffd803e693 100644 --- a/core/modules/navigation/css/components/admin-toolbar.pcss.css +++ b/core/modules/navigation/css/components/admin-toolbar.pcss.css @@ -95,7 +95,7 @@ body { @media (--admin-toolbar-desktop) { block-size: calc(100vh - var(--drupal-displace-offset-top, 0px)); transform: none; - inset-block-start: var(--drupal-displace-offset-top, 0); + inset-block-start: 0; } @media only screen and (max-height: 300px) { @@ -354,7 +354,7 @@ body { display: none; width: 100vw; height: 100vh; - background-color: rgba(0, 0, 0, 0.14); + background-color: rgb(0, 0, 0, 0.14); :where([data-admin-toolbar="expanded"]) & { display: block; diff --git a/core/modules/navigation/css/components/toolbar-dropdown.css b/core/modules/navigation/css/components/toolbar-dropdown.css index f21bf044137a..eca3b63b27e4 100644 --- a/core/modules/navigation/css/components/toolbar-dropdown.css +++ b/core/modules/navigation/css/components/toolbar-dropdown.css @@ -50,7 +50,7 @@ padding: var(--admin-toolbar-space-8) var(--admin-toolbar-space-16); border-radius: var(--admin-toolbar-space-12); background: white; - box-shadow: 0 14px 30px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 14px 30px 0 rgb(0, 0, 0, 0.1); } [data-drupal-dropdown][aria-expanded="true"] + .toolbar-dropdown__menu { display: block; diff --git a/core/modules/navigation/css/components/toolbar-dropdown.pcss.css b/core/modules/navigation/css/components/toolbar-dropdown.pcss.css index 6c462a08ba86..91cd88d0a5fc 100644 --- a/core/modules/navigation/css/components/toolbar-dropdown.pcss.css +++ b/core/modules/navigation/css/components/toolbar-dropdown.pcss.css @@ -49,7 +49,7 @@ padding: var(--admin-toolbar-space-8) var(--admin-toolbar-space-16); border-radius: var(--admin-toolbar-space-12); background: white; - box-shadow: 0 14px 30px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 14px 30px 0 rgb(0, 0, 0, 0.1); } [data-drupal-dropdown][aria-expanded="true"] + .toolbar-dropdown__menu { diff --git a/core/modules/navigation/css/components/toolbar-menu.css b/core/modules/navigation/css/components/toolbar-menu.css index 33e2af3bcb9a..9b411c7cba75 100644 --- a/core/modules/navigation/css/components/toolbar-menu.css +++ b/core/modules/navigation/css/components/toolbar-menu.css @@ -51,7 +51,7 @@ -webkit-text-decoration: none; text-decoration: none; letter-spacing: var(--admin-toolbar-letter-spacing-0-06); - word-break: break-word; + overflow-wrap: break-word; color: var(--admin-toolbar-color-gray-800); border: none; background-color: transparent; @@ -133,5 +133,5 @@ rotate: -90deg; } [dir="rtl"] :is([aria-expanded="true"] .toolbar-menu__chevron) { - rotate: 0; + rotate: none; } diff --git a/core/modules/navigation/css/components/toolbar-menu.pcss.css b/core/modules/navigation/css/components/toolbar-menu.pcss.css index 7f2c98950cc1..60fc599d7122 100644 --- a/core/modules/navigation/css/components/toolbar-menu.pcss.css +++ b/core/modules/navigation/css/components/toolbar-menu.pcss.css @@ -55,7 +55,7 @@ text-align: start; text-decoration: none; letter-spacing: var(--admin-toolbar-letter-spacing-0-06); - word-break: break-word; + overflow-wrap: break-word; color: var(--admin-toolbar-color-gray-800); border: none; background-color: transparent; @@ -150,7 +150,7 @@ rotate: -90deg; [dir="rtl"] & { - rotate: 0; + rotate: none; } } } diff --git a/core/modules/navigation/css/components/toolbar-message.css b/core/modules/navigation/css/components/toolbar-message.css index 11b50e9459be..8a852a0fc703 100644 --- a/core/modules/navigation/css/components/toolbar-message.css +++ b/core/modules/navigation/css/components/toolbar-message.css @@ -15,7 +15,7 @@ text-align: start; -webkit-text-decoration: none; text-decoration: none; - word-break: break-word; + overflow-wrap: break-word; color: var(--admin-toolbar-color-gray-800); border: 0; border-radius: var(--admin-toolbar-space-8); diff --git a/core/modules/navigation/css/components/toolbar-message.pcss.css b/core/modules/navigation/css/components/toolbar-message.pcss.css index 9689014aab43..9e0f401fb4a5 100644 --- a/core/modules/navigation/css/components/toolbar-message.pcss.css +++ b/core/modules/navigation/css/components/toolbar-message.pcss.css @@ -7,7 +7,7 @@ cursor: pointer; text-align: start; text-decoration: none; - word-break: break-word; + overflow-wrap: break-word; color: var(--admin-toolbar-color-gray-800); border: 0; border-radius: var(--admin-toolbar-space-8); diff --git a/core/modules/navigation/css/components/toolbar-popover.css b/core/modules/navigation/css/components/toolbar-popover.css index 76f587a325e6..532e873d96e6 100644 --- a/core/modules/navigation/css/components/toolbar-popover.css +++ b/core/modules/navigation/css/components/toolbar-popover.css @@ -48,9 +48,9 @@ padding-block-start: var(--admin-toolbar-space-16); transform: translateX(0); box-shadow: - 0 0 72px rgba(0, 0, 0, 0.2), - 0 0 8px rgba(0, 0, 0, 0.04), - 0 0 40px rgba(0, 0, 0, 0.06); + 0 0 72px rgb(0, 0, 0, 0.2), + 0 0 8px rgb(0, 0, 0, 0.04), + 0 0 40px rgb(0, 0, 0, 0.06); inline-size: var(--admin-toolbar-popover-width); inset-block-start: var(--drupal-displace-offset-top, 0); inset-inline-start: 1px; diff --git a/core/modules/navigation/css/components/toolbar-popover.pcss.css b/core/modules/navigation/css/components/toolbar-popover.pcss.css index 6a8b2a019c24..a12ebe955edb 100644 --- a/core/modules/navigation/css/components/toolbar-popover.pcss.css +++ b/core/modules/navigation/css/components/toolbar-popover.pcss.css @@ -47,9 +47,9 @@ padding-block-start: var(--admin-toolbar-space-16); transform: translateX(0); box-shadow: - 0 0 72px rgba(0, 0, 0, 0.2), - 0 0 8px rgba(0, 0, 0, 0.04), - 0 0 40px rgba(0, 0, 0, 0.06); + 0 0 72px rgb(0, 0, 0, 0.2), + 0 0 8px rgb(0, 0, 0, 0.04), + 0 0 40px rgb(0, 0, 0, 0.06); inline-size: var(--admin-toolbar-popover-width); inset-block-start: var(--drupal-displace-offset-top, 0); inset-inline-start: 1px; diff --git a/core/modules/navigation/css/components/top-bar.css b/core/modules/navigation/css/components/top-bar.css index 65a489cd78b7..134b0a506c75 100644 --- a/core/modules/navigation/css/components/top-bar.css +++ b/core/modules/navigation/css/components/top-bar.css @@ -22,7 +22,7 @@ .top-bar { block-size: var(--admin-toolbar-top-bar-height); position: fixed; - inset-block-start: var(--drupal-displace-offset-top, 0); + inset-block-start: 0; inset-inline-start: 0; width: 100vw; padding-block: var(--admin-toolbar-space-12); diff --git a/core/modules/navigation/css/components/top-bar.pcss.css b/core/modules/navigation/css/components/top-bar.pcss.css index b55604dfa569..0a34a4b17dae 100644 --- a/core/modules/navigation/css/components/top-bar.pcss.css +++ b/core/modules/navigation/css/components/top-bar.pcss.css @@ -18,7 +18,7 @@ @media (--admin-toolbar-desktop) { block-size: var(--admin-toolbar-top-bar-height); position: fixed; - inset-block-start: var(--drupal-displace-offset-top, 0); + inset-block-start: 0; inset-inline-start: 0; width: 100vw; padding-block: var(--admin-toolbar-space-12); diff --git a/core/modules/navigation/js/admin-toolbar-wrapper.js b/core/modules/navigation/js/admin-toolbar-wrapper.js index c9e2ecb9cae9..6c32da0b6f6c 100644 --- a/core/modules/navigation/js/admin-toolbar-wrapper.js +++ b/core/modules/navigation/js/admin-toolbar-wrapper.js @@ -81,31 +81,35 @@ Drupal.displace(true); }); - - /** - * Initialize Drupal.displace() - * - * We add the displace attribute to a separate full width element because we - * don't want this element to have transitions. Note that this element and the - * navbar share the same exact width. - */ - const initDisplace = () => { - const displaceElement = doc - .querySelector('.admin-toolbar') - ?.querySelector('.admin-toolbar__displace-placeholder'); - const edge = document.documentElement.dir === 'rtl' ? 'right' : 'left'; - displaceElement?.setAttribute(`data-offset-${edge}`, ''); - Drupal.displace(true); - }; - - initDisplace(); } + /** + * Initialize Drupal.displace() + * + * We add the displace attribute to a separate full width element because we + * don't want this element to have transitions. Note that this element and the + * navbar share the same exact width. + * + * @param {HTMLElement} el - The admin toolbar wrapper. + */ + const initDisplace = (el) => { + const displaceElement = el.querySelector( + '.admin-toolbar__displace-placeholder', + ); + const edge = document.documentElement.dir === 'rtl' ? 'right' : 'left'; + displaceElement?.setAttribute(`data-offset-${edge}`, ''); + Drupal.displace(true); + }; + // Any triggers on page. Inside or outside sidebar. // For now button in sidebar + mobile header and background. Drupal.behaviors.navigationProcessToolbarTriggers = { attach: (context) => { + once('navigation-displace', '.admin-toolbar', context).forEach( + initDisplace, + ); + const triggers = once( 'admin-toolbar-trigger', '[aria-controls="admin-toolbar"]', diff --git a/core/modules/navigation/navigation.services.yml b/core/modules/navigation/navigation.services.yml index 88b6826409a2..925efe58a4e1 100644 --- a/core/modules/navigation/navigation.services.yml +++ b/core/modules/navigation/navigation.services.yml @@ -45,3 +45,6 @@ services: class: Drupal\navigation\TopBarItemManager parent: default_plugin_manager Drupal\navigation\TopBarItemManagerInterface: '@plugin.manager.top_bar_item' + + Drupal\navigation\Menu\NavigationMenuLinkTreeManipulators: + autowire: true diff --git a/core/modules/navigation/src/Hook/NavigationHooks.php b/core/modules/navigation/src/Hook/NavigationHooks.php index ed4eb8283668..540a2659af53 100644 --- a/core/modules/navigation/src/Hook/NavigationHooks.php +++ b/core/modules/navigation/src/Hook/NavigationHooks.php @@ -62,7 +62,7 @@ class NavigationHooks { $output = ''; $output .= '<h3>' . $this->t('About') . '</h3>'; $output .= '<p>' . $this->t('The Navigation module provides a left-aligned, collapsible, vertical sidebar navigation.') . '</p>'; - $output .= '<p>' . $this->t('For more information, see the <a href=":docs">online documentation for the Navigation module</a>.', [':docs' => 'https://www.drupal.org/project/navigation']) . '</p>'; + $output .= '<p>' . $this->t('For more information, see the <a href=":docs">online documentation for the Navigation module</a>.', [':docs' => 'https://www.drupal.org/docs/develop/core-modules-and-themes/core-modules/navigation-module']) . '</p>'; return $output; } $configuration_route = 'layout_builder.navigation.'; diff --git a/core/modules/navigation/src/Menu/NavigationMenuLinkTreeManipulators.php b/core/modules/navigation/src/Menu/NavigationMenuLinkTreeManipulators.php new file mode 100644 index 000000000000..75fefdf15417 --- /dev/null +++ b/core/modules/navigation/src/Menu/NavigationMenuLinkTreeManipulators.php @@ -0,0 +1,159 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\navigation\Menu; + +use Drupal\Core\Menu\MenuLinkDefault; +use Drupal\Core\Menu\MenuLinkTreeElement; +use Drupal\Core\Menu\StaticMenuLinkOverridesInterface; +use Drupal\Core\Routing\RouteProviderInterface; +use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\Core\StringTranslation\TranslationInterface; +use Drupal\system\Controller\SystemController; +use Symfony\Component\Routing\Exception\RouteNotFoundException; + +/** + * Provides a menu link tree manipulator for the navigation menu block. + */ +class NavigationMenuLinkTreeManipulators { + + use StringTranslationTrait; + + public function __construct( + protected readonly RouteProviderInterface $routeProvider, + protected readonly StaticMenuLinkOverridesInterface $overrides, + TranslationInterface $translation, + ) { + $this->setStringTranslation($translation); + } + + /** + * Adds an "overview" child link to second level menu links with children. + * + * In the navigation menu, a second-level menu item is a link if it does not + * have children, but if it does, it instead becomes a button that opens + * its child menu. To provide a way to access the page a second-level menu + * item links to, add an "overview" link that links to the page as a child + * (third-level) menu item. + * + * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree + * The menu link tree to manipulate. + * + * @return \Drupal\Core\Menu\MenuLinkTreeElement[] + * The manipulated menu link tree. + */ + public function addSecondLevelOverviewLinks(array $tree): array { + if (!$tree) { + return []; + } + + foreach ($tree as $item) { + if (!$this->isEnabledAndAccessible($item)) { + continue; + } + foreach ($item->subtree as $sub_item) { + if ($this->shouldAddOverviewLink($sub_item)) { + $this->addOverviewLink($sub_item); + } + } + } + + return $tree; + } + + /** + * Whether a menu tree element should have an overview link added to it. + * + * @param \Drupal\Core\Menu\MenuLinkTreeElement $element + * The menu link tree element to check. + * + * @return bool + * TRUE if menu tree element should have a child overview link added. + */ + protected function shouldAddOverviewLink(MenuLinkTreeElement $element): bool { + if (empty($element->subtree) || !$this->isEnabledAndAccessible($element)) { + return FALSE; + } + + $route_name = $element->link->getRouteName(); + if (in_array($route_name, ['<nolink>', '<button>'])) { + return FALSE; + } + + $has_visible_children = FALSE; + foreach ($element->subtree as $sub_element) { + // Do not add overview link if there are no accessible or enabled + // children. + if ($this->isEnabledAndAccessible($sub_element)) { + $has_visible_children = TRUE; + } + + // Do not add overview link if there is already a child linking to the + // same URL. + if ($sub_element->link->getRouteName() === $route_name) { + return FALSE; + } + } + + if (!$has_visible_children) { + return FALSE; + } + + // The systemAdminMenuBlockPage() method in SystemController returns a list + // of child menu links for the page. If the second-level menu item link's + // route uses that controller, do not add the overview link, because that + // duplicates what is already in the navigation menu. + try { + $controller = ltrim($this->routeProvider->getRouteByName($route_name)->getDefault('_controller') ?? '', "\\"); + return $controller !== SystemController::class . '::systemAdminMenuBlockPage'; + } + catch (RouteNotFoundException) { + return TRUE; + } + } + + /** + * Checks whether the menu link tree element is accessible and enabled. + * + * Generally, the 'checkAccess' manipulator should run before this manipulator + * does, so the access objects should be set on all the links, but if it is + * not, treat the link as accessible for the purpose of adding the overview + * child link. + * + * @param \Drupal\Core\Menu\MenuLinkTreeElement $element + * The menu link tree element to be checked. + * + * @return bool + * TRUE if the menu link tree element is enabled and has access allowed. + */ + protected function isEnabledAndAccessible(MenuLinkTreeElement $element): bool { + return $element->link->isEnabled() && (!isset($element->access) || $element->access->isAllowed()); + } + + /** + * Adds "overview" menu tree element as child of a menu tree element. + * + * @param \Drupal\Core\Menu\MenuLinkTreeElement $element + * The menu link tree element to add the overview child element to. + */ + protected function addOverviewLink(MenuLinkTreeElement $element): void { + // Copy the menu link for the menu link element to a new menu link + // definition, except with overrides to make 'Overview' the title, set the + // parent to the original menu link, and set weight to a low number so that + // it likely goes to the top. + $definition = [ + 'title' => $this->t('Overview', [ + '@title' => $element->link->getTitle(), + ]), + 'parent' => $element->link->getPluginId(), + 'provider' => 'navigation', + 'weight' => -1000, + ] + $element->link->getPluginDefinition(); + $link = new MenuLinkDefault([], $element->link->getPluginId() . '.navigation_overview', $definition, $this->overrides); + $overview_element = new MenuLinkTreeElement($link, FALSE, $element->depth + 1, $element->inActiveTrail, []); + $overview_element->access = $element->access ? clone $element->access : NULL; + $element->subtree[$element->link->getPluginId() . '.navigation_overview'] = $overview_element; + } + +} diff --git a/core/modules/navigation/src/Plugin/Block/NavigationMenuBlock.php b/core/modules/navigation/src/Plugin/Block/NavigationMenuBlock.php index 380cc8540aa3..8b75563b92f1 100644 --- a/core/modules/navigation/src/Plugin/Block/NavigationMenuBlock.php +++ b/core/modules/navigation/src/Plugin/Block/NavigationMenuBlock.php @@ -9,6 +9,7 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Menu\MenuTreeParameters; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\navigation\Menu\NavigationMenuLinkTreeManipulators; use Drupal\navigation\Plugin\Derivative\SystemMenuNavigationBlock as SystemMenuNavigationBlockDeriver; use Drupal\system\Plugin\Block\SystemMenuBlock; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -85,6 +86,7 @@ final class NavigationMenuBlock extends SystemMenuBlock implements ContainerFact $tree = $this->menuTree->load($menu_name, $parameters); $manipulators = [ ['callable' => 'menu.default_tree_manipulators:checkAccess'], + ['callable' => NavigationMenuLinkTreeManipulators::class . ':addSecondLevelOverviewLinks'], ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'], ]; $tree = $this->menuTree->transform($tree, $manipulators); diff --git a/core/modules/navigation/src/WorkspacesLazyBuilder.php b/core/modules/navigation/src/WorkspacesLazyBuilder.php index 3134fa4745ed..146f7d83dc9b 100644 --- a/core/modules/navigation/src/WorkspacesLazyBuilder.php +++ b/core/modules/navigation/src/WorkspacesLazyBuilder.php @@ -59,6 +59,9 @@ final class WorkspacesLazyBuilder { 'title' => $active_workspace ? $active_workspace->label() : $this->t('Live'), 'url' => $url, 'class' => 'workspaces', + 'icon' => [ + 'icon_id' => 'workspaces', + ], ], ], '#attached' => [ diff --git a/core/modules/navigation/templates/top-bar.html.twig b/core/modules/navigation/templates/top-bar.html.twig index 6efdeed523f9..319f97f67478 100644 --- a/core/modules/navigation/templates/top-bar.html.twig +++ b/core/modules/navigation/templates/top-bar.html.twig @@ -13,17 +13,19 @@ */ #} {% set attributes = create_attribute() %} -<aside {{ attributes.addClass('top-bar').setAttribute('data-drupal-admin-styles', '').setAttribute('aria-labelledby', 'top-bar__title') }}> - <h3 id="top-bar__title" class="visually-hidden">{{ 'Administrative top bar'|t }}</h3> - <div class="top-bar__content"> - <div class="top-bar__tools"> - {{- tools -}} +{% if tools or context|render or actions|render %} + <aside {{ attributes.addClass('top-bar').setAttribute('data-drupal-admin-styles', '').setAttribute('aria-labelledby', 'top-bar__title').setAttribute('data-offset-top', true) }}> + <h3 id="top-bar__title" class="visually-hidden">{{ 'Administrative top bar'|t }}</h3> + <div class="top-bar__content"> + <div class="top-bar__tools"> + {{- tools -}} + </div> + <div class="top-bar__context"> + {{- context -}} + </div> + <div class="top-bar__actions"> + {{- actions -}} + </div> </div> - <div class="top-bar__context"> - {{- context -}} - </div> - <div class="top-bar__actions"> - {{- actions -}} - </div> - </div> -</aside> + </aside> +{% endif %} diff --git a/core/modules/navigation/tests/src/Functional/NavigationWorkspacesUiTest.php b/core/modules/navigation/tests/src/Functional/NavigationWorkspacesUiTest.php new file mode 100644 index 000000000000..48de404b65ae --- /dev/null +++ b/core/modules/navigation/tests/src/Functional/NavigationWorkspacesUiTest.php @@ -0,0 +1,49 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\navigation\Functional; + +use Drupal\Tests\BrowserTestBase; + +/** + * Tests for \Drupal\navigation\WorkspacesLazyBuilder. + * + * @group navigation + */ +class NavigationWorkspacesUiTest extends BrowserTestBase { + + /** + * {@inheritdoc} + */ + protected static $modules = ['navigation', 'workspaces_ui']; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + + $admin_user = $this->drupalCreateUser([ + 'access navigation', + 'administer workspaces', + ]); + $this->drupalLogin($admin_user); + } + + /** + * Tests the Workspaces button in the navigation bar. + */ + public function testWorkspacesNavigationButton(): void { + $this->drupalGet('<front>'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->elementAttributeContains('css', 'a.toolbar-button--icon--workspaces svg', 'width', '20'); + $this->assertSession()->elementAttributeContains('css', 'a.toolbar-button--icon--workspaces svg', 'class', 'toolbar-button__icon'); + } + +} diff --git a/core/modules/navigation/tests/src/Kernel/NavigationMenuBlockTest.php b/core/modules/navigation/tests/src/Kernel/NavigationMenuBlockTest.php index 496b7d1f7af5..d9cf1f70a090 100644 --- a/core/modules/navigation/tests/src/Kernel/NavigationMenuBlockTest.php +++ b/core/modules/navigation/tests/src/Kernel/NavigationMenuBlockTest.php @@ -11,6 +11,7 @@ use Drupal\Core\Routing\RouteObjectInterface; use Drupal\Core\Routing\UrlGenerator; use Drupal\KernelTests\KernelTestBase; use Drupal\navigation\Plugin\Block\NavigationMenuBlock; +use Drupal\system\Controller\SystemController; use Drupal\system\Entity\Menu; use Drupal\system\Tests\Routing\MockRouteProvider; use Drupal\Tests\Core\Menu\MenuLinkMock; @@ -106,9 +107,16 @@ class NavigationMenuBlockTest extends KernelTestBase { $options = ['_access_checks' => ['access_check.default']]; $special_options = $options + ['_no_path' => TRUE]; $routes->add('example2', new Route('/example2', [], $requirements, $options)); - $routes->add('example4', new Route('/example4', [], $requirements, $options)); + $routes->add('example4', new Route('/example4', ['_controller' => SystemController::class . '::systemAdminMenuBlockPage'], $requirements, $options)); $routes->add('example9', new Route('/example9', [], $requirements, $options)); - $routes->add('example11', new Route('/example11', [], $requirements, $options)); + $routes->add('example11', new Route('/example11', ['_controller' => SystemController::class . '::systemAdminMenuBlockPage'], $requirements, $options)); + $routes->add('example13', new Route('/example13', [], $requirements, $options)); + $routes->add('example14', new Route('/example14', [], $requirements, $options)); + $routes->add('example15', new Route('/example15', [], $requirements, $options)); + $routes->add('example16', new Route('/example16', [], $requirements, $options)); + $routes->add('example17', new Route('/example17', [], $requirements, $options)); + $routes->add('example18', new Route('/example18', [], $requirements, $options)); + $routes->add('example19', new Route('/example19', [], ['_access' => 'FALSE'], $options)); // Mock special routes defined in system.routing.yml. $routes->add('<nolink>', new Route('', [], $requirements, $special_options)); @@ -144,15 +152,23 @@ class NavigationMenuBlockTest extends KernelTestBase { // - 1 (nolink) // - 2 // - 3 (nolink) - // - 4 + // - 4 (list of child links) // - 9 // - 5 (button) // - 7 (button) // - 10 (nolink) // - 6 // - 8 (nolink) - // - 11 + // - 11 (list of child links) // - 12 (button) + // - 13 + // - 14 (not a list of child links) + // - 15 + // - 16 + // - 17 + // - 18 (disabled) + // - 19 (access denied) + // - 20 (links to same routed URL as 17) // With link 6 being the only external link. // phpcs:disable $links = [ @@ -168,6 +184,14 @@ class NavigationMenuBlockTest extends KernelTestBase { 10 => MenuLinkMock::create(['id' => 'test.example10', 'route_name' => '<nolink>', 'title' => 'title 10', 'parent' => 'test.example7', 'weight' => 7]), 11 => MenuLinkMock::create(['id' => 'test.example11', 'route_name' => 'example11', 'title' => 'title 11', 'parent' => 'test.example8', 'weight' => 7]), 12 => MenuLinkMock::create(['id' => 'test.example12', 'route_name' => '<button>', 'title' => 'title 12', 'parent' => 'test.example11', 'weight' => 7]), + 13 => MenuLinkMock::create(['id' => 'test.example13', 'route_name' => 'example13', 'title' => 'title 13', 'parent' => '', 'weight' => 8]), + 14 => MenuLinkMock::create(['id' => 'test.example14', 'route_name' => 'example14', 'title' => 'title 14', 'parent' => 'test.example13', 'weight' => 8]), + 15 => MenuLinkMock::create(['id' => 'test.example15', 'route_name' => 'example15', 'title' => 'title 15', 'parent' => 'test.example14', 'weight' => 8]), + 16 => MenuLinkMock::create(['id' => 'test.example16', 'route_name' => 'example16', 'title' => 'title 16', 'parent' => '', 'weight' => 9]), + 17 => MenuLinkMock::create(['id' => 'test.example17', 'route_name' => 'example17', 'title' => 'title 17', 'parent' => 'test.example16', 'weight' => 9]), + 18 => MenuLinkMock::create(['id' => 'test.example18', 'route_name' => 'example18', 'title' => 'title 18', 'parent' => 'test.example17', 'weight' => 9, 'enabled' => FALSE]), + 19 => MenuLinkMock::create(['id' => 'test.example19', 'route_name' => 'example19', 'title' => 'title 19', 'parent' => 'test.example17', 'weight' => 9]), + 20 => MenuLinkMock::create(['id' => 'test.example20', 'route_name' => 'example17', 'title' => 'title 20', 'parent' => 'test.example17', 'weight' => 9]), ]; // phpcs:enable foreach ($links as $instance) { @@ -234,16 +258,22 @@ class NavigationMenuBlockTest extends KernelTestBase { 'test.example5' => [], 'test.example6' => [], 'test.example8' => [], + 'test.example13' => [], + 'test.example16' => [], ]; $expectations['level_2_only'] = [ 'test.example3' => [], 'test.example7' => [], 'test.example11' => [], + 'test.example14' => [], + 'test.example17' => [], ]; $expectations['level_3_only'] = [ 'test.example4' => [], 'test.example10' => [], 'test.example12' => [], + 'test.example15' => [], + 'test.example20' => [], ]; $expectations['level_1_and_beyond'] = [ 'test.example1' => [], @@ -263,6 +293,20 @@ class NavigationMenuBlockTest extends KernelTestBase { 'test.example12' => [], ], ], + 'test.example13' => [ + 'test.example14' => [ + 'test.example14.navigation_overview' => [], + 'test.example15' => [], + ], + ], + 'test.example16' => [ + // 17 only has inaccessible and disabled child links, and a child item + // that links to the same url as 17, so there should be no overview link + // child added. + 'test.example17' => [ + 'test.example20' => [], + ], + ], ]; $expectations['level_2_and_beyond'] = [ 'test.example3' => [ @@ -276,6 +320,12 @@ class NavigationMenuBlockTest extends KernelTestBase { 'test.example11' => [ 'test.example12' => [], ], + 'test.example14' => [ + 'test.example15' => [], + ], + 'test.example17' => [ + 'test.example20' => [], + ], ]; $expectations['level_3_and_beyond'] = [ 'test.example4' => [ @@ -283,6 +333,8 @@ class NavigationMenuBlockTest extends KernelTestBase { ], 'test.example10' => [], 'test.example12' => [], + 'test.example15' => [], + 'test.example20' => [], ]; // Scenario 1: test all navigation block instances when there's no active // trail. @@ -346,6 +398,10 @@ class NavigationMenuBlockTest extends KernelTestBase { "//li[contains(@class,'toolbar-menu__item--level-2')]/span[text()='title 10']", "//li[contains(@class,'toolbar-menu__item--level-1')]/button/span[text()='title 11']", "//li[contains(@class,'toolbar-menu__item--level-2')]/button[text()='title 12']", + "//li[contains(@class,'toolbar-block__list-item')]/button/span[text()='title 13']", + "//li[contains(@class,'toolbar-menu__item--level-1')]/button/span[text()='title 14']", + "//li[contains(@class,'toolbar-menu__item--level-2')]/a[text()='Overview']", + "//li[contains(@class,'toolbar-menu__item--level-1')]/button/span[text()='title 17']", ]; foreach ($items_query as $query) { $span = $xpath->query($query); diff --git a/core/modules/navigation/tests/src/Nightwatch/Tests/navigationDisplaceTest.js b/core/modules/navigation/tests/src/Nightwatch/Tests/navigationDisplaceTest.js new file mode 100644 index 000000000000..ce9acfacc514 --- /dev/null +++ b/core/modules/navigation/tests/src/Nightwatch/Tests/navigationDisplaceTest.js @@ -0,0 +1,26 @@ +/** + * Verify that Drupal.displace() attribute is properly added by JavaScript. + */ +module.exports = { + '@tags': ['core', 'navigation'], + browser(browser) { + browser + .drupalInstall() + .drupalInstallModule('navigation', true) + .drupalInstallModule('big_pipe') + .setWindowSize(1220, 800); + }, + after(browser) { + browser.drupalUninstall(); + }, + + 'Verify displace attribute': (browser) => { + browser.drupalLoginAsAdmin(() => { + browser + .drupalRelativeURL('/admin/') + .waitForElementPresent( + '.admin-toolbar__displace-placeholder[data-offset-left]', + ); + }); + }, +}; diff --git a/core/modules/navigation/tests/src/Unit/NavigationMenuLinkTreeManipulatorsTest.php b/core/modules/navigation/tests/src/Unit/NavigationMenuLinkTreeManipulatorsTest.php new file mode 100644 index 000000000000..257033b5feac --- /dev/null +++ b/core/modules/navigation/tests/src/Unit/NavigationMenuLinkTreeManipulatorsTest.php @@ -0,0 +1,308 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\navigation\Unit; + +use Drupal\Core\Access\AccessResult; +use Drupal\Core\Menu\MenuLinkTreeElement; +use Drupal\Core\Menu\StaticMenuLinkOverridesInterface; +use Drupal\Core\Routing\RouteProviderInterface; +use Drupal\Core\StringTranslation\TranslationInterface; +use Drupal\navigation\Menu\NavigationMenuLinkTreeManipulators; +use Drupal\system\Controller\SystemController; +use Drupal\Tests\Core\Menu\MenuLinkMock; +use Drupal\Tests\UnitTestCase; +use Symfony\Component\Routing\Route; + +/** + * Tests the navigation menu link tree manipulator. + * + * @group navigation + * + * @coversDefaultClass \Drupal\navigation\Menu\NavigationMenuLinkTreeManipulators + */ +class NavigationMenuLinkTreeManipulatorsTest extends UnitTestCase { + + /** + * Tests the addSecondLevelOverviewLinks() tree manipulator. + * + * @covers ::addSecondLevelOverviewLinks + */ + public function testAddSecondLevelOverviewLinks(): void { + $routeProvider = $this->createMock(RouteProviderInterface::class); + // For only the route named 'child_list', return a route object with the + // SystemController::systemAdminMenuBlockPage as the controller. + $childListRoute = new Route('/test-child-list', ['_controller' => SystemController::class . '::systemAdminMenuBlockPage']); + $routeProvider->expects($this->any()) + ->method('getRouteByName') + ->willReturnCallback(static fn ($name) => $name === 'child_list' ? $childListRoute : new Route("/$name")); + $overrides = $this->createMock(StaticMenuLinkOverridesInterface::class); + $translation = $this->createMock(TranslationInterface::class); + $translation + ->method('translateString') + ->willReturnCallback(static fn ($string) => $string); + $manipulator = new NavigationMenuLinkTreeManipulators($routeProvider, $overrides, $translation); + + $originalTree = $this->mockTree(); + // Make sure overview links do not already exist. + $this->assertArrayNotHasKey('test.example3.navigation_overview', $originalTree[2]->subtree[3]->subtree); + $this->assertArrayNotHasKey('test.example6.navigation_overview', $originalTree[5]->subtree[6]->subtree); + $tree = $manipulator->addSecondLevelOverviewLinks($originalTree); + + // First level menu items should not have any children added. + $this->assertEmpty($tree[1]->subtree); + $this->assertEquals($originalTree[2]->subtree, $tree[2]->subtree); + $this->assertEquals($originalTree[5]->subtree, $tree[5]->subtree); + $this->assertEquals($originalTree[8]->subtree, $tree[8]->subtree); + $this->assertEquals($originalTree[11]->subtree, $tree[11]->subtree); + $this->assertEquals($originalTree[13]->subtree, $tree[13]->subtree); + $this->assertEquals($originalTree[16]->subtree, $tree[16]->subtree); + $this->assertEquals($originalTree[19]->subtree, $tree[19]->subtree); + + // Leaves should not have any children added. + $this->assertEmpty($tree[2]->subtree[3]->subtree[4]->subtree); + $this->assertEmpty($tree[5]->subtree[6]->subtree[7]->subtree); + $this->assertEmpty($tree[8]->subtree[9]->subtree[10]->subtree); + $this->assertEmpty($tree[11]->subtree[12]->subtree); + $this->assertEmpty($tree[13]->subtree[14]->subtree[15]->subtree); + $this->assertEmpty($tree[16]->subtree[17]->subtree[18]->subtree); + $this->assertEmpty($tree[19]->subtree[20]->subtree[21]->subtree); + $this->assertEmpty($tree[19]->subtree[20]->subtree[22]->subtree); + + // Links 3 and 6 should have overview children, even though 6 is unrouted. + $this->assertArrayHasKey('test.example3.navigation_overview', $tree[2]->subtree[3]->subtree); + $this->assertArrayHasKey('test.example6.navigation_overview', $tree[5]->subtree[6]->subtree); + + // Link 9 is a child list page, so it should not have an overview child. + $this->assertArrayNotHasKey('test.example9.navigation_overview', $tree[8]->subtree[9]->subtree); + + // Link 14 and Link 17 are <nolink> and <button> routes, so they should not + // have overview children. + $this->assertArrayNotHasKey('test.example14.navigation_overview', $tree[13]->subtree[14]->subtree); + $this->assertArrayNotHasKey('test.example17.navigation_overview', $tree[16]->subtree[17]->subtree); + + // Link 20's child links are either inaccessible, disabled, or link to the + // same route as 20, so it should not have an overview child. + $this->assertArrayNotHasKey('test.example20.navigation_overview', $tree[19]->subtree[20]->subtree); + } + + /** + * Creates a mock tree. + * + * This mocks a tree with the following structure: + * - 1 + * - 2 + * - 3 + * - 4 + * - 5 + * - 6 (external) + * - 7 + * - 8 + * - 9 + * - 10 + * - 11 + * - 12 + * - 13 + * - 14 (nolink) + * - 15 + * - 16 + * - 17 (button) + * - 18 + * - 19 + * - 20 + * - 21 (disabled) + * - 22 (access denied) + * - 23 (links to same routed URL as 20) + * + * With link 9 linking to a page that contains a list of child menu links. + * + * @return \Drupal\Core\Menu\MenuLinkTreeElement[] + * The mock menu tree. + */ + protected function mockTree(): array { + $links = [ + 1 => MenuLinkMock::create([ + 'id' => 'test.example1', + 'route_name' => 'example1', + 'title' => 'foo', + 'parent' => '', + ]), + 2 => MenuLinkMock::create([ + 'id' => 'test.example2', + 'route_name' => 'example2', + 'title' => 'foo', + 'parent' => '', + ]), + 3 => MenuLinkMock::create([ + 'id' => 'test.example3', + 'route_name' => 'example3', + 'title' => 'baz', + 'parent' => 'test.example2', + ]), + 4 => MenuLinkMock::create([ + 'id' => 'test.example4', + 'route_name' => 'example4', + 'title' => 'qux', + 'parent' => 'test.example3', + ]), + 5 => MenuLinkMock::create([ + 'id' => 'test.example5', + 'route_name' => 'example5', + 'title' => 'title5', + 'parent' => '', + ]), + 6 => MenuLinkMock::create([ + 'id' => 'test.example6', + 'route_name' => '', + 'url' => 'https://www.drupal.org/', + 'title' => 'bar_bar', + 'parent' => 'test.example5', + ]), + 7 => MenuLinkMock::create([ + 'id' => 'test.example7', + 'route_name' => 'example7', + 'title' => 'title7', + 'parent' => 'test.example6', + ]), + 8 => MenuLinkMock::create([ + 'id' => 'test.example8', + 'route_name' => 'example8', + 'title' => 'title8', + 'parent' => '', + ]), + 9 => MenuLinkMock::create([ + 'id' => 'test.example9', + 'route_name' => 'child_list', + 'title' => 'title9', + 'parent' => 'test.example8', + ]), + 10 => MenuLinkMock::create([ + 'id' => 'test.example10', + 'route_name' => 'example9', + 'title' => 'title10', + 'parent' => 'test.example9', + ]), + 11 => MenuLinkMock::create([ + 'id' => 'test.example11', + 'route_name' => 'example11', + 'title' => 'title11', + 'parent' => '', + ]), + 12 => MenuLinkMock::create([ + 'id' => 'test.example12', + 'route_name' => 'example12', + 'title' => 'title12', + 'parent' => 'text.example11', + ]), + 13 => MenuLinkMock::create([ + 'id' => 'test.example13', + 'route_name' => 'example13', + 'title' => 'title13', + 'parent' => '', + ]), + 14 => MenuLinkMock::create([ + 'id' => 'test.example14', + 'route_name' => '<nolink>', + 'title' => 'title14', + 'parent' => 'text.example13', + ]), + 15 => MenuLinkMock::create([ + 'id' => 'test.example15', + 'route_name' => 'example15', + 'title' => 'title15', + 'parent' => 'text.example14', + ]), + 16 => MenuLinkMock::create([ + 'id' => 'test.example16', + 'route_name' => 'example16', + 'title' => 'title16', + 'parent' => '', + ]), + 17 => MenuLinkMock::create([ + 'id' => 'test.example17', + 'route_name' => '<button>', + 'title' => 'title17', + 'parent' => 'text.example16', + ]), + 18 => MenuLinkMock::create([ + 'id' => 'test.example18', + 'route_name' => 'example18', + 'title' => 'title18', + 'parent' => 'text.example17', + ]), + 19 => MenuLinkMock::create([ + 'id' => 'test.example19', + 'route_name' => 'example19', + 'title' => 'title19', + 'parent' => '', + ]), + 20 => MenuLinkMock::create([ + 'id' => 'test.example20', + 'route_name' => 'example20', + 'title' => 'title20', + 'parent' => 'test.example19', + ]), + 21 => MenuLinkMock::create([ + 'id' => 'test.example21', + 'route_name' => 'example21', + 'title' => 'title21', + 'parent' => 'test.example20', + 'enabled' => FALSE, + ]), + 22 => MenuLinkMock::create([ + 'id' => 'test.example22', + 'route_name' => 'no_access', + 'title' => 'title22', + 'parent' => 'test.example20', + ]), + 23 => MenuLinkMock::create([ + 'id' => 'test.example23', + 'route_name' => 'example20', + 'title' => 'title23', + 'parent' => 'test.example20', + ]), + ]; + $tree = []; + $tree[1] = new MenuLinkTreeElement($links[1], FALSE, 1, FALSE, []); + $tree[2] = new MenuLinkTreeElement($links[2], TRUE, 1, FALSE, [ + 3 => new MenuLinkTreeElement($links[3], TRUE, 2, FALSE, [ + 4 => new MenuLinkTreeElement($links[4], FALSE, 3, FALSE, []), + ]), + ]); + $tree[5] = new MenuLinkTreeElement($links[5], TRUE, 1, FALSE, [ + 6 => new MenuLinkTreeElement($links[6], TRUE, 2, FALSE, [ + 7 => new MenuLinkTreeElement($links[7], FALSE, 3, FALSE, []), + ]), + ]); + $tree[8] = new MenuLinkTreeElement($links[8], TRUE, 1, FALSE, [ + 9 => new MenuLinkTreeElement($links[9], TRUE, 2, FALSE, [ + 10 => new MenuLinkTreeElement($links[10], FALSE, 3, FALSE, []), + ]), + ]); + $tree[11] = new MenuLinkTreeElement($links[11], TRUE, 1, FALSE, [ + 12 => new MenuLinkTreeElement($links[12], FALSE, 2, FALSE, []), + ]); + $tree[13] = new MenuLinkTreeElement($links[13], TRUE, 1, FALSE, [ + 14 => new MenuLinkTreeElement($links[14], TRUE, 2, FALSE, [ + 15 => new MenuLinkTreeElement($links[15], FALSE, 3, FALSE, []), + ]), + ]); + $tree[16] = new MenuLinkTreeElement($links[16], TRUE, 1, FALSE, [ + 17 => new MenuLinkTreeElement($links[17], TRUE, 2, FALSE, [ + 18 => new MenuLinkTreeElement($links[18], FALSE, 3, FALSE, []), + ]), + ]); + $tree[19] = new MenuLinkTreeElement($links[19], TRUE, 1, FALSE, [ + 20 => new MenuLinkTreeElement($links[20], TRUE, 2, FALSE, [ + 21 => new MenuLinkTreeElement($links[21], FALSE, 3, FALSE, []), + 22 => new MenuLinkTreeElement($links[22], FALSE, 3, FALSE, []), + 23 => new MenuLinkTreeElement($links[23], FALSE, 3, FALSE, []), + ]), + ]); + $tree[19]->subtree[20]->subtree[22]->access = AccessResult::forbidden(); + + return $tree; + } + +} diff --git a/core/modules/node/node.module b/core/modules/node/node.module index 4ee3c48a00b2..f14d843faa10 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -387,6 +387,11 @@ function node_form_system_themes_admin_form_submit($form, FormStateInterface $fo } /** + * @addtogroup node_access + * @{ + */ + +/** * Fetches an array of permission IDs granted to the given user ID. * * The implementation here provides only the universal "all" grant. A node @@ -658,6 +663,10 @@ function _node_access_rebuild_batch_finished($success, $results, $operations): v } /** + * @} End of "addtogroup node_access". + */ + +/** * Marks a node to be re-indexed by the node_search plugin. * * @param int $nid diff --git a/core/modules/node/src/Hook/NodeHooks1.php b/core/modules/node/src/Hook/NodeHooks1.php index 8e25f2eb066c..d2dbf545c3ca 100644 --- a/core/modules/node/src/Hook/NodeHooks1.php +++ b/core/modules/node/src/Hook/NodeHooks1.php @@ -92,7 +92,7 @@ class NodeHooks1 { case 'entity.entity_view_display.node.default': case 'entity.entity_view_display.node.view_mode': $type = $route_match->getParameter('node_type'); - return '<p>' . $this->t('Content items can be displayed using different view modes: Teaser, Full content, Print, RSS, etc. <em>Teaser</em> is a short format that is typically used in lists of multiple content items. <em>Full content</em> is typically used when the content is displayed on its own page.') . '</p>' . '<p>' . $this->t('Here, you can define which fields are shown and hidden when %type content is displayed in each view mode, and define how the fields are displayed in each view mode.', ['%type' => $type->label()]) . '</p>'; + return '<p>' . $this->t('Content items can be displayed using different view modes: Teaser, Full content, Print, RSS, etc. <em>Teaser</em> is a short format that is typically used in lists of multiple content items. <em>Full content</em> is typically used when the content is displayed on its own page.') . '</p><p>' . $this->t('Here, you can define which fields are shown and hidden when %type content is displayed in each view mode, and define how the fields are displayed in each view mode.', ['%type' => $type->label()]) . '</p>'; case 'entity.node.version_history': return '<p>' . $this->t('Revisions allow you to track differences between multiple versions of your content, and revert to older versions.') . '</p>'; diff --git a/core/modules/node/src/NodeAccessControlHandlerInterface.php b/core/modules/node/src/NodeAccessControlHandlerInterface.php index 588391394eec..0d67cfb7bd69 100644 --- a/core/modules/node/src/NodeAccessControlHandlerInterface.php +++ b/core/modules/node/src/NodeAccessControlHandlerInterface.php @@ -30,6 +30,8 @@ interface NodeAccessControlHandlerInterface { /** * Creates the default node access grant entry on the grant storage. + * + * @see \Drupal\node\NodeGrantDatabaseStorageInterface::writeDefault() */ public function writeDefaultGrant(); diff --git a/core/modules/node/src/NodeGrantDatabaseStorageInterface.php b/core/modules/node/src/NodeGrantDatabaseStorageInterface.php index cce744765630..5e81e1d04d0b 100644 --- a/core/modules/node/src/NodeGrantDatabaseStorageInterface.php +++ b/core/modules/node/src/NodeGrantDatabaseStorageInterface.php @@ -83,6 +83,12 @@ interface NodeGrantDatabaseStorageInterface { /** * Creates the default node access grant entry. + * + * The default node access grant is a special grant added to the node_access + * table when no modules implement hook_node_grants. It grants view access + * to any published node. + * + * @see self::access() */ public function writeDefault(); diff --git a/core/modules/node/tests/modules/node_test/src/Hook/NodeTestHooks.php b/core/modules/node/tests/modules/node_test/src/Hook/NodeTestHooks.php index 1887bc56ea6c..201e781d1963 100644 --- a/core/modules/node/tests/modules/node_test/src/Hook/NodeTestHooks.php +++ b/core/modules/node/tests/modules/node_test/src/Hook/NodeTestHooks.php @@ -32,14 +32,14 @@ class NodeTestHooks { ]; // Add content that should be displayed only in the RSS feed. $build['extra_feed_content'] = [ - '#markup' => '<p>' . 'Extra data that should appear only in the RSS feed for node ' . $node->id() . '.</p>', + '#markup' => '<p>Extra data that should appear only in the RSS feed for node ' . $node->id() . '.</p>', '#weight' => 10, ]; } if ($view_mode != 'rss') { // Add content that should NOT be displayed in the RSS feed. $build['extra_non_feed_content'] = [ - '#markup' => '<p>' . 'Extra data that should appear everywhere except the RSS feed for node ' . $node->id() . '.</p>', + '#markup' => '<p>Extra data that should appear everywhere except the RSS feed for node ' . $node->id() . '.</p>', ]; } } diff --git a/core/modules/package_manager/package_manager.services.yml b/core/modules/package_manager/package_manager.services.yml index d7bbaf94820c..059be5542701 100644 --- a/core/modules/package_manager/package_manager.services.yml +++ b/core/modules/package_manager/package_manager.services.yml @@ -203,8 +203,15 @@ services: class: PhpTuf\ComposerStager\Internal\Translation\Service\SymfonyTranslatorProxy public: false - Drupal\package_manager\DirectWritePreconditionBypass: + package_manager.direct_write_precondition.directories: + class: Drupal\package_manager\DirectWritePreconditionBypass decorates: 'PhpTuf\ComposerStager\API\Precondition\Service\ActiveAndStagingDirsAreDifferentInterface' arguments: - '@.inner' public: false + package_manager.direct_write_precondition.rsync: + class: Drupal\package_manager\DirectWritePreconditionBypass + decorates: 'PhpTuf\ComposerStager\API\Precondition\Service\RsyncIsAvailableInterface' + arguments: + - '@.inner' + public: false diff --git a/core/modules/package_manager/src/DirectWritePreconditionBypass.php b/core/modules/package_manager/src/DirectWritePreconditionBypass.php index ba456d270d7f..ef346b0ae254 100644 --- a/core/modules/package_manager/src/DirectWritePreconditionBypass.php +++ b/core/modules/package_manager/src/DirectWritePreconditionBypass.php @@ -8,6 +8,7 @@ use Drupal\Core\StringTranslation\StringTranslationTrait; use PhpTuf\ComposerStager\API\Path\Value\PathInterface; use PhpTuf\ComposerStager\API\Path\Value\PathListInterface; use PhpTuf\ComposerStager\API\Precondition\Service\ActiveAndStagingDirsAreDifferentInterface; +use PhpTuf\ComposerStager\API\Precondition\Service\RsyncIsAvailableInterface; use PhpTuf\ComposerStager\API\Process\Service\ProcessInterface; use PhpTuf\ComposerStager\API\Translation\Value\TranslatableInterface; @@ -22,7 +23,7 @@ use PhpTuf\ComposerStager\API\Translation\Value\TranslatableInterface; * at any time without warning. External code should not interact with this * class. */ -final class DirectWritePreconditionBypass implements ActiveAndStagingDirsAreDifferentInterface { +final class DirectWritePreconditionBypass implements ActiveAndStagingDirsAreDifferentInterface, RsyncIsAvailableInterface { use StringTranslationTrait; @@ -34,7 +35,7 @@ final class DirectWritePreconditionBypass implements ActiveAndStagingDirsAreDiff private static bool $isBypassed = FALSE; public function __construct( - private readonly ActiveAndStagingDirsAreDifferentInterface $decorated, + private readonly ActiveAndStagingDirsAreDifferentInterface|RsyncIsAvailableInterface $decorated, ) {} /** diff --git a/core/modules/package_manager/tests/modules/package_manager_test_validation/src/EventSubscriber/TestSubscriber.php b/core/modules/package_manager/tests/modules/package_manager_test_validation/src/EventSubscriber/TestSubscriber.php index 61e50a1f81a2..7179299efd00 100644 --- a/core/modules/package_manager/tests/modules/package_manager_test_validation/src/EventSubscriber/TestSubscriber.php +++ b/core/modules/package_manager/tests/modules/package_manager_test_validation/src/EventSubscriber/TestSubscriber.php @@ -127,7 +127,7 @@ class TestSubscriber implements EventSubscriberInterface { $results = $this->state->get(self::getStateKey(get_class($event)), []); // Record that value of maintenance mode for each event. - $this->state->set(get_class($event) . '.' . 'system.maintenance_mode', $this->state->get('system.maintenance_mode')); + $this->state->set(get_class($event) . '.system.maintenance_mode', $this->state->get('system.maintenance_mode')); if ($results instanceof \Throwable) { throw $results; diff --git a/core/modules/package_manager/tests/src/Kernel/DirectWriteTest.php b/core/modules/package_manager/tests/src/Kernel/DirectWriteTest.php index 3208fddbbf43..8c34ae002732 100644 --- a/core/modules/package_manager/tests/src/Kernel/DirectWriteTest.php +++ b/core/modules/package_manager/tests/src/Kernel/DirectWriteTest.php @@ -18,12 +18,14 @@ use Drupal\package_manager\StatusCheckTrait; use Drupal\package_manager\ValidationResult; use PhpTuf\ComposerStager\API\Core\BeginnerInterface; use PhpTuf\ComposerStager\API\Core\CommitterInterface; +use PhpTuf\ComposerStager\API\Path\Factory\PathFactoryInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * @covers \Drupal\package_manager\EventSubscriber\DirectWriteSubscriber * @covers \Drupal\package_manager\SandboxManagerBase::isDirectWrite + * @covers \Drupal\package_manager\DirectWritePreconditionBypass * * @group package_manager */ @@ -231,4 +233,40 @@ class DirectWriteTest extends PackageManagerKernelTestBase implements EventSubsc $this->assertFalse($sandbox_manager->isDirectWrite()); } + /** + * Tests that direct-write bypasses certain Composer Stager preconditions. + * + * @param class-string $service_class + * The class name of the precondition service. + * + * @testWith ["PhpTuf\\ComposerStager\\API\\Precondition\\Service\\ActiveAndStagingDirsAreDifferentInterface"] + * ["PhpTuf\\ComposerStager\\API\\Precondition\\Service\\RsyncIsAvailableInterface"] + */ + public function testPreconditionBypass(string $service_class): void { + // Set up conditions where the active and sandbox directories are the same, + // and the path to rsync isn't valid. + $path = $this->container->get(PathFactoryInterface::class) + ->create('/the/absolute/apex'); + $this->config('package_manager.settings') + ->set('executables.rsync', "C:\Not Rsync.exe") + ->save(); + + /** @var \PhpTuf\ComposerStager\API\Precondition\Service\PreconditionInterface $precondition */ + $precondition = $this->container->get($service_class); + // The precondition should be unfulfilled. + $this->assertFalse($precondition->isFulfilled($path, $path)); + + // Initializing a sandbox manager with direct-write support should bypass + // the precondition. + $this->setSetting('package_manager_allow_direct_write', TRUE); + $sandbox_manager = $this->createStage(TestDirectWriteSandboxManager::class); + $sandbox_manager->create(); + $this->assertTrue($sandbox_manager->isDirectWrite()); + + // The precondition should be fulfilled, and clear that it's because we're + // in direct-write mode. + $this->assertTrue($precondition->isFulfilled($path, $path)); + $this->assertSame('This precondition has been skipped because it is not needed in direct-write mode.', (string) $precondition->getStatusMessage($path, $path)); + } + } diff --git a/core/modules/search/src/Plugin/ConfigurableSearchPluginBase.php b/core/modules/search/src/Plugin/ConfigurableSearchPluginBase.php index 7ad95f16823b..acc2e49a5cb6 100644 --- a/core/modules/search/src/Plugin/ConfigurableSearchPluginBase.php +++ b/core/modules/search/src/Plugin/ConfigurableSearchPluginBase.php @@ -2,14 +2,16 @@ namespace Drupal\search\Plugin; -use Drupal\Component\Utility\NestedArray; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Plugin\ConfigurableTrait; /** * Provides a base implementation for a configurable Search plugin. */ abstract class ConfigurableSearchPluginBase extends SearchPluginBase implements ConfigurableSearchPluginInterface { + use ConfigurableTrait; + /** * The unique ID for the search page using this plugin. * @@ -29,27 +31,6 @@ abstract class ConfigurableSearchPluginBase extends SearchPluginBase implements /** * {@inheritdoc} */ - public function defaultConfiguration() { - return []; - } - - /** - * {@inheritdoc} - */ - public function getConfiguration() { - return $this->configuration; - } - - /** - * {@inheritdoc} - */ - public function setConfiguration(array $configuration) { - $this->configuration = NestedArray::mergeDeep($this->defaultConfiguration(), $configuration); - } - - /** - * {@inheritdoc} - */ public function validateConfigurationForm(array &$form, FormStateInterface $form_state) { } diff --git a/core/modules/settings_tray/css/settings_tray.theme.css b/core/modules/settings_tray/css/settings_tray.theme.css index 9363baad5ecb..28070a0f7273 100644 --- a/core/modules/settings_tray/css/settings_tray.theme.css +++ b/core/modules/settings_tray/css/settings_tray.theme.css @@ -61,10 +61,10 @@ /* Style the editables while in edit mode. */ .dialog-off-canvas-main-canvas.js-settings-tray-edit-mode .settings-tray-editable { - outline: 1px dashed rgba(0, 0, 0, 0.5); - box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.7); + outline: 1px dashed rgb(0, 0, 0, 0.5); + box-shadow: 0 0 0 1px rgb(255, 255, 255, 0.7); } .dialog-off-canvas-main-canvas.js-settings-tray-edit-mode .settings-tray-editable:hover, .dialog-off-canvas-main-canvas.js-settings-tray-edit-mode .settings-tray-editable.settings-tray-active-editable { - background-color: rgba(0, 0, 0, 0.2); + background-color: rgb(0, 0, 0, 0.2); } diff --git a/core/modules/settings_tray/css/settings_tray.toolbar.css b/core/modules/settings_tray/css/settings_tray.toolbar.css index 61b1fa268282..5655111787ce 100644 --- a/core/modules/settings_tray/css/settings_tray.toolbar.css +++ b/core/modules/settings_tray/css/settings_tray.toolbar.css @@ -23,7 +23,7 @@ color: #eee; background-color: #0066a1; background-image: linear-gradient(to bottom, #0066a1, #005b98); - text-shadow: 0 1px hsla(0, 0%, 0%, 0.5); + text-shadow: 0 1px hsl(0, 0%, 0%, 0.5); font-weight: 700; -webkit-font-smoothing: antialiased; } @@ -31,7 +31,7 @@ color: #fff; background-color: #0a7bc1; background-image: linear-gradient(to bottom, #0a7bc1, #0a6eb4); - text-shadow: 0 1px hsla(0, 0%, 0%, 0.5); + text-shadow: 0 1px hsl(0, 0%, 0%, 0.5); font-weight: 700; -webkit-font-smoothing: antialiased; } diff --git a/core/modules/shortcut/css/shortcut.theme.css b/core/modules/shortcut/css/shortcut.theme.css index d7a5fa146f71..d98e6f1864b3 100644 --- a/core/modules/shortcut/css/shortcut.theme.css +++ b/core/modules/shortcut/css/shortcut.theme.css @@ -43,7 +43,7 @@ color: #fff; border-radius: 5px; background: #000; - background: rgba(0, 0, 0, 0.5); + background: rgb(0, 0, 0, 0.5); -webkit-backface-visibility: hidden; backface-visibility: hidden; } diff --git a/core/modules/sqlite/src/Driver/Database/sqlite/Schema.php b/core/modules/sqlite/src/Driver/Database/sqlite/Schema.php index cbcdffcd2f95..fa526a9f5d03 100644 --- a/core/modules/sqlite/src/Driver/Database/sqlite/Schema.php +++ b/core/modules/sqlite/src/Driver/Database/sqlite/Schema.php @@ -249,6 +249,11 @@ class Schema extends DatabaseSchema { 'blob:big' => 'BLOB', 'blob:normal' => 'BLOB', + + // Only the SQLite driver has this field map to due to a fatal error + // error caused by this driver's schema on table introspection. + // @todo Add support to all drivers in https://drupal.org/i/3343634 + 'json:normal' => 'JSON', ]; return $map; } diff --git a/core/modules/system/css/components/system-status-report-counters.css b/core/modules/system/css/components/system-status-report-counters.css index 7040c257a0f2..54ffabe5fc1c 100644 --- a/core/modules/system/css/components/system-status-report-counters.css +++ b/core/modules/system/css/components/system-status-report-counters.css @@ -9,7 +9,7 @@ padding: 0.5em 0; text-align: center; white-space: nowrap; - background-color: rgba(0, 0, 0, 0.063); + background-color: rgb(0, 0, 0, 0.063); } @media screen and (min-width: 60em) { diff --git a/core/modules/system/src/Hook/SystemHooks.php b/core/modules/system/src/Hook/SystemHooks.php index 86d181646239..800a1d718f37 100644 --- a/core/modules/system/src/Hook/SystemHooks.php +++ b/core/modules/system/src/Hook/SystemHooks.php @@ -159,10 +159,6 @@ class SystemHooks { } /** - * @} End of "defgroup authorize". - */ - - /** * Implements hook_updater_info(). */ #[Hook('updater_info')] diff --git a/core/modules/system/system.module b/core/modules/system/system.module index dbda1e1b6b4b..0fbcf9b6c1fd 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -307,6 +307,10 @@ function system_authorized_batch_process() { } /** + * @} End of "defgroup authorize". + */ + +/** * Implements hook_preprocess_HOOK() for block templates. */ function system_preprocess_block(&$variables): void { diff --git a/core/modules/system/tests/modules/delay_cache_tags_invalidation/src/Hook/DelayCacheTagsInvalidationHooks.php b/core/modules/system/tests/modules/delay_cache_tags_invalidation/src/Hook/DelayCacheTagsInvalidationHooks.php index c543a1d3e533..f444b69a427b 100644 --- a/core/modules/system/tests/modules/delay_cache_tags_invalidation/src/Hook/DelayCacheTagsInvalidationHooks.php +++ b/core/modules/system/tests/modules/delay_cache_tags_invalidation/src/Hook/DelayCacheTagsInvalidationHooks.php @@ -25,11 +25,11 @@ class DelayCacheTagsInvalidationHooks { } // Read the pre-transaction cache writes. // @see \Drupal\KernelTests\Core\Cache\EndOfTransactionQueriesTest::testEntitySave() - \Drupal::state()->set('delay_cache_tags_invalidation_entity_test_insert' . '__pre-transaction_foobar', \Drupal::cache()->get('test_cache_pre-transaction_foobar')); - \Drupal::state()->set('delay_cache_tags_invalidation_entity_test_insert' . '__pre-transaction_entity_test_list', \Drupal::cache()->get('test_cache_pre-transaction_entity_test_list')); + \Drupal::state()->set('delay_cache_tags_invalidation_entity_test_insert__pre-transaction_foobar', \Drupal::cache()->get('test_cache_pre-transaction_foobar')); + \Drupal::state()->set('delay_cache_tags_invalidation_entity_test_insert__pre-transaction_entity_test_list', \Drupal::cache()->get('test_cache_pre-transaction_entity_test_list')); // Write during the transaction. - \Drupal::cache()->set('delay_cache_tags_invalidation_entity_test_insert' . '__during_transaction_foobar', 'something', Cache::PERMANENT, ['foobar']); - \Drupal::cache()->set('delay_cache_tags_invalidation_entity_test_insert' . '__during_transaction_entity_test_list', 'something', Cache::PERMANENT, ['entity_test_list']); + \Drupal::cache()->set('delay_cache_tags_invalidation_entity_test_insert__during_transaction_foobar', 'something', Cache::PERMANENT, ['foobar']); + \Drupal::cache()->set('delay_cache_tags_invalidation_entity_test_insert__during_transaction_entity_test_list', 'something', Cache::PERMANENT, ['entity_test_list']); // Trigger a nested entity save and hence a nested transaction. User::create(['name' => 'john doe', 'status' => 1])->save(); } @@ -42,8 +42,8 @@ class DelayCacheTagsInvalidationHooks { if ($entity->getAccountName() === 'john doe') { // Read the in-transaction cache writes. // @see delay_cache_tags_invalidation_entity_test_insert() - \Drupal::state()->set('delay_cache_tags_invalidation_user_insert' . '__during_transaction_foobar', \Drupal::cache()->get('delay_cache_tags_invalidation_entity_test_insert__during_transaction_foobar')); - \Drupal::state()->set('delay_cache_tags_invalidation_user_insert' . '__during_transaction_entity_test_list', \Drupal::cache()->get('delay_cache_tags_invalidation_entity_test_insert__during_transaction_entity_test_list')); + \Drupal::state()->set('delay_cache_tags_invalidation_user_insert__during_transaction_foobar', \Drupal::cache()->get('delay_cache_tags_invalidation_entity_test_insert__during_transaction_foobar')); + \Drupal::state()->set('delay_cache_tags_invalidation_user_insert__during_transaction_entity_test_list', \Drupal::cache()->get('delay_cache_tags_invalidation_entity_test_insert__during_transaction_entity_test_list')); } } diff --git a/core/modules/system/tests/modules/entity_crud_hook_test/src/Hook/EntityCrudHookTestHooks.php b/core/modules/system/tests/modules/entity_crud_hook_test/src/Hook/EntityCrudHookTestHooks.php index c552a268952a..8e16b55b4c69 100644 --- a/core/modules/system/tests/modules/entity_crud_hook_test/src/Hook/EntityCrudHookTestHooks.php +++ b/core/modules/system/tests/modules/entity_crud_hook_test/src/Hook/EntityCrudHookTestHooks.php @@ -17,7 +17,7 @@ class EntityCrudHookTestHooks { */ #[Hook('entity_create')] public function entityCreate(EntityInterface $entity): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_entity_create' . ' called for type ' . $entity->getEntityTypeId(); + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_entity_create called for type ' . $entity->getEntityTypeId(); } /** @@ -25,7 +25,7 @@ class EntityCrudHookTestHooks { */ #[Hook('block_create')] public function blockCreate(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_block_create' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_block_create called'; } /** @@ -33,7 +33,7 @@ class EntityCrudHookTestHooks { */ #[Hook('comment_create')] public function commentCreate(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_comment_create' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_comment_create called'; } /** @@ -41,7 +41,7 @@ class EntityCrudHookTestHooks { */ #[Hook('file_create')] public function fileCreate(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_file_create' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_file_create called'; } /** @@ -49,7 +49,7 @@ class EntityCrudHookTestHooks { */ #[Hook('node_create')] public function nodeCreate(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_node_create' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_node_create called'; } /** @@ -57,7 +57,7 @@ class EntityCrudHookTestHooks { */ #[Hook('taxonomy_term_create')] public function taxonomyTermCreate(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_term_create' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_term_create called'; } /** @@ -65,7 +65,7 @@ class EntityCrudHookTestHooks { */ #[Hook('taxonomy_vocabulary_create')] public function taxonomyVocabularyCreate(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_vocabulary_create' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_vocabulary_create called'; } /** @@ -73,7 +73,7 @@ class EntityCrudHookTestHooks { */ #[Hook('user_create')] public function userCreate(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_user_create' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_user_create called'; } /** @@ -81,7 +81,7 @@ class EntityCrudHookTestHooks { */ #[Hook('entity_presave')] public function entityPresave(EntityInterface $entity): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_entity_presave' . ' called for type ' . $entity->getEntityTypeId(); + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_entity_presave called for type ' . $entity->getEntityTypeId(); } /** @@ -89,7 +89,7 @@ class EntityCrudHookTestHooks { */ #[Hook('block_presave')] public function blockPresave(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_block_presave' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_block_presave called'; } /** @@ -97,7 +97,7 @@ class EntityCrudHookTestHooks { */ #[Hook('comment_presave')] public function commentPresave(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_comment_presave' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_comment_presave called'; } /** @@ -105,7 +105,7 @@ class EntityCrudHookTestHooks { */ #[Hook('file_presave')] public function filePresave(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_file_presave' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_file_presave called'; } /** @@ -113,7 +113,7 @@ class EntityCrudHookTestHooks { */ #[Hook('node_presave')] public function nodePresave(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_node_presave' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_node_presave called'; } /** @@ -121,7 +121,7 @@ class EntityCrudHookTestHooks { */ #[Hook('taxonomy_term_presave')] public function taxonomyTermPresave(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_term_presave' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_term_presave called'; } /** @@ -129,7 +129,7 @@ class EntityCrudHookTestHooks { */ #[Hook('taxonomy_vocabulary_presave')] public function taxonomyVocabularyPresave(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_vocabulary_presave' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_vocabulary_presave called'; } /** @@ -137,7 +137,7 @@ class EntityCrudHookTestHooks { */ #[Hook('user_presave')] public function userPresave(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_user_presave' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_user_presave called'; } /** @@ -145,7 +145,7 @@ class EntityCrudHookTestHooks { */ #[Hook('entity_insert')] public function entityInsert(EntityInterface $entity): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_entity_insert' . ' called for type ' . $entity->getEntityTypeId(); + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_entity_insert called for type ' . $entity->getEntityTypeId(); } /** @@ -153,7 +153,7 @@ class EntityCrudHookTestHooks { */ #[Hook('block_insert')] public function blockInsert(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_block_insert' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_block_insert called'; } /** @@ -161,7 +161,7 @@ class EntityCrudHookTestHooks { */ #[Hook('comment_insert')] public function commentInsert(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_comment_insert' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_comment_insert called'; } /** @@ -169,7 +169,7 @@ class EntityCrudHookTestHooks { */ #[Hook('file_insert')] public function fileInsert(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_file_insert' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_file_insert called'; } /** @@ -177,7 +177,7 @@ class EntityCrudHookTestHooks { */ #[Hook('node_insert')] public function nodeInsert(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_node_insert' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_node_insert called'; } /** @@ -185,7 +185,7 @@ class EntityCrudHookTestHooks { */ #[Hook('taxonomy_term_insert')] public function taxonomyTermInsert(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_term_insert' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_term_insert called'; } /** @@ -193,7 +193,7 @@ class EntityCrudHookTestHooks { */ #[Hook('taxonomy_vocabulary_insert')] public function taxonomyVocabularyInsert(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_vocabulary_insert' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_vocabulary_insert called'; } /** @@ -201,7 +201,7 @@ class EntityCrudHookTestHooks { */ #[Hook('user_insert')] public function userInsert(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_user_insert' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_user_insert called'; } /** @@ -209,7 +209,7 @@ class EntityCrudHookTestHooks { */ #[Hook('entity_preload')] public function entityPreload(array $entities, $type): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_entity_preload' . ' called for type ' . $type; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_entity_preload called for type ' . $type; } /** @@ -217,7 +217,7 @@ class EntityCrudHookTestHooks { */ #[Hook('entity_load')] public function entityLoad(array $entities, $type): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_entity_load' . ' called for type ' . $type; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_entity_load called for type ' . $type; } /** @@ -225,7 +225,7 @@ class EntityCrudHookTestHooks { */ #[Hook('block_load')] public function blockLoad(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_block_load' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_block_load called'; } /** @@ -233,7 +233,7 @@ class EntityCrudHookTestHooks { */ #[Hook('comment_load')] public function commentLoad(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_comment_load' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_comment_load called'; } /** @@ -241,7 +241,7 @@ class EntityCrudHookTestHooks { */ #[Hook('file_load')] public function fileLoad(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_file_load' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_file_load called'; } /** @@ -249,7 +249,7 @@ class EntityCrudHookTestHooks { */ #[Hook('node_load')] public function nodeLoad(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_node_load' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_node_load called'; } /** @@ -257,7 +257,7 @@ class EntityCrudHookTestHooks { */ #[Hook('taxonomy_term_load')] public function taxonomyTermLoad(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_term_load' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_term_load called'; } /** @@ -265,7 +265,7 @@ class EntityCrudHookTestHooks { */ #[Hook('taxonomy_vocabulary_load')] public function taxonomyVocabularyLoad(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_vocabulary_load' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_vocabulary_load called'; } /** @@ -273,7 +273,7 @@ class EntityCrudHookTestHooks { */ #[Hook('user_load')] public function userLoad(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_user_load' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_user_load called'; } /** @@ -281,7 +281,7 @@ class EntityCrudHookTestHooks { */ #[Hook('entity_update')] public function entityUpdate(EntityInterface $entity): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_entity_update' . ' called for type ' . $entity->getEntityTypeId(); + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_entity_update called for type ' . $entity->getEntityTypeId(); } /** @@ -289,7 +289,7 @@ class EntityCrudHookTestHooks { */ #[Hook('block_update')] public function blockUpdate(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_block_update' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_block_update called'; } /** @@ -297,7 +297,7 @@ class EntityCrudHookTestHooks { */ #[Hook('comment_update')] public function commentUpdate(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_comment_update' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_comment_update called'; } /** @@ -305,7 +305,7 @@ class EntityCrudHookTestHooks { */ #[Hook('file_update')] public function fileUpdate(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_file_update' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_file_update called'; } /** @@ -313,7 +313,7 @@ class EntityCrudHookTestHooks { */ #[Hook('node_update')] public function nodeUpdate(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_node_update' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_node_update called'; } /** @@ -321,7 +321,7 @@ class EntityCrudHookTestHooks { */ #[Hook('taxonomy_term_update')] public function taxonomyTermUpdate(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_term_update' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_term_update called'; } /** @@ -329,7 +329,7 @@ class EntityCrudHookTestHooks { */ #[Hook('taxonomy_vocabulary_update')] public function taxonomyVocabularyUpdate(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_vocabulary_update' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_vocabulary_update called'; } /** @@ -337,7 +337,7 @@ class EntityCrudHookTestHooks { */ #[Hook('user_update')] public function userUpdate(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_user_update' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_user_update called'; } /** @@ -345,7 +345,7 @@ class EntityCrudHookTestHooks { */ #[Hook('entity_predelete')] public function entityPredelete(EntityInterface $entity): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_entity_predelete' . ' called for type ' . $entity->getEntityTypeId(); + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_entity_predelete called for type ' . $entity->getEntityTypeId(); } /** @@ -353,7 +353,7 @@ class EntityCrudHookTestHooks { */ #[Hook('block_predelete')] public function blockPredelete(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_block_predelete' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_block_predelete called'; } /** @@ -361,7 +361,7 @@ class EntityCrudHookTestHooks { */ #[Hook('comment_predelete')] public function commentPredelete(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_comment_predelete' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_comment_predelete called'; } /** @@ -369,7 +369,7 @@ class EntityCrudHookTestHooks { */ #[Hook('file_predelete')] public function filePredelete(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_file_predelete' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_file_predelete called'; } /** @@ -377,7 +377,7 @@ class EntityCrudHookTestHooks { */ #[Hook('node_predelete')] public function nodePredelete(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_node_predelete' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_node_predelete called'; } /** @@ -385,7 +385,7 @@ class EntityCrudHookTestHooks { */ #[Hook('taxonomy_term_predelete')] public function taxonomyTermPredelete(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_term_predelete' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_term_predelete called'; } /** @@ -393,7 +393,7 @@ class EntityCrudHookTestHooks { */ #[Hook('taxonomy_vocabulary_predelete')] public function taxonomyVocabularyPredelete(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_vocabulary_predelete' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_vocabulary_predelete called'; } /** @@ -401,7 +401,7 @@ class EntityCrudHookTestHooks { */ #[Hook('user_predelete')] public function userPredelete(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_user_predelete' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_user_predelete called'; } /** @@ -409,7 +409,7 @@ class EntityCrudHookTestHooks { */ #[Hook('entity_delete')] public function entityDelete(EntityInterface $entity): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_entity_delete' . ' called for type ' . $entity->getEntityTypeId(); + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_entity_delete called for type ' . $entity->getEntityTypeId(); } /** @@ -417,7 +417,7 @@ class EntityCrudHookTestHooks { */ #[Hook('block_delete')] public function blockDelete(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_block_delete' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_block_delete called'; } /** @@ -425,7 +425,7 @@ class EntityCrudHookTestHooks { */ #[Hook('comment_delete')] public function commentDelete(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_comment_delete' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_comment_delete called'; } /** @@ -433,7 +433,7 @@ class EntityCrudHookTestHooks { */ #[Hook('file_delete')] public function fileDelete(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_file_delete' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_file_delete called'; } /** @@ -441,7 +441,7 @@ class EntityCrudHookTestHooks { */ #[Hook('node_delete')] public function nodeDelete(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_node_delete' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_node_delete called'; } /** @@ -449,7 +449,7 @@ class EntityCrudHookTestHooks { */ #[Hook('taxonomy_term_delete')] public function taxonomyTermDelete(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_term_delete' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_term_delete called'; } /** @@ -457,7 +457,7 @@ class EntityCrudHookTestHooks { */ #[Hook('taxonomy_vocabulary_delete')] public function taxonomyVocabularyDelete(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_vocabulary_delete' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_taxonomy_vocabulary_delete called'; } /** @@ -465,7 +465,7 @@ class EntityCrudHookTestHooks { */ #[Hook('user_delete')] public function userDelete(): void { - $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_user_delete' . ' called'; + $GLOBALS['entity_crud_hook_test'][] = 'entity_crud_hook_test_user_delete called'; } } diff --git a/core/modules/system/tests/modules/module_test/module_test.file.inc b/core/modules/system/tests/modules/module_test/module_test.file.inc index c0cee6f1905e..5ba5f5614ca7 100644 --- a/core/modules/system/tests/modules/module_test/module_test.file.inc +++ b/core/modules/system/tests/modules/module_test/module_test.file.inc @@ -16,3 +16,17 @@ declare(strict_types=1); function module_test_test_hook(): array { return ['module_test' => 'success!']; } + +/** + * Implements hook_test_reset_implementations_hook(). + */ +function module_test_test_reset_implementations_hook(): string { + return __FUNCTION__; +} + +/** + * Implements hook_test_reset_implementations_alter(). + */ +function module_test_test_reset_implementations_alter(array &$data): void { + $data[] = __FUNCTION__; +} diff --git a/core/modules/system/tests/modules/sdc_test/components/my-banner/my-banner.component.yml b/core/modules/system/tests/modules/sdc_test/components/my-banner/my-banner.component.yml index 195903e9ee74..0c89a0740a6b 100644 --- a/core/modules/system/tests/modules/sdc_test/components/my-banner/my-banner.component.yml +++ b/core/modules/system/tests/modules/sdc_test/components/my-banner/my-banner.component.yml @@ -29,6 +29,10 @@ props: enum: - '' - _blank + meta:enum: + '': 'Open in same window' + _blank: 'Open in a new window' + x-translation-context: Banner link target image: title: Media Image description: Background image for the banner. diff --git a/core/modules/system/tests/modules/sdc_test/components/my-button/my-button.component.yml b/core/modules/system/tests/modules/sdc_test/components/my-button/my-button.component.yml index 65b3c472096b..d0d4f8c73b46 100644 --- a/core/modules/system/tests/modules/sdc_test/components/my-button/my-button.component.yml +++ b/core/modules/system/tests/modules/sdc_test/components/my-button/my-button.component.yml @@ -24,3 +24,7 @@ props: - power - like - external + meta:enum: + power: 'Power' + like: 'Like' + external: 'External' diff --git a/core/modules/system/tests/modules/sdc_test/components/my-cta/my-cta.component.yml b/core/modules/system/tests/modules/sdc_test/components/my-cta/my-cta.component.yml index 889dfe885205..6d16be49cf74 100644 --- a/core/modules/system/tests/modules/sdc_test/components/my-cta/my-cta.component.yml +++ b/core/modules/system/tests/modules/sdc_test/components/my-cta/my-cta.component.yml @@ -17,12 +17,23 @@ props: type: string title: URL format: uri + examples: + - https://drupal.org target: type: string title: Target + description: The target for opening the link. enum: - '' - - _blank + - '_blank' + meta:enum: + '': 'Open in same window' + _blank: 'Open in a new window' + x-translation-context: CTA link target + default: '' + examples: + - '' + - '_blank' attributes: type: Drupal\Core\Template\Attribute name: Attributes diff --git a/core/modules/system/tests/modules/sdc_test_replacements/components/my-button/my-button.component.yml b/core/modules/system/tests/modules/sdc_test_replacements/components/my-button/my-button.component.yml index b87f1180111e..053387cf9c4f 100644 --- a/core/modules/system/tests/modules/sdc_test_replacements/components/my-button/my-button.component.yml +++ b/core/modules/system/tests/modules/sdc_test_replacements/components/my-button/my-button.component.yml @@ -24,3 +24,7 @@ props: - power - like - external + meta:enum: + power: 'Power' + like: 'Like' + external: 'External' diff --git a/core/modules/system/tests/modules/theme_suggestions_test/src/Hook/ThemeSuggestionsTestHooks.php b/core/modules/system/tests/modules/theme_suggestions_test/src/Hook/ThemeSuggestionsTestHooks.php index 8f5d5ee18a8f..ff4086a0c2a8 100644 --- a/core/modules/system/tests/modules/theme_suggestions_test/src/Hook/ThemeSuggestionsTestHooks.php +++ b/core/modules/system/tests/modules/theme_suggestions_test/src/Hook/ThemeSuggestionsTestHooks.php @@ -16,7 +16,7 @@ class ThemeSuggestionsTestHooks { */ #[Hook('theme_suggestions_alter')] public function themeSuggestionsAlter(array &$suggestions, array &$variables, $hook): void { - \Drupal::messenger()->addStatus('theme_suggestions_test_theme_suggestions_alter' . '() executed.'); + \Drupal::messenger()->addStatus('theme_suggestions_test_theme_suggestions_alter() executed.'); if ($hook == 'theme_test_general_suggestions') { $suggestions[] = $hook . '__module_override'; $variables['module_hook'] = 'theme_suggestions_test_theme_suggestions_alter'; @@ -28,7 +28,7 @@ class ThemeSuggestionsTestHooks { */ #[Hook('theme_suggestions_theme_test_suggestions_alter')] public function themeSuggestionsThemeTestSuggestionsAlter(array &$suggestions, array $variables): void { - \Drupal::messenger()->addStatus('theme_suggestions_test_theme_suggestions_theme_test_suggestions_alter' . '() executed.'); + \Drupal::messenger()->addStatus('theme_suggestions_test_theme_suggestions_theme_test_suggestions_alter() executed.'); $suggestions[] = 'theme_test_suggestions__module_override'; } diff --git a/core/modules/system/tests/modules/theme_test/src/EventSubscriber/ThemeTestSubscriber.php b/core/modules/system/tests/modules/theme_test/src/EventSubscriber/ThemeTestSubscriber.php index 00b51bc72b57..6c6f67d77eb8 100644 --- a/core/modules/system/tests/modules/theme_test/src/EventSubscriber/ThemeTestSubscriber.php +++ b/core/modules/system/tests/modules/theme_test/src/EventSubscriber/ThemeTestSubscriber.php @@ -19,10 +19,11 @@ class ThemeTestSubscriber implements EventSubscriberInterface { /** * The used container. * + * @var object + * * @todo This variable is never initialized, so we don't know what it is. * See https://www.drupal.org/node/2721315 */ - // phpcs:ignore Drupal.Commenting.VariableComment.Missing, Drupal.Commenting.VariableComment.MissingVar protected $container; /** diff --git a/core/modules/system/tests/modules/theme_test/src/Hook/ThemeTestHooks.php b/core/modules/system/tests/modules/theme_test/src/Hook/ThemeTestHooks.php index 8e27524449f1..9b3fe6cd66a5 100644 --- a/core/modules/system/tests/modules/theme_test/src/Hook/ThemeTestHooks.php +++ b/core/modules/system/tests/modules/theme_test/src/Hook/ThemeTestHooks.php @@ -85,7 +85,7 @@ class ThemeTestHooks { */ #[Hook('theme_suggestions_alter')] public function themeSuggestionsAlter(array &$suggestions, array $variables, $hook): void { - \Drupal::messenger()->addStatus('theme_test_theme_suggestions_alter' . '() executed for ' . $hook . '.'); + \Drupal::messenger()->addStatus('theme_test_theme_suggestions_alter() executed for ' . $hook . '.'); } /** @@ -93,7 +93,7 @@ class ThemeTestHooks { */ #[Hook('theme_suggestions_theme_test_suggestions_alter')] public function themeSuggestionsThemeTestSuggestionsAlter(array &$suggestions, array $variables): void { - \Drupal::messenger()->addStatus('theme_test_theme_suggestions_theme_test_suggestions_alter' . '() executed.'); + \Drupal::messenger()->addStatus('theme_test_theme_suggestions_theme_test_suggestions_alter() executed.'); } /** diff --git a/core/modules/system/tests/src/Functional/Entity/Traits/EntityDefinitionTestTrait.php b/core/modules/system/tests/src/Functional/Entity/Traits/EntityDefinitionTestTrait.php index e130b89bf327..94221d8165fe 100644 --- a/core/modules/system/tests/src/Functional/Entity/Traits/EntityDefinitionTestTrait.php +++ b/core/modules/system/tests/src/Functional/Entity/Traits/EntityDefinitionTestTrait.php @@ -24,7 +24,7 @@ trait EntityDefinitionTestTrait { * (optional) Applies changes only for the specified entity type ID. * Defaults to NULL. */ - protected function applyEntityUpdates($entity_type_id = NULL) { + protected function applyEntityUpdates($entity_type_id = NULL): void { $complete_change_list = \Drupal::entityDefinitionUpdateManager()->getChangeList(); if ($complete_change_list) { // In case there are changes, explicitly invalidate caches. @@ -68,7 +68,7 @@ trait EntityDefinitionTestTrait { * @param string $entity_type_id * The entity type ID. */ - protected function doEntityUpdate($op, $entity_type_id) { + protected function doEntityUpdate($op, $entity_type_id): void { $entity_type = \Drupal::entityTypeManager()->getDefinition($entity_type_id); $field_storage_definitions = \Drupal::service('entity_field.manager')->getFieldStorageDefinitions($entity_type_id); switch ($op) { @@ -96,7 +96,7 @@ trait EntityDefinitionTestTrait { * @param array|null $original_storage_definition * The original field storage definition. */ - protected function doFieldUpdate($op, $storage_definition = NULL, $original_storage_definition = NULL) { + protected function doFieldUpdate($op, $storage_definition = NULL, $original_storage_definition = NULL): void { switch ($op) { case EntityDefinitionUpdateManagerInterface::DEFINITION_CREATED: \Drupal::service('field_storage_definition.listener')->onFieldStorageDefinitionCreate($storage_definition); @@ -115,7 +115,7 @@ trait EntityDefinitionTestTrait { /** * Enables a new entity type definition. */ - protected function enableNewEntityType() { + protected function enableNewEntityType(): void { $this->state->set('entity_test_new', TRUE); $this->applyEntityUpdates('entity_test_new'); } @@ -123,7 +123,7 @@ trait EntityDefinitionTestTrait { /** * Resets the entity type definition. */ - protected function resetEntityType() { + protected function resetEntityType(): void { $updated_entity_type = $this->getUpdatedEntityTypeDefinition(FALSE, FALSE); $updated_field_storage_definitions = $this->getUpdatedFieldStorageDefinitions(FALSE, FALSE); $this->entityDefinitionUpdateManager->updateFieldableEntityType($updated_entity_type, $updated_field_storage_definitions); @@ -136,7 +136,7 @@ trait EntityDefinitionTestTrait { * (optional) Whether the change should be performed by the entity * definition update manager. */ - protected function updateEntityTypeToRevisionable($perform_update = FALSE) { + protected function updateEntityTypeToRevisionable($perform_update = FALSE): void { $translatable = $this->entityDefinitionUpdateManager->getEntityType('entity_test_update')->isTranslatable(); $updated_entity_type = $this->getUpdatedEntityTypeDefinition(TRUE, $translatable); @@ -154,7 +154,7 @@ trait EntityDefinitionTestTrait { * (optional) Whether the change should be performed by the entity * definition update manager. */ - protected function updateEntityTypeToNotRevisionable($perform_update = FALSE) { + protected function updateEntityTypeToNotRevisionable($perform_update = FALSE): void { $translatable = $this->entityDefinitionUpdateManager->getEntityType('entity_test_update')->isTranslatable(); $updated_entity_type = $this->getUpdatedEntityTypeDefinition(FALSE, $translatable); @@ -172,7 +172,7 @@ trait EntityDefinitionTestTrait { * (optional) Whether the change should be performed by the entity * definition update manager. */ - protected function updateEntityTypeToTranslatable($perform_update = FALSE) { + protected function updateEntityTypeToTranslatable($perform_update = FALSE): void { $revisionable = $this->entityDefinitionUpdateManager->getEntityType('entity_test_update')->isRevisionable(); $updated_entity_type = $this->getUpdatedEntityTypeDefinition($revisionable, TRUE); @@ -190,7 +190,7 @@ trait EntityDefinitionTestTrait { * (optional) Whether the change should be performed by the entity * definition update manager. */ - protected function updateEntityTypeToNotTranslatable($perform_update = FALSE) { + protected function updateEntityTypeToNotTranslatable($perform_update = FALSE): void { $revisionable = $this->entityDefinitionUpdateManager->getEntityType('entity_test_update')->isRevisionable(); $updated_entity_type = $this->getUpdatedEntityTypeDefinition($revisionable, FALSE); @@ -208,7 +208,7 @@ trait EntityDefinitionTestTrait { * (optional) Whether the change should be performed by the entity * definition update manager. */ - protected function updateEntityTypeToRevisionableAndTranslatable($perform_update = FALSE) { + protected function updateEntityTypeToRevisionableAndTranslatable($perform_update = FALSE): void { $updated_entity_type = $this->getUpdatedEntityTypeDefinition(TRUE, TRUE); $updated_field_storage_definitions = $this->getUpdatedFieldStorageDefinitions(TRUE, TRUE); @@ -235,7 +235,7 @@ trait EntityDefinitionTestTrait { * (optional) If the base field should be translatable or not. Defaults to * FALSE. */ - protected function addBaseField($type = 'string', $entity_type_id = 'entity_test_update', $is_revisionable = FALSE, $set_label = TRUE, $is_translatable = FALSE) { + protected function addBaseField($type = 'string', $entity_type_id = 'entity_test_update', $is_revisionable = FALSE, $set_label = TRUE, $is_translatable = FALSE): void { $definitions['new_base_field'] = BaseFieldDefinition::create($type) ->setName('new_base_field') ->setRevisionable($is_revisionable) @@ -251,7 +251,7 @@ trait EntityDefinitionTestTrait { /** * Adds a long-named base field to the 'entity_test_update' entity type. */ - protected function addLongNameBaseField() { + protected function addLongNameBaseField(): void { $key = 'entity_test_update.additional_base_field_definitions'; $definitions = $this->state->get($key, []); $definitions['new_long_named_entity_reference_base_field'] = BaseFieldDefinition::create('entity_reference') @@ -268,7 +268,7 @@ trait EntityDefinitionTestTrait { * @param string $type * (optional) The field type for the new field. Defaults to 'string'. */ - protected function addRevisionableBaseField($type = 'string') { + protected function addRevisionableBaseField($type = 'string'): void { $definitions['new_base_field'] = BaseFieldDefinition::create($type) ->setName('new_base_field') ->setLabel(t('A new revisionable base field')) @@ -279,14 +279,14 @@ trait EntityDefinitionTestTrait { /** * Modifies the new base field from 'string' to 'text'. */ - protected function modifyBaseField() { + protected function modifyBaseField(): void { $this->addBaseField('text'); } /** * Promotes a field to an entity key. */ - protected function makeBaseFieldEntityKey() { + protected function makeBaseFieldEntityKey(): void { $entity_type = clone \Drupal::entityTypeManager()->getDefinition('entity_test_update'); $entity_keys = $entity_type->getKeys(); $entity_keys['new_base_field'] = 'new_base_field'; @@ -300,21 +300,21 @@ trait EntityDefinitionTestTrait { * @param string $entity_type_id * (optional) The entity type ID the base field should be attached to. */ - protected function removeBaseField($entity_type_id = 'entity_test_update') { + protected function removeBaseField($entity_type_id = 'entity_test_update'): void { $this->state->delete($entity_type_id . '.additional_base_field_definitions'); } /** * Adds a single-field index to the base field. */ - protected function addBaseFieldIndex() { + protected function addBaseFieldIndex(): void { $this->state->set('entity_test_update.additional_field_index.entity_test_update.new_base_field', TRUE); } /** * Removes the index added in addBaseFieldIndex(). */ - protected function removeBaseFieldIndex() { + protected function removeBaseFieldIndex(): void { $this->state->delete('entity_test_update.additional_field_index.entity_test_update.new_base_field'); } @@ -328,7 +328,7 @@ trait EntityDefinitionTestTrait { * @param bool $translatable * (optional) Whether the field should be translatable. Defaults to FALSE. */ - protected function addBundleField($type = 'string', $revisionable = FALSE, $translatable = FALSE) { + protected function addBundleField($type = 'string', $revisionable = FALSE, $translatable = FALSE): void { $definitions['new_bundle_field'] = FieldStorageDefinition::create($type) ->setName('new_bundle_field') ->setLabel(t('A new bundle field')) @@ -342,14 +342,14 @@ trait EntityDefinitionTestTrait { /** * Modifies the new bundle field from 'string' to 'text'. */ - protected function modifyBundleField() { + protected function modifyBundleField(): void { $this->addBundleField('text'); } /** * Removes the new bundle field from the 'entity_test_update' entity type. */ - protected function removeBundleField() { + protected function removeBundleField(): void { $this->state->delete('entity_test_update.additional_field_storage_definitions'); $this->state->delete('entity_test_update.additional_bundle_field_definitions.test_bundle'); } @@ -359,7 +359,7 @@ trait EntityDefinitionTestTrait { * * @see \Drupal\entity_test\EntityTestStorageSchema::getEntitySchema() */ - protected function addEntityIndex() { + protected function addEntityIndex(): void { $indexes = [ 'entity_test_update__new_index' => ['name', 'test_single_property'], ]; @@ -369,14 +369,14 @@ trait EntityDefinitionTestTrait { /** * Removes the index added in addEntityIndex(). */ - protected function removeEntityIndex() { + protected function removeEntityIndex(): void { $this->state->delete('entity_test_update.additional_entity_indexes'); } /** * Renames the base table to 'entity_test_update_new'. */ - protected function renameBaseTable() { + protected function renameBaseTable(): void { $entity_type = clone \Drupal::entityTypeManager()->getDefinition('entity_test_update'); $entity_type->set('base_table', 'entity_test_update_new'); @@ -387,7 +387,7 @@ trait EntityDefinitionTestTrait { /** * Renames the data table to 'entity_test_update_data_new'. */ - protected function renameDataTable() { + protected function renameDataTable(): void { $entity_type = clone \Drupal::entityTypeManager()->getDefinition('entity_test_update'); $entity_type->set('data_table', 'entity_test_update_data_new'); @@ -398,7 +398,7 @@ trait EntityDefinitionTestTrait { /** * Renames the revision table to 'entity_test_update_revision_new'. */ - protected function renameRevisionBaseTable() { + protected function renameRevisionBaseTable(): void { $entity_type = clone \Drupal::entityTypeManager()->getDefinition('entity_test_update'); $entity_type->set('revision_table', 'entity_test_update_revision_new'); @@ -409,7 +409,7 @@ trait EntityDefinitionTestTrait { /** * Renames the revision data table to 'entity_test_update_revision_data_new'. */ - protected function renameRevisionDataTable() { + protected function renameRevisionDataTable(): void { $entity_type = clone \Drupal::entityTypeManager()->getDefinition('entity_test_update'); $entity_type->set('revision_data_table', 'entity_test_update_revision_data_new'); @@ -420,7 +420,7 @@ trait EntityDefinitionTestTrait { /** * Removes the entity type. */ - protected function deleteEntityType() { + protected function deleteEntityType(): void { $this->state->set('entity_test_update.entity_type', 'null'); } diff --git a/core/modules/system/tests/src/Functional/Menu/LinksetControllerMultiLingualTest.php b/core/modules/system/tests/src/Functional/Menu/LinksetControllerMultiLingualTest.php index d6b44d4bb9d9..b5e208474668 100644 --- a/core/modules/system/tests/src/Functional/Menu/LinksetControllerMultiLingualTest.php +++ b/core/modules/system/tests/src/Functional/Menu/LinksetControllerMultiLingualTest.php @@ -151,7 +151,7 @@ final class LinksetControllerMultiLingualTest extends LinksetControllerTestBase ]); foreach (['aa', 'bb', 'cc'] as $language_code) { $multi_lingual_menu_item->addTranslation($language_code, [ - 'title' => $language_code . '|' . 'A multi-lingual-node', + 'title' => $language_code . '|A multi-lingual-node', ]); $multi_lingual_menu_item->save(); } @@ -170,7 +170,7 @@ final class LinksetControllerMultiLingualTest extends LinksetControllerTestBase ]); foreach (['aa', 'bb'] as $language_code) { $multi_lingual_menu_item->addTranslation($language_code, [ - 'title' => $language_code . '|' . 'Second multi-lingual-node', + 'title' => $language_code . '|Second multi-lingual-node', ]); $multi_lingual_menu_item->save(); } @@ -189,7 +189,7 @@ final class LinksetControllerMultiLingualTest extends LinksetControllerTestBase ]); foreach (['aa', 'bb'] as $language_code) { $multi_lingual_menu_item->addTranslation($language_code, [ - 'title' => $language_code . '|' . 'Third multi-lingual-node', + 'title' => $language_code . '|Third multi-lingual-node', ]); $multi_lingual_menu_item->save(); } diff --git a/core/modules/system/tests/src/Functional/UpdateSystem/UpdatePathTestJavaScriptTest.php b/core/modules/system/tests/src/Functional/UpdateSystem/UpdatePathTestJavaScriptTest.php index ffaaba1119aa..32ca94f100b0 100644 --- a/core/modules/system/tests/src/Functional/UpdateSystem/UpdatePathTestJavaScriptTest.php +++ b/core/modules/system/tests/src/Functional/UpdateSystem/UpdatePathTestJavaScriptTest.php @@ -50,7 +50,7 @@ class UpdatePathTestJavaScriptTest extends BrowserTestBase { } // Source is a root-relative URL. Transform it to an absolute URL to allow // file_get_contents() to access the file. - $src = preg_replace('#^' . $GLOBALS['base_path'] . '(.*)#i', $GLOBALS['base_url'] . '/' . '${1}', $script->getAttribute('src')); + $src = preg_replace('#^' . $GLOBALS['base_path'] . '(.*)#i', $GLOBALS['base_url'] . '/${1}', $script->getAttribute('src')); $file_content = file_get_contents($src); if (str_contains($file_content, 'window.drupalSettings =')) { diff --git a/core/modules/system/tests/src/Kernel/System/CronQueueTest.php b/core/modules/system/tests/src/Kernel/System/CronQueueTest.php index 96a02f8f1644..069a26c3eb5f 100644 --- a/core/modules/system/tests/src/Kernel/System/CronQueueTest.php +++ b/core/modules/system/tests/src/Kernel/System/CronQueueTest.php @@ -70,7 +70,6 @@ class CronQueueTest extends KernelTestBase { parent::setUp(); $this->connection = Database::getConnection(); - $this->cron = \Drupal::service('cron'); $time = $this->prophesize('Drupal\Component\Datetime\TimeInterface'); $time->getCurrentTime()->willReturn($this->currentTime); @@ -91,6 +90,8 @@ class CronQueueTest extends KernelTestBase { }); $this->container->set('queue', $queue_factory->reveal()); + // Instantiate the `cron` service after the mock queue factory is set. + $this->cron = \Drupal::service('cron'); } /** diff --git a/core/modules/system/tests/themes/test_theme/test_theme.theme b/core/modules/system/tests/themes/test_theme/test_theme.theme index 80214af02d0b..d0b3b2b71bf1 100644 --- a/core/modules/system/tests/themes/test_theme/test_theme.theme +++ b/core/modules/system/tests/themes/test_theme/test_theme.theme @@ -54,7 +54,7 @@ function test_theme_theme_suggestions_alter(array &$suggestions, array &$variabl // the theme_suggestions_test module can be picked up when that module is // enabled. if ($hook == 'theme_test_general_suggestions') { - array_unshift($suggestions, 'theme_test_general_suggestions__' . 'theme_override'); + array_unshift($suggestions, 'theme_test_general_suggestions__theme_override'); $variables['theme_hook'] = 'test_theme_theme_suggestions_alter'; } } @@ -68,7 +68,7 @@ function test_theme_theme_suggestions_theme_test_suggestions_alter(array &$sugge // suggestion to the beginning of the array so that the suggestion added by // the theme_suggestions_test module can be picked up when that module is // enabled. - array_unshift($suggestions, 'theme_test_suggestions__' . 'theme_override'); + array_unshift($suggestions, 'theme_test_suggestions__theme_override'); } /** diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php index 4cc0a6f6eb61..82a88ce8a198 100644 --- a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php +++ b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php @@ -180,4 +180,9 @@ class TaxonomyHooks { } } + // phpcs:ignore Drupal.Commenting.InlineComment.DocBlock + /** + * @} End of "defgroup taxonomy_index". + */ + } diff --git a/core/modules/taxonomy/src/Plugin/views/field/TaxonomyIndexTid.php b/core/modules/taxonomy/src/Plugin/views/field/TaxonomyIndexTid.php index bf83b7067c52..b41086d059e2 100644 --- a/core/modules/taxonomy/src/Plugin/views/field/TaxonomyIndexTid.php +++ b/core/modules/taxonomy/src/Plugin/views/field/TaxonomyIndexTid.php @@ -174,10 +174,10 @@ class TaxonomyIndexTid extends PrerenderList { * {@inheritdoc} */ protected function documentSelfTokens(&$tokens) { - $tokens['{{ ' . $this->options['id'] . '__tid' . ' }}'] = $this->t('The taxonomy term ID for the term.'); - $tokens['{{ ' . $this->options['id'] . '__name' . ' }}'] = $this->t('The taxonomy term name for the term.'); - $tokens['{{ ' . $this->options['id'] . '__vocabulary_vid' . ' }}'] = $this->t('The machine name for the vocabulary the term belongs to.'); - $tokens['{{ ' . $this->options['id'] . '__vocabulary' . ' }}'] = $this->t('The name for the vocabulary the term belongs to.'); + $tokens['{{ ' . $this->options['id'] . '__tid }}'] = $this->t('The taxonomy term ID for the term.'); + $tokens['{{ ' . $this->options['id'] . '__name }}'] = $this->t('The taxonomy term name for the term.'); + $tokens['{{ ' . $this->options['id'] . '__vocabulary_vid }}'] = $this->t('The machine name for the vocabulary the term belongs to.'); + $tokens['{{ ' . $this->options['id'] . '__vocabulary }}'] = $this->t('The name for the vocabulary the term belongs to.'); } /** diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module index 04c00e36b6c2..28e54b11f71b 100644 --- a/core/modules/taxonomy/taxonomy.module +++ b/core/modules/taxonomy/taxonomy.module @@ -90,6 +90,11 @@ function taxonomy_term_is_page(Term $term) { } /** + * @addtogroup taxonomy_index + * @{ + */ + +/** * Builds and inserts taxonomy index entries for a given node. * * The index lists all terms that are related to a given node entity, and is @@ -152,5 +157,5 @@ function taxonomy_delete_node_index(EntityInterface $node): void { } /** - * @} End of "defgroup taxonomy_index". + * @} End of "addtogroup taxonomy_index". */ diff --git a/core/modules/toolbar/css/toolbar.theme.css b/core/modules/toolbar/css/toolbar.theme.css index ea108f658098..d6def4739400 100644 --- a/core/modules/toolbar/css/toolbar.theme.css +++ b/core/modules/toolbar/css/toolbar.theme.css @@ -5,10 +5,10 @@ font-family: "Source Sans Pro", "Lucida Grande", Verdana, sans-serif; /* Set base font size to 13px based on root ems. */ font-size: 0.8125rem; - -moz-tap-highlight-color: rgba(0, 0, 0, 0); - -o-tap-highlight-color: rgba(0, 0, 0, 0); - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); - tap-highlight-color: rgba(0, 0, 0, 0); + -moz-tap-highlight-color: rgb(0, 0, 0, 0); + -o-tap-highlight-color: rgb(0, 0, 0, 0); + -webkit-tap-highlight-color: rgb(0, 0, 0, 0); + tap-highlight-color: rgb(0, 0, 0, 0); -moz-touch-callout: none; -o-touch-callout: none; -webkit-touch-callout: none; @@ -31,10 +31,10 @@ .toolbar .toolbar-bar { color: #ddd; background-color: #0f0f0f; - box-shadow: -1px 0 3px 1px rgba(0, 0, 0, 0.3333); /* LTR */ + box-shadow: -1px 0 3px 1px rgb(0, 0, 0, 0.3333); /* LTR */ } [dir="rtl"] .toolbar .toolbar-bar { - box-shadow: 1px 0 3px 1px rgba(0, 0, 0, 0.3333); + box-shadow: 1px 0 3px 1px rgb(0, 0, 0, 0.3333); } .toolbar .toolbar-bar .toolbar-item { color: #fff; @@ -44,7 +44,7 @@ } .toolbar .toolbar-bar .toolbar-tab > .toolbar-item:hover, .toolbar .toolbar-bar .toolbar-tab > .toolbar-item:focus { - background-image: linear-gradient(rgba(255, 255, 255, 0.125) 20%, transparent 200%); + background-image: linear-gradient(rgb(255, 255, 255, 0.125) 20%, transparent 200%); } .toolbar .toolbar-bar .toolbar-tab > .toolbar-item.is-active { color: #000; @@ -68,19 +68,19 @@ .toolbar .toolbar-tray-vertical { border-right: 1px solid #aaa; /* LTR */ background-color: #f5f5f5; - box-shadow: -1px 0 5px 2px rgba(0, 0, 0, 0.3333); /* LTR */ + box-shadow: -1px 0 5px 2px rgb(0, 0, 0, 0.3333); /* LTR */ } [dir="rtl"] .toolbar .toolbar-tray-vertical { border-right: 0 none; border-left: 1px solid #aaa; - box-shadow: 1px 0 5px 2px rgba(0, 0, 0, 0.3333); + box-shadow: 1px 0 5px 2px rgb(0, 0, 0, 0.3333); } .toolbar-horizontal .toolbar-tray { border-bottom: 1px solid #aaa; - box-shadow: -2px 1px 3px 1px rgba(0, 0, 0, 0.3333); /* LTR */ + box-shadow: -2px 1px 3px 1px rgb(0, 0, 0, 0.3333); /* LTR */ } [dir="rtl"] .toolbar-horizontal .toolbar-tray { - box-shadow: 2px 1px 3px 1px rgba(0, 0, 0, 0.3333); + box-shadow: 2px 1px 3px 1px rgb(0, 0, 0, 0.3333); } .toolbar .toolbar-tray-horizontal .toolbar-tray { background-color: #f5f5f5; diff --git a/core/modules/user/src/Plugin/views/field/Roles.php b/core/modules/user/src/Plugin/views/field/Roles.php index 096e161a3f9e..bc1ab4fb2841 100644 --- a/core/modules/user/src/Plugin/views/field/Roles.php +++ b/core/modules/user/src/Plugin/views/field/Roles.php @@ -108,8 +108,8 @@ class Roles extends PrerenderList { * {@inheritdoc} */ protected function documentSelfTokens(&$tokens) { - $tokens['{{ ' . $this->options['id'] . '__role' . ' }}'] = $this->t('The name of the role.'); - $tokens['{{ ' . $this->options['id'] . '__rid' . ' }}'] = $this->t('The role machine-name of the role.'); + $tokens['{{ ' . $this->options['id'] . '__role }}'] = $this->t('The name of the role.'); + $tokens['{{ ' . $this->options['id'] . '__rid }}'] = $this->t('The role machine-name of the role.'); } /** diff --git a/core/modules/views/src/Plugin/views/argument/DayDate.php b/core/modules/views/src/Plugin/views/argument/DayDate.php index 884355a72a4b..a4a94da06998 100644 --- a/core/modules/views/src/Plugin/views/argument/DayDate.php +++ b/core/modules/views/src/Plugin/views/argument/DayDate.php @@ -29,7 +29,7 @@ class DayDate extends Date { $day = str_pad($data->{$this->name_alias}, 2, '0', STR_PAD_LEFT); // strtotime() respects server timezone, so we need to set the time fixed // as utc time - return $this->dateFormatter->format(strtotime("2005" . "05" . $day . " 00:00:00 UTC"), 'custom', $this->format, 'UTC'); + return $this->dateFormatter->format(strtotime("200505" . $day . " 00:00:00 UTC"), 'custom', $this->format, 'UTC'); } /** @@ -37,7 +37,7 @@ class DayDate extends Date { */ public function title() { $day = str_pad($this->argument, 2, '0', STR_PAD_LEFT); - return $this->dateFormatter->format(strtotime("2005" . "05" . $day . " 00:00:00 UTC"), 'custom', $this->format, 'UTC'); + return $this->dateFormatter->format(strtotime("200505" . $day . " 00:00:00 UTC"), 'custom', $this->format, 'UTC'); } /** diff --git a/core/modules/views/src/Plugin/views/argument/MonthDate.php b/core/modules/views/src/Plugin/views/argument/MonthDate.php index cec2159c9a3d..a24f23f120d9 100644 --- a/core/modules/views/src/Plugin/views/argument/MonthDate.php +++ b/core/modules/views/src/Plugin/views/argument/MonthDate.php @@ -28,7 +28,7 @@ class MonthDate extends Date { public function summaryName($data) { $month = str_pad($data->{$this->name_alias}, 2, '0', STR_PAD_LEFT); try { - return $this->dateFormatter->format(strtotime("2005" . $month . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC'); + return $this->dateFormatter->format(strtotime("2005" . $month . "15 00:00:00 UTC"), 'custom', $this->format, 'UTC'); } catch (\InvalidArgumentException) { return parent::summaryName($data); @@ -41,7 +41,7 @@ class MonthDate extends Date { public function title() { $month = str_pad($this->argument, 2, '0', STR_PAD_LEFT); try { - return $this->dateFormatter->format(strtotime("2005" . $month . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC'); + return $this->dateFormatter->format(strtotime("2005" . $month . "15 00:00:00 UTC"), 'custom', $this->format, 'UTC'); } catch (\InvalidArgumentException) { return parent::title(); diff --git a/core/modules/views/src/Plugin/views/argument/YearMonthDate.php b/core/modules/views/src/Plugin/views/argument/YearMonthDate.php index 16410ad25564..b82071f6d6ae 100644 --- a/core/modules/views/src/Plugin/views/argument/YearMonthDate.php +++ b/core/modules/views/src/Plugin/views/argument/YearMonthDate.php @@ -27,14 +27,14 @@ class YearMonthDate extends Date { */ public function summaryName($data) { $created = $data->{$this->name_alias}; - return $this->dateFormatter->format(strtotime($created . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC'); + return $this->dateFormatter->format(strtotime($created . "15 00:00:00 UTC"), 'custom', $this->format, 'UTC'); } /** * {@inheritdoc} */ public function title() { - return $this->dateFormatter->format(strtotime($this->argument . "15" . " 00:00:00 UTC"), 'custom', $this->format, 'UTC'); + return $this->dateFormatter->format(strtotime($this->argument . "15 00:00:00 UTC"), 'custom', $this->format, 'UTC'); } } diff --git a/core/modules/views/src/Plugin/views/pager/PagerPluginBase.php b/core/modules/views/src/Plugin/views/pager/PagerPluginBase.php index 3356d703c93d..5796488746cc 100644 --- a/core/modules/views/src/Plugin/views/pager/PagerPluginBase.php +++ b/core/modules/views/src/Plugin/views/pager/PagerPluginBase.php @@ -29,14 +29,18 @@ abstract class PagerPluginBase extends PluginBase { /** * The current page. + * + * @phpcs:ignore Drupal.Commenting.VariableComment.MissingVar */ - // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName, Drupal.Commenting.VariableComment.Missing + // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName public $current_page = NULL; /** * The total number of lines. + * + * @phpcs:ignore Drupal.Commenting.VariableComment.MissingVar */ - // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName, Drupal.Commenting.VariableComment.Missing + // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName public $total_items = 0; /** diff --git a/core/modules/views/src/Plugin/views/style/StylePluginBase.php b/core/modules/views/src/Plugin/views/style/StylePluginBase.php index 3f555cfec9fd..ca8df3ba8fef 100644 --- a/core/modules/views/src/Plugin/views/style/StylePluginBase.php +++ b/core/modules/views/src/Plugin/views/style/StylePluginBase.php @@ -85,12 +85,12 @@ abstract class StylePluginBase extends PluginBase { /** * Stores the rendered field values, keyed by the row index and field name. * + * @var array|null + * * @see \Drupal\views\Plugin\views\style\StylePluginBase::renderFields() * @see \Drupal\views\Plugin\views\style\StylePluginBase::getField() - * - * @var array|null */ - // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName, Drupal.Commenting.VariableComment.Missing + // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName protected $rendered_fields; /** diff --git a/core/modules/views/src/ViewExecutable.php b/core/modules/views/src/ViewExecutable.php index 4867ba48f9a6..407260ed285d 100644 --- a/core/modules/views/src/ViewExecutable.php +++ b/core/modules/views/src/ViewExecutable.php @@ -400,21 +400,21 @@ class ViewExecutable { /** * Force the query to calculate the total number of results. * - * @todo Move to the query. - * * @var bool + * + * @todo Move to the query. */ - // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName, Drupal.Commenting.VariableComment.Missing + // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName public $get_total_rows; /** * Indicates if the sorts have been built. * - * @todo Group with other static properties. - * * @var bool + * + * @todo Group with other static properties. */ - // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName, Drupal.Commenting.VariableComment.Missing + // phpcs:ignore Drupal.NamingConventions.ValidVariableName.LowerCamelName public $build_sort; /** diff --git a/core/modules/views_ui/css/views_ui.admin.theme.css b/core/modules/views_ui/css/views_ui.admin.theme.css index 529e8fa77c63..554d5044cb79 100644 --- a/core/modules/views_ui/css/views_ui.admin.theme.css +++ b/core/modules/views_ui/css/views_ui.admin.theme.css @@ -39,11 +39,11 @@ background: linear-gradient(-90deg, #fff 0, #e8e8e8 100%) no-repeat, repeat-y; - box-shadow: 0 0 0 rgba(0, 0, 0, 0.3333) inset; + box-shadow: 0 0 0 rgb(0, 0, 0, 0.3333) inset; } .views-admin a.icon:hover { border-color: #d0d0d0; - box-shadow: 0 0 1px rgba(0, 0, 0, 0.3333) inset; + box-shadow: 0 0 1px rgb(0, 0, 0, 0.3333) inset; } .views-admin a.icon:active { border-color: #c0c0c0; diff --git a/core/modules/views_ui/src/Form/Ajax/AddHandler.php b/core/modules/views_ui/src/Form/Ajax/AddHandler.php index 2f5c9590bc2c..1934593779e3 100644 --- a/core/modules/views_ui/src/Form/Ajax/AddHandler.php +++ b/core/modules/views_ui/src/Form/Ajax/AddHandler.php @@ -169,7 +169,7 @@ class AddHandler extends ViewsFormBase { // Add a div to show the selected items $form['selected'] = [ '#type' => 'item', - '#markup' => '<span class="views-ui-view-title">' . $this->t('Selected:') . '</span> ' . '<div class="views-selected-options"></div>', + '#markup' => '<span class="views-ui-view-title">' . $this->t('Selected:') . '</span><div class="views-selected-options"></div>', '#theme_wrappers' => ['form_element', 'views_ui_container'], '#attributes' => [ 'class' => ['container-inline', 'views-add-form-selected', 'views-offset-bottom'], diff --git a/core/modules/workflows/src/Plugin/WorkflowTypeBase.php b/core/modules/workflows/src/Plugin/WorkflowTypeBase.php index 47488b38801b..e86b77a22857 100644 --- a/core/modules/workflows/src/Plugin/WorkflowTypeBase.php +++ b/core/modules/workflows/src/Plugin/WorkflowTypeBase.php @@ -2,7 +2,7 @@ namespace Drupal\workflows\Plugin; -use Drupal\Component\Plugin\PluginBase; +use Drupal\Core\Plugin\ConfigurablePluginBase; use Drupal\Core\Plugin\PluginWithFormsTrait; use Drupal\workflows\State; use Drupal\workflows\StateInterface; @@ -16,7 +16,7 @@ use Drupal\workflows\WorkflowTypeInterface; * * @see \Drupal\workflows\Annotation\WorkflowType */ -abstract class WorkflowTypeBase extends PluginBase implements WorkflowTypeInterface { +abstract class WorkflowTypeBase extends ConfigurablePluginBase implements WorkflowTypeInterface { use PluginWithFormsTrait; @@ -28,14 +28,6 @@ abstract class WorkflowTypeBase extends PluginBase implements WorkflowTypeInterf /** * {@inheritdoc} */ - public function __construct(array $configuration, $plugin_id, $plugin_definition) { - parent::__construct($configuration, $plugin_id, $plugin_definition); - $this->setConfiguration($configuration); - } - - /** - * {@inheritdoc} - */ public function label() { $definition = $this->getPluginDefinition(); // The label can be an object. @@ -60,15 +52,9 @@ abstract class WorkflowTypeBase extends PluginBase implements WorkflowTypeInterf /** * {@inheritdoc} */ - public function getConfiguration() { - return $this->configuration; - } - - /** - * {@inheritdoc} - */ public function setConfiguration(array $configuration) { $this->configuration = $configuration + $this->defaultConfiguration(); + return $this; } /** diff --git a/core/modules/workspaces/css/workspaces.toolbar.pcss.css b/core/modules/workspaces/css/workspaces.toolbar.pcss.css index 84b3fa8f986f..a603d53949cd 100644 --- a/core/modules/workspaces/css/workspaces.toolbar.pcss.css +++ b/core/modules/workspaces/css/workspaces.toolbar.pcss.css @@ -52,7 +52,7 @@ text-align: start; color: inherit; - @nest .toolbar-oriented & { + .toolbar-oriented & { width: auto; text-align: initial; } diff --git a/core/modules/workspaces/src/Controller/WorkspacesHtmlEntityFormController.php b/core/modules/workspaces/src/Controller/WorkspacesHtmlEntityFormController.php index 6f9d6d5b6563..aa5aa49f9d20 100644 --- a/core/modules/workspaces/src/Controller/WorkspacesHtmlEntityFormController.php +++ b/core/modules/workspaces/src/Controller/WorkspacesHtmlEntityFormController.php @@ -35,11 +35,16 @@ class WorkspacesHtmlEntityFormController extends FormController { */ public function getContentResult(Request $request, RouteMatchInterface $route_match): array { $form_arg = $this->getFormArgument($route_match); - $form_object = $this->getFormObject($route_match, $form_arg); + // If no operation is provided, use 'default'. + $form_arg .= '.default'; + [$entity_type_id, $operation] = explode('.', $form_arg); - /** @var \Drupal\Core\Entity\EntityInterface $entity */ - $entity = $form_object->getEntity(); - if ($this->workspaceInfo->isEntitySupported($entity)) { + if ($route_match->getRawParameter($entity_type_id) !== NULL) { + /** @var \Drupal\Core\Entity\EntityInterface $entity */ + $entity = $route_match->getParameter($entity_type_id); + } + + if (isset($entity) && $this->workspaceInfo->isEntitySupported($entity)) { $active_workspace = $this->workspaceManager->getActiveWorkspace(); // Prepare a minimal render array in case we need to return it. @@ -48,7 +53,7 @@ class WorkspacesHtmlEntityFormController extends FormController { $build['#cache']['max-age'] = $entity->getCacheMaxAge(); // Prevent entities from being edited if they're tracked in workspace. - if ($form_object->getOperation() !== 'delete') { + if ($operation !== 'delete') { $constraints = array_values(array_filter($entity->getTypedData()->getConstraints(), function ($constraint) { return $constraint instanceof EntityWorkspaceConflictConstraint; })); @@ -68,7 +73,7 @@ class WorkspacesHtmlEntityFormController extends FormController { // Prevent entities from being deleted in a workspace if they have a // published default revision. - if ($form_object->getOperation() === 'delete' && $active_workspace && !$this->workspaceInfo->isEntityDeletable($entity, $active_workspace)) { + if ($operation === 'delete' && $active_workspace && !$this->workspaceInfo->isEntityDeletable($entity, $active_workspace)) { $build['#markup'] = $this->t('This @entity_type_label can only be deleted in the Live workspace.', [ '@entity_type_label' => $entity->getEntityType()->getSingularLabel(), ]); diff --git a/core/modules/workspaces/tests/modules/workspaces_test/src/Hook/WorkspacesTestHooks.php b/core/modules/workspaces/tests/modules/workspaces_test/src/Hook/WorkspacesTestHooks.php index d452d343ca3d..d5d64ca55495 100644 --- a/core/modules/workspaces/tests/modules/workspaces_test/src/Hook/WorkspacesTestHooks.php +++ b/core/modules/workspaces/tests/modules/workspaces_test/src/Hook/WorkspacesTestHooks.php @@ -4,13 +4,21 @@ declare(strict_types=1); namespace Drupal\workspaces_test\Hook; +use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Hook\Attribute\Hook; +use Drupal\Core\KeyValueStore\KeyValueFactoryInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; /** * Hook implementations for workspaces_test. */ class WorkspacesTestHooks { + public function __construct( + #[Autowire(service: 'keyvalue')] + protected readonly KeyValueFactoryInterface $keyValueFactory, + ) {} + /** * Implements hook_entity_type_alter(). */ @@ -31,7 +39,53 @@ class WorkspacesTestHooks { public function entityTranslationCreate(): void { /** @var \Drupal\workspaces\WorkspaceManagerInterface $workspace_manager */ $workspace_manager = \Drupal::service('workspaces.manager'); - \Drupal::keyValue('ws_test')->set('workspace_was_active', $workspace_manager->hasActiveWorkspace()); + $this->keyValueFactory->get('ws_test')->set('workspace_was_active', $workspace_manager->hasActiveWorkspace()); + } + + /** + * Implements hook_entity_create(). + */ + #[Hook('entity_create')] + public function entityCreate(EntityInterface $entity): void { + $this->incrementHookCount('hook_entity_create', $entity); + } + + /** + * Implements hook_entity_presave(). + */ + #[Hook('entity_presave')] + public function entityPresave(EntityInterface $entity): void { + $this->incrementHookCount('hook_entity_presave', $entity); + } + + /** + * Implements hook_entity_insert(). + */ + #[Hook('entity_insert')] + public function entityInsert(EntityInterface $entity): void { + $this->incrementHookCount('hook_entity_insert', $entity); + } + + /** + * Implements hook_entity_update(). + */ + #[Hook('entity_update')] + public function entityUpdate(EntityInterface $entity): void { + $this->incrementHookCount('hook_entity_update', $entity); + } + + /** + * Increments the invocation count for a specific entity hook. + * + * @param string $hook_name + * The name of the hook being invoked (e.g., 'hook_entity_create'). + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object involved in the hook. + */ + protected function incrementHookCount(string $hook_name, EntityInterface $entity): void { + $key = $entity->getEntityTypeId() . '.' . $hook_name . '.count'; + $count = $this->keyValueFactory->get('ws_test')->get($key, 0); + $this->keyValueFactory->get('ws_test')->set($key, $count + 1); } } diff --git a/core/modules/workspaces/tests/src/Functional/PathWorkspacesTest.php b/core/modules/workspaces/tests/src/Functional/PathWorkspacesTest.php index c3fe0e722a2e..19007def89d9 100644 --- a/core/modules/workspaces/tests/src/Functional/PathWorkspacesTest.php +++ b/core/modules/workspaces/tests/src/Functional/PathWorkspacesTest.php @@ -7,7 +7,6 @@ namespace Drupal\Tests\workspaces\Functional; use Drupal\Tests\BrowserTestBase; use Drupal\Tests\content_translation\Traits\ContentTranslationTestTrait; use Drupal\Tests\WaitTerminateTestTrait; -use Drupal\workspaces\Entity\Workspace; /** * Tests path aliases with workspaces. @@ -91,9 +90,8 @@ class PathWorkspacesTest extends BrowserTestBase { 'status' => TRUE, ]); - // Switch to Stage and create an alias for the node. - $stage = Workspace::load('stage'); - $this->switchToWorkspace($stage); + // Activate a workspace and create an alias for the node. + $stage = $this->createAndActivateWorkspaceThroughUi('Stage', 'stage'); $edit = [ 'path[0][alias]' => '/' . $this->randomMachineName(), @@ -131,9 +129,8 @@ class PathWorkspacesTest extends BrowserTestBase { 'status' => TRUE, ]); - // Switch to Stage and create an alias for the node. - $stage = Workspace::load('stage'); - $this->switchToWorkspace($stage); + // Activate a workspace and create an alias for the node. + $stage = $this->createAndActivateWorkspaceThroughUi('Stage', 'stage'); $edit = [ 'path[0][alias]' => '/' . $this->randomMachineName(), @@ -169,7 +166,7 @@ class PathWorkspacesTest extends BrowserTestBase { * Tests path aliases with workspaces for translatable nodes. */ public function testPathAliasesWithTranslation(): void { - $stage = Workspace::load('stage'); + $stage = $this->createWorkspaceThroughUi('Stage', 'stage'); // Create one node with a random alias. $default_node = $this->drupalCreateNode([ diff --git a/core/modules/workspaces/tests/src/Functional/Rest/WorkspaceResourceTestBase.php b/core/modules/workspaces/tests/src/Functional/Rest/WorkspaceResourceTestBase.php index b998af426b25..3cbddf127d9a 100644 --- a/core/modules/workspaces/tests/src/Functional/Rest/WorkspaceResourceTestBase.php +++ b/core/modules/workspaces/tests/src/Functional/Rest/WorkspaceResourceTestBase.php @@ -123,7 +123,7 @@ abstract class WorkspaceResourceTestBase extends EntityResourceTestBase { ], 'revision_id' => [ [ - 'value' => 2, + 'value' => 1, ], ], 'parent' => [], diff --git a/core/modules/workspaces/tests/src/Functional/WorkspaceCacheContextTest.php b/core/modules/workspaces/tests/src/Functional/WorkspaceCacheContextTest.php index 2109552e7619..9f9dad806f66 100644 --- a/core/modules/workspaces/tests/src/Functional/WorkspaceCacheContextTest.php +++ b/core/modules/workspaces/tests/src/Functional/WorkspaceCacheContextTest.php @@ -66,17 +66,22 @@ class WorkspaceCacheContextTest extends BrowserTestBase { $cache_bin = $variation_cache_factory->get($build['#cache']['bin']); $this->assertInstanceOf(\stdClass::class, $cache_bin->get($build['#cache']['keys'], CacheableMetadata::createFromRenderArray($build))); - // Switch to the 'stage' workspace and check that the correct workspace - // cache context is used. + // Switch to the test workspace and check that the correct workspace cache + // context is used. $test_user = $this->drupalCreateUser(['view any workspace']); $this->drupalLogin($test_user); - $stage = Workspace::load('stage'); + $vultures = Workspace::create([ + 'id' => 'vultures', + 'label' => 'Vultures', + ]); + $vultures->save(); + $workspace_manager = \Drupal::service('workspaces.manager'); - $workspace_manager->setActiveWorkspace($stage); + $workspace_manager->setActiveWorkspace($vultures); $cache_context = new WorkspaceCacheContext($workspace_manager); - $this->assertSame('stage', $cache_context->getContext()); + $this->assertSame('vultures', $cache_context->getContext()); $build = \Drupal::entityTypeManager()->getViewBuilder('node')->view($node, 'full'); @@ -85,7 +90,7 @@ class WorkspaceCacheContextTest extends BrowserTestBase { $this->assertContains('workspace', $build['#cache']['contexts']); $context_tokens = $cache_contexts_manager->convertTokensToKeys($build['#cache']['contexts'])->getKeys(); - $this->assertContains('[workspace]=stage', $context_tokens); + $this->assertContains('[workspace]=vultures', $context_tokens); // Test that a cache entry is created. $cache_bin = $variation_cache_factory->get($build['#cache']['bin']); diff --git a/core/modules/workspaces/tests/src/Functional/WorkspaceEntityDeleteTest.php b/core/modules/workspaces/tests/src/Functional/WorkspaceEntityDeleteTest.php index 165eb6c1d959..25ce72c1af41 100644 --- a/core/modules/workspaces/tests/src/Functional/WorkspaceEntityDeleteTest.php +++ b/core/modules/workspaces/tests/src/Functional/WorkspaceEntityDeleteTest.php @@ -5,7 +5,6 @@ declare(strict_types=1); namespace Drupal\Tests\workspaces\Functional; use Drupal\Tests\BrowserTestBase; -use Drupal\workspaces\Entity\Workspace; /** * Tests entity deletions with workspaces. @@ -56,7 +55,7 @@ class WorkspaceEntityDeleteTest extends BrowserTestBase { $this->drupalLogin($editor); // Create a Dev workspace as a child of Stage. - $stage = Workspace::load('stage'); + $stage = $this->createWorkspaceThroughUi('Stage', 'stage'); $dev = $this->createWorkspaceThroughUi('Dev', 'dev', 'stage'); // Create a published and an unpublished node in Live. @@ -141,8 +140,7 @@ class WorkspaceEntityDeleteTest extends BrowserTestBase { // Create a published node in Live. $published_live = $this->createNodeThroughUi('Test 1 published - live', 'article'); - $stage = Workspace::load('stage'); - $this->switchToWorkspace($stage); + $this->createAndActivateWorkspaceThroughUi('Stage', 'stage'); // A user with the 'bypass node access' permission will be able to see the // 'Delete' operation button, but it shouldn't be able to perform the diff --git a/core/modules/workspaces/tests/src/Functional/WorkspaceFormValidationTest.php b/core/modules/workspaces/tests/src/Functional/WorkspaceFormValidationTest.php index efd3bef34c21..f01c554cea7a 100644 --- a/core/modules/workspaces/tests/src/Functional/WorkspaceFormValidationTest.php +++ b/core/modules/workspaces/tests/src/Functional/WorkspaceFormValidationTest.php @@ -5,7 +5,6 @@ declare(strict_types=1); namespace Drupal\Tests\workspaces\Functional; use Drupal\Tests\BrowserTestBase; -use Drupal\workspaces\Entity\Workspace; /** * Tests Workspaces form validation. @@ -40,8 +39,7 @@ class WorkspaceFormValidationTest extends BrowserTestBase { * Tests partial form validation through #limit_validation_errors. */ public function testValidateLimitErrors(): void { - $stage = Workspace::load('stage'); - $this->switchToWorkspace($stage); + $this->createAndActivateWorkspaceThroughUi(); $edit = [ 'test' => 'test1', diff --git a/core/modules/workspaces/tests/src/Functional/WorkspaceMenuLinkContentIntegrationTest.php b/core/modules/workspaces/tests/src/Functional/WorkspaceMenuLinkContentIntegrationTest.php index 864ac8c1a365..75f6db02b153 100644 --- a/core/modules/workspaces/tests/src/Functional/WorkspaceMenuLinkContentIntegrationTest.php +++ b/core/modules/workspaces/tests/src/Functional/WorkspaceMenuLinkContentIntegrationTest.php @@ -5,7 +5,6 @@ declare(strict_types=1); namespace Drupal\Tests\workspaces\Functional; use Drupal\Tests\BrowserTestBase; -use Drupal\workspaces\Entity\Workspace; /** * Tests workspace integration for custom menu links. @@ -61,7 +60,7 @@ class WorkspaceMenuLinkContentIntegrationTest extends BrowserTestBase { * Tests custom menu links in non-default workspaces. */ public function testWorkspacesWithCustomMenuLinks(): void { - $stage = Workspace::load('stage'); + $stage = $this->createWorkspaceThroughUi('Stage', 'stage'); $this->setupWorkspaceSwitcherBlock(); diff --git a/core/modules/workspaces/tests/src/Functional/WorkspaceSwitcherTest.php b/core/modules/workspaces/tests/src/Functional/WorkspaceSwitcherTest.php index d7ac36a5e889..eef28c5ff65f 100644 --- a/core/modules/workspaces/tests/src/Functional/WorkspaceSwitcherTest.php +++ b/core/modules/workspaces/tests/src/Functional/WorkspaceSwitcherTest.php @@ -7,6 +7,7 @@ namespace Drupal\Tests\workspaces\Functional; use Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber; use Drupal\Tests\BrowserTestBase; use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait; +use Drupal\workspaces\Entity\Workspace; /** * Tests workspace switching functionality. @@ -52,14 +53,18 @@ class WorkspaceSwitcherTest extends BrowserTestBase { $mayer = $this->drupalCreateUser($permissions); $this->drupalLogin($mayer); + + $this->createWorkspaceThroughUi('Vultures', 'vultures'); + $this->createWorkspaceThroughUi('Gravity', 'gravity'); } /** * Tests switching workspace via the switcher block and admin page. */ public function testSwitchingWorkspaces(): void { - $this->createAndActivateWorkspaceThroughUi('Vultures', 'vultures'); - $gravity = $this->createWorkspaceThroughUi('Gravity', 'gravity'); + $vultures = Workspace::load('vultures'); + $gravity = Workspace::load('gravity'); + $this->switchToWorkspace($vultures); // Confirm the block shows on the front page. $this->drupalGet('<front>'); @@ -89,12 +94,12 @@ class WorkspaceSwitcherTest extends BrowserTestBase { // When adding a query parameter the workspace will be switched. $current_user_url = \Drupal::currentUser()->getAccount()->toUrl(); - $this->drupalGet($current_user_url, ['query' => ['workspace' => 'stage']]); - $web_assert->elementContains('css', '#block-workspace-switcher', 'Stage'); + $this->drupalGet($current_user_url, ['query' => ['workspace' => 'vultures']]); + $web_assert->elementContains('css', '#block-workspace-switcher', 'Vultures'); // The workspace switching via query parameter should persist. $this->drupalGet($current_user_url); - $web_assert->elementContains('css', '#block-workspace-switcher', 'Stage'); + $web_assert->elementContains('css', '#block-workspace-switcher', 'Vultures'); // Check that WorkspaceCacheContext provides the cache context used to // support its functionality. diff --git a/core/modules/workspaces/tests/src/Functional/WorkspaceTest.php b/core/modules/workspaces/tests/src/Functional/WorkspaceTest.php index 0684f46467e0..b632e60efd50 100644 --- a/core/modules/workspaces/tests/src/Functional/WorkspaceTest.php +++ b/core/modules/workspaces/tests/src/Functional/WorkspaceTest.php @@ -33,6 +33,7 @@ class WorkspaceTest extends BrowserTestBase { 'user', 'workspaces', 'workspaces_ui', + 'workspaces_test', ]; /** @@ -157,6 +158,7 @@ class WorkspaceTest extends BrowserTestBase { public function testWorkspaceFormRevisions(): void { $this->drupalLogin($this->editor1); $storage = \Drupal::entityTypeManager()->getStorage('workspace'); + $this->createWorkspaceThroughUi('Stage', 'stage'); // The current 'stage' workspace entity should be revision 1. $stage_workspace = $storage->load('stage'); @@ -334,7 +336,7 @@ class WorkspaceTest extends BrowserTestBase { $user->delete(); $this->drupalGet('/admin/config/workflow/workspaces'); $this->assertSession()->pageTextContains('Summer event'); - $summer_event_workspace_row = $page->find('css', 'table tbody tr:nth-of-type(3)'); + $summer_event_workspace_row = $page->find('css', 'table tbody tr:nth-of-type(2)'); $this->assertEquals('N/A', $summer_event_workspace_row->find('css', 'td:nth-of-type(2)')->getText()); } @@ -364,7 +366,9 @@ class WorkspaceTest extends BrowserTestBase { $this->assertSession()->pageTextContains('There are no changes that can be published from Test workspace to Live.'); // Create a node in the workspace. - $this->createNodeThroughUi('Test node', 'test'); + $this->drupalGet('/node/add/test'); + $this->assertEquals(1, \Drupal::keyValue('ws_test')->get('node.hook_entity_create.count')); + $this->submitForm(['title[0][value]' => 'Test node'], 'Save'); $this->drupalGet('/admin/config/workflow/workspaces/manage/test_workspace/publish'); $this->assertSession()->statusCodeEquals(200); diff --git a/core/modules/workspaces/tests/src/Functional/WorkspaceTestUtilities.php b/core/modules/workspaces/tests/src/Functional/WorkspaceTestUtilities.php index 7f4230b07733..56e91d8a26ba 100644 --- a/core/modules/workspaces/tests/src/Functional/WorkspaceTestUtilities.php +++ b/core/modules/workspaces/tests/src/Functional/WorkspaceTestUtilities.php @@ -56,9 +56,9 @@ trait WorkspaceTestUtilities { /** * Creates and activates a new Workspace through the UI. * - * @param string $label + * @param string|null $label * The label of the workspace to create. - * @param string $id + * @param string|null $id * The ID of the workspace to create. * @param string $parent * (optional) The ID of the parent workspace. Defaults to '_none'. @@ -66,7 +66,10 @@ trait WorkspaceTestUtilities { * @return \Drupal\workspaces\WorkspaceInterface * The workspace that was just created. */ - protected function createAndActivateWorkspaceThroughUi(string $label, string $id, string $parent = '_none'): WorkspaceInterface { + protected function createAndActivateWorkspaceThroughUi(?string $label = NULL, ?string $id = NULL, string $parent = '_none'): WorkspaceInterface { + $id ??= $this->randomMachineName(); + $label ??= $this->randomString(); + $this->drupalGet('/admin/config/workflow/workspaces/add'); $this->submitForm([ 'id' => $id, @@ -76,15 +79,19 @@ trait WorkspaceTestUtilities { $this->getSession()->getPage()->hasContent("$label ($id)"); - return Workspace::load($id); + // Keep the test runner in sync with the system under test. + $workspace = Workspace::load($id); + \Drupal::service('workspaces.manager')->setActiveWorkspace($workspace); + + return $workspace; } /** * Creates a new Workspace through the UI. * - * @param string $label + * @param string|null $label * The label of the workspace to create. - * @param string $id + * @param string|null $id * The ID of the workspace to create. * @param string $parent * (optional) The ID of the parent workspace. Defaults to '_none'. @@ -92,7 +99,10 @@ trait WorkspaceTestUtilities { * @return \Drupal\workspaces\WorkspaceInterface * The workspace that was just created. */ - protected function createWorkspaceThroughUi($label, $id, $parent = '_none') { + protected function createWorkspaceThroughUi(?string $label = NULL, ?string $id = NULL, string $parent = '_none') { + $id ??= $this->randomMachineName(); + $label ??= $this->randomString(); + $this->drupalGet('/admin/config/workflow/workspaces/add'); $this->submitForm([ 'id' => $id, diff --git a/core/modules/workspaces/tests/src/Functional/WorkspaceViewsBulkFormTest.php b/core/modules/workspaces/tests/src/Functional/WorkspaceViewsBulkFormTest.php index de8795b644ab..92b2673341e6 100644 --- a/core/modules/workspaces/tests/src/Functional/WorkspaceViewsBulkFormTest.php +++ b/core/modules/workspaces/tests/src/Functional/WorkspaceViewsBulkFormTest.php @@ -5,7 +5,6 @@ declare(strict_types=1); namespace Drupal\Tests\workspaces\Functional; use Drupal\Tests\views\Functional\BulkFormTest; -use Drupal\workspaces\Entity\Workspace; /** * Tests the views bulk form in a workspace. @@ -40,8 +39,7 @@ class WorkspaceViewsBulkFormTest extends BulkFormTest { // Ensure that all the test methods are executed in the context of a // workspace. $this->setupWorkspaceSwitcherBlock(); - $stage = Workspace::load('stage'); - $this->switchToWorkspace($stage); + $this->createAndActivateWorkspaceThroughUi('Test workspace', 'test'); } /** diff --git a/core/modules/workspaces/tests/src/Functional/WorkspacesUninstallTest.php b/core/modules/workspaces/tests/src/Functional/WorkspacesUninstallTest.php index c14fe48effbc..487e0dc5f55c 100644 --- a/core/modules/workspaces/tests/src/Functional/WorkspacesUninstallTest.php +++ b/core/modules/workspaces/tests/src/Functional/WorkspacesUninstallTest.php @@ -43,18 +43,12 @@ class WorkspacesUninstallTest extends BrowserTestBase { */ public function testUninstallingWorkspace(): void { $this->createContentType(['type' => 'article']); - $this->drupalGet('/admin/modules/uninstall'); - $session = $this->assertSession(); - $session->linkExists('Remove workspaces'); - $this->clickLink('Remove workspaces'); - $session->pageTextContains('Are you sure you want to delete all workspaces?'); - $this->drupalGet('/admin/modules/uninstall/entity/workspace'); - $this->submitForm([], 'Delete all workspaces'); $this->drupalGet('admin/modules/uninstall'); $this->submitForm(['uninstall[workspaces_ui]' => TRUE], 'Uninstall'); $this->submitForm([], 'Uninstall'); $this->submitForm(['uninstall[workspaces]' => TRUE], 'Uninstall'); $this->submitForm([], 'Uninstall'); + $session = $this->assertSession(); $session->pageTextContains('The selected modules have been uninstalled.'); $session->pageTextNotContains('Workspaces'); diff --git a/core/modules/workspaces/tests/src/FunctionalJavascript/WorkspacesLayoutBuilderIntegrationTest.php b/core/modules/workspaces/tests/src/FunctionalJavascript/WorkspacesLayoutBuilderIntegrationTest.php index d058cfcc8382..f59aba78bb5f 100644 --- a/core/modules/workspaces/tests/src/FunctionalJavascript/WorkspacesLayoutBuilderIntegrationTest.php +++ b/core/modules/workspaces/tests/src/FunctionalJavascript/WorkspacesLayoutBuilderIntegrationTest.php @@ -62,6 +62,7 @@ class WorkspacesLayoutBuilderIntegrationTest extends InlineBlockTestBase { ]); $this->drupalLogin($this->defaultUser); $this->setupWorkspaceSwitcherBlock(); + Workspace::create(['id' => 'stage', 'label' => 'Stage'])->save(); // Enable layout builder. $this->drupalGet(static::FIELD_UI_PREFIX . '/display/default'); diff --git a/core/modules/workspaces/tests/src/FunctionalJavascript/WorkspacesMediaLibraryIntegrationTest.php b/core/modules/workspaces/tests/src/FunctionalJavascript/WorkspacesMediaLibraryIntegrationTest.php index 83ecb8e434f9..49cac2860ae7 100644 --- a/core/modules/workspaces/tests/src/FunctionalJavascript/WorkspacesMediaLibraryIntegrationTest.php +++ b/core/modules/workspaces/tests/src/FunctionalJavascript/WorkspacesMediaLibraryIntegrationTest.php @@ -47,8 +47,9 @@ class WorkspacesMediaLibraryIntegrationTest extends EntityReferenceWidgetTest { // Ensure that all the test methods are executed in the context of a // workspace. - $stage = Workspace::load('stage'); - \Drupal::service('workspaces.manager')->setActiveWorkspace($stage); + $workspace = Workspace::create(['id' => 'test', 'label' => 'Test']); + $workspace->save(); + \Drupal::service('workspaces.manager')->setActiveWorkspace($workspace); } /** diff --git a/core/modules/workspaces/workspaces.install b/core/modules/workspaces/workspaces.install index 6c9c99f29a3c..be1f19a3a30f 100644 --- a/core/modules/workspaces/workspaces.install +++ b/core/modules/workspaces/workspaces.install @@ -6,38 +6,6 @@ */ use Drupal\Core\Entity\EntityTypeInterface; -use Drupal\workspaces\Entity\Workspace; - -/** - * Implements hook_install(). - */ -function workspaces_install(): void { - // Set the owner of these default workspaces to be first user which has the - // 'administrator' role. This way we avoid hard coding user ID 1 for sites - // that prefer to not give it any special meaning. - $admin_roles = \Drupal::entityTypeManager()->getStorage('user_role')->getQuery() - ->condition('is_admin', TRUE) - ->execute(); - if (!empty($admin_roles)) { - $query = \Drupal::entityTypeManager()->getStorage('user')->getQuery() - ->accessCheck(FALSE) - ->condition('roles', $admin_roles, 'IN') - ->condition('status', 1) - ->sort('uid', 'ASC') - ->range(0, 1); - $result = $query->execute(); - } - - // Default to user ID 1 if we could not find any other administrator users. - $owner_id = !empty($result) ? reset($result) : 1; - - // Create a 'stage' workspace by default. - Workspace::create([ - 'id' => 'stage', - 'label' => 'Stage', - 'uid' => $owner_id, - ])->save(); -} /** * Implements hook_schema(). diff --git a/core/modules/workspaces_ui/tests/src/FunctionalJavascript/WorkspaceToolbarIntegrationTest.php b/core/modules/workspaces_ui/tests/src/FunctionalJavascript/WorkspaceToolbarIntegrationTest.php index 488a6dd34c3c..b83953de37e4 100644 --- a/core/modules/workspaces_ui/tests/src/FunctionalJavascript/WorkspaceToolbarIntegrationTest.php +++ b/core/modules/workspaces_ui/tests/src/FunctionalJavascript/WorkspaceToolbarIntegrationTest.php @@ -5,10 +5,12 @@ declare(strict_types=1); namespace Drupal\Tests\workspaces_ui\FunctionalJavascript; use Drupal\Tests\system\FunctionalJavascript\OffCanvasTestBase; +use Drupal\workspaces\Entity\Workspace; /** * Tests workspace settings stray integration. * + * @group workspaces * @group workspaces_ui */ class WorkspaceToolbarIntegrationTest extends OffCanvasTestBase { @@ -34,6 +36,7 @@ class WorkspaceToolbarIntegrationTest extends OffCanvasTestBase { 'access administration pages', ]); $this->drupalLogin($admin_user); + Workspace::create(['id' => 'stage', 'label' => 'Stage'])->save(); } /** |