Problem/Motivation
Forms that are displayed in the Layout Builder form are submittable.
This can
- Take you away from the layout builder
- Create changes to your site.
For example in the node layout override form the comments form is displayed. You can actually create a comment from here. It also may be confusing if you are scrolling up and down the page and you see Save and Preview buttons you might not see the comment for it is attached and then click "Save" and see the message "Comment field is required." field is required(not speaking from personal experience or anything 😜).
The search form could also be placed which will take you away from the page.
With contrib modules you would have any more fields that might expose forms. Inline Entity Form and Webform for example.
Additionally but related are there could be other blocks/field that expose links that take you away from the page. Or certain links like for example links from the Flag module might actually save data("Bookmark this") from the rendered blocks.
Submitting these forms and clicking the links could be accidental click or the user might get confused and think they are looking at the entity view page.
Proposed resolution
Similar to Settings Tray Edit mode forms and links on Layout Builder preview blocks should be inoperable. This effects both the default and override layout forms.
Possible ways to do this:
Via Javascript see: core/modules/settings_tray/js/settings_tray.es6.js
When rendering a block preview we could set #disabled on all form elements and links.
Remaining tasks
- Confirm we want to disable forms and links
- write failing tests
- Write fix
- review
- 🎉
User interface changes
All links and forms in layout builder form will be disabled.
API changes
None
Data model changes
None
Comment | File | Size | Author |
---|---|---|---|
#90 | 2973921-90.patch | 18.69 KB | bnjmnm |
#90 | interdiff_84-90.txt | 4.32 KB | bnjmnm |
#84 | 2973921-84.patch | 18.93 KB | bnjmnm |
#84 | interdiff_81-84.txt | 2.59 KB | bnjmnm |
#81 | 2973921-81.patch | 16.34 KB | bnjmnm |
Comments
Comment #2
tim.plunkettTitle change?
Comment #3
tedbowHere is patch that prevents clicks and mousedown events for any blocks rendered in the layout builder.
Comment #4
tedbowHere is the same patch with a test and a test-only patch to prove it fails without the fix.
Comment #5
GrandmaGlassesRopeManWhat's going on with this additional space in the selector?
Comment #6
yogeshmpawarComment #7
yogeshmpawar@drpal - I think it's a miss from @tedbow so doing changes to previous patch because there is no update on this issue from last 4 days. also added an interdiff to highlight changes.
Comment #8
johnwebdev CreditAttribution: johnwebdev commentedI think the patch looks, just a quick thought:
Can't we add context to the event listeners for slightly better performance when LB is re-rendered through AJAX?
Comment #9
tedbowDoing @johndevman's suggestion in #8
Comment #10
GrandmaGlassesRopeManSomewhat interesting that we do this two different ways. Maybe a followup to figure out which one is more 🎉
Comment #13
alexpottI tested this and it works well even if you tab around the form and use the return key. One thing I'm wondering is accessibility. Do we need to announce that the action is disabled in some way? Or would that as annoying as a javascript alert message that informs the users the click has been ignored. Maybe what we should do is add something to the help to tell the user that links and forms in the blocks will be disabled in the preview - i.e. add something to layout_builder_help().
Comment #14
tedbowAdd a message to help on the layout builder pages.
Comment #16
tim.plunkettComment #17
tedbowRerolled #14 and fixed test.
Comment #19
tim.plunkettComment #20
tedbowJust test changes, adding waits to try to get it to pass. Passes locally.
Comment #22
tedbowI think the problem
This where the test fails.
I think it is because the previous dialog is still open or is closing.
So I changed to wait till "Add block" is visible not exists.
Changed core/drupalci.yml to only run this test
Comment #24
tedbowTrying to figure out what makes this test different and realized this is the only that adds to blocks in 1 page load. Testing the dialogs is tricky.
Going to save the layout in between adding the blocks.
Comment #26
tedbowFailed at a different point.
Removing the check until after the layout is saved.
Comment #28
tedbowMaybe we also need to check the dialog is closed?
Comment #30
tedbowHaving weird problem using "Save layout" without reloading page in testing. Also in #2919795: Add visual hints that Layout Builder work is in tempstore and will not be lost, or take effect until saved
Comment #31
tedbowSo now #31 is passing. I don't think #28 was necessary.
Also adding back check removed in #26
Comment #32
tedbowNow that this is passing.
Should be protected
s/one with/a block with/
Change to a more specific class name for this test
Comment #33
tedbowI realized that in keyboard navigation you can still tab to these from elements and input or submit. Generally I think for keyboard navigation it would better for these elements not to be in the tab order at all.
This patch adds removing elements beside contextual links from the tab order.
Comment #34
andrewmacpherson CreditAttribution: andrewmacpherson as a volunteer commentedI think it would be best to disable all interactive controls, not just forms and links. Videos, embedded Prezi slideshows, social share widgets, could all have the potential to take you away from the layout builder.
Is "click mousedown" going to be enough? Especially given that we have a "mouseup" in our ajax.js and third-party embeds have who-knows-what. I don't know how robust we can be, but I think we should consider all the mouse*, pointer*, and touch* events here.
Aside: we'll need to replace "mousedown" in core with "mouseup" in lots of places for #2958654: Assess JavaScript behaviours for WCAG 2.1 Pointer Cancellation
Nit: "remove".
The
.focusable
selector is from jQueryUI, right? There's also .tabbable which might be more readable here.Will these approaches be effective at disabling controls inside an iframe?
Comment #35
tedbow@andrewmacpherson thanks for the review
disabled
property for all items except links. This means we don't have JS events here and I think is more robust as far it gaining focus.also has the bonus of making CKEditor be disabled which seems to be very hard otherwise: see: https://ckeditor.com/docs/ckeditor4/latest/guide/dev_readonly.html
Pretty sure it will not work if the iframe src is from another domain but I think this impossible to get around and is by design.
I am not sure about if it is the same domain. it wasn't working for me when I just tried to by making an inline block with an iframe point to /node/1/edit for the same site. but it might be possible
Comment #36
GrandmaGlassesRopeManWhat specifically are you trying to capture? All interaction events?
You should be careful here. If `context.closest` is somehow a `String`, `Date` or `Object`, `typeof` will tell you they are functions.
There's a warning about `context.closest` needed to be destructured.
Comment #37
tedbow@drpal thanks for the review.
Comment #38
tedbowComment #39
tedbowComment #40
GrandmaGlassesRopeMan@tedbow - The changes look good. I would just want to make sure we are capturing all the input events we need to from @andrewmacpherson's comment in #34.
Comment #41
bnjmnmAdded JS to make iframes non-interactive
Added
pointer-events: none;
to preview CSS so cursor/hover behavior does not act as if items are clickable.Refactored tests to account for this CSS change - now we check for non-clickability vs. the previous check for default-click behavior being suppressed.
Checked video & audio elements and concluded no changes were necessary - while its possible play those media items, none of the controls take the user away from Layout Builder or alter anything on the site.
Comment #42
tedbow@bnjmnm I like these changes. Nice solution for iframes.
The tab index on iframes is actually being set above. I would say move the comment above or just rely on the existing comment about tab index without specifically mentioning iframes.
Is there any chance that a theme would add margin or padding to all divs that would alter this admin view when compared to the regular output?
If so should put margin and padding of 0 in here also?
I am assuming this done inline as opposed to in a style sheet because we want to not overwritten anything? Could we do it in style sheet with
!important
. I know we don't usually want to use this but would this be a case? not sure.Also instead of html string maybe we should use createElement?
Line should be under 80 chars. Method should have 1 line description and then blank link before further comment(if needed)
We don't include the @throws unless the method directly throws the exception
/tedbow wishes we did
Missing @param for $element. Also should be type hinted to
\Behat\Mink\Element\NodeElement
You could also just change this method to an assert like
assertElementUnclickable()
. You would have to assert the string and replace thereturn FALSE
with a$this->fail()
call.Comment #43
bnjmnmPatch addresses feedback from @tedbow in #42 (including refactoring
assertElementUnclickable()
- much nicer.Went with the
important!
approach for the mask + container. I'm inclined to think this is one of those legitimate uses of!important
despite it being one of the most commonly discouraged anythings in web development.Comment #44
bnjmnmComment #45
tedbowSorry what I meant here is don't change$element->click()
but after your new$this->assertContains('is not clickable at point', $e->getMessage());
return;
because assertion would have passed.But after the catch block call something like$this->fail('Element was clickable but should not have been');
Because if it made it there then the
click()
call did not throw the exception.I am not sure why the testing now with the direct call to fail.I read the interdiff wrong 😬
Comment #46
bnjmnmRe: #45 (2): I provided a test-only patch.
Also a small change to the #43 patch - added fail message to click test.
Comment #47
tedbowsetting to Needs Review to trigger test
Comment #48
tedbow@bnjmnm thanks for providing the failing test.
I think this looks good if the tests come back as expected.
I probably can't RTBC since I worked on it.
Comment #50
tim.plunkettComment #51
Kristen PolThanks for the patch. I have reviewed and found only very minor things including one typo (see below). I will try to test this.
Nitpick: Other parts of core have a space before !important.
Same as above.
Nitpick: No period at end of sentence.
Nitpick: Alignment of * is off.
"trasparent" is a typo.
Nitpick: Same as above.
Nitpick: Consider formatting so it's easier to read.
Nitpick: Should be first in the list.
Nitpick: Make alphabetical?
Nitpick: Remove extra space before https?
Nitpick: The order in the comments is not the same as the code. Comment has link, form, and then iframe. Code has form, link, and then iframe. Would be good if they matched.
Nitpick: Consider double quotes around string to avoid escaping quote since double quotes aren't used in the string.
Nitpick: Use Oxford comma.
Comment #52
Kristen PolI have tested the patch from #46 by:
Marking back to "Needs work" in case any changes from previous comment should be done.
Comment #53
bnjmnmThank you for the thorough review & testing @kristen-pol
Items in #51 are addressed other than ones commented on below
6)
core/modules/layout_builder/js/layout-builder.js
is automatically generated fromcore/modules/layout_builder/js/layout-builder.es6.js
so it's not a change that can be made. The.es6.js
file is fair game though and should be formatted with readability in mind.9) There isn't (afaik) a firm coding standard for inline comments using tags, but I prefer using the indentation so IDEs format the additional lines as part of the @todo statement.
Comment #54
bnjmnmComment #55
GrandmaGlassesRopeManI wonder if this makes sense. Could we possibly update the previous selector to provide an equivalent result?
Additionally, from #53, formatting is not fair game. We have a pipeline which includes Prettier for a reason. Having a wild-west environment where every file is formatted differently makes it quite difficult to parse unfamiliar files.
Comment #56
bnjmnmSummary of changes in this patch
context
to the creation of$blocks
, I was able to remove everything related tocontainingElements
and just work with$blocks
. Despite the tests passing, I was still concerned that I overlooked the use case that promotedcontainingElements
to be distinct from$blocks
, so I did some manual sanity-checking as well. This included taking into account pre and post Ajax requests, using quickedit, mouse & tab navigation, and making sure LB contextual links continue to work. All seems fine?pointer-events: none;
was added. This successfully prevents mouse interactions, and the setting of tabindex to -1 prevents keyboard interactions.Comment #57
bnjmnmDiscussed #56 with @tedbow and we agreed it needed a few more changes. A revised patch will arrive shortly.
Comment #58
bnjmnm@tedbow explained the use case I was wondering if I overlooked in #56.1
containingElements
was added to catch any AJAX changes applied directly to a block's content from other modules.We realized that the same could be achieved by removing
context
from the creation of$block
.To mitigate the performance hit of removing
context
, the Layout builder ID was added to the selectorconst $blocks = $('#layout-builder [data-layout-block-uuid]');
Comment #59
tedbow@bnjmnm thanks for the updated patch. Setting to Needs Review for tests
Comment #60
Kristen PolI tested #58 using the search form, links, and an iframe. Interactivity for all of these was disabled.
I reviewed the interdiff and, while I don't see anything obviously wrong, it would be good if @tedbow could confirm the changes are as expected. If so, this looks RTBC to me.
Comment #61
bnjmnmSplit JS into multiple behaviors & added JS Documentation.
Comment #62
Kristen PolChecked that #61 still works and it does. Someone with more js chops will need to verify the interdiff is ok.
Comment #63
tedbowSince this is JS patch just uploading patch to run #61 30x.
To test for random drupalci failures that might happen. I think it should be fine though
Comment #64
tedbowThis looks good to me. Good test coverage, straight forward JS and updated help text.
Comment #65
xjmThere's a missing blank line before the docblock. Was this eslinted? (It could be that the blank line just isn't in the AirBnB standards, but I've not seen this before in our JS.)
Comment #66
tedbowI ran just ran
yarn lint:core-js-passing
This had no errors.
I then ran
node ./node_modules/eslint/bin/eslint.js modules/layout_builder/js/layout-builder.es6.js
which is the higher standard but not guaranteed to pass on our js code.
The blank line is not in our standards but I did find 1 other minor problem
Which corresponds to
announce
is never used. Probably we needed earlier in the patch or just c/p error.It should be removed
context
here is also not used but our convention is to leave it in since this variable is always sent via Drupal behaviors API.Setting to needs work for 1)
Comment #67
bnjmnmAddressed #66.1
Comment #68
tedbow#67 looks good
Sorry I didn't catch this before. No I am not sure why we changing this first line here at all.
The only reason I know to not destructure
Drupal
here is if we need to useDrupal.t
because we can't use thet
function in a destructure way.Comment #69
bnjmnmPatch addresses the goof spotted in #68.
Comment #70
tedbowLOoks good!
Comment #71
lauriiiComment #72
bnjmnmReroll 🥖
Comment #73
Kristen PolDoes this need another round of manual testing?
Comment #74
Kristen PolJust in case, I did and it is working. Marking RTBC.
Comment #75
lauriiiThis selector only works with themes that extend Classy. We should add class to blocks that are rendered inside the layout builder editor.
Why is this needed?
Comment #76
tedbowRe #75.2
I think I added this. The idea was to stop links from being used to drag and dropped. But I test taking this out and it act the same. You can click anywhere inside a block to drag it, even on the disabled links. Which seem to work fine.
Comment #77
bnjmnmComment #79
tedbowthe changes in #77 look good to me but I manually tested the patch and it seems that it is stopping the contextual links to configure block from working. Not sure why. I have tried a few test themes.
The problem is here. This also stops contextual links form working not sure why it doesn't fail in tests so @bnjmnm if you could confirm you are seeing this behavior.
I tested and adding
:not([data-contextual-id] a)
to the end of the selector work.This issue doesn't deal with contextual links but #3002608: Remove contextual links not related to layout administration inside layout builder blocks will remove all non layout builder contextual links so we should be good.
Comment #80
GrandmaGlassesRopeManYou're passing `context` here but you never use it inside the function.
Comment #81
bnjmnm#80 addressed by removing `context`
For #79 I had to address the nonfuncitoning contextual links differently than suggested - this solution would make the contextual links clickable, but they would still not be tabbable. This problem was probably not notices sooner as it requires a specific order events. Very pleased @tedbow discovered it. The easiest way to reproduce is go to the layout builder UI and refresh the page. On a refresh, it looks like contextual links init and
behaviors.layoutBuilderDisableInteractiveElements
happen in a different sequence and the contextual links are disabled.Reproducing this in tests was not as simple as refreshing the page, but I think I found steps to reliably reproduce the issue. I attached x25 and x25-FAIL versions of the patch to confirm this.
Comment #84
bnjmnmAdding the new block class required updating some unit tests.
Comment #85
tedbowI used the "Test Wild West" which is not based on stable.
with the patch in #77 the contextual links do not work
with the patch in #84 the contextual links do work
In both cases the other links which should be disabled are disabled.
Test with bartik too. It works in both cases.
The test coverage looks good the fail patch proves we have a fix.
I ran all unit and kernel tests locally to be sure
I
RTBC! if test fail in #84 for some reason this will push it back to Needs Work.
Comment #86
lauriiiIt seems like #75.2 is now relevant because contextual links can be used and shouldn't start sorting.
Comment #87
tedbowI think the solution in #75.2 is actually a problem that is out of scope of the current issue.
Currently in 8.7.x you can use the contextual links to drag and drop. Though you have to actually think to do this.
1. Open up the contextual links
2. drag the link instead of clicking it
So this problem has really nothing to do with disabling other links and other items inside the form area.
I just happen to have added the code to this issue for some reason, sorry.
Comment #88
lauriiiWe shouldn't use the modifier pattern here.
Comment #89
lauriiiLet's also make sure that follow-up gets opened for #75.2.
Comment #90
bnjmnmComment #91
tedbowLooks good!
Comment #92
lauriiiDo we still need
.layout-section
and.layout-builder--layout__region
in the selector?Comment #93
bnjmnmRe #92
Good call. These are no longer necessary and they've been removed.
These became unnecessary in the rule above it as well
was changed to
And these were moved in the file as to not interrupt the grouping of
.layout-section .layout-builder--layout__region
rules.Comment #94
bnjmnm@tedbow spotted an issue with the patch - will upload a corrected one
Comment #95
bnjmnmThis is identical to the patch actually uploaded in #93, so the interdiff is from #90
Them being identical is only apparent if you view the patch with a cache busting query. Visiting the URL directly gets a cached version that was removed before saving #93. Re-uploading the patch and interdiff with new filenames.
Comment #96
tedbowok #92 is now addressed.
RTBC!
Comment #98
lauriiiLooks good! Thank you everyone!
Committed ef68ad6 and pushed to 8.7.x. Thanks!
Comment #100
andrewmacpherson CreditAttribution: andrewmacpherson as a volunteer commentedfixing accessibility tag