Commit 36cf1a23 authored by webchick's avatar webchick

Issue #2968500 by tedbow, bendeguz.csirmaz, samuel.mortenson, phenaproxima,...

Issue #2968500 by tedbow, bendeguz.csirmaz, samuel.mortenson, phenaproxima, lauriii, AaronMcHale: Change inline blocks workflow in Layout Builder to match mocks

(cherry picked from commit 257cfc72)
parent 790e3091
......@@ -85,3 +85,32 @@
display: block;
padding-top: 0.55em;
}
#drupal-off-canvas .inline-block-create-button {
display: block;
padding: 24px;
padding-left: 44px;
font-size: 16px;
color: #eee;
background: url(../../../misc/icons/bebebe/plus.svg) transparent 16px no-repeat;
}
#drupal-off-canvas .inline-block-create-button,
#drupal-off-canvas .inline-block-list__item {
margin: 0 -20px;
background-color: #444;
}
#drupal-off-canvas .inline-block-create-button:hover,
#drupal-off-canvas .inline-block-list__item:hover {
background-color: #333;
}
#drupal-off-canvas .inline-block-list {
margin-bottom: 15px;
}
#drupal-off-canvas .inline-block-list__item {
display: block;
padding: 15px 0 15px 25px;
}
......@@ -177,7 +177,7 @@ function layout_builder_cron() {
function layout_builder_plugin_filter_block_alter(array &$definitions, array $extra, $consumer) {
// @todo Determine the 'inline_block' blocks should be allowed outside
// of layout_builder https://www.drupal.org/node/2979142.
if ($consumer !== 'layout_builder') {
if ($consumer !== 'layout_builder' || !isset($extra['list']) || $extra['list'] !== 'inline_blocks') {
foreach ($definitions as $id => $definition) {
if ($definition['id'] === 'inline_block') {
unset($definitions[$id]);
......
......@@ -80,6 +80,19 @@ layout_builder.add_block:
section_storage:
layout_builder_tempstore: TRUE
layout_builder.choose_inline_block:
path: '/layout_builder/choose/inline-block/{section_storage_type}/{section_storage}/{delta}/{region}'
defaults:
_controller: '\Drupal\layout_builder\Controller\ChooseBlockController::inlineBlockList'
_title: 'Add a new Inline Block'
requirements:
_permission: 'configure any layout'
options:
_admin_route: TRUE
parameters:
section_storage:
layout_builder_tempstore: TRUE
layout_builder.update_block:
path: '/layout_builder/update/block/{section_storage_type}/{section_storage}/{delta}/{region}/{uuid}'
defaults:
......
......@@ -5,6 +5,7 @@
use Drupal\Core\Ajax\AjaxHelperTrait;
use Drupal\Core\Block\BlockManagerInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\layout_builder\Context\LayoutBuilderContextTrait;
......@@ -29,14 +30,24 @@ class ChooseBlockController implements ContainerInjectionInterface {
*/
protected $blockManager;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* ChooseBlockController constructor.
*
* @param \Drupal\Core\Block\BlockManagerInterface $block_manager
* The block manager.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(BlockManagerInterface $block_manager) {
public function __construct(BlockManagerInterface $block_manager, EntityTypeManagerInterface $entity_type_manager) {
$this->blockManager = $block_manager;
$this->entityTypeManager = $entity_type_manager;
}
/**
......@@ -44,7 +55,8 @@ public function __construct(BlockManagerInterface $block_manager) {
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('plugin.manager.block')
$container->get('plugin.manager.block'),
$container->get('entity_type.manager')
);
}
......@@ -63,8 +75,43 @@ public static function create(ContainerInterface $container) {
*/
public function build(SectionStorageInterface $section_storage, $delta, $region) {
$build['#title'] = $this->t('Choose a block');
$build['#type'] = 'container';
$build['#attributes']['class'][] = 'block-categories';
if ($this->entityTypeManager->hasDefinition('block_content_type') && $types = $this->entityTypeManager->getStorage('block_content_type')->loadMultiple()) {
if (count($types) === 1) {
$type = reset($types);
$plugin_id = 'inline_block:' . $type->id();
if ($this->blockManager->hasDefinition($plugin_id)) {
$url = Url::fromRoute('layout_builder.add_block', [
'section_storage_type' => $section_storage->getStorageType(),
'section_storage' => $section_storage->getStorageId(),
'delta' => $delta,
'region' => $region,
'plugin_id' => $plugin_id,
]);
}
}
else {
$url = Url::fromRoute('layout_builder.choose_inline_block', [
'section_storage_type' => $section_storage->getStorageType(),
'section_storage' => $section_storage->getStorageId(),
'delta' => $delta,
'region' => $region,
]);
}
if (isset($url)) {
$build['add_block'] = [
'#type' => 'link',
'#url' => $url,
'#title' => $this->t('Create @entity_type', [
'@entity_type' => $this->entityTypeManager->getDefinition('block_content')->getSingularLabel(),
]),
'#attributes' => $this->getAjaxAttributes(),
];
$build['add_block']['#attributes']['class'][] = 'inline-block-create-button';
}
}
$block_categories['#type'] = 'container';
$block_categories['#attributes']['class'][] = 'block-categories';
// @todo Explicitly cast delta to an integer, remove this in
// https://www.drupal.org/project/drupal/issues/2984509.
......@@ -75,35 +122,116 @@ public function build(SectionStorageInterface $section_storage, $delta, $region)
'delta' => $delta,
'region' => $region,
]);
foreach ($this->blockManager->getGroupedDefinitions($definitions) as $category => $blocks) {
$build[$category]['#type'] = 'details';
$build[$category]['#open'] = TRUE;
$build[$category]['#title'] = $category;
$build[$category]['links'] = [
'#theme' => 'links',
];
foreach ($blocks as $block_id => $block) {
$link = [
'title' => $block['admin_label'],
'url' => Url::fromRoute('layout_builder.add_block',
[
'section_storage_type' => $section_storage->getStorageType(),
'section_storage' => $section_storage->getStorageId(),
'delta' => $delta,
'region' => $region,
'plugin_id' => $block_id,
]
),
];
if ($this->isAjax()) {
$link['attributes']['class'][] = 'use-ajax';
$link['attributes']['data-dialog-type'][] = 'dialog';
$link['attributes']['data-dialog-renderer'][] = 'off_canvas';
}
$build[$category]['links']['#links'][] = $link;
$grouped_definitions = $this->blockManager->getGroupedDefinitions($definitions);
foreach ($grouped_definitions as $category => $blocks) {
$block_categories[$category]['#type'] = 'details';
$block_categories[$category]['#open'] = TRUE;
$block_categories[$category]['#title'] = $category;
$block_categories[$category]['links'] = $this->getBlockLinks($section_storage, $delta, $region, $blocks);
}
$build['block_categories'] = $block_categories;
return $build;
}
/**
* Provides the UI for choosing a new inline block.
*
* @param \Drupal\layout_builder\SectionStorageInterface $section_storage
* The section storage.
* @param int $delta
* The delta of the section to splice.
* @param string $region
* The region the block is going in.
*
* @return array
* A render array.
*/
public function inlineBlockList(SectionStorageInterface $section_storage, $delta, $region) {
$definitions = $this->blockManager->getFilteredDefinitions('layout_builder', $this->getAvailableContexts($section_storage), [
'section_storage' => $section_storage,
'region' => $region,
'list' => 'inline_blocks',
]);
$blocks = $this->blockManager->getGroupedDefinitions($definitions);
$build = [];
if (isset($blocks['Inline blocks'])) {
$build['links'] = $this->getBlockLinks($section_storage, $delta, $region, $blocks['Inline blocks']);
$build['links']['#attributes']['class'][] = 'inline-block-list';
foreach ($build['links']['#links'] as &$link) {
$link['attributes']['class'][] = 'inline-block-list__item';
}
$build['back_button'] = [
'#type' => 'link',
'#url' => Url::fromRoute('layout_builder.choose_block',
[
'section_storage_type' => $section_storage->getStorageType(),
'section_storage' => $section_storage->getStorageId(),
'delta' => $delta,
'region' => $region,
]
),
'#title' => $this->t('Back'),
'#attributes' => $this->getAjaxAttributes(),
];
}
return $build;
}
/**
* Gets a render array of block links.
*
* @param \Drupal\layout_builder\SectionStorageInterface $section_storage
* The section storage.
* @param int $delta
* The delta of the section to splice.
* @param string $region
* The region the block is going in.
* @param array $blocks
* The information for each block.
*
* @return array
* The block links render array.
*/
protected function getBlockLinks(SectionStorageInterface $section_storage, $delta, $region, array $blocks) {
$links = [];
foreach ($blocks as $block_id => $block) {
$link = [
'title' => $block['admin_label'],
'url' => Url::fromRoute('layout_builder.add_block',
[
'section_storage_type' => $section_storage->getStorageType(),
'section_storage' => $section_storage->getStorageId(),
'delta' => $delta,
'region' => $region,
'plugin_id' => $block_id,
]
),
'attributes' => $this->getAjaxAttributes(),
];
$links[] = $link;
}
return [
'#theme' => 'links',
'#links' => $links,
];
}
/**
* Get dialog attributes if an ajax request.
*
* @return array
* The attributes array.
*/
protected function getAjaxAttributes() {
if ($this->isAjax()) {
return [
'class' => ['use-ajax'],
'data-dialog-type' => 'dialog',
'data-dialog-renderer' => 'off_canvas',
];
}
return [];
}
}
......@@ -192,8 +192,8 @@ protected function addInlineFileBlockToLayout($title, File $file) {
$page = $this->getSession()->getPage();
$page->clickLink('Add Block');
$assert_session->assertWaitOnAjaxRequest();
$this->assertNotEmpty($assert_session->waitForElementVisible('css', '.block-categories details:contains(Create new block)'));
$this->clickLink('Basic block');
$this->assertNotEmpty($assert_session->waitForLink('Create custom block'));
$this->clickLink('Create custom block');
$assert_session->assertWaitOnAjaxRequest();
$assert_session->fieldValueEquals('Title', '');
$page->findField('Title')->setValue($title);
......
......@@ -428,4 +428,74 @@ public function testAccess() {
$assert_session->pageTextNotContains('You are not authorized to access this page');
}
/**
* Tests the workflow for adding an inline block depending on number of types.
*
* @throws \Behat\Mink\Exception\ElementNotFoundException
* @throws \Behat\Mink\Exception\ExpectationException
*/
public function testAddWorkFlow() {
$assert_session = $this->assertSession();
$page = $this->getSession()->getPage();
$type_storage = $this->container->get('entity_type.manager')->getStorage('block_content_type');
foreach ($type_storage->loadByProperties() as $type) {
$type->delete();
}
$this->drupalLogin($this->drupalCreateUser([
'access contextual links',
'configure any layout',
'administer node display',
'administer node fields',
]));
// Enable layout builder and overrides.
$this->drupalPostForm(
static::FIELD_UI_PREFIX . '/display/default',
['layout[enabled]' => TRUE, 'layout[allow_custom]' => TRUE],
'Save'
);
$layout_default_path = 'admin/structure/types/manage/bundle_with_section_field/display-layout/default';
$this->drupalGet($layout_default_path);
// Add a basic block with the body field set.
$page->clickLink('Add Block');
$assert_session->assertWaitOnAjaxRequest();
// Confirm that with no block content types the link does not appear.
$assert_session->linkNotExists('Create custom block');
$this->createBlockContentType('basic', 'Basic block');
$this->drupalGet($layout_default_path);
// Add a basic block with the body field set.
$page->clickLink('Add Block');
$assert_session->assertWaitOnAjaxRequest();
// Confirm with only 1 type the "Create custom block" link goes directly t
// block add form.
$assert_session->linkNotExists('Basic block');
$this->clickLink('Create custom block');
$assert_session->assertWaitOnAjaxRequest();
$assert_session->fieldExists('Title');
$this->createBlockContentType('advanced', 'Advanced block');
$this->drupalGet($layout_default_path);
// Add a basic block with the body field set.
$page->clickLink('Add Block');
// Confirm that, when more than 1 type exists, "Create custom block" shows a
// list of block types.
$assert_session->assertWaitOnAjaxRequest();
$assert_session->linkNotExists('Basic block');
$assert_session->linkNotExists('Advanced block');
$this->clickLink('Create custom block');
$assert_session->assertWaitOnAjaxRequest();
$assert_session->fieldNotExists('Title');
$assert_session->linkExists('Basic block');
$assert_session->linkExists('Advanced block');
$this->clickLink('Advanced block');
$assert_session->assertWaitOnAjaxRequest();
$assert_session->fieldExists('Title');
}
}
......@@ -71,13 +71,7 @@ protected function setUp() {
],
],
]);
$bundle = BlockContentType::create([
'id' => 'basic',
'label' => 'Basic block',
'revision' => 1,
]);
$bundle->save();
block_content_add_body_field($bundle->id());
$this->createBlockContentType('basic', 'Basic block');
$this->blockStorage = $this->container->get('entity_type.manager')->getStorage('block_content');
}
......@@ -146,8 +140,8 @@ protected function addInlineBlockToLayout($title, $body) {
$page = $this->getSession()->getPage();
$page->clickLink('Add Block');
$assert_session->assertWaitOnAjaxRequest();
$this->assertNotEmpty($assert_session->waitForElementVisible('css', '.block-categories details:contains(Create new block)'));
$this->clickLink('Basic block');
$this->assertNotEmpty($assert_session->waitForLink('Create custom block'));
$this->clickLink('Create custom block');
$assert_session->assertWaitOnAjaxRequest();
$textarea = $assert_session->waitForElement('css', '[name="settings[block_form][body][0][value]"]');
$this->assertNotEmpty($textarea);
......@@ -219,4 +213,22 @@ protected function assertDialogClosedAndTextVisible($text, $css_locator = NULL)
}
}
/**
* Creates a block content type.
*
* @param string $id
* The block type id.
* @param string $label
* The block type label.
*/
protected function createBlockContentType($id, $label) {
$bundle = BlockContentType::create([
'id' => $id,
'label' => $label,
'revision' => 1,
]);
$bundle->save();
block_content_add_body_field($bundle->id());
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment