Code Coverage |
||||||||||||||||
Lines |
Branches |
Paths |
Functions and Methods |
Classes and Traits |
||||||||||||
| Total | |
80.39% |
41 / 51 |
|
51.28% |
20 / 39 |
|
16.67% |
5 / 30 |
|
60.00% |
9 / 15 |
CRAP | |
0.00% |
0 / 1 |
| DisplayBuilderEventsSubscriber | |
80.39% |
41 / 51 |
|
51.28% |
20 / 39 |
|
16.67% |
5 / 30 |
|
60.00% |
9 / 15 |
417.20 | |
0.00% |
0 / 1 |
| __construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getSubscribedEvents | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| onActive | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| onAttachToRoot | |
100.00% |
1 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| onAttachToSlot | |
100.00% |
1 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| onDelete | |
100.00% |
1 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| onHistoryChange | |
100.00% |
1 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| onRestore | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| onRevert | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| onMove | |
100.00% |
1 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| onUpdate | |
100.00% |
1 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| onPublish | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| onPresetSave | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| dispatchToIslands | |
100.00% |
16 / 16 |
|
100.00% |
14 / 14 |
|
10.00% |
1 / 10 |
|
100.00% |
1 / 1 |
42.72 | |||
| shouldDefer | |
50.00% |
5 / 10 |
|
33.33% |
4 / 12 |
|
28.57% |
2 / 7 |
|
0.00% |
0 / 1 |
19.12 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Drupal\display_builder\Event; |
| 6 | |
| 7 | use Drupal\display_builder\Island\IslandInterface; |
| 8 | use Drupal\display_builder\Island\IslandPluginManagerInterface; |
| 9 | use Drupal\display_builder\Island\IslandType; |
| 10 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
| 11 | |
| 12 | /** |
| 13 | * The event subscriber for Display Builder islands. |
| 14 | */ |
| 15 | class DisplayBuilderEventsSubscriber implements EventSubscriberInterface { |
| 16 | |
| 17 | /** |
| 18 | * Constructs a new DisplayBuilderEventsSubscriber object. |
| 19 | */ |
| 20 | public function __construct( |
| 21 | protected IslandPluginManagerInterface $islandManager, |
| 22 | ) {} |
| 23 | |
| 24 | /** |
| 25 | * {@inheritdoc} |
| 26 | */ |
| 27 | public static function getSubscribedEvents(): array { |
| 28 | return [ |
| 29 | DisplayBuilderEvents::ON_ACTIVE => 'onActive', |
| 30 | DisplayBuilderEvents::ON_ATTACH_TO_ROOT => 'onAttachToRoot', |
| 31 | DisplayBuilderEvents::ON_ATTACH_TO_SLOT => 'onAttachToSlot', |
| 32 | DisplayBuilderEvents::ON_DELETE => 'onDelete', |
| 33 | DisplayBuilderEvents::ON_HISTORY_CHANGE => 'onHistoryChange', |
| 34 | DisplayBuilderEvents::ON_RESTORE => 'onRestore', |
| 35 | DisplayBuilderEvents::ON_REVERT => 'onRevert', |
| 36 | DisplayBuilderEvents::ON_MOVE => 'onMove', |
| 37 | DisplayBuilderEvents::ON_UPDATE => 'onUpdate', |
| 38 | DisplayBuilderEvents::ON_PUBLISH => 'onPublish', |
| 39 | DisplayBuilderEvents::ON_PRESET_SAVE => 'onPresetSave', |
| 40 | ]; |
| 41 | } |
| 42 | |
| 43 | /** |
| 44 | * Event handler for when a block becomes active. |
| 45 | * |
| 46 | * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event |
| 47 | * The event object. |
| 48 | */ |
| 49 | public function onActive(DisplayBuilderEvent $event): void { |
| 50 | $this->dispatchToIslands($event, __FUNCTION__, [$event->getData()]); |
| 51 | } |
| 52 | |
| 53 | /** |
| 54 | * Event handler for when a block is attached to the root. |
| 55 | * |
| 56 | * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event |
| 57 | * The event object. |
| 58 | */ |
| 59 | public function onAttachToRoot(DisplayBuilderEvent $event): void { |
| 60 | $this->dispatchToIslands($event, __FUNCTION__, [$event->getNodeId()]); |
| 61 | } |
| 62 | |
| 63 | /** |
| 64 | * Event handler for when a block is attached to a slot. |
| 65 | * |
| 66 | * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event |
| 67 | * The event object. |
| 68 | */ |
| 69 | public function onAttachToSlot(DisplayBuilderEvent $event): void { |
| 70 | $this->dispatchToIslands($event, __FUNCTION__, [$event->getNodeId(), $event->getParentId()]); |
| 71 | } |
| 72 | |
| 73 | /** |
| 74 | * Event handler for when a block is deleted. |
| 75 | * |
| 76 | * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event |
| 77 | * The event object. |
| 78 | */ |
| 79 | public function onDelete(DisplayBuilderEvent $event): void { |
| 80 | $this->dispatchToIslands($event, __FUNCTION__, [$event->getParentId()]); |
| 81 | } |
| 82 | |
| 83 | /** |
| 84 | * Event handler for when the history changes. |
| 85 | * |
| 86 | * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event |
| 87 | * The event object. |
| 88 | */ |
| 89 | public function onHistoryChange(DisplayBuilderEvent $event): void { |
| 90 | $this->dispatchToIslands($event, __FUNCTION__); |
| 91 | } |
| 92 | |
| 93 | /** |
| 94 | * Event handler for when the builder is restored to its last saved state. |
| 95 | * |
| 96 | * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event |
| 97 | * The event object. |
| 98 | */ |
| 99 | public function onRestore(DisplayBuilderEvent $event): void { |
| 100 | $this->dispatchToIslands($event, __FUNCTION__); |
| 101 | } |
| 102 | |
| 103 | /** |
| 104 | * Event handler for when an override is reverted to its default state. |
| 105 | * |
| 106 | * Reuses the history-change island callbacks since the UI refresh is |
| 107 | * identical: all islands must re-render the updated state and history. |
| 108 | * |
| 109 | * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event |
| 110 | * The event object. |
| 111 | */ |
| 112 | public function onRevert(DisplayBuilderEvent $event): void { |
| 113 | $this->dispatchToIslands($event, __FUNCTION__); |
| 114 | } |
| 115 | |
| 116 | /** |
| 117 | * Event handler for when a block is moved. |
| 118 | * |
| 119 | * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event |
| 120 | * The event object. |
| 121 | */ |
| 122 | public function onMove(DisplayBuilderEvent $event): void { |
| 123 | $this->dispatchToIslands($event, __FUNCTION__, [$event->getNodeId()]); |
| 124 | } |
| 125 | |
| 126 | /** |
| 127 | * Event handler for when a block is updated. |
| 128 | * |
| 129 | * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event |
| 130 | * The event object. |
| 131 | */ |
| 132 | public function onUpdate(DisplayBuilderEvent $event): void { |
| 133 | $this->dispatchToIslands($event, __FUNCTION__, [$event->getNodeId()]); |
| 134 | } |
| 135 | |
| 136 | /** |
| 137 | * Event handler for when a display is saved. |
| 138 | * |
| 139 | * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event |
| 140 | * The event object. |
| 141 | */ |
| 142 | public function onPublish(DisplayBuilderEvent $event): void { |
| 143 | $this->dispatchToIslands($event, __FUNCTION__, [$event->getData()]); |
| 144 | } |
| 145 | |
| 146 | /** |
| 147 | * Event handler for when a preset is saved. |
| 148 | * |
| 149 | * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event |
| 150 | * The event object. |
| 151 | */ |
| 152 | public function onPresetSave(DisplayBuilderEvent $event): void { |
| 153 | $this->dispatchToIslands($event, __FUNCTION__); |
| 154 | } |
| 155 | |
| 156 | /** |
| 157 | * Dispatch the event with a generic code. |
| 158 | * |
| 159 | * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event |
| 160 | * The event object. |
| 161 | * @param string $method |
| 162 | * The method to dispatch. |
| 163 | * @param array $parameters |
| 164 | * (Optional) The parameters to the method. |
| 165 | */ |
| 166 | private function dispatchToIslands(DisplayBuilderEvent $event, string $method, array $parameters = []): void { |
| 167 | \array_unshift($parameters, $event->getInstance()); |
| 168 | |
| 169 | $configuration = $event->getIslandConfiguration(); |
| 170 | $contexts = $event->getInstance()->getAvailableContexts(); |
| 171 | $islands = $this->islandManager->createInstances($this->islandManager->getDefinitions(), $contexts, $configuration); |
| 172 | |
| 173 | $island_enabled = $event->getEnabledIslands(); |
| 174 | $visible_islands = $event->getVisibleIslands(); |
| 175 | |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 178 | continue; |
| 179 | } |
| 180 | |
| 181 | // Skip the island triggering the HTMX event. Useful to avoid swapping |
| 182 | // the content of an island which is already in the expected state. |
| 183 | // For examples, if we move an instance in Builder, Wireframe or Tree |
| 184 | // panels, if we change the settings in InstanceForm. |
| 185 | // @see Drupal\display_builder\Controller\ApiControllerBase::islandId |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 187 | continue; |
| 188 | } |
| 189 | |
| 190 | // Skip panels the client told us are off screen. They are rebuilt on |
| 191 | // demand when the user brings them back into view. |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 193 | continue; |
| 194 | } |
| 195 | |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 199 | $event->appendResult($island_id, $result); |
| 200 | } |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | /** |
| 205 | * Determines whether an island's rebuild can be deferred until it is shown. |
| 206 | * |
| 207 | * Only panels the user cannot currently see are worth deferring, and only |
| 208 | * where the client is able to notice they went stale and ask for them again. |
| 209 | * That is true of View panels in the tabbed main area and in the start |
| 210 | * sidebar drawer - one visible at a time in each - and of the Floating |
| 211 | * controls which are shown and hidden along with the panel they attach to. |
| 212 | * |
| 213 | * Everything else (toolbar buttons, contextual menu entries, Library and |
| 214 | * Contextual tabs) is always rendered: it is either permanently on screen or |
| 215 | * cheap enough that deferring it would cost more than it saves. |
| 216 | * |
| 217 | * Which islands are eligible at all is the island's own answer, so a panel |
| 218 | * that cannot survive a standalone reload can decline. This method only |
| 219 | * decides whether an eligible island is currently off screen. |
| 220 | * |
| 221 | * The region is deliberately not consulted: IslandType::regions() offers a |
| 222 | * View island only 'main' and 'sidebar', both of which show one panel at a |
| 223 | * time, so every View island qualifies. Testing the region would also be |
| 224 | * wrong, since it is only stored on the profile when explicitly configured |
| 225 | * (@see \Drupal\display_builder\Entity\Profile::setIslandConfiguration()) - |
| 226 | * an island left at its default would fall through and never be deferred. |
| 227 | * |
| 228 | * @param \Drupal\display_builder\Island\IslandInterface $island |
| 229 | * The island to test. |
| 230 | * @param array $visible_islands |
| 231 | * The island plugin IDs the client reports as currently visible. |
| 232 | * |
| 233 | * @return bool |
| 234 | * TRUE if this island's rebuild should be skipped for this request. |
| 235 | * |
| 236 | * @see \Drupal\display_builder\Island\IslandInterface::isDeferrable() |
| 237 | * @see \Drupal\display_builder\Controller\ApiController::reloadIsland() |
| 238 | */ |
| 239 | private function shouldDefer(IslandInterface $island, array $visible_islands): bool { |
| 240 | if (!$island->isDeferrable()) { |
| 241 | return FALSE; |
| 242 | } |
| 243 | |
| 244 | $type = $island->getTypeId(); |
| 245 | |
| 246 | if ($type === IslandType::View->value) { |
| 247 | return !\in_array($island->getPluginId(), $visible_islands, TRUE); |
| 248 | } |
| 249 | |
| 250 | // A Floating island rides along with the panel(s) it is attached to, so it |
| 251 | // is off screen exactly when all of them are. |
| 252 | // @see \Drupal\display_builder\ProfileViewBuilder::buildFloatingControlsRegion() |
| 253 | if ($type === IslandType::Floating->value) { |
| 254 | $definition = $island->getPluginDefinition(); |
| 255 | $attach_to = \is_array($definition) ? ($definition['attach_to'] ?? []) : []; |
| 256 | |
| 257 | return $attach_to !== [] && \array_intersect($attach_to, $visible_islands) === []; |
| 258 | } |
| 259 | |
| 260 | return FALSE; |
| 261 | } |
| 262 | |
| 263 | } |
Below are the source code lines that represent each code path as identified by Xdebug. Please note a path is not
necessarily coterminous with a line, a line may contain multiple paths and therefore show up more than once.
Please also be aware that some paths may include implicit rather than explicit branches, e.g. an if statement
always has an else as part of its logical flow even if you didn't write one.
| 21 | protected IslandPluginManagerInterface $islandManager, |
| 22 | ) {} |
| 166 | private function dispatchToIslands(DisplayBuilderEvent $event, string $method, array $parameters = []): void { |
| 167 | \array_unshift($parameters, $event->getInstance()); |
| 168 | |
| 169 | $configuration = $event->getIslandConfiguration(); |
| 170 | $contexts = $event->getInstance()->getAvailableContexts(); |
| 171 | $islands = $this->islandManager->createInstances($this->islandManager->getDefinitions(), $contexts, $configuration); |
| 172 | |
| 173 | $island_enabled = $event->getEnabledIslands(); |
| 174 | $visible_islands = $event->getVisibleIslands(); |
| 175 | |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 178 | continue; |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 178 | continue; |
| 179 | } |
| 180 | |
| 181 | // Skip the island triggering the HTMX event. Useful to avoid swapping |
| 182 | // the content of an island which is already in the expected state. |
| 183 | // For examples, if we move an instance in Builder, Wireframe or Tree |
| 184 | // panels, if we change the settings in InstanceForm. |
| 185 | // @see Drupal\display_builder\Controller\ApiControllerBase::islandId |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 187 | continue; |
| 188 | } |
| 189 | |
| 190 | // Skip panels the client told us are off screen. They are rebuilt on |
| 191 | // demand when the user brings them back into view. |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 193 | continue; |
| 194 | } |
| 195 | |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 199 | $event->appendResult($island_id, $result); |
| 200 | } |
| 201 | } |
| 202 | } |
| 166 | private function dispatchToIslands(DisplayBuilderEvent $event, string $method, array $parameters = []): void { |
| 167 | \array_unshift($parameters, $event->getInstance()); |
| 168 | |
| 169 | $configuration = $event->getIslandConfiguration(); |
| 170 | $contexts = $event->getInstance()->getAvailableContexts(); |
| 171 | $islands = $this->islandManager->createInstances($this->islandManager->getDefinitions(), $contexts, $configuration); |
| 172 | |
| 173 | $island_enabled = $event->getEnabledIslands(); |
| 174 | $visible_islands = $event->getVisibleIslands(); |
| 175 | |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 187 | continue; |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 178 | continue; |
| 179 | } |
| 180 | |
| 181 | // Skip the island triggering the HTMX event. Useful to avoid swapping |
| 182 | // the content of an island which is already in the expected state. |
| 183 | // For examples, if we move an instance in Builder, Wireframe or Tree |
| 184 | // panels, if we change the settings in InstanceForm. |
| 185 | // @see Drupal\display_builder\Controller\ApiControllerBase::islandId |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 187 | continue; |
| 188 | } |
| 189 | |
| 190 | // Skip panels the client told us are off screen. They are rebuilt on |
| 191 | // demand when the user brings them back into view. |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 193 | continue; |
| 194 | } |
| 195 | |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 199 | $event->appendResult($island_id, $result); |
| 200 | } |
| 201 | } |
| 202 | } |
| 166 | private function dispatchToIslands(DisplayBuilderEvent $event, string $method, array $parameters = []): void { |
| 167 | \array_unshift($parameters, $event->getInstance()); |
| 168 | |
| 169 | $configuration = $event->getIslandConfiguration(); |
| 170 | $contexts = $event->getInstance()->getAvailableContexts(); |
| 171 | $islands = $this->islandManager->createInstances($this->islandManager->getDefinitions(), $contexts, $configuration); |
| 172 | |
| 173 | $island_enabled = $event->getEnabledIslands(); |
| 174 | $visible_islands = $event->getVisibleIslands(); |
| 175 | |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 193 | continue; |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 178 | continue; |
| 179 | } |
| 180 | |
| 181 | // Skip the island triggering the HTMX event. Useful to avoid swapping |
| 182 | // the content of an island which is already in the expected state. |
| 183 | // For examples, if we move an instance in Builder, Wireframe or Tree |
| 184 | // panels, if we change the settings in InstanceForm. |
| 185 | // @see Drupal\display_builder\Controller\ApiControllerBase::islandId |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 187 | continue; |
| 188 | } |
| 189 | |
| 190 | // Skip panels the client told us are off screen. They are rebuilt on |
| 191 | // demand when the user brings them back into view. |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 193 | continue; |
| 194 | } |
| 195 | |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 199 | $event->appendResult($island_id, $result); |
| 200 | } |
| 201 | } |
| 202 | } |
| 166 | private function dispatchToIslands(DisplayBuilderEvent $event, string $method, array $parameters = []): void { |
| 167 | \array_unshift($parameters, $event->getInstance()); |
| 168 | |
| 169 | $configuration = $event->getIslandConfiguration(); |
| 170 | $contexts = $event->getInstance()->getAvailableContexts(); |
| 171 | $islands = $this->islandManager->createInstances($this->islandManager->getDefinitions(), $contexts, $configuration); |
| 172 | |
| 173 | $island_enabled = $event->getEnabledIslands(); |
| 174 | $visible_islands = $event->getVisibleIslands(); |
| 175 | |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 178 | continue; |
| 179 | } |
| 180 | |
| 181 | // Skip the island triggering the HTMX event. Useful to avoid swapping |
| 182 | // the content of an island which is already in the expected state. |
| 183 | // For examples, if we move an instance in Builder, Wireframe or Tree |
| 184 | // panels, if we change the settings in InstanceForm. |
| 185 | // @see Drupal\display_builder\Controller\ApiControllerBase::islandId |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 187 | continue; |
| 188 | } |
| 189 | |
| 190 | // Skip panels the client told us are off screen. They are rebuilt on |
| 191 | // demand when the user brings them back into view. |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 193 | continue; |
| 194 | } |
| 195 | |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 199 | $event->appendResult($island_id, $result); |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 178 | continue; |
| 179 | } |
| 180 | |
| 181 | // Skip the island triggering the HTMX event. Useful to avoid swapping |
| 182 | // the content of an island which is already in the expected state. |
| 183 | // For examples, if we move an instance in Builder, Wireframe or Tree |
| 184 | // panels, if we change the settings in InstanceForm. |
| 185 | // @see Drupal\display_builder\Controller\ApiControllerBase::islandId |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 187 | continue; |
| 188 | } |
| 189 | |
| 190 | // Skip panels the client told us are off screen. They are rebuilt on |
| 191 | // demand when the user brings them back into view. |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 193 | continue; |
| 194 | } |
| 195 | |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 199 | $event->appendResult($island_id, $result); |
| 200 | } |
| 201 | } |
| 202 | } |
| 166 | private function dispatchToIslands(DisplayBuilderEvent $event, string $method, array $parameters = []): void { |
| 167 | \array_unshift($parameters, $event->getInstance()); |
| 168 | |
| 169 | $configuration = $event->getIslandConfiguration(); |
| 170 | $contexts = $event->getInstance()->getAvailableContexts(); |
| 171 | $islands = $this->islandManager->createInstances($this->islandManager->getDefinitions(), $contexts, $configuration); |
| 172 | |
| 173 | $island_enabled = $event->getEnabledIslands(); |
| 174 | $visible_islands = $event->getVisibleIslands(); |
| 175 | |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 178 | continue; |
| 179 | } |
| 180 | |
| 181 | // Skip the island triggering the HTMX event. Useful to avoid swapping |
| 182 | // the content of an island which is already in the expected state. |
| 183 | // For examples, if we move an instance in Builder, Wireframe or Tree |
| 184 | // panels, if we change the settings in InstanceForm. |
| 185 | // @see Drupal\display_builder\Controller\ApiControllerBase::islandId |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 187 | continue; |
| 188 | } |
| 189 | |
| 190 | // Skip panels the client told us are off screen. They are rebuilt on |
| 191 | // demand when the user brings them back into view. |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 193 | continue; |
| 194 | } |
| 195 | |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 199 | $event->appendResult($island_id, $result); |
| 200 | } |
| 201 | } |
| 202 | } |
| 166 | private function dispatchToIslands(DisplayBuilderEvent $event, string $method, array $parameters = []): void { |
| 167 | \array_unshift($parameters, $event->getInstance()); |
| 168 | |
| 169 | $configuration = $event->getIslandConfiguration(); |
| 170 | $contexts = $event->getInstance()->getAvailableContexts(); |
| 171 | $islands = $this->islandManager->createInstances($this->islandManager->getDefinitions(), $contexts, $configuration); |
| 172 | |
| 173 | $island_enabled = $event->getEnabledIslands(); |
| 174 | $visible_islands = $event->getVisibleIslands(); |
| 175 | |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 193 | continue; |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 178 | continue; |
| 179 | } |
| 180 | |
| 181 | // Skip the island triggering the HTMX event. Useful to avoid swapping |
| 182 | // the content of an island which is already in the expected state. |
| 183 | // For examples, if we move an instance in Builder, Wireframe or Tree |
| 184 | // panels, if we change the settings in InstanceForm. |
| 185 | // @see Drupal\display_builder\Controller\ApiControllerBase::islandId |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 187 | continue; |
| 188 | } |
| 189 | |
| 190 | // Skip panels the client told us are off screen. They are rebuilt on |
| 191 | // demand when the user brings them back into view. |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 193 | continue; |
| 194 | } |
| 195 | |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 199 | $event->appendResult($island_id, $result); |
| 200 | } |
| 201 | } |
| 202 | } |
| 166 | private function dispatchToIslands(DisplayBuilderEvent $event, string $method, array $parameters = []): void { |
| 167 | \array_unshift($parameters, $event->getInstance()); |
| 168 | |
| 169 | $configuration = $event->getIslandConfiguration(); |
| 170 | $contexts = $event->getInstance()->getAvailableContexts(); |
| 171 | $islands = $this->islandManager->createInstances($this->islandManager->getDefinitions(), $contexts, $configuration); |
| 172 | |
| 173 | $island_enabled = $event->getEnabledIslands(); |
| 174 | $visible_islands = $event->getVisibleIslands(); |
| 175 | |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 178 | continue; |
| 179 | } |
| 180 | |
| 181 | // Skip the island triggering the HTMX event. Useful to avoid swapping |
| 182 | // the content of an island which is already in the expected state. |
| 183 | // For examples, if we move an instance in Builder, Wireframe or Tree |
| 184 | // panels, if we change the settings in InstanceForm. |
| 185 | // @see Drupal\display_builder\Controller\ApiControllerBase::islandId |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 187 | continue; |
| 188 | } |
| 189 | |
| 190 | // Skip panels the client told us are off screen. They are rebuilt on |
| 191 | // demand when the user brings them back into view. |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 193 | continue; |
| 194 | } |
| 195 | |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 199 | $event->appendResult($island_id, $result); |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 178 | continue; |
| 179 | } |
| 180 | |
| 181 | // Skip the island triggering the HTMX event. Useful to avoid swapping |
| 182 | // the content of an island which is already in the expected state. |
| 183 | // For examples, if we move an instance in Builder, Wireframe or Tree |
| 184 | // panels, if we change the settings in InstanceForm. |
| 185 | // @see Drupal\display_builder\Controller\ApiControllerBase::islandId |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 187 | continue; |
| 188 | } |
| 189 | |
| 190 | // Skip panels the client told us are off screen. They are rebuilt on |
| 191 | // demand when the user brings them back into view. |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 193 | continue; |
| 194 | } |
| 195 | |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 199 | $event->appendResult($island_id, $result); |
| 200 | } |
| 201 | } |
| 202 | } |
| 166 | private function dispatchToIslands(DisplayBuilderEvent $event, string $method, array $parameters = []): void { |
| 167 | \array_unshift($parameters, $event->getInstance()); |
| 168 | |
| 169 | $configuration = $event->getIslandConfiguration(); |
| 170 | $contexts = $event->getInstance()->getAvailableContexts(); |
| 171 | $islands = $this->islandManager->createInstances($this->islandManager->getDefinitions(), $contexts, $configuration); |
| 172 | |
| 173 | $island_enabled = $event->getEnabledIslands(); |
| 174 | $visible_islands = $event->getVisibleIslands(); |
| 175 | |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 178 | continue; |
| 179 | } |
| 180 | |
| 181 | // Skip the island triggering the HTMX event. Useful to avoid swapping |
| 182 | // the content of an island which is already in the expected state. |
| 183 | // For examples, if we move an instance in Builder, Wireframe or Tree |
| 184 | // panels, if we change the settings in InstanceForm. |
| 185 | // @see Drupal\display_builder\Controller\ApiControllerBase::islandId |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 187 | continue; |
| 188 | } |
| 189 | |
| 190 | // Skip panels the client told us are off screen. They are rebuilt on |
| 191 | // demand when the user brings them back into view. |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 193 | continue; |
| 194 | } |
| 195 | |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 199 | $event->appendResult($island_id, $result); |
| 200 | } |
| 201 | } |
| 202 | } |
| 166 | private function dispatchToIslands(DisplayBuilderEvent $event, string $method, array $parameters = []): void { |
| 167 | \array_unshift($parameters, $event->getInstance()); |
| 168 | |
| 169 | $configuration = $event->getIslandConfiguration(); |
| 170 | $contexts = $event->getInstance()->getAvailableContexts(); |
| 171 | $islands = $this->islandManager->createInstances($this->islandManager->getDefinitions(), $contexts, $configuration); |
| 172 | |
| 173 | $island_enabled = $event->getEnabledIslands(); |
| 174 | $visible_islands = $event->getVisibleIslands(); |
| 175 | |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 178 | continue; |
| 179 | } |
| 180 | |
| 181 | // Skip the island triggering the HTMX event. Useful to avoid swapping |
| 182 | // the content of an island which is already in the expected state. |
| 183 | // For examples, if we move an instance in Builder, Wireframe or Tree |
| 184 | // panels, if we change the settings in InstanceForm. |
| 185 | // @see Drupal\display_builder\Controller\ApiControllerBase::islandId |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 187 | continue; |
| 188 | } |
| 189 | |
| 190 | // Skip panels the client told us are off screen. They are rebuilt on |
| 191 | // demand when the user brings them back into view. |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 193 | continue; |
| 194 | } |
| 195 | |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 199 | $event->appendResult($island_id, $result); |
| 200 | } |
| 201 | } |
| 202 | } |
| 166 | private function dispatchToIslands(DisplayBuilderEvent $event, string $method, array $parameters = []): void { |
| 167 | \array_unshift($parameters, $event->getInstance()); |
| 168 | |
| 169 | $configuration = $event->getIslandConfiguration(); |
| 170 | $contexts = $event->getInstance()->getAvailableContexts(); |
| 171 | $islands = $this->islandManager->createInstances($this->islandManager->getDefinitions(), $contexts, $configuration); |
| 172 | |
| 173 | $island_enabled = $event->getEnabledIslands(); |
| 174 | $visible_islands = $event->getVisibleIslands(); |
| 175 | |
| 176 | foreach ($islands as $island_id => $island) { |
| 176 | foreach ($islands as $island_id => $island) { |
| 177 | if (!isset($island_enabled[$island_id])) { |
| 178 | continue; |
| 179 | } |
| 180 | |
| 181 | // Skip the island triggering the HTMX event. Useful to avoid swapping |
| 182 | // the content of an island which is already in the expected state. |
| 183 | // For examples, if we move an instance in Builder, Wireframe or Tree |
| 184 | // panels, if we change the settings in InstanceForm. |
| 185 | // @see Drupal\display_builder\Controller\ApiControllerBase::islandId |
| 186 | if ($island_id === $event->getCurrentIslandId()) { |
| 187 | continue; |
| 188 | } |
| 189 | |
| 190 | // Skip panels the client told us are off screen. They are rebuilt on |
| 191 | // demand when the user brings them back into view. |
| 192 | if ($visible_islands !== NULL && $this->shouldDefer($island, $visible_islands)) { |
| 193 | continue; |
| 194 | } |
| 195 | |
| 196 | $result = $island->{$method}(...$parameters); |
| 197 | |
| 198 | if ($result !== NULL) { |
| 199 | $event->appendResult($island_id, $result); |
| 200 | } |
| 201 | } |
| 202 | } |
| 29 | DisplayBuilderEvents::ON_ACTIVE => 'onActive', |
| 30 | DisplayBuilderEvents::ON_ATTACH_TO_ROOT => 'onAttachToRoot', |
| 31 | DisplayBuilderEvents::ON_ATTACH_TO_SLOT => 'onAttachToSlot', |
| 32 | DisplayBuilderEvents::ON_DELETE => 'onDelete', |
| 33 | DisplayBuilderEvents::ON_HISTORY_CHANGE => 'onHistoryChange', |
| 34 | DisplayBuilderEvents::ON_RESTORE => 'onRestore', |
| 35 | DisplayBuilderEvents::ON_REVERT => 'onRevert', |
| 36 | DisplayBuilderEvents::ON_MOVE => 'onMove', |
| 37 | DisplayBuilderEvents::ON_UPDATE => 'onUpdate', |
| 38 | DisplayBuilderEvents::ON_PUBLISH => 'onPublish', |
| 39 | DisplayBuilderEvents::ON_PRESET_SAVE => 'onPresetSave', |
| 40 | ]; |
| 41 | } |
| 49 | public function onActive(DisplayBuilderEvent $event): void { |
| 50 | $this->dispatchToIslands($event, __FUNCTION__, [$event->getData()]); |
| 51 | } |
| 59 | public function onAttachToRoot(DisplayBuilderEvent $event): void { |
| 60 | $this->dispatchToIslands($event, __FUNCTION__, [$event->getNodeId()]); |
| 61 | } |
| 69 | public function onAttachToSlot(DisplayBuilderEvent $event): void { |
| 70 | $this->dispatchToIslands($event, __FUNCTION__, [$event->getNodeId(), $event->getParentId()]); |
| 71 | } |
| 79 | public function onDelete(DisplayBuilderEvent $event): void { |
| 80 | $this->dispatchToIslands($event, __FUNCTION__, [$event->getParentId()]); |
| 81 | } |
| 89 | public function onHistoryChange(DisplayBuilderEvent $event): void { |
| 90 | $this->dispatchToIslands($event, __FUNCTION__); |
| 91 | } |
| 122 | public function onMove(DisplayBuilderEvent $event): void { |
| 123 | $this->dispatchToIslands($event, __FUNCTION__, [$event->getNodeId()]); |
| 124 | } |
| 152 | public function onPresetSave(DisplayBuilderEvent $event): void { |
| 153 | $this->dispatchToIslands($event, __FUNCTION__); |
| 154 | } |
| 142 | public function onPublish(DisplayBuilderEvent $event): void { |
| 143 | $this->dispatchToIslands($event, __FUNCTION__, [$event->getData()]); |
| 144 | } |
| 99 | public function onRestore(DisplayBuilderEvent $event): void { |
| 100 | $this->dispatchToIslands($event, __FUNCTION__); |
| 101 | } |
| 112 | public function onRevert(DisplayBuilderEvent $event): void { |
| 113 | $this->dispatchToIslands($event, __FUNCTION__); |
| 114 | } |
| 132 | public function onUpdate(DisplayBuilderEvent $event): void { |
| 133 | $this->dispatchToIslands($event, __FUNCTION__, [$event->getNodeId()]); |
| 134 | } |
| 239 | private function shouldDefer(IslandInterface $island, array $visible_islands): bool { |
| 240 | if (!$island->isDeferrable()) { |
| 241 | return FALSE; |
| 239 | private function shouldDefer(IslandInterface $island, array $visible_islands): bool { |
| 240 | if (!$island->isDeferrable()) { |
| 244 | $type = $island->getTypeId(); |
| 245 | |
| 246 | if ($type === IslandType::View->value) { |
| 247 | return !\in_array($island->getPluginId(), $visible_islands, TRUE); |
| 239 | private function shouldDefer(IslandInterface $island, array $visible_islands): bool { |
| 240 | if (!$island->isDeferrable()) { |
| 244 | $type = $island->getTypeId(); |
| 245 | |
| 246 | if ($type === IslandType::View->value) { |
| 253 | if ($type === IslandType::Floating->value) { |
| 254 | $definition = $island->getPluginDefinition(); |
| 255 | $attach_to = \is_array($definition) ? ($definition['attach_to'] ?? []) : []; |
| 255 | $attach_to = \is_array($definition) ? ($definition['attach_to'] ?? []) : []; |
| 255 | $attach_to = \is_array($definition) ? ($definition['attach_to'] ?? []) : []; |
| 256 | |
| 257 | return $attach_to !== [] && \array_intersect($attach_to, $visible_islands) === []; |
| 257 | return $attach_to !== [] && \array_intersect($attach_to, $visible_islands) === []; |
| 257 | return $attach_to !== [] && \array_intersect($attach_to, $visible_islands) === []; |
| 239 | private function shouldDefer(IslandInterface $island, array $visible_islands): bool { |
| 240 | if (!$island->isDeferrable()) { |
| 244 | $type = $island->getTypeId(); |
| 245 | |
| 246 | if ($type === IslandType::View->value) { |
| 253 | if ($type === IslandType::Floating->value) { |
| 254 | $definition = $island->getPluginDefinition(); |
| 255 | $attach_to = \is_array($definition) ? ($definition['attach_to'] ?? []) : []; |
| 255 | $attach_to = \is_array($definition) ? ($definition['attach_to'] ?? []) : []; |
| 255 | $attach_to = \is_array($definition) ? ($definition['attach_to'] ?? []) : []; |
| 256 | |
| 257 | return $attach_to !== [] && \array_intersect($attach_to, $visible_islands) === []; |
| 257 | return $attach_to !== [] && \array_intersect($attach_to, $visible_islands) === []; |
| 239 | private function shouldDefer(IslandInterface $island, array $visible_islands): bool { |
| 240 | if (!$island->isDeferrable()) { |
| 244 | $type = $island->getTypeId(); |
| 245 | |
| 246 | if ($type === IslandType::View->value) { |
| 253 | if ($type === IslandType::Floating->value) { |
| 254 | $definition = $island->getPluginDefinition(); |
| 255 | $attach_to = \is_array($definition) ? ($definition['attach_to'] ?? []) : []; |
| 255 | $attach_to = \is_array($definition) ? ($definition['attach_to'] ?? []) : []; |
| 255 | $attach_to = \is_array($definition) ? ($definition['attach_to'] ?? []) : []; |
| 256 | |
| 257 | return $attach_to !== [] && \array_intersect($attach_to, $visible_islands) === []; |
| 257 | return $attach_to !== [] && \array_intersect($attach_to, $visible_islands) === []; |
| 257 | return $attach_to !== [] && \array_intersect($attach_to, $visible_islands) === []; |
| 239 | private function shouldDefer(IslandInterface $island, array $visible_islands): bool { |
| 240 | if (!$island->isDeferrable()) { |
| 244 | $type = $island->getTypeId(); |
| 245 | |
| 246 | if ($type === IslandType::View->value) { |
| 253 | if ($type === IslandType::Floating->value) { |
| 254 | $definition = $island->getPluginDefinition(); |
| 255 | $attach_to = \is_array($definition) ? ($definition['attach_to'] ?? []) : []; |
| 255 | $attach_to = \is_array($definition) ? ($definition['attach_to'] ?? []) : []; |
| 255 | $attach_to = \is_array($definition) ? ($definition['attach_to'] ?? []) : []; |
| 256 | |
| 257 | return $attach_to !== [] && \array_intersect($attach_to, $visible_islands) === []; |
| 257 | return $attach_to !== [] && \array_intersect($attach_to, $visible_islands) === []; |
| 239 | private function shouldDefer(IslandInterface $island, array $visible_islands): bool { |
| 240 | if (!$island->isDeferrable()) { |
| 244 | $type = $island->getTypeId(); |
| 245 | |
| 246 | if ($type === IslandType::View->value) { |
| 253 | if ($type === IslandType::Floating->value) { |
| 260 | return FALSE; |
| 261 | } |