Problem/Motivation

The Outside In prototype introduced in #2753941: [Experimental] Create Outside In module MVP to provide block configuration in Off-Canvas tray and expand site edit mode allows a user to configure page elements in context. Something very frustating happens when trying to edit the page title.

This is partly an existing usability issue with the page title block (the title and display title make no sense for that block), but it's made much worse with the introduction of a module that lets me click on those words and get a sidebar to do everything but change those words. There are several problems:

  1. The "Display title" checkbox makes no sense for this block.
  2. The "Display title" checkbox does not display the thing in the title box for this block.
  3. The contents of the title box are ignored.
  4. When I click on this, I don't actually want to configure this block at all. I want to edit the node title!

Proposed resolution

Since the nothing you can do to the page title block will actually have any visible effect it should be not get the "Quick Edit" contextual link provided by this module.

  1. Add new function _outside_in_is_block_editable() that will be called to determine if a block should exclude from getting the Quick Edit link. This sets the Main Content(which was already excluded) and Page Title block.
  2. Set an attribute data-outside-in-exclude on blocks should not include a Quick Edit link which will remove the link via Javascript. (It is very complicated to remove contextual links on the server side see @Wim Leers' comment in #12)

Remaining tasks

None

User interface changes

No "Quick Edit" contextual link for the Page Title block.
User doesn't get access of the Off-canvas form for the Page Title block which would have no effect anyways.

API changes

None

Data model changes

None

CommentFileSizeAuthor
#103 2782891-outsidein-103.patch24.7 KBtim.plunkett
#103 2782891-outsidein-103-interdiff.txt9.94 KBtim.plunkett
#98 2782891-98.patch23.79 KBtedbow
#98 interdiff-97-98.txt1.13 KBtedbow
#97 2782891-outsidein-97.patch24.92 KBtim.plunkett
#97 2782891-outsidein-97-interdiff.txt6.55 KBtim.plunkett
#95 2782891-95.patch25.99 KBtedbow
#95 interdiff-94-95.txt4.53 KBtedbow
#94 2782891-94.patch30.28 KBtedbow
#94 interdiff-93-94.txt3.61 KBtedbow
display_title_on_title_block_makes_no_sense.png163.56 KBxjm
#8 2782891-8.patch3.45 KBtedbow
#13 2782891-13.patch4.04 KBtedbow
#13 interdiff-9-13.txt3.99 KBtedbow
#15 interdiff-13-14.txt3.48 KBtedbow
#15 2782891-15.patch3.28 KBtedbow
#16 interdiff-13-16.txt1.02 KBtedbow
#16 2782891-16-TEST_ONLY.patch1.02 KBtedbow
#16 2782891-16.patch4.3 KBtedbow
#19 interdiff-16-19.txt1.86 KBtedbow
#19 2782891-19.patch4.91 KBtedbow
#21 interdiff-19-21.txt2.16 KBtedbow
#21 2782891-21.patch5.11 KBtedbow
#23 2782891-23.patch5.18 KBrajeevk
#27 2782891-27-reroll.patch5.14 KBtedbow
#30 2782891-30.patch5.07 KBtedbow
#32 interdiff-2782891-27-32.txt0 bytestedbow
#32 2782891-32.patch6.09 KBtedbow
#33 interdiff-2782891-30-32.txt3.43 KBtedbow
#35 2782891-32-reroll.patch6.15 KBtedbow
#40 interdiff-35-40.txt3.37 KBtedbow
#40 2782891-40.patch7.06 KBtedbow
#42 2782891-42.patch8.55 KBpk188
#42 interdiff-40-42.txt1.67 KBpk188
#49 2782891-49.patch8.92 KBtedbow
#50 all-commits.patch15.99 KBwim leers
#50 2782891-50.patch13.82 KBwim leers
#51 interdiff-2782891-50-51.txt13.3 KBtedbow
#51 2782891-51.patch13.3 KBtedbow
#55 interdiff-2782891-50-51.txt1.11 KBtedbow
#56 2542050-56.patch14.37 KBwim leers
#56 interdiff.txt1.43 KBwim leers
#57 interdiff.txt825 byteswim leers
#57 2782891-57.patch13.87 KBwim leers
#62 interdiff.txt15.6 KBwim leers
#62 2782891-62.patch28.15 KBwim leers
#64 interdiff.txt1.68 KBwim leers
#64 2782891-64.patch28.04 KBwim leers
#67 interdiff.txt6.13 KBwim leers
#67 2782891-67.patch28.08 KBwim leers
#70 interdiff.txt4.17 KBwim leers
#70 2782891-70.patch28.61 KBwim leers
#74 interdiff.txt962 byteswim leers
#74 2782891-74.patch28.62 KBwim leers
#76 interdiff.txt6.69 KBwim leers
#76 2782891-76.patch31.24 KBwim leers
#78 interdiff.txt1.61 KBwim leers
#78 2782891-78.patch31.16 KBwim leers
#81 2782891-81.patch29.5 KBpk188
#86 2782891-86.patch29.69 KBpk188
#89 2782891-89.patch29.5 KBpk188
#93 interdiff.txt8.37 KBada hernandez
#93 2782891-93.patch30.19 KBada hernandez

Comments

xjm created an issue. See original summary.

xjm’s picture

xjm’s picture

Issue summary: View changes
tedbow’s picture

Component: quickedit.module » outside_in.module
tkoleary’s picture

Taking another look at this in the current state of the module I think I have a simple solution. The user who wants to edit the title should have a contextual lin k from the page title block "edit title".

We have another issue to change the 'quick edit' on the block to 'open settings tray' so that would give us three links in the page title block dropdown:

  • Configure block
  • Open settings tray
  • Edit title

Configure block will go to the backend form, Open settings tray will show the settings for the block in-place (in this case the block title name which is still confusing...), and edit title should trigger quick edit mode with focus on the title field.

This removes the most annoying WTF of this experience which is that I need to go to the third contextual link down to edit the title of the node. 'Configure block' and 'Open settings tray' are still not crystal clear but at least with the third option the user can do some trial and error and get to where they need to be.

tkoleary’s picture

Issue tags: +Usability
tedbow’s picture

I think once #2782915: Standardize the behavior of links when Outside In editing mode is enabled lands(hopefully soon) this problem will be easier with better UX.

With that issue in "Edit Mode" if you click an area that is covered by QuickEdit then you the quick edit toolbar will be invoked.
We could extend this functionality to the Title block if it for a QuickEdit entity. The title in this block has the attribute data-quickedit-field-id if it is for a QuickEdit entity.

Then I think we should remove the Settings Tray functionality altogether for this block. It is a form without any real functionality. It has 2 elements. A checkbox for "Display title" that in all other blocks shows the title of the block. If you click it shows the page title twice. The textfield has even less functionality. It literally has no functionality. It updates the title of the block but because the way the checkbox behaves the textfield changes will never show on the site.

You would still be able to get the advanced block form where you could delete the block or changes its region if needed.

tedbow’s picture

StatusFileSize
new3.45 KB

Thought a little more about it and no reason to wait for #2782915: Standardize the behavior of links when Outside In editing mode is enabled

Removing the page title block from the "Edit mode" makes sense regardless. Adding the trigger for QuickEdit could be a follow up issue.

This page remove the page title block from the Setting Tray module functionality.

tedbow’s picture

Status: Active » Needs review

Setting needs review.

Also couple question about my patch

  1. +++ b/core/modules/outside_in/outside_in.module
    @@ -55,6 +60,12 @@ function outside_in_block_view_alter(array &$build) {
    +    // If this block should not be editable flag for contextual link removable.
    +    // The individual links are not available here to remove.
    +    $build['#contextual_links']['block']['metadata']['remove_outside_in'] = TRUE;
    

    I could find a better to flag that the block should not have the contextual link. In hook_contextual_links_view_alter we don't have plugin_id any more. We could check from the block id = "*_page_title" but that seems hacky and nothing would stop someone from using that block id pattern for another block.

  2. +++ b/core/modules/outside_in/src/OutsideInManagerInterface.php
    @@ -15,4 +15,15 @@
    +  public function isBlockEditable($plugin_id);
    

    Wasn't sure if this belonged in the interface but fits the description "Provides an interface for managing information related to Outside-In."

tkoleary’s picture

Tested in simplytest.me. Passes usability review.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

wim leers’s picture

Status: Needs review » Needs work
  1. +++ b/core/modules/outside_in/outside_in.module
    @@ -34,6 +34,11 @@ function outside_in_help($route_name, RouteMatchInterface $route_match) {
    +    if (!empty($element['#contextual_links']['block']['metadata']['remove_outside_in'])) {
    +      unset($element['#links']['outside-inblock-configure']);
    +      unset($items['outside_in.block_configure']);
    +      return;
    +    }
    
    @@ -55,6 +60,12 @@ function outside_in_block_view_alter(array &$build) {
    +  if (!\Drupal::service('outside_in.manager')->isBlockEditable($build['#plugin_id']) && isset($build['#contextual_links']['block'])) {
    +    // If this block should not be editable flag for contextual link removable.
    +    // The individual links are not available here to remove.
    +    $build['#contextual_links']['block']['metadata']['remove_outside_in'] = TRUE;
    +  }
    

    This needs some documentation. I needed to re-read this 5 times to figure out what's going on.

    The second hunk sets a "fake" bit of contextual link metadata.

    The first hunk detects the presence of that, and if so, unsets a particular contextual link.

  2. +++ b/core/modules/outside_in/src/OutsideInManager.php
    @@ -63,4 +63,12 @@ public function isApplicable() {
    +    $non_editable_blocks = ['page_title_block', 'system_main_block'];
    

    Nit: $readonly_blocks probably makes more sense?

  3. +++ b/core/modules/outside_in/src/OutsideInManager.php
    @@ -63,4 +63,12 @@ public function isApplicable() {
    +    return !in_array($plugin_id, $non_editable_blocks);
    

    Let's make this strict (in_array(…, …, TRUE)

  4. +++ b/core/modules/outside_in/src/OutsideInManagerInterface.php
    @@ -15,4 +15,15 @@
    +   * Checks whether a block should be covered by this module.
    ...
    +  public function isBlockEditable($plugin_id);
    

    Nit: comment does not match function name.

  5. +++ b/core/modules/outside_in/src/OutsideInManagerInterface.php
    @@ -15,4 +15,15 @@
    +   *   The plugin id for the block to check.
    

    Nit: s/id/ID/

  6. +++ b/core/modules/outside_in/src/OutsideInManagerInterface.php
    @@ -15,4 +15,15 @@
    +   *   TRUE if the block should the "Quick Edit" link provided by this module.
    

    Incomplete sentence.

The reason this is so surprisingly complex: the Contextual Links API was never designed for conditional contextual links. The Quick Edit module generates contextual links in JS (on the client side), so it can do this conditionally quite easily. This patch opts to do it on the server side. Hence it's fairly convoluted.

The approach in this patch can work. I think it's okay… but I can't help but wonder whether it wouldn't be a whole lot simpler to do this on the client side instead, much like Quick Edit.

tedbow’s picture

Status: Needs work » Needs review
Issue tags: +JavaScript
StatusFileSize
new4.04 KB
new3.99 KB

@Wim Leers thanks for the review.

Yes I think you right it is complicated to do the removal on the server side.

This patch just sets an attribute if the link should be removed. Then the actual removal is done via Javascript.

From the review
1. Mostly removed now. I add @see comment to point the .js file and to the the module file. Hopefully clearer what is going on.
2. I like "non_editable" because it directly says what the user is restricted by.
3. fixed
4. fixed
5. fixed

wim leers’s picture

  1. +++ b/core/modules/outside_in/outside_in.module
    @@ -55,6 +55,14 @@ function outside_in_block_view_alter(array &$build) {
    +    // to remove the link on the client-side.
    

    s/client-side/client side/

  2. +++ b/core/modules/outside_in/src/OutsideInManagerInterface.php
    @@ -15,4 +15,16 @@
    +  public function isBlockEditable($plugin_id);
    

    Are you sure you want to add a block-specific method to the interface? Outside-In is not restricted to blocks AFAIK?

    Related: I'd strongly recommend doing what BigPipe did here too: #2835604: BigPipe provides functionality, not an API: mark all classes & interfaces @internal + #2835758: Remove BigPipeInterface and move all of its docs to the implementation.

tedbow’s picture

StatusFileSize
new3.48 KB
new3.28 KB

re #14
1. fixed
2. Removed this from the interface and moved to a function in the module file.

On the related note I think that makes sense and will make follow up issues.

tedbow’s picture

StatusFileSize
new1.02 KB
new1.02 KB
new4.3 KB

Ok adding test for the contextual link for the title block being excluded.

Also attaching a TEST_ONLY patch.

The last submitted patch, 16: 2782891-16-TEST_ONLY.patch, failed testing.

wim leers’s picture

Status: Needs review » Needs work
+++ b/core/modules/outside_in/outside_in.module
@@ -154,3 +164,18 @@ function outside_in_css_alter(&$css, AttachedAssetsInterface $assets) {
+  $non_editable_blocks = ['page_title_block', 'system_main_block'];

+++ b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
@@ -364,4 +364,16 @@ protected function pressToolbarEditButton() {
+   * Tests that title block does not have a outside_in contextual link.

Shouldn't we also test the system_main_block block?

Other than that, RTBC.

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new1.86 KB
new4.91 KB

@Wim Leers thanks for the review!

Yes we should check the content block also. I also realized that not only should we be checking for the contextual link being excluded we should also make sure that the data-drupal-outsidein attribute is not added which would mark the the block as "editable".

wim leers’s picture

Status: Needs review » Needs work
+++ b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
@@ -368,12 +368,23 @@ protected function pressToolbarEditButton() {
+    // We do not need to place the main content block.
+    // It's ID will just be 'content'.

Well, that's just the fallback behavior in \Drupal\block\Plugin\DisplayVariant\BlockPageVariant::build(). In that case, it's not even an actual block.

So I'm not sure that this patch is correct. I think we should place the block. And we should have a separate test ensuring that you also don't get outside in functionality in case no "main content" block is placed.

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new2.16 KB
new5.11 KB

So I'm not sure that this patch is correct. I think we should place the block.

Ok now placing both the blocks that should be excluded in the same way.

And we should have a separate test ensuring that you also don't get outside in functionality in case no "main content" block is placed.

I am not sure we need this \Drupal\Tests\outside_in\FunctionalJavascript\OutsideInBlockFormTest::testBlocks tests Settings Tray edit mode functionality with explicitly placing the main content block.

tedbow’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

Needs re-roll because of #2862625: Rename offcanvas to two words in code and comments. and other recent commits

rajeevk’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new5.18 KB

Re-rolling patch for test & review after rebase.

tedbow’s picture

@RajeevK reroll looks great, Thanks!!!

Leaving as needs review because changes in #21(rerolled in #23 still need be reviewed.

wim leers’s picture

Status: Needs review » Reviewed & tested by the community
+++ b/core/modules/outside_in/outside_in.module
@@ -163,3 +173,18 @@ function outside_in_css_alter(&$css, AttachedAssetsInterface $assets) {
+function _outside_in_is_block_editable($plugin_id) {

Perhaps add an explicit @internal?

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 23: 2782891-23.patch, failed testing.

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new5.14 KB

Re-rolled #23 plus Wims' idea in #25

wim leers’s picture

Status: Needs review » Reviewed & tested by the community

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 27: 2782891-27-reroll.patch, failed testing. View results

tedbow’s picture

Status: Needs work » Reviewed & tested by the community
StatusFileSize
new5.07 KB

Need a re-roll. No changes.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 30: 2782891-30.patch, failed testing. View results

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new0 bytes
new6.09 KB

Ok although the patch in #27 applied cleaning there were 3 problems.

  1. It needed es6.js changes.
  2. \Drupal\Tests\outside_in\FunctionalJavascript\OutsideInBlockFormTest::setUp changed so there "Powered by Drupal" block is no longer being place there. We have to place it in testBlockExcluded() as an example of a non-excluded block - This caused the test fail.
  3. The getBlockSelector() helper function was added so we should now use that in our test.
tedbow’s picture

StatusFileSize
new3.43 KB

Ok so messed the interdiff on #32.

Here is the correct interdiff between #30 and #32.
You can see it has the 3 changes I described in #32

wim leers’s picture

Status: Needs review » Reviewed & tested by the community

That all made sense. I was confused by the *.js vs *.es6.js changes at first, but they actually make sense :)

tedbow’s picture

tedbow’s picture

Issue summary: View changes
tedbow’s picture

Issue summary: View changes
webchick’s picture

Status: Reviewed & tested by the community » Needs work

Thanks for the issue summary updates!

Talked about this some with @tedbow. Both @xjm and I felt a bit ooky about committing a new underscore-prefixed function for this. @tedbow explained that the reason this is wrapped in a function is to avoid inlining the same array twice. Makes sense. Another option which @tedbow thought of was, rather than _outside_in_is_block_editable(), add a method to OutsideInManagerInterface isBlockExcluded() because the phpDoc for the interface says “Provides an interface for managing information related to Outside-In.” which presumably would cover this. Marking needs work for that change.

This also addresses another my concerns which was "if contrib defines a block that wants to opt-out as well for whatever reason, what do they do?" Bearing in mind that we want to avoid making an explicit API, per #2894584: Settings Tray provides functionality, not an API: mark PHP and JS as internal.

xjm’s picture

Edit: Wrong issue, too many tabs, etc.

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new3.37 KB
new7.06 KB

I have created \Drupal\outside_in\OutsideInManagerInterface::isBlockEditable() and _outside_in_is_block_editable()

isBlockEditable is actually the exact same code that was in the earlier patch up till #13 and was reviewed by @Wim Leers

I removed in for the _outside_in_is_block_editable() in #15 because of his comment in #14.2

Are you sure you want to add a block-specific method to the interface? Outside-In is not restricted to blocks AFAIK?

Now after working with the Settings Tray module more and it almost stable I realize it's Edit only deals with Editing Block forms(plus other config added the form). So these seems like a good place for it.
The dialog tray itself could be used by other modules but Settings Tray Edit mode is always triggered through block contextual links and shows the Off-Canvas form for block plugin.

wim leers’s picture

Status: Needs review » Needs work
+++ b/core/modules/outside_in/outside_in.module
@@ -174,19 +174,3 @@ function outside_in_css_alter(&$css, AttachedAssetsInterface $assets) {
diff --git a/core/modules/outside_in/src/OutsideInManager.php b/core/modules/outside_in/src/OutsideInManager.php

diff --git a/core/modules/outside_in/src/OutsideInManager.php b/core/modules/outside_in/src/OutsideInManager.php
index 666a93837b..26bda75685 100644

index 666a93837b..26bda75685 100644
--- a/core/modules/outside_in/src/OutsideInManager.php

--- a/core/modules/outside_in/src/OutsideInManager.php
+++ b/core/modules/outside_in/src/OutsideInManager.php

+++ b/core/modules/outside_in/src/OutsideInManager.php
+++ b/core/modules/outside_in/src/OutsideInManager.php
@@ -63,4 +63,12 @@ public function isApplicable() {

@@ -63,4 +63,12 @@ public function isApplicable() {
     return $this->account->hasPermission('administer blocks') && !$is_admin_route && !$is_admin_demo_route;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function isBlockEditable($plugin_id) {
+    $non_editable_blocks = ['page_title_block', 'system_main_block'];
+    return !in_array($plugin_id, $non_editable_blocks, TRUE);
+  }
+
 }
diff --git a/core/modules/outside_in/src/OutsideInManagerInterface.php b/core/modules/outside_in/src/OutsideInManagerInterface.php

diff --git a/core/modules/outside_in/src/OutsideInManagerInterface.php b/core/modules/outside_in/src/OutsideInManagerInterface.php
index 684adb3f0d..054074e4c8 100644

index 684adb3f0d..054074e4c8 100644
--- a/core/modules/outside_in/src/OutsideInManagerInterface.php

--- a/core/modules/outside_in/src/OutsideInManagerInterface.php
+++ b/core/modules/outside_in/src/OutsideInManagerInterface.php

+++ b/core/modules/outside_in/src/OutsideInManagerInterface.php
+++ b/core/modules/outside_in/src/OutsideInManagerInterface.php
@@ -15,4 +15,16 @@

@@ -15,4 +15,16 @@
    */
   public function isApplicable();
 
+  /**
+   * Checks whether a block is editable by this module.
+   *
+   * @param string $plugin_id
+   *   The plugin ID for the block to check.
+   *
+   * @return bool
+   *   TRUE if the block should have the "Quick Edit" link provided by this
+   *   module.
+   */
+  public function isBlockEditable($plugin_id);
+

I don't understand how this is an explicit API as described in #38.

This is

  1. adding more to the interface that #2894584: Settings Tray provides functionality, not an API: mark PHP and JS as internal is planning to remove
  2. still not extensible — only a single module is able to override this

Why not instead make this something that can be specified in the @Block annotation? That'd make for an elegant solution: if outside_in_block_alter() would be altering the annotation of every block plugin rather than the two it's currently modifying, and would then skip these two, then there would be nothing special anymore, and no need for an extra API.

So instead of:

function outside_in_block_alter(&$definitions) {
  if (!empty($definitions['system_branding_block'])) {
    $definitions['system_branding_block']['forms']['off_canvas'] = SystemBrandingOffCanvasForm::class;
  }

  // Since menu blocks use derivatives, check the definition ID instead of
  // relying on the plugin ID.
  foreach ($definitions as &$definition) {
    if ($definition['id'] === 'system_menu_block') {
      $definition['forms']['off_canvas'] = SystemMenuOffCanvasForm::class;
    }
  }
}

do this:

function outside_in_block_alter(&$definitions) {
  foreach ($definitions as &$definition) {
    switch ($definition['id']) {
      // Don't provide Outside-In capabilities for these two very special blocks.
      // @see \Drupal\Core\Block\MainContentBlockPluginInterface
      // @see \Drupal\Core\Block\TitleBlockPluginInterface
      case 'page_title_block':
      case 'system_main_block':
        continue;

      // Use specialized off-canvas forms when they're available.
      // @todo move these into the corresponding block plugin annotations when Outside In becomes stable.
      case 'system_menu_block':
        $definition['forms']['off_canvas'] = SystemMenuOffCanvasForm::class;
        break;
      case 'system_branding_block':
        $definition['forms']['off_canvas'] = SystemBrandingOffCanvasForm::class;
        break;

      // Otherwise fall back to the default off-canvas form.
      default:
        $definition['forms']['off_canvas'] = BlockEntityOffCanvasForm::class;
        break;
    }
  }
}

EDIT: this would probably even mean that you can remove all the JS changes in this patch.

pk188’s picture

Status: Needs work » Needs review
StatusFileSize
new8.55 KB
new1.67 KB

I have updated the "outside_in_block_alter" function as mentioned in #41.
@Wim Leers, please update me about initial part of #41. We should remove these changes or you are saying something else?

Status: Needs review » Needs work

The last submitted patch, 42: 2782891-42.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

xjm’s picture

  1. +++ b/core/modules/outside_in/js/outside_in.es6.js
    @@ -9,6 +9,8 @@
    +  const excludedLinksSelector = '[data-outside-in-exclude] [data-outside-in-edit]';
    +
    
    @@ -21,6 +23,10 @@
    +    // Remove contextual links that should be excluded.
    +    // @see outside_in_block_view_alter().
    +    $(excludedLinksSelector).remove();
    
    +++ b/core/modules/outside_in/js/outside_in.js
    @@ -11,8 +11,11 @@
    +  var excludedLinksSelector = '[data-outside-in-exclude] [data-outside-in-edit]';
    ...
    +    $(excludedLinksSelector).remove();
    +
    
    +++ b/core/modules/outside_in/outside_in.module
    @@ -64,6 +64,14 @@ function outside_in_block_view_alter(array &$build) {
    +  if (!\Drupal::service('outside_in.manager')->isBlockEditable($build['#plugin_id']) && isset($build['#contextual_links']['block'])) {
    +    // If this block should not be editable set an attribute which will be used
    +    // to remove the link on the client side.
    +    // The individual links are not available here to remove.
    +    // @see outside_in.js
    +    $build['#attributes']['data-outside-in-exclude'] = TRUE;
    +  }
    
    @@ -102,7 +110,9 @@ function outside_in_entity_type_build(array &$entity_types) {
    -  if ($variables['plugin_id'] !== 'system_main_block' && \Drupal::service('outside_in.manager')->isApplicable()) {
    +  /** @var \Drupal\outside_in\OutsideInManagerInterface $outside_in_manager */
    +  $outside_in_manager = \Drupal::service('outside_in.manager');
    +  if (\Drupal::service('outside_in.manager')->isBlockEditable($variables['plugin_id']) && $outside_in_manager->isApplicable()) {
    
    +++ b/core/modules/outside_in/src/OutsideInManager.php
    @@ -63,4 +63,12 @@ public function isApplicable() {
    +  /**
    +   * {@inheritdoc}
    +   */
    +  public function isBlockEditable($plugin_id) {
    +    $non_editable_blocks = ['page_title_block', 'system_main_block'];
    +    return !in_array($plugin_id, $non_editable_blocks, TRUE);
    +  }
    +
    
    +++ b/core/modules/outside_in/src/OutsideInManagerInterface.php
    @@ -15,4 +15,16 @@
    +  /**
    +   * Checks whether a block is editable by this module.
    +   *
    +   * @param string $plugin_id
    +   *   The plugin ID for the block to check.
    +   *
    +   * @return bool
    +   *   TRUE if the block should have the "Quick Edit" link provided by this
    +   *   module.
    +   */
    +  public function isBlockEditable($plugin_id);
    +
    

    All of these changes would need to be removed from the patch for Wim's approach.

  2. +++ b/core/modules/outside_in/outside_in.module
    @@ -138,15 +148,28 @@ function outside_in_toolbar_alter(&$items) {
    -  // Since menu blocks use derivatives, check the definition ID instead of
    -  // relying on the plugin ID.
    

    This comment doesn't need to be removed.

However, it looks like the test is failing; at first I assumed it was because the patch in #42 is incomplete, but on reading the test I couldn't say for sure that any of the now-dead code was causing the problem.

xjm’s picture

On #44, not actually sure on the contextual links changes. Maybe that's what's failing? But the goal of the approach is to remove the need for the API additions.

xjm’s picture

Ah here we go; this is the issue:
seText: The website encountered an unexpected error. Please try again later.Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException: The "system_powered_by_block" plugin did not specify a valid "off_canvas" form class, must implement \Drupal\Core\Plugin\PluginFormInterface in Drupal\Core\Plugin\PluginFormFactory->createInstance() (line 57 of core/lib/Drupal/Core/Plugin/PluginFormFactory.php).

@Wim Leers' proposal was sort of pseudocode; maybe there is a small bug in the alter hook?

wim leers’s picture

@Wim Leers' proposal was sort of pseudocode

Indeed it was.

I'll review this once @tedbow rerolls this.

tedbow’s picture

After some investigation I don't think the approach in #41 will work.

The default off_canvas form handler class is actually set in outside_in_entity_type_build() not outside_in_block_alter()
Settings it in outside_in_entity_type_build() is similar to setting in the annotation of core/modules/block/src/Entity/Block.php

Presumably we could remove it from outside_in_entity_type_build() and only set it per definition in outside_in_block_alter() but then we no longer would have a default off_canvas form handler for Block entity.

So if removed it from outside_in_entity_type_build() but had it only outside_in_block_alter() setting it for all blocks except the 2 we want to exclude then we would have no information on the form Entity type level for the block off_canvas form handler.

So this would affect:
\Drupal\Core\Entity\EntityTypeInterface::getFormClass()
\Drupal\Core\Entity\EntityTypeInterface::getHandlerClasses()

I have tried removing the logic in outside_in_entity_type_build() you get this error(in the logs) when trying to open block quick edit form

if (!$class = $this->getDefinition($entity_type, TRUE)->getFormClass($operation)) {
      throw new InvalidPluginDefinitionException($entity_type, sprintf('The "%s" entity type did not specify a "%s" form class.', $entity_type, $operation));
    }

From \Drupal\Core\Entity\EntityTypeManager::getFormObject().

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new8.92 KB

Ok. here is patch that adds
$definition['outside_in_exclude'] = TRUE;
To the block plugin definitions that should be excluded.

it adds a api.php file to document how to do this on other blocks and a \Drupal\outside_in_test\Plugin\Block\ExcludedTestBlock which tests that this works.

Then every things is driven by this. It does add a new "_foo" function to the .module file but this is just to avoid duplicate logic.

wim leers’s picture

StatusFileSize
new15.99 KB
new13.82 KB

Don't ever press option+command+W. It caused me to lose hours worth of time spent on a comment I'd been writing here. Hours. And if there's one thing I hate, it's repeating work. I got pretty close to kicking my computer.


#48: yep, I understand it now. class BlockEntityOffCanvasForm extends BlockForm, so it's an alternative for the default block form. SystemBrandingOffCanvasForm and SystemMenuOffCanvasForm are "plugin forms". BlockForm displays the "default" or built-in form of a block plugin. BlockEntityOffCanvasForm displays the "off canvas" form if it exists, and only those two exist.

#49: My key concern still stands: we're doing work to then later undo it again. It's a step in the right direction though. But I think it can be simpler: rather than adding yet another annotation, allow forms = { "off_canvas" = FALSE' }.


So here's what I propose.

Step 1: stop duplicating (commits 1+2+3)

outside_in_preprocess_block() in HEAD is duplicating the existing logic in system_block_view_system_main_block_alter(), and it's forgetting about doing the same for the Help block (because help_block_view_help_block_alter()).
They both do unset($build['#contextual_links']);.

So, just like #2784853: Determine when Outside In library should be loaded: piggyback on contextual_toolbar() piggybacked on what the Contextual Links module is already doing, I'm proposing to do the same here. Which means relying on the fact that the Contextual Links module adds the .contextual-region class. So rather than depending on the selector [data-drupal-outsidein="editable"] (in most of Settings Tray's JS) and .outside-in-editable (in all of Settings Tray's CSS), we rely on that too.

Commit 1 fixes the PHP, commit 2 updates the JS selectors, commit 3 updates the CSS selectors.

P.S.: there's no reason for the .outside-in-editable class — it should either all use the data- attribute, or the class, we shouldn't be adding both. And in fact, we shouldn't be adding either one.

Step 2: conditional contextual links (commit 4)

The reason we're doing all this, is because Settings Tray has a need for conditional contextual links. Rather than reinventing how that is supposed to work (which is what Settings Tray is doing today), it can just rely on the already established mechanisms, either:

  1. client-side: Quick Edit, which means no contextual link defined in a *.links.contextual.yml file — see core/modules/quickedit/js/views/ContextualLinkView.es6.js
  2. server-side: 403 response for the entity.block.off_canvas_form route for the contextual link would mean the contextual link would be inaccessible when appropriate

Since Settings Tray is already defining a contextual links in outside_in.links.contextual.yml, I'm going with the server-side approach. Proof that this works can be found in the tests at \Drupal\Tests\contextual\FunctionalJavascript\ContextualLinksTest
and \Drupal\Tests\Core\Menu\ContextualLinkManagerTest::testGetContextualLinksArrayByGroupAccessCheck().

Includes test coverage.

Step 3: marking page_title_block to not have an 'off_canvas' form (commit 5)

This builds upon the cleaned up infrastructure to solve what this issue is actually about very simply/elegantly.

Doesn't need extra test coverage because relies on Contextual Links module infrastructure (see previous step).

Step 4: setting the .outside-in-editable class in JS (NOT YET DONE)

Right now we're unconditionally setting this class, which means that the Page Title block still is clickable. We need to have Outside In's JS add this class to the closest .contextual-region DOM node if the outside_in.block_configure link is present.

Conclusion

End result:

  1. maximally uses Contextual Links module's infrastructure, which Settings Tray is building upon in the first place
  2. therefore reduces amount of code
  3. is still wholly controllable via a single declarative thing: forms[off_canvas] in a Block plugin annotation

I think this is the least confusing API, and also the smallest possible API.


In case it helps, these are my notes to capture the high-level reasoning:

specify "off_canvas" form plugin for all block plugins by default, i.e. set it to equal the default block plugin
EXCEPT for the page title one, there we set it to FALSE
         RESULT: declarative
Change \Drupal\outside_in\Block\BlockEntityOffCanvasForm::getPluginForm() from <code>return $this->pluginFormFactory->createInstance($block, 'off_canvas', 'configure'); to return $this->pluginFormFactory->createInstance($block, 'off_canvas'), i.e. no automatic fallback
        RESULT: off_canvas=FALSE can actually result in not falling back to a fallback form
Add custom access check to entity.block.off_canvas_form route. This calls logic similar to BlockEntityOffCanvasForm::getPluginForm(). If a InvalidPluginDefinitionException exception is thrown: access forbidden, otherwise access allowed
        RESULT: 403 => no Settings Tray contextual link => no Settings Tray interactivity
tedbow’s picture

StatusFileSize
new13.3 KB
new13.3 KB
tedbow’s picture

Whoops submitted before I commented.

@Wim Leers yes I like the idea of throwing a 403 and then the Contextual link not being produced at all.

This all looks very good!

P.S.: there's no reason for the .outside-in-editable class — it should either all use the data- attribute, or the class, we shouldn't be adding both. And in fact, we shouldn't be adding either one.

I thought we tried to drive CSS off classes and JS functionality off data attributes.

So a theme could still alter the class names and the JS functionality would still work. Like maybe they already have general highlighted-area the would rather use instead but the JS functionality would still work because it all based of data attributes(except Contextual module CSS classes because it is not using data attributes)

We already changed to using this method in previous issues.

RE

Step 4: setting the .outside-in-editable class in JS (NOT YET DONE)

Couldn't we just do this by not adding the class in the first place by checking if plugin doesn't have an 'off_canvas' form?
Seems much simplier than relying on inspecting the DOM in JS.
Reading https://www.drupal.org/core/d8-bc-policy it seems doing it on the server side and not relying on DOM or CSS classes at all is more future proof.

Uploading a patch for this.

wim leers’s picture

In the terse, re-typed version of #50, I failed to mention again that the 403 idea was in fact proposed by @tedbow in a call we had yesterday about this issue :)

wim leers’s picture

So a theme could still alter the class names and the JS functionality would still work.

Well, contextual_preprocess() sets .contextual-region. It's a class that's "functional" and not "aestethic". Themes don't modify this class. So you can choose either a class or a data- attribute. The latter is perhaps the more "modern" approach, but there's no clear standards for this. Whichever you prefer :)

Couldn't we just do this by not adding the class in the first place by checking if plugin doesn't have an 'off_canvas' form?

But then we're still duplicating other logic. We're doing the same calculations in two places. In one case, to generate the contextual links (= markup), and then in this case to determine whether to set a certain class (= markup).

It's better to derive additional markup from existing markup. Besides, if we'd …………………………

Seems much simplier than relying on inspecting the DOM in JS.

Well, now that you mention that: there's another issue we need to open for Settings Tray: it's doing its JS magic to transform the existing Edit button + toolbar always, even on pages where Drupal.contextual.collection is empty, i.e. on pages where there are zero contextual links.

Reading https://www.drupal.org/core/d8-bc-policy it seems doing it on the server side and not relying on DOM or CSS classes at all is more future proof.

Why/where? https://www.drupal.org/core/d8-bc-policy#themes is referring to themes, and CSS for themes. It's not referring to attributes. Besides, #2894584: Settings Tray provides functionality, not an API: mark PHP and JS as internal is explicitly marking everything as internal. The end goal (which this issue helps to achieve) is that there is only one single API: forms = { "off_canvas" = "FQCN" } on block plugin annotations!

tedbow’s picture

StatusFileSize
new1.11 KB

The interdiff I uploaded for 51 was wrong

wim leers’s picture

StatusFileSize
new14.37 KB
new1.43 KB

I like how #51/#55 is a pragmatic solution that minimizes change, yet still helps settle on the forms[off_canvas] annotation as the single source of truth.

Improving this further can totally be done in a follow-up. OTOH, it means that we still are duplicating logic. #51/#55 duplicates in outside_in_preprocess_block() what \Drupal\outside_in\Access\BlockPluginHasOffCanvasFormAccessCheck does. And for a not-so-clear reason.

Ted mentioned in chat:

but also doing it on clientside won’t that let to more pontential flickr if there was alot going on in JS. the page can start in edit mode

But Settings Tray's JS is already waiting for Contextual Links JS. To which Ted responded:

well but if you started in Edit Mode. and we did it in the JS then the class would NOT be on all blocks from the start. then we wait for contextual links to load. then we can added the class. So the toolbar Edit mode change would be there from the start. then highlight blocks don’t show up until contextual links load. As opposed to doing on server side. Toolbar and block formatting from the start.

While not yet proven, that is a clear reason. D8's Toolbar definitely suffered from this problem until very recently: #2542050: Toolbar implementation creates super annoying re-rendering..

But if we make the change that #51/#55 makes, it's overriding commit 1 from #50, which means we can also revert commits 2 and 3. So the entire "step 1: stop duplicating" from #50 is then undone. I think that's fine though: this patch then becomes smaller, its scope becomes tighter, and this patch can then add documentation as to why it's being done this way. It's an implementation detail anyway — it can be improved later!

So, embracing #51/#55, reverting commits 1+2+3 from #50.

D'oh, that doesn't work either, because that means the system_block_view_system_main_block_alter() + help_block_view_help_block_alter() hooks aren't respected! I forgot about that for a moment. Which means that for example the main content block shows up as a Settings Tray-clickable region :(
So… let's not do that. The .contextual-region class that was added to the selectors in commits 2+3 is set on the server side anyway (by contextual_preprocess()), so that can't cause flicker. The only thing that can cause flicker, is setting .outside-in-editable and [data-drupal-outsidein] in JS, because that'd have to wait on Contextual Links' JS.

Which means that all that remains to be done here, is adding documentation to outside_in_preprocess_block(), to document why it's done here on the server side.

wim leers’s picture

StatusFileSize
new825 bytes
new13.87 KB

I'm comfortable with this patch being committed. But I can't RTBC this, I did most of the work. I think @tedbow should be the one to RTBC this eventually.

I did spot one mistake in the ES6 vs ES5 JS file. yarn run watch:js is kinda brittle sadly:

/Users/wim.leers/Work/d8/core/scripts/js/compile.js:21
        throw new Error(err);
        ^

Error: SyntaxError: modules/outside_in/js/outside_in.es6.js: Unexpected token (31:4)
    at babel.transformFile (/Users/wim.leers/Work/d8/core/scripts/js/compile.js:21:15)
    at /Users/wim.leers/Work/d8/core/node_modules/babel-core/lib/api/node.js:141:7
    at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:416:3)

This is how the ES6 vs ES5 files got out of sync.

tedbow’s picture

Status: Needs review » Needs work
  1. +++ b/core/modules/outside_in/outside_in.module
    @@ -100,8 +100,16 @@ function outside_in_entity_type_build(array &$entity_types) {
    +  // Only blocks that have an off_canvas form will have a "Quick Edit" link. We
    +  // could wait for the contextual links to be initialized on the client side,
    +  // and then add the class and data- attribute below there (via JavaScript).
    +  // But that means that it will be impossible to show Settings Tray's clickable
    +  // regions immediately when the page loads. When latency is high, this will
    +  // cause flicker. Therefore, for now, we choose to duplicate some logic to
    +  // guarantee a smooth experience.
    +  // This is an implementation detail that may change in the future.
    +  // @see \Drupal\outside_in\Access\BlockPluginHasOffCanvasFormAccessCheck
    +  if (\Drupal::service('plugin.manager.block')->createInstance($variables['plugin_id'])->hasFormClass('off_canvas')) {
    

    Thanks for the detailed comment here.

  2. +++ b/core/modules/outside_in/outside_in.module
    @@ -139,17 +147,40 @@ function outside_in_toolbar_alter(&$items) {
    +      // @todo move these into the corresponding block plugin annotations when Settings Tray becomes stable.
    

    Create the follow up issue #2896356: Move 'settings_tray' forms out of Settings Tray and into respective modules and annotations we now need to update the todo

  3. +++ b/core/modules/outside_in/outside_in.module
    @@ -139,17 +147,40 @@ function outside_in_toolbar_alter(&$items) {
    +      // No off-canvas form for the page title block, despite it having
    +      // contextual links: it's too confusing that you're editing configuration,
    +      // not content, so the title itself cannot actually be changed.
    +      case 'page_title_block':
    +        $definition['forms']['off_canvas'] = FALSE;
    +        break;
    

    Should we have @todo and an issue to move this to the PageTitleBlock annotation?

  1. +++ b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
    @@ -498,4 +499,33 @@ protected function isLabelInputVisible() {
    +  /**
    +   * Tests that title block does not have a outside_in contextual link.
    +   */
    +  public function testBlockExcluded() {
    

    This test function was removed. Should we add it and the corresponding test module back in. We don't have functional test that proves you can exclude block though we are adding that functionality.

  2. +++ b/core/modules/outside_in/tests/modules/outside_in_test/src/Plugin/Block/ExcludedTestBlock.php
    @@ -0,0 +1,32 @@
    + *   outside_in_exclude = true
    

    If we did add it back we would need to change this to

    forms {
     off_canvas = false,
    }
    

    Or something like that. Otherwise the test should still pass I think

tim.plunkett’s picture

  1. +++ b/core/modules/outside_in/outside_in.module
    @@ -100,8 +100,16 @@ function outside_in_entity_type_build(array &$entity_types) {
    +  if (\Drupal::service('plugin.manager.block')->createInstance($variables['plugin_id'])->hasFormClass('off_canvas')) {
    
    +++ b/core/modules/outside_in/src/Access/BlockPluginHasOffCanvasFormAccessCheck.php
    @@ -0,0 +1,29 @@
    +    return AccessResult::allowedIf($block_plugin->hasFormClass('off_canvas'));
    

    Now that I look again, there's even more robust fallback code in \Drupal\Core\Plugin\PluginFormFactory::createInstance(). These two different has FormClass checks are different, and that is odd. Not the fault of this code though...

  2. +++ b/core/modules/outside_in/outside_in.module
    @@ -139,17 +147,40 @@ function outside_in_toolbar_alter(&$items) {
    +      // Otherwise fall back to the built-in form for the block plugin.
    +      default:
    +        $definition['forms']['off_canvas'] = $definition['class'];
    +        break;
    

    This is an interesting change from HEAD.

    \Drupal\Core\Plugin\PluginWithFormsTrait::getFormClass() already provides it's own fallback mechanism, and in HEAD that is relied upon. This changes it so that we explicitly declare the "configure" form as used by "off_canvas" operation.

    This isn't bad, but possibly slightly confusing.
    That said, the entire concept of multiple plugin forms was added to core to support off_canvas.

wim leers’s picture

#58:

2. Thanks! Will update.
3. Great point, will do.
4+5: yep, we should, and will do.

#59.2: Yep, I am proposing this change because rather than relying on run-time logic that might change, I think it's clearer to rely on metadata (declarative) instead. Are you +1, or do you have doubts about that?

tim.plunkett’s picture

+1, but can you open a follow-up to discuss the differences and a way to resolve them? As the only implementation of this, we need to be clear about how others should use multiple forms

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new15.6 KB
new28.15 KB

#58: All done. Brought over test coverage & API docs from #49, and adjusted it quite a bit, which makes you still eligible for review/RTBC. Also added test blocks for the other two possible kinds of annotations. Big interdiff because big test coverage expansion.

Status: Needs review » Needs work

The last submitted patch, 62: 2782891-62.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new1.68 KB
new28.04 KB

Fixed nits. Should also cause the patch to pass tests again.

tedbow’s picture

  1. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -0,0 +1,65 @@
    + * The goal of the Settings Tray module is to make administering blocks easier,
    + * and therefore to make the site building experience faster and more pleasant.
    + *
    + * It achieves this by building on the infrastructure that the Contextual
    + * Links module provides: Settings Tray provides a "Quick Edit" contextual link
    + * for blocks. Clicking this contextual link opens the Settings Tray, which
    + * allows to change the contents of the block (not the visibility conditions).
    + * This means blocks can be modified without leaving the page.
    + *
    + * The Settings Tray uses a variant of a standard dialog: an off-canvas dialog.
    + *
    

    Not sure if we should include such extensive description of the module in this patch or add this a follow. I agree it is good idea to include the parts in the this patch that affect the excluding of the blocks.

    For instances there are other things besides the visibility conditions that aren't shown.

  2. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -0,0 +1,65 @@
    + * However, many blocks would benefit from a tailored form which limits the form
    + * to only the form items that affect the content of the rendered block: this
    + * results in a better experience.
    

    The tailored experience at least in the 2 forms that are provided by this module is not about "limits the form" but actually adding relevant config to the form.

  3. +++ b/core/modules/outside_in/outside_in.module
    @@ -100,8 +100,16 @@ function outside_in_entity_type_build(array &$entity_types) {
    +  // @see \Drupal\outside_in\Access\BlockPluginHasOffCanvasFormAccessCheck
    +  if (\Drupal::service('plugin.manager.block')->createInstance($variables['plugin_id'])->hasFormClass('off_canvas')) {
    
    +++ b/core/modules/outside_in/src/Access/BlockPluginHasOffCanvasFormAccessCheck.php
    @@ -0,0 +1,29 @@
    +    return AccessResult::allowedIf($block_plugin->hasFormClass('off_canvas'));
    

    This 2 lines do the same check. We could add back a service(without an interface this time)

    With

    public function isSettingsTraySupportedBlockPlugin(BlockPluginInterface $block_plugin) {
    return $block_plugin->hasFormClass('off_canvas');
    }
    

    Then of course we would want to rename BlockPluginHasOffCanvasFormAccessCheck to BlockPluginSupportSettingsTrayAccessCheck

    Actually since BlockPluginHasOffCanvasFormAccessCheck is already a service could we just call it in outside_in_preprocess_block directly?
    I know it implements AccessInterface but is there any reason we can't add another public function, isSettingsTraySupportedBlockPlugin, that checks access also but with plugin id or BlockPluginInterface instead of a BlockInterface. Especially considering #2266817: Deprecate empty AccessInterface and remove usages

  4. +++ b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
    @@ -176,6 +181,24 @@ public function providerTestBlocks() {
    +        'button_text' => 'Save Settings Tray test block: forms[off_canvas]=class',
    ...
    +        'button_text' => 'Save Settings Tray test block: forms[off_canvas] is not specified',
    

    'button_text' here can be set to NULL for each of these. $button_text in testBlocks() is only used if 'new_page_text' is specified.

    Actually 'label_selector' should also be set to NULL. Neither of these tests case will save the form and check for updates on the page after the form is saved.

    (I realize this is actually true for 'block-search' test case but that is out of scope for this issue)

wim leers’s picture

Related issues: +#2897272: Fix module description, hook_help(), and document module scope in *.api.php file
StatusFileSize
new6.13 KB
new28.08 KB

Status: Needs review » Needs work

The last submitted patch, 67: 2782891-67.patch, failed testing. View results

tedbow’s picture

+++ b/core/modules/outside_in/src/Access/BlockPluginHasOffCanvasFormAccessCheck.php
@@ -20,9 +21,22 @@ class BlockPluginHasOffCanvasFormAccessCheck implements AccessInterface {
-  public function access(BlockInterface $block) {
+  public function accessBlock(BlockInterface $block) {

You do actually have to have a callable "access" method @see \Drupal\Core\Access\CheckProvider::loadCheck
the errors for this test

Drupal\Core\Access\AccessException: Access check method access in service access_check.outside_in.block.off_canvas_form must be callable.

So I am not sure if we leave "access" the way it was and still add accessBlockPlugin(). that would work

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new4.17 KB
new28.61 KB

I implemented #66.3 incorrectly anyway: I forgot to update outside_in_preprocess_block()!

Regarding #69: #2266817: Deprecate empty AccessInterface and remove usages is pretty misleading then, seems that AccessInterface does have a purpose… :( Done.

wim leers’s picture

+++ b/core/modules/outside_in/src/Access/BlockPluginHasOffCanvasFormAccessCheck.php
@@ -9,6 +9,8 @@
+ *
+ * @internal

I also added this in #70, I realized that since #2894584: Settings Tray provides functionality, not an API: mark PHP and JS as internal has landed, we should mark any new classes @internal too.

Status: Needs review » Needs work

The last submitted patch, 70: 2782891-70.patch, failed testing. View results

wim leers’s picture

Assigned: Unassigned » wim leers

Rerolling…

wim leers’s picture

Assigned: wim leers » Unassigned
Status: Needs work » Needs review
StatusFileSize
new962 bytes
new28.62 KB
tedbow’s picture

Status: Needs review » Needs work
+++ b/core/modules/outside_in/src/Access/BlockPluginHasOffCanvasFormAccessCheck.php
@@ -0,0 +1,48 @@
+  public function accessBlockPlugin(BlockPluginInterface $block_plugin) {
+    return AccessResult::allowedIf($block_plugin->hasFormClass('off_canvas'));
...
diff --git a/core/modules/outside_in/tests/modules/outside_in_test/outside_in_test.info.yml b/core/modules/outside_in/tests/modules/outside_in_test/outside_in_test.info.yml

So just looking at \Drupal\outside_in\Block\BlockEntityOffCanvasForm::getPluginForm I realized that BlockPluginInterface does not implement PluginWithFormsInterface so it is not guaranteed to have hasFormClass().

Should we check for instanceof PluginWithFormsInterface like \Drupal\outside_in\Block\BlockEntityOffCanvasForm::getPluginForm does?

The disallow access if it doesn't implement the interface.

Otherwise looks done!

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new6.69 KB
new31.24 KB

So just looking at \Drupal\outside_in\Block\BlockEntityOffCanvasForm::getPluginForm I realized that BlockPluginInterface does not implement PluginWithFormsInterface so it is not guaranteed to have hasFormClass().

Interesting point! However … it's literally impossible to implement blocks by implementing the interface, you must extend \Drupal\Core\Block\BlockBase, which does always implement that interface. But doing what you said prepares us better for a smooth future without unpleasant surprises, so let's do it!

Expanded test coverage.

Status: Needs review » Needs work

The last submitted patch, 76: 2782891-76.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new1.61 KB
new31.16 KB
+++ b/core/modules/outside_in/src/Access/BlockPluginHasOffCanvasFormAccessCheck.php
similarity index 26%
rename from core/modules/outside_in/tests/src/Unit/Access/BlockPluginHasOffCanvasFormAccessCheckTest.php

rename from core/modules/outside_in/tests/src/Unit/Access/BlockPluginHasOffCanvasFormAccessCheckTest.php
rename to core/modules/outside_in/tests/src/Unit/Access/BlockPluginHasOffCanvasFormAccessCheckTestFormsWithForms.php

Ugh this rename should never have happened. PHPStorm--

Also fixing coding standards violations that I added in #76.

tedbow’s picture

Status: Needs review » Reviewed & tested by the community

@Wim Leers thanks for these last changes. RTBC! 🎉

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 78: 2782891-78.patch, failed testing. View results

pk188’s picture

Status: Needs work » Needs review
StatusFileSize
new29.5 KB

As #78 failed to apply.
I am submitting patch again after updating it.

wim leers’s picture

Status: Needs review » Reviewed & tested by the community

@pk188 Thanks!

#78 failed because Settings Tray patches have been committed in the mean time (yay!).

I diffed #78 and #81. The reasons the size is different (31 vs 29 KB):

  1. core/modules/outside_in/tests/modules/outside_in_test/outside_in_test.info.yml has already been added in another issue — so this patch no longer needs to add it
  2. #78 includes a diffstat at the top of the file #81 does not

The patches are functionally identical. Therefore back to RTBC.

pk188’s picture

Thanks! @Wim Leers for reviewing the patch.
And yes you are right.

#78 failed because Settings Tray patches have been committed in the mean time (yay!).

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

xjm’s picture

Version: 8.5.x-dev » 8.4.x-dev
Status: Reviewed & tested by the community » Needs work

Unfortunately it does not apply again. :) Probably following the CSS reset issue. Although it's odd that the patch has not been retested since?

pk188’s picture

Status: Needs work » Needs review
StatusFileSize
new29.69 KB

As the patch was not applying.
So, I rerolled it.

wim leers’s picture

Status: Needs review » Reviewed & tested by the community

I manually diffed #81 and #86, I can confirm it's a straight rebase, no other changes. So back to RTBC.

xjm’s picture

Lots of files in this patch are missing their trailing newline. I haven't finished reviewing the patch yet, but the newline coding standard rule is already enabled and so this needs to be fixed before commit.

pk188’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new29.5 KB

Fixed according to #88.

xjm’s picture

Thanks @pk188! In the future, you can also help by providing an interdiff whenever you make patch updates so that others can easily review your changes to the patch.

xjm’s picture

Status: Needs review » Needs work

Partial review, got about halfway through the patch so far... marking NW so someone could fix these things while I continue to review (or in case I don't get back to it today).

  1. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -0,0 +1,56 @@
    + * By default, every block will show their built-in form in the Settings Tray.
    

    Nit: Every block will show its built-in form.

  2. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -0,0 +1,56 @@
    + * - limits the form to only the form items that affect the content of the
    + *   rendered block, or
    

    This phrase is difficult to understand. I think it means:
    "Limits the form items displayed in the Settings Tray to only items that affect the content of the rendered block, or..."

  3. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -0,0 +1,56 @@
    + * - adds additional form items to edit configuration that is rendered by the
    + *   block.
    

    For both this item and the one before it, an example would help.

  4. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -0,0 +1,56 @@
    + * This results in a better experience: the Settings Tray form always allows the
    + * user to change what is rendered by the block.
    

    This also doesn't quite make sense to me as written. It doesn't always allow the user to change what is rendered by the block (and it won't always necessarily result in better experience, either). Maybe: "These can be used to provide a better experience, so that the Settings Tray only displays what the user will expect to change when editing the block." Is that accurate?

  5. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -0,0 +1,56 @@
    + * Each block plugin can specify which form to use in the off-canvas dialog:
    

    Perhaps it would be useful to add "in their plugin annotation" here? Otherwise it's not necessarily obvious where a developer should put this code snippet.

  6. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -0,0 +1,56 @@
    + * title, main content and help blocks. In these cases, you can opt-out:
    

    Nit: Missing serial comma between "main content" and "help".

  7. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -0,0 +1,56 @@
    + * Finally, blocks that do not provide "off-canvas forms" will automatically
    

    "off-canvas forms" in quotes is weird. Maybe: "blocks that do not specify an off-canvas form using the annotations above will automatically...".

  8. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -0,0 +1,56 @@
    + * plugin (\Drupal\system\Plugin\Block\SystemPoweredByBlock) automatically gets
    + * this added to its annotation:
    

    When does it get added?

  9. +++ b/core/modules/outside_in/outside_in.module
    @@ -94,8 +94,22 @@ function outside_in_entity_type_build(array &$entity_types) {
    -  if ($variables['plugin_id'] !== 'system_main_block') {
    ...
    +  if ($access_checker->accessBlockPlugin($block_plugin)->isAllowed()) {
    

    This switches it from hardcoding one special-flower block to providing an API. I like that!

  10. +++ b/core/modules/outside_in/outside_in.module
    @@ -94,8 +94,22 @@ function outside_in_entity_type_build(array &$entity_types) {
    +  // regions immediately when the page loads. When latency is high, this will
    

    "...that would mean..." (if it's contrary to what actually happens).

    Also why would it mean that?

  11. +++ b/core/modules/outside_in/outside_in.module
    @@ -94,8 +94,22 @@ function outside_in_entity_type_build(array &$entity_types) {
    +  // cause flicker. Therefore, for now, we choose to duplicate some logic to
    +  // guarantee a smooth experience.
    

    For now, until what? Is there a followup issue? If not "For now" is probably not helpful as it just adds more words to read.

  12. +++ b/core/modules/outside_in/outside_in.module
    @@ -94,8 +94,22 @@ function outside_in_entity_type_build(array &$entity_types) {
    +  // This is an implementation detail that may change in the future.
    

    This comment seems unnecessary unless there is a followup issue we want to reference

Some notes about how I reviewed it: I used
git diff --color-words="[^[:space:],\.\[\[\']+" --staged
to understand the CSS and JS changes since I don't speak those so well. :P

  • CSS changes replacing .outside-in-editable with the more specific .contextual-region.outside-in-editable
  • JS changes similarly replacing [data-drupal-outsidein="editable"] with .contextual-region[data-drupal-outsidein="editable"]
xjm’s picture

Okay finished my code review. Mostly just small documentation issues like above.

  1. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -0,0 +1,56 @@
    + * Each block plugin can specify which form to use in the off-canvas dialog:
    + * @code
    + * forms = {
    + *   "off_canvas" = "\Drupal\some_module\Form\MyBlockOffCanvasForm",
    + * },
    + * @encode
    

    I'm wondering whether off_canvas is the correct name for this. It doesn't have anything directly to do with the offcanvas renderer; it has to do with the Settings Tray module. No?

  2. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -0,0 +1,56 @@
    + * In rare cases, a block's content cannot be modified — for example the page
    + * title, main content and help blocks. In these cases, you can opt-out:
    

    In the examples given, the block's content can be modified modules, or on different forms. So maybe:

    In some cases, a block's content is not configurable (for example, the title, main content, and help blocks). Such blocks can opt out of providing an off-canvas form: [...]

  3. +++ b/core/modules/outside_in/outside_in.module
    @@ -94,8 +94,22 @@ function outside_in_entity_type_build(array &$entity_types) {
    +  // cause flicker. Therefore, for now, we choose to duplicate some logic to
    +  // guarantee a smooth experience.
    

    Oh, and which logic is duplicated?

  4. +++ b/core/modules/outside_in/outside_in.module
    @@ -133,17 +147,47 @@ function outside_in_toolbar_alter(&$items) {
    +    // If the block plugin already defines an 'off_canvas' form, there's nothing
    +    // to do.
    +    if (isset($definition['forms']['off_canvas'])) {
    +      continue;
    +    }
    

    I think there's something to do, just that it's not being done here. ;) "If a block plugin already defines its own off_canvas form, use that form instead of specifying one here."

  5. +++ b/core/modules/outside_in/outside_in.module
    @@ -133,17 +147,47 @@ function outside_in_toolbar_alter(&$items) {
    +      // Use specialized off-canvas forms when they're available.
    

    So this comment does not describe what's actually happening (I think maybe it did in an earlier version of the patch before we added the new API). Rather, maybe:

    Use specialized forms for certain blocks that do not yet provide the form with their own annotation.

    Then the @todo after that makes sense as well.

  6. +++ b/core/modules/outside_in/outside_in.module
    @@ -133,17 +147,47 @@ function outside_in_toolbar_alter(&$items) {
    +      // @todo move these into the corresponding block plugin annotations in https://www.drupal.org/node/2896356
    ...
    +      // @todo move these into the corresponding block plugin annotations in https://www.drupal.org/node/2896356
    

    I was about to ask if we would move this logic into each module once Settings Tray is stable, and indeed based on this comment and #2896356: Move 'settings_tray' forms out of Settings Tray and into respective modules and annotations the answer is "Yes!". :)

    However, this comment is formatted incorrectly; it does not begin with a capital letter and does not wrap at 80 chars. After it's wrapped, the second line should also be indented two spaces form the // similarly to https://www.drupal.org/node/1354#todo.

  7. +++ b/core/modules/outside_in/outside_in.module
    @@ -133,17 +147,47 @@ function outside_in_toolbar_alter(&$items) {
    +      // Otherwise fall back to the built-in form for the block plugin.
    

    "Built-in" confused me here.

    Otherwise,
    use the block plugin's normal form rather than a custom form for Outside In.

  8. +++ b/core/modules/outside_in/src/Access/BlockPluginHasOffCanvasFormAccessCheck.php
    @@ -0,0 +1,49 @@
    +   * @todo Remove when outside_in_preprocess_block() is removed.
    

    We should add the link for the relevant followup issue here. So far #2896356: Move 'settings_tray' forms out of Settings Tray and into respective modules and annotations doesn't seem to include removing the preprocess in its scope; is it that issue or a different one? I also don't see any other issues referenced in outside_in_preprocess_block(). Is that the same mysterious "implementation that may change in the future"? ;)

    Also, is this comment even in the right place? Would we be removing the whole access checker? Because right now access() jus t wraps this.

  9. +++ b/core/modules/outside_in/tests/modules/outside_in_test/src/Form/OffCanvasFormAnntationIsClassBlockForm.php
    @@ -0,0 +1,44 @@
    +class OffCanvasFormAnntationIsClassBlockForm extends PluginFormBase {
    
    +++ b/core/modules/outside_in/tests/modules/outside_in_test/src/Plugin/Block/OffCanvasFormAnnotationIsClassBlock.php
    @@ -0,0 +1,27 @@
    + *     "off_canvas" = "\Drupal\outside_in_test\Form\OffCanvasFormAnntationIsClassBlockForm",
    

    I was going to ask how the test was passing when the class name was misspelled; fortunately, it's misspelled in both places. ;) However, we probably should add the "o" to annotation to avoid future development headaches.

  10. +++ b/core/modules/outside_in/tests/src/Functional/OutsideInTest.php
    @@ -0,0 +1,108 @@
    + * Testing opening and saving block forms in the off-canvas dialog.
    

    s/Testing/Tests/

  11. +++ b/core/modules/outside_in/tests/src/Functional/OutsideInTest.php
    @@ -0,0 +1,108 @@
    +   * 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()
    

    Nit: I read & as a bitwise operator on first pass. For the low, low price of two characters, we can use the English word "and". :)

    Non-nit: Where is the functional coverage? I don't know that as a person reading this comment and might like to if it's worth mentioning to me at all.

    Non-nit: From this sentence, it sounds like there are only two blocks that support settings tray and that they are called "class" and "none". I don't know how to parse this paragraph. Are "class" and "none" "blocks"? I don't think they are?

    Is @see related to this and so the following would be true?

    OutsideInBlockFormTest::testBlocks()
    also provides functional test coverage for the "class"
    and "none" cases.

  12. +++ b/core/modules/outside_in/tests/src/Functional/OutsideInTest.php
    @@ -0,0 +1,108 @@
    +      // All blocks except 'outside_in_test_false' are editable. For more
    +      // detailed test coverage, which requires JS execution, see
    +      // OutsideInBlockFormTest::testBlocks().
    

    Okay this answered my question. :)

  13. +++ b/core/modules/outside_in/tests/src/Functional/OutsideInTest.php
    @@ -0,0 +1,108 @@
    +    // 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()
    

    Excellent inline documentation!

ada hernandez’s picture

Status: Needs work » Needs review
StatusFileSize
new30.19 KB
new8.37 KB

For #91
1.done
2.done
3.pending
4.done
5.done
6.done
7.done
8.pending
9…
10.pending
11.pending
12.the comment was removed but css and js changes wasn’t done
#92
1.done
2.done
3.pending (11 by #91)
4.done
5.done
6.done
7.done
8.pending
9.done
10.done
11.nit: & done, non-nit 12 is the answer

tedbow’s picture

StatusFileSize
new3.61 KB
new30.28 KB

#91.3 Added an example for this 1. For the 1 before this limiting the form items actually happens in BlockEntityOffCanvasForm which is not used for the block plugin form but for the block entity form. So I am not sure if the comment actually makes sense here because this is talking about the block plugin form.
8. This happens in outside_in_block_alter() added a @see link
10. Fixed comment.
This would happened because contextual links aren't actually on the page when the page loads so we would have to wait till they are to tell which blocks would need the class. Contextual links html is actually stored in the localstorage of the user's browser. When when new blocks are placed or visible for the first time(when could mean multiple blocks at once) each block must make a ajax call back to get the rendered contextual links html. When the page was already in "Edit Mode" and the page first loads then the existing blocks that had the contextual links html stored on the client side would have the class from this module applied quickly but new blocks would have to make individual ajax calls back and it could not be determined if each block should get the class until the ajax call came back.

So the existing blocks would have "editable" look at first page load but new blocks would get the "editable" look 1 at a time as ajax calls come back.
11. Removing "for now" because I don't actually think this is not the desired logic. This limitation of how Contextual links work.
12. I don't CSS and JS should change see 11

#92.1 changed the comment to say " by Settings Tray in the off-canvas dialog"
3. Removing this comment about duplicated logic. Earlier in the patch we were duplicating the logic inside BlockPluginHasOffCanvasFormAccessCheck(or what is was previously named) but now since we are actually getting the service itself we are not duplicating the logic.
7. Just changed comment to use "Settings Tray" instead of "Outside In"
8. The access checker is used in the route "entity.block.off_canvas_form" so it will not be removed.
I am removing the @todo comment about removing the code because I don't think it needs to be. @see my comment above about #91.11

tedbow’s picture

StatusFileSize
new4.53 KB
new25.99 KB

chatted with @xjm she pointed there were out of scope change regarding the css selector .contextual-region

Removed

tedbow’s picture

Just to clear for any further reviewers

I have checked @Adita's review and all the changes look unless I noted a change in #94

So together with #93 to #95 we I think have covered @xjm reviews in #91 and #92

tim.plunkett’s picture

StatusFileSize
new6.55 KB
new24.92 KB
  1. +++ b/core/modules/outside_in/js/outside_in.es6.js
    @@ -142,7 +142,7 @@
    -      $editables = $('[data-drupal-outsidein="editable"]').once('outsidein');
    +      $editables = $('.contextual-region[data-drupal-outsidein="editable"]').once('outsidein');
    
    @@ -176,7 +176,7 @@
    -      $editables = $('[data-drupal-outsidein="editable"]').removeOnce('outsidein');
    +      $editables = $('.contextual-region[data-drupal-outsidein="editable"]').removeOnce('outsidein');
    

    Can this change be removed, similar to the removal of the CSS changes?

  2. +++ b/core/modules/outside_in/tests/src/Unit/Access/BlockPluginHasOffCanvasFormAccessCheckTest.php
    @@ -0,0 +1,100 @@
    +class BlockPluginHasOffCanvasFormAccessCheckTest extends UnitTestCase {
    

    Rewriting this test class to not need the empty implementations.

tedbow’s picture

StatusFileSize
new1.13 KB
new23.79 KB

#97.1 Look like in #95 I removed these changes from outside_in.js but not outside_in.es6.js version. That was a mistake. Removing. This should effect tests because in #95 they were already removed from outside_in.js which is what is actually loaded.

#97.2 look good.

tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community

Looks great, thanks!

xjm’s picture

Status: Reviewed & tested by the community » Needs work

Just a bunch of nits and coding standards issues. The patch looks great. The refactored test coverage is also an improvement.

  1. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -12,33 +12,36 @@
    + * - Limits the form items displayed in the Settings Tray to only items
    + * that affect the content of the rendered block, or
    + * - Adds additional form items to edit configuration that is rendered by the
    

    Error in the list indentation here. I can fix this on commit except that I found 14 other things.

    Also, this shouldn't actually be capitalized because it's not a complete sentence. Ditto the second bullet.

  2. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -12,33 +12,36 @@
    + * Each block plugin can specify which form to use in the Settings Tray dialog
    + * in their plugin annotation:
    

    s/their/its/

  3. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -12,33 +12,36 @@
    + * Finally, blocks that do not specify an off-canvas form using the annotations
    

    I guess it's "annotation" singular.

  4. +++ b/core/modules/outside_in/outside_in.module
    @@ -122,7 +121,8 @@ function outside_in_preprocess_block(&$variables) {
    + * @todo Remove the "administer blocks" requirement in
    + *   https://www.drupal.org/node/2822965
    

    Nit: missing period.

  5. +++ b/core/modules/outside_in/outside_in.module
    @@ -154,15 +154,17 @@ function outside_in_toolbar_alter(&$items) {
    +      // @todo move these into the corresponding block plugin annotations in
    +      //   https://www.drupal.org/node/2896356
    
    @@ -173,7 +175,8 @@ function outside_in_block_alter(&$definitions) {
    +      // @todo move these into the corresponding block plugin annotations in
    +      //   https://www.drupal.org/node/2896356
    

    Nit: Capitalize the 'm' and add a period.

  6. (Edit: Removed; the bullet that was here was fixed in a later version of the patch. Retaining the item for the list numbering.)
  7. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -0,0 +1,62 @@
    + * Each block plugin can specify which form is to be used by n some cases, a block' in their plugin annotation:
    

    This line is not wrapped. Also "Used by n some cases" sounds like some kind of bargain cereal.

  8. +++ b/core/modules/outside_in/outside_in.api.php
    @@ -0,0 +1,62 @@
    + *
    + * @see outside_in_block_alter()
    

    @see should always go at the end of the docblock. We already have this one down at the end so we can just delete these two lines. Edit: Realized I didn't highlight enough context, but it's the one that's not at the end of the docblock. :P

  9. +++ b/core/modules/outside_in/outside_in.module
    @@ -94,8 +94,20 @@ function outside_in_entity_type_build(array &$entity_types) {
    +  $access_checker = \Drupal::service('access_check.outside_in.block.off_canvas_form');
    

    I almost said "Let's use the dedicated method for the access manager service" but that's access_manager rather than access_check. Note to self: read the default implementations for both services.

  10. +++ b/core/modules/outside_in/outside_in.module
    @@ -108,7 +120,8 @@ function outside_in_preprocess_block(&$variables) {
    + *   https://www.drupal.org/node/2822965
    

    Missing period again.

  11. +++ b/core/modules/outside_in/outside_in.module
    @@ -133,17 +146,51 @@ function outside_in_toolbar_alter(&$items) {
    +    // If a block plugin already defines its own off_canvas form,
    +    // use that form instead of specifying one here.
    ...
    +      // Otherwise, use the block plugin's normal form rather than
    +      // a custom form for Settings Tray.
    

    Nit: Both these comments wrap way too early.

  12. +++ b/core/modules/outside_in/tests/src/Functional/OutsideInTest.php
    @@ -0,0 +1,108 @@
    +   * that support Settings Tray (the "class" and "none" cases) do work correctly.
    

    This line is 81 chars so we will need to wrap the last word.

  13. +++ b/core/modules/outside_in/tests/src/Functional/OutsideInTest.php
    @@ -0,0 +1,108 @@
    +      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\"]");
    +      }
    

    The logic here is a little weird and inverted, kind of a double negative. I'd have said if $plugin_id === 'outside_in_test_false' with that condition first and then let the else be all other cases. Also easier to extend that way if we add other kinds of test blocks in the future. This is a total nitpick though.

  14. +++ b/core/modules/outside_in/tests/src/Functional/OutsideInTest.php
    @@ -0,0 +1,108 @@
    +    // - and does not have the Settings Tray contextual link
    

    Nit: missing final period.

  15. +++ b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
    @@ -176,6 +181,24 @@ public function providerTestBlocks() {
    +      // This is the functional JS test coverage accompanying testPossibleAnnotations().
    ...
    +      // This is the functional JS test coverage accompanying testPossibleAnnotations().
    

    Over 80 chars and needs to be wrapped.

    Also, that test method is on a totally different class, so we should refer to it with the FQCN.

xjm’s picture

Also is there a followup for the selector specificity change we removed? I don't see it in the comments or sidebar.

xjm’s picture

+++ b/core/modules/outside_in/outside_in.api.php
@@ -0,0 +1,62 @@
+ * main content, and help blocks). Such blocks can opt out of
+ * providing an off-canvas form:
...
+ * above will automatically have it set to their plugin class.
+ * For example, the "Powered by Drupal" block plugin

These also wrap too soon.

tim.plunkett’s picture

Status: Needs work » Needs review
StatusFileSize
new9.94 KB
new24.7 KB

#100
1) Done
2) Done
3) Done
4) Done
5) Done
6) Done
7) Done
8) Done
9) Skipped (not actionable?)
10) Done
11) Done
12) Done
13) Done
14) Done
15) Done

#101
Skipped

#102
Done

tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community

As all of those changes were to docs nits, I think I can safely RTBC this.

xjm’s picture

xjm’s picture

Title: Page Title block's title behaves in a confusing way, especially with Outside In » The Page Title block's title behaves in a confusing way with Settings Tray and the Help block incorrectly has Settings Tray styling

  • xjm committed 8189fad on 8.5.x
    Issue #2782891 by tedbow, Wim Leers, pk188, tim.plunkett, Adita, RajeevK...

  • xjm committed f0b88eb on 8.4.x
    Issue #2782891 by tedbow, Wim Leers, pk188, tim.plunkett, Adita, RajeevK...
xjm’s picture

Status: Reviewed & tested by the community » Fixed

So looking at #100.9. In generally using the generic \Drupal::service() method is something we want to avoid; it's more of a convenience wrapper for upgrade paths from D7. I couldn't find any other places in core that were loading an access checker service directly this way except in one test:

[ibnsina:d8git | Fri 10:33:37] $ grep -r "Drupal::service" * | grep "\baccess_check"
core/modules/node/tests/src/Functional/NodeRevisionPermissionsTest.php:    $node_revision_access = \Drupal::service('access_check.node.revision');
core/modules/node/tests/src/Functional/NodeRevisionPermissionsTest.php:    $node_revision_access = \Drupal::service('access_check.node.revision');
core/modules/outside_in/outside_in.module:  $access_checker = \Drupal::service('access_check.outside_in.block.off_canvas_form');

But, I couldn't find a good example of this being done in a different way either, especially in procedural code. (Quick Edit injects its access checker in its MetadataGenerator). And there are a few examples of loading the block plugin manager this way (although mostly to only clear the block plugin definition cache). TLDR I still don't have any actionable feedback on that point. If someone can think of a cleaner way to do what we're doing with this preprocess, feel free to file an issue, but it doesn't make sense to sidetrack this since there might not be a "better way" anyway.

I noticed a few other issues in the process of testing this.

  1. To allow a user to use Settings Tray, you actually need to grant three different permissions:
    • administer blocks
    • use the toolbar
    • access contextual links

    This took me some trial-and-error to figure out so it made me wonder if we should communicate that somewhere. I did confirm that Settings Tray does declare dependencies on all three corresponding modules.

  2. We got rid of the big empty white space in #2894427: White toolbar background when in edit mode is distracting and not pretty and made it match the edit button. However, sometime between when that patch was rolled and now, the colors on the edit button itself changed so the gradient no longer matches exactly. This is also the case in HEAD.
  3. I also noticed that when you resize your window, the Settings Tray's permission is updated separately from the background and the rest of the page after a noticeable delay. It wasn't bad exactly, but it was noticeable and a little strange.

I'll try to get to filing followup issues for those three things. So, anyway, un-sidetracking!

I manually tested and confirmed that this patch does what it's supposed to: the page title, help, and main system blocks do not have any Settings Trays interactions (no styling, no hover behavior, and no clickability). I was a little worried before I tested the patch that the lack of interaction around the title would be confusing, but it's not at all. If I didn't know it was a separate block because D8 skillz, it wouldn't even occur to me to try to interact with the page title.

Per @webchick's suggestion, I tested the Help block on a frontend page with the submission guidelines for a content type for a user that did not have access to the admin theme, pages, etc. and so saw the article form as a frontend page rather than a backend one. Turns out this also fixes an additional bug in HEAD where the help block incorrectly had Settings Tray styling (although not the clickability).

Committed and pushed to 8.5.x! I also backported it to 8.4.x despite the API additions since Settings Tray is still in alpha. Thanks everyone for working through the many iterations of this patch and for cleaning up the slough of small issues.

xjm’s picture

Issue tags: +8.4.0 release notes

Tagging for the Settings Tray section of the release notes since this both resolves a UX issue and adds a useful new API.

wim leers’s picture

#92.1 was not actually fixed by #93, even though it claimed it did. Nor in #94, where @tedbow wrote changed the comment to say " by Settings Tray in the off-canvas dialog", but I don't see that in the actual patch. We kept using the off_canvas name. That's fine while this module is in alpha, but we either need to explain why we keep using that name, or we need to change it, before reaching beta.
(I share @xjm's concern, but didn't raise it here, because it's out of scope to change here.)

So, opened a new issue for that: #2904134: Settings Tray uses the off-canvas dialog type, but "off_canvas" is not an accurate form plugin name, "settings_tray" is.

#95's reversal of .contextual-region CSS changes caused a regression and #98's related reversal in JS makes this a definite regression. See #50. Nope, it doesn't cause a regression, because of our decision to duplicate some of the logic to avoid flicker. +1 for this change then!

wim leers’s picture

I missed #2903198: Use more specific CSS when attaching Settings Tray links to contextual links because it wasn't added as a related issue. Fixed that.

Note that per #111, I don't think we need that follow-up at all.

tedbow’s picture

Component: outside_in.module » settings_tray.module

Changing to new settings_tray.module component. @drpal thanks for script help! :)

xjm’s picture

Issue tags: +Needs followup

For the followup issues I still didn't file.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.