core/modules/outside_in/outside_in.api.php | 63 ++++++++++++
core/modules/outside_in/outside_in.module | 9 +-
.../outside_in_test/outside_in_test.info.yml | 9 ++
.../OffCanvasFormAnntationIsClassBlockForm.php | 44 +++++++++
.../Block/OffCanvasFormAnnotationIsClassBlock.php | 27 +++++
.../Block/OffCanvasFormAnnotationIsFalseBlock.php | 27 +++++
.../Block/OffCanvasFormAnnotationNoneBlock.php | 24 +++++
.../tests/src/Functional/OutsideInTest.php | 110 +++++++++++++++++++++
.../OutsideInBlockFormTest.php | 23 +++++
9 files changed, 335 insertions(+), 1 deletion(-)
diff --git a/core/modules/outside_in/outside_in.api.php b/core/modules/outside_in/outside_in.api.php
new file mode 100644
index 0000000..2f9439f
--- /dev/null
+++ b/core/modules/outside_in/outside_in.api.php
@@ -0,0 +1,63 @@
+plugin->buildConfigurationForm($form, $form_state);
+
+ $form['some_setting'] = [
+ '#type' => 'select',
+ '#title' => t('Some setting'),
+ '#options' => [
+ 'a' => 'A',
+ 'b' => 'B',
+ ],
+ '#required' => TRUE,
+ ];
+
+ return $form;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {}
+
+}
diff --git a/core/modules/outside_in/tests/modules/outside_in_test/src/Plugin/Block/OffCanvasFormAnnotationIsClassBlock.php b/core/modules/outside_in/tests/modules/outside_in_test/src/Plugin/Block/OffCanvasFormAnnotationIsClassBlock.php
new file mode 100644
index 0000000..41af9dc
--- /dev/null
+++ b/core/modules/outside_in/tests/modules/outside_in_test/src/Plugin/Block/OffCanvasFormAnnotationIsClassBlock.php
@@ -0,0 +1,27 @@
+ 'class'];
+ }
+
+}
diff --git a/core/modules/outside_in/tests/modules/outside_in_test/src/Plugin/Block/OffCanvasFormAnnotationIsFalseBlock.php b/core/modules/outside_in/tests/modules/outside_in_test/src/Plugin/Block/OffCanvasFormAnnotationIsFalseBlock.php
new file mode 100644
index 0000000..6458fa1
--- /dev/null
+++ b/core/modules/outside_in/tests/modules/outside_in_test/src/Plugin/Block/OffCanvasFormAnnotationIsFalseBlock.php
@@ -0,0 +1,27 @@
+ 'FALSE'];
+ }
+
+}
diff --git a/core/modules/outside_in/tests/modules/outside_in_test/src/Plugin/Block/OffCanvasFormAnnotationNoneBlock.php b/core/modules/outside_in/tests/modules/outside_in_test/src/Plugin/Block/OffCanvasFormAnnotationNoneBlock.php
new file mode 100644
index 0000000..1e67f23
--- /dev/null
+++ b/core/modules/outside_in/tests/modules/outside_in_test/src/Plugin/Block/OffCanvasFormAnnotationNoneBlock.php
@@ -0,0 +1,24 @@
+ 'none'];
+ }
+
+}
diff --git a/core/modules/outside_in/tests/src/Functional/OutsideInTest.php b/core/modules/outside_in/tests/src/Functional/OutsideInTest.php
new file mode 100644
index 0000000..3a009bb
--- /dev/null
+++ b/core/modules/outside_in/tests/src/Functional/OutsideInTest.php
@@ -0,0 +1,110 @@
+id();
+ }
+
+ /**
+ * Tests the three possible forms[off_canvas] annotations: class, FALSE, none.
+ *
+ * There is also functional JS test coverage to ensure that the two blocks
+ * that support Settings Tray (the "class" & "none" cases) do work correctly.
+ *
+ * @see OutsideInBlockFormTest::testBlocks()
+ */
+ public function testPossibleAnnotations() {
+ $test_block_plugin_ids = [
+ // Block that explicitly provides an "off_canvas" form class.
+ 'outside_in_test_class',
+ // Block that explicitly provides no "off_canvas" form, thus opting out.
+ 'outside_in_test_false',
+ // Block that does nothing explicit for Settings Tray.
+ 'outside_in_test_none',
+ ];
+
+ $placed_blocks = [];
+ foreach ($test_block_plugin_ids as $plugin_id) {
+ $placed_blocks[$plugin_id] = $this->placeBlock($plugin_id);
+ }
+
+ $this->drupalGet('');
+ $web_assert = $this->assertSession();
+ foreach ($placed_blocks as $plugin_id => $placed_block) {
+ $block_selector = $this->getBlockSelector($placed_block);
+
+ // All blocks are rendered.
+ $web_assert->elementExists('css', $block_selector);
+
+ // All blocks except 'outside_in_test_false' are editable. For more
+ // detailed test coverage, which requires JS execution, see
+ // OutsideInBlockFormTest::testBlocks().
+ if ($plugin_id !== 'outside_in_test_false') {
+ $web_assert->elementExists('css', "{$block_selector}[data-drupal-outsidein=\"editable\"]");
+ }
+ else {
+ $web_assert->elementNotExists('css', "{$block_selector}[data-drupal-outsidein=\"editable\"]");
+ }
+ }
+ }
+
+ /**
+ * Tests that certain blocks opt out from Settings Tray.
+ */
+ public function testOptOut() {
+ $web_assert = $this->assertSession();
+
+ $non_excluded_block = $this->placeBlock('system_powered_by_block');
+ $excluded_block_plugin_ids = ['page_title_block', 'system_main_block', 'outside_in_test_false'];
+ $block_selectors = [];
+ // Place blocks that should be excluded.
+ foreach ($excluded_block_plugin_ids as $excluded_block_plugin_id) {
+ // The block HTML 'id' attribute will be "block-[block_id]".
+ $block_selectors[] = $this->getBlockSelector($this->placeBlock($excluded_block_plugin_id));
+ }
+ $this->drupalGet('');
+ // Assert that block has been marked as "editable" and contextual that
+ // should exist does.
+ $web_assert->elementExists('css', $this->getBlockSelector($non_excluded_block) . "[data-drupal-outsidein=\"editable\"]");
+ // Assert that each block that has a "forms[off_canvas] = FALSE" annotation:
+ // - is still rendered on the page
+ // - but is not marked as "editable" by outside_in_preprocess_block()
+ // - and does not have the Settings Tray contextual link
+ foreach ($block_selectors as $block_selector) {
+ $web_assert->elementExists('css', $block_selector);
+ $web_assert->elementNotExists('css', "{$block_selector}[data-drupal-outsidein=\"editable\"]");
+ $web_assert->elementNotExists('css', "$block_selector [data-outside-in-edit]");
+ }
+ }
+}
diff --git a/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
index 04fc230..4353355 100644
--- a/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
+++ b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
@@ -35,6 +35,7 @@ class OutsideInBlockFormTest extends OutsideInJavascriptTestBase {
// Add test module to override CSS pointer-events properties because they
// cause test failures.
'outside_in_test_css',
+ 'outside_in_test',
];
/**
@@ -109,6 +110,10 @@ public function testBlocks($block_plugin, $new_page_text, $element_selector, $la
// Fill out form, save the form.
$page->fillField('settings[site_information][site_name]', $new_page_text);
break;
+
+ case 'outside_in_test_class':
+ $web_assert->elementExists('css', '[data-drupal-selector="edit-settings-some-setting"]');
+ break;
}
if (isset($new_page_text)) {
@@ -176,6 +181,24 @@ public function providerTestBlocks() {
'button_text' => 'Save Search form',
'toolbar_item' => NULL,
],
+ // This is the functional JS test coverage accompanying testPossibleAnnotations().
+ '\Drupal\outside_in_test\Plugin\Block\OffCanvasFormAnnotationIsClassBlock' => [
+ 'block_plugin' => 'outside_in_test_class',
+ 'new_page_text' => NULL,
+ 'element_selector' => 'span',
+ 'label_selector' => 'h2',
+ 'button_text' => 'Save Settings Tray test block: forms[off_canvas]=class',
+ 'toolbar_item' => NULL,
+ ],
+ // This is the functional JS test coverage accompanying testPossibleAnnotations().
+ '\Drupal\outside_in_test\Plugin\Block\OffCanvasFormAnnotationNoneBlock' => [
+ 'block_plugin' => 'outside_in_test_none',
+ 'new_page_text' => NULL,
+ 'element_selector' => 'span',
+ 'label_selector' => 'h2',
+ 'button_text' => 'Save Settings Tray test block: forms[off_canvas] is not specified',
+ 'toolbar_item' => NULL,
+ ],
];
return $blocks;
}