/** * Act on a Panels Display before it is saved via the IPE. * * @param \Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVariant $panels_display * The current Panels display. * @param array $layout_model * The decoded LayoutModel from our App. */ function hook_panels_ipe_panels_display_presave(PanelsDisplayVariant $panels_display, array $layout_model) { if (isset($layout_model['use_custom_storage'])) { $configuration = $panels_display->getConfiguration(); $panels_display->setStorage('custom_storage_key', $configuration['storage_id']); } }
/** * @inheritdoc */ protected function handle(PanelsDisplayVariant $panels_display, $decoded_request, $save_to_temp_store = FALSE) { $panels_display->removeBlock($decoded_request); if ($save_to_temp_store) { $this->savePanelsDisplayToTempStore($panels_display); } else { $this->savePanelsDisplay($panels_display); } }
/** * {@inheritdoc} */ public function save(PanelsDisplayVariant $panels_display) { $id = $panels_display->getStorageId(); if ($id && ($page_variant = $this->loadPageVariant($id))) { $variant_plugin = $page_variant->getVariantPlugin(); if (!$variant_plugin instanceof PanelsDisplayVariant) { throw new \Exception("Page variant doesn't use a Panels display variant"); } $variant_plugin->setConfiguration($panels_display->getConfiguration()); $page_variant->save(); } else { throw new \Exception("Couldn't find page variant to store Panels display"); } }
/** * Updates the current Panels display based on the changes done in our app. * * @param \Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVariant $panels_display * The current Panels display. * @param array $layout_model * The decoded LayoutModel from our App. * * @return \Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVariant */ private static function updatePanelsDisplay(PanelsDisplayVariant $panels_display, array $layout_model) { // Set our weight and region based on the metadata in our Backbone app. foreach ($layout_model['regionCollection'] as $region) { $weight = 0; foreach ($region['blockCollection'] as $block) { /** @var \Drupal\Core\Block\BlockBase $block_instance */ $block_instance = $panels_display->getBlock($block['uuid']); $block_instance->setConfigurationValue('region', $region['name']); $block_instance->setConfigurationValue('weight', ++$weight); $panels_display->updateBlock($block['uuid'], $block_instance->getConfiguration()); } } return $panels_display; }
/** * @covers ::save * * @expectedException \Exception * @expectedExceptionMessage Page variant doesn't use a Panels display variant */ public function testSaveNotPanels() { $this->storage->load('not_a_panel')->willReturn($this->pageVariantNotPanels->reveal()); $this->panelsDisplay->setConfiguration(Argument::cetera())->shouldNotBeCalled(); $this->pageVariant->save()->shouldNotBeCalled(); $panels_display = $this->prophesize(PanelsDisplayVariant::class); $panels_display->getStorageId()->willReturn('not_a_panel'); $panels_display->getConfiguration()->shouldNotBeCalled(); $panels_storage = new PageManagerPanelsStorage([], '', [], $this->entityTypeManager->reveal()); $panels_storage->save($panels_display->reveal()); }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { // Return early if there are any errors. if ($form_state->hasAnyErrors()) { return $form; } $panels_display = $this->panelsDisplay; // Submit the layout form. $layout_form_state = (new FormState())->setValues($form_state->getValue('settings', [])); $this->layout->submitConfigurationForm($form, $layout_form_state); $layout_config = $this->layout->getConfiguration(); // Shift our blocks to the first available region. The IPE can control // re-assigning blocks in a smarter way. $region_definitions = $this->layout->getRegionDefinitions(); $first_region = reset(array_keys($region_definitions)); // For each block, set the region to match the new layout. foreach ($panels_display->getRegionAssignments() as $region => $region_assignment) { /** @var \Drupal\Core\Block\BlockPluginInterface $block */ foreach ($region_assignment as $block_id => $block) { $block_config = $block->getConfiguration(); // If the new layout does not have a region with the same name, use the // first available region. if (!isset($region_definitions[$block_config['region']])) { $block_config['region'] = $first_region; $panels_display->updateBlock($block_id, $block_config); } } } // Have our panels display use the new layout. $this->panelsDisplay->setLayout($this->layout, $layout_config); // Update tempstore. $this->tempStore->set($panels_display->id(), $panels_display->getConfiguration()); $region_data = []; $region_content = []; // Compile region content and metadata. $regions = $panels_display->getRegionAssignments(); foreach ($regions as $id => $label) { // Wrap the region with a class/data attribute that our app can use. $region_name = Html::getClass("block-region-{$id}"); $region_content[$id] = ['#prefix' => '<div class="' . $region_name . '" data-region-name="' . $id . '">', '#suffix' => '</div>']; // Format region metadata. $region_data[] = ['name' => $id, 'label' => $label]; } $build = $panels_display->getLayout()->build($region_content); $form['build'] = $build; $data = ['id' => $this->layout->getPluginId(), 'label' => $layout_config['label'], 'current' => TRUE, 'html' => $this->renderer->render($build), 'regions' => $region_data]; // Add Block metadata and HTML as a drupalSetting. $form['#attached']['drupalSettings']['panels_ipe']['updated_layout'] = $data; return $form; }
/** * Compiles a render array for the given Block instance based on the form. * * @param \Drupal\Core\Block\BlockBase $block_instance * The Block instance you want to render. * * @return array $build * The Block render array. */ protected function buildBlockInstance($block_instance) { // Get the new block configuration. $configuration = $block_instance->getConfiguration(); // Add context to the block. if ($block_instance instanceof ContextAwarePluginInterface) { $this->contextHandler->applyContextMapping($block_instance, $this->panelsDisplay->getContexts()); } // Build the block content. $content = $block_instance->build(); // Disable any nested forms from the render array. $content = $this->removeFormWrapperRecursive($content); // Compile the render array. $build = ['#theme' => 'block', '#attributes' => [], '#contextual_links' => [], '#configuration' => $configuration, '#plugin_id' => $block_instance->getPluginId(), '#base_plugin_id' => $block_instance->getBaseId(), '#derivative_plugin_id' => $block_instance->getDerivativeId(), 'content' => $content]; return $build; }
/** * Loads or creates a Block Plugin instance suitable for rendering or testing. * * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * * @return \Drupal\Core\Block\BlockBase * The Block Plugin instance. */ protected function getBlockInstance(FormStateInterface $form_state) { // If a UUID is provided, the Block should already exist. if ($uuid = $form_state->getValue('uuid')) { // If a temporary configuration for this variant exists, use it. $temp_store_key = $this->panelsDisplay->id(); if ($variant_config = $this->tempStore->get($temp_store_key)) { $this->panelsDisplay->setConfiguration($variant_config); } // Load the existing Block instance. $block_instance = $this->panelsDisplay->getBlock($uuid); } else { // Create an instance of this Block plugin. /** @var \Drupal\Core\Block\BlockBase $block_instance */ $block_instance = $this->blockManager->createInstance($form_state->getValue('plugin_id')); } // Add context to the block. if ($block_instance instanceof ContextAwarePluginInterface) { $this->contextHandler->applyContextMapping($block_instance, $this->panelsDisplay->getContexts()); } return $block_instance; }
/** * {@inheritdoc} */ public function exportDisplay(PanelsDisplayVariant $display) { return $display->getConfiguration(); }
/** * @covers ::defaultConfiguration */ public function testDefaultConfiguration() { $defaults = $this->variant->defaultConfiguration(); $this->assertSame('', $defaults['layout']); $this->assertSame('', $defaults['page_title']); }
/** * {@inheritdoc} */ public function build(PanelsDisplayVariant $panels_display) { // Check to see if the current user has permissions to use the IPE. $has_permission = $this->account->hasPermission('access panels in-place editing'); // Attach the Panels In-place editor library based on permissions. if ($has_permission) { // This flag tracks whether or not there are unsaved changes. $unsaved = FALSE; // If a temporary configuration for this variant exists, use it. $temp_store_key = $panels_display->id(); if ($variant_config = $this->tempStore->get($temp_store_key)) { unset($variant_config['id']); $panels_display->setConfiguration($variant_config); // Indicate that the user is viewing un-saved changes. $unsaved = TRUE; } $build = parent::build($panels_display); $regions = $panels_display->getRegionAssignments(); $layout = $panels_display->getLayout(); foreach ($regions as $region => $blocks) { // Wrap each region with a unique class and data attribute. $region_name = Html::getClass("block-region-{$region}"); $build[$region]['#prefix'] = '<div class="' . $region_name . '" data-region-name="' . $region . '">'; $build[$region]['#suffix'] = '</div>'; if ($blocks) { foreach ($blocks as $block_id => $block) { $build[$region][$block_id]['#attributes']['data-block-id'] = $block_id; } } } // Attach the required settings and IPE. $build['#attached']['library'][] = 'panels_ipe/panels_ipe'; $build['#attached']['drupalSettings']['panels_ipe'] = $this->getDrupalSettings($regions, $layout, $panels_display, $unsaved); // Add our custom elements to the build. $build['#prefix'] = '<div id="panels-ipe-content">'; $build['#suffix'] = '</div><div id="panels-ipe-tray"></div>'; } else { $build = parent::build($panels_display); } return $build; }
/** * Build the render array for a single panelized entity. * * @param \Drupal\Core\Entity\EntityInterface $entity * @param \Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVariant $panels_display * @param string $view_mode * @param string $langcode * * @return array */ protected function buildPanelized(EntityInterface $entity, PanelsDisplayVariant $panels_display, $view_mode, $langcode) { $contexts = $panels_display->getContexts(); $entity_context = new Context(new ContextDefinition('entity:' . $this->entityTypeId, NULL, TRUE), $entity); $contexts['@panelizer.entity_context:' . $this->entityTypeId] = $entity_context; $panels_display->setContexts($contexts); $build = $panels_display->build(); // @todo: I'm sure more is necessary to get the cache contexts right... CacheableMetadata::createFromObject($entity)->applyTo($build); $this->getPanelizerPlugin()->alterBuild($build, $entity, $panels_display, $view_mode); return $build; }
/** * {@inheritdoc} */ public function save(PanelsDisplayVariant $panels_display) { $storage = $this->getStorage($panels_display->getStorageType()); $storage->save($panels_display); }
/** * {@inheritdoc} */ public function build(PanelsDisplayVariant $panels_display) { $regions = $panels_display->getRegionAssignments(); $contexts = $panels_display->getContexts(); $layout = $panels_display->getLayout(); $regions = $this->buildRegions($regions, $contexts); if ($layout) { $regions = $layout->build($regions); } return $regions; }
/** * Updates the current Panels display based on the changes done in our app. * * @param \Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVariant $panels_display * The current Panels display. * @param array $layout_model * The decoded LayoutModel from our App. * * @return \Symfony\Component\HttpFoundation\JsonResponse */ protected function updatePanelsDisplay(PanelsDisplayVariant $panels_display, array $layout_model) { // Set our weight and region based on the metadata in our Backbone app. foreach ($layout_model['regionCollection'] as $region) { $weight = 0; foreach ($region['blockCollection'] as $block) { /** @var \Drupal\Core\Block\BlockBase $block_instance */ $block_instance = $panels_display->getBlock($block['uuid']); $block_instance->setConfigurationValue('region', $region['name']); $block_instance->setConfigurationValue('weight', ++$weight); $panels_display->updateBlock($block['uuid'], $block_instance->getConfiguration()); } } // Remove blocks that need removing. // @todo We should do this on the fly instead of at on save. foreach ($layout_model['deletedBlocks'] as $uuid) { $panels_display->removeBlock($uuid); } // Save the variant and remove temp storage. $this->savePanelsDisplay($panels_display, FALSE); return new JsonResponse(['deletedBlocks' => []]); }
/** * {@inheritdoc} */ public function build(PanelsDisplayVariant $panels_display) { $regions = $panels_display->getRegionAssignments(); return $regions; }
/** * Deletes the given Panels Display from TempStore. * * @param \Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVariant $panels_display * @throws \Drupal\user\TempStoreException */ protected function deletePanelsDisplayTempStore(PanelsDisplayVariant $panels_display) { $this->tempStore->delete($panels_display->id()); }