Problem/Motivation
Provide a consistent method for displaying messages in JavaScript.
Currently the Settings tray module needs to provide various message via JavaScript in:
#2773601: Display "You are now in edit mode" prompt when user enters edit mode
#2785047: In Outside In mode, form validation messages should appear in the off-canvas tray, not the main page
And also Inline Form Errors needs to be able to update messages through JavaScript:
#2876321: Update inline form errors summary after form validation with AJAX
Proposed resolution
Change div for {{ messages }} to always be rendered and add a data-drupal-messages
attribute for JavaScript to select.
Add new methods for:
- Adding a message
- Removing one or multiple messages
- Clearing all messages of a specific type
- Clearing all messages
How to test manually
- Apply the latest patch
- Install standard
- Install the js_message_test module. You need to ensure
$settings['extension_discovery_scan_tests'] = TRUE;
is in your settings.php in order to enable it. - Visit the url
/js_message_test_link
on your site.
Remaining tasks
Review patch
Write change record
API changes
Persistent div for {{ messages }} would be required in themes.
API Additions
const messageInterface = new Drupal.Message();
const messageId = messageInterface.add(message, options);
const messageList = messageInterface.select(type);
messageInterface.remove(messageId);
messageInterface.clear();
Original report by kkaefer
While developing some JavaScript enhancements for Drupal, I am facing the problem of how to indicate the status of an action properly. For example, when editing a label, the user needs to know if the action has been successful (saving the new title) or if it failed. Of course, some widgets can use their own status indicating system (like the autocomplete textfield), but others have to display text.
But – we already have status messages in Drupal! Take a look at theme_status_message()
. We just need to make sure that the status message div
is always there so that we can inject new items via JavaScript... How about that? Post your opinion or your own suggestion for this issue.
Release notes
In order to provide the ability to indicate the status of an action from JavaScript, a new new API has been added. This interface provides the ability to add and remove single or multiple messages, and clear all messages to a global or unique location on the page.
Comment | File | Size | Author |
---|---|---|---|
#419 | interdiff.txt | 1.46 KB | lauriii |
#419 | 77245-419.patch | 45.37 KB | lauriii |
#415 | interdiff-77245-414.txt | 821 bytes | GrandmaGlassesRopeMan |
#411 | interdiff-77245-406-411.txt | 1.87 KB | phenaproxima |
#411 | 77245-411.patch | 45.31 KB | phenaproxima |
Comments
Comment #1
Anonymous (not verified) CreditAttribution: Anonymous commentedPLEASE! This was something I wanted a while ago.
Every theme would need to remove the if statement if $message != ''
would be great to have this.
Comment #2
Steven CreditAttribution: Steven commentedThere would need to be a style to make the div invisible if empty though, so that JS can reveal it. Otherwise you might get an empty container, depending on the theme.
Comment #5
nod_I'd like that, it should be fairly simple.
Comment #7
vineet.osscube CreditAttribution: vineet.osscube commentedSo initial patch for review :)-
Comment #8
shivenduray CreditAttribution: shivenduray commentedPatch is not working due to white space problem in patch "content_edit_ajax_message-7342336-7.patch" !!!
Comment #9
vineet.osscube CreditAttribution: vineet.osscube commentedHi Team,
I've updated the toolbar-view.js file to show status message under div as a solution for displaying status message on field edit. Attaching patch for review.
Comment #10
vineet.osscube CreditAttribution: vineet.osscube commentedI've updated the toolbar-view.js file to show status message under div as a solution for displaying status message on field edit. Attaching patch for review :)-
Comment #11
nod_The current patch won't work for core. We need something more generic.
If we're going down this road we need to add a JS API to handle messages. Like it was said in #1 we'd need all theme to remove the
if ($messages) {}
so that the DOM element is always available. We could be using that for the tabledrag and views warning about unsaved changes too.Ideally I wouldn't mind to have Drupal.announce use that message area to put all it's stuff for screen readers too. Would keep everything at the same place.
Comment #12
nod_Totally not ready but putting NR for attention.
Patch contains what I mean. Needs to be polished and all, probably merged with drupal.announce too actually.
adds 2 methods:
The message area is designated with a
data-drupal-messages
attribute because id of the zone is different in default template and the seven theme. Also bartik adds a wrapper we don't want to have to deal with.I don't think we want a fancy "dismiss message" functionality. If you want to get rid of the messages, just reload the page like it's done currently. simple > fancy.
Comment #13
jessebeach CreditAttribution: jessebeach commented(bolding added).
Yes, indeed. We've already solved an issue with
aria-live
and near-simultaneous messages: #1959306: Drupal.announce does not handle multiple messages at the same time; Improve the utility so that simultaneously calls are read..I'd be fine with renaming announce to message or with merging a visual output component to announce in addition to the audio output it currently supports.
I see mention of aria-live in comments in the patch.
but I don't see the attribute in the code yet.
vineet.osscube, do you feel like you can take a shot at merging the code here in this issue into the existing
announce
method?Comment #14
nod_yeah I copied the annouce file and removed all the comments, not all of them it seems. It'll need commenting.
Comment #15
nod_merged in announce.js, not too bad. At least I don't have the whole library mess like before.
Comment #16
ericduran CreditAttribution: ericduran commentedHmm, Do we really need to do this?
Wouldn't it be better to do a simple class toggling.
Comment #17
nod_yeah that was a very rough patch. new one is better.
Comment #18
ericduran CreditAttribution: ericduran commentedAlso a lot of people are going to dis-like the forcing of the message block to be printed at all times.
Comment #19
oresh CreditAttribution: oresh commentedprint only when it fails :)
Comment #20
Wim LeersGreat to see this nicely integrated with
Drupal.announce
:)- What if a theme specifically doesn't want a
<div data-drupal-messages />
? Shouldn't that still be allowed?- When a theme specifically doesn't have such an element, this will break
Drupal.announce()
too, because it now effectively depends on such an element.I don't like that
Drupal.announce()
is now also handling the rendering forDrupal.message()
.AFAICT there are valid use cases to use
Drupal.announce()
*without* showing a visible message, so I don't think we should let this internal overlap occur.Comment #21
seutje CreditAttribution: seutje commentedIt also seems to imply a single instance, is that something we want to force people into, or would supporting multiple messages areas be a bit over the top?
Comment #23
nod_about
[drupal-data-messages]
I think it should be required for theme to have an element with the attribute all the time.Technically it's not
Drupal.announce()
that takes care of displaying, it'sannounce()
. If I rename itprocessQueues()
would that help? it's what it's doing after all. If you want announce and not a message then don't fill both queues at the same time :pI'd say we keep it in only one place. If contrib want to use it somewhere else they'll probably want to be able to "stick" one message over pages, close a specific message, make it show up fancy and all. All sort of stuff we're not supporting with the current patch. I'm pretty sure someone will throw together a module with some jQuery plugin to handle that (and they'll just need to override
Drupal.message()
).Comment #24
nod_Updated patch, there is a problem in how the debounce is actually used.
I separated the messages and announce processing so that should make you happy Wim :) They're even in two files just in case contrib wants to mess with it.
Comment #25
nod_ok little small patch creation issue :p
Comment #27
nod_BTW to see what's happening try that in the JS console:
Comment #29
designfitsu CreditAttribution: designfitsu commentedPatch doesn't apply anymore since removal of tpl.php files for TWIG. Tagging for reroll.
Comment #31
socketwench CreditAttribution: socketwench commentedRe-rolled.
Comment #32
jibranI think some
page.html.twig
changes are missing. Thanks for the re-roll.Comment #33
nod_reroll with template changes.
Comment #34
mr_tuff CreditAttribution: mr_tuff commentedAt DrupalCon Portland 2013 I was assigned to manually test this patch. Patch 25 worked for me but changes happened rapidly and I was unsure how to reset my git branch to the latest.
Patch 25 tests I completed:
System:
OS X 10.8.3 (12D78)
Browsers tested:
Safari
6.0.4 (8536.29.13) - PASSED
Firefox
13.0.1 and 21.0 - PASSED
Opera
12.15 build 1748 - PASSED
UPDATE: I did some reading and figured out how to update my branch and apply the patch but now I get this:
MBP:drupal user$ patch -p1 < core-js-status-messages-77245-33.patch
patching file core/misc/announce.js
The next patch would create the file core/misc/message.js,
which already exists! Assume -R? [n] yes
patching file core/misc/message.js
patching file core/modules/system/system.module
Hunk #1 succeeded at 1212 (offset -13 lines).
patching file core/modules/system/templates/page.html.twig
patching file core/themes/bartik/templates/page.html.twig
patching file core/themes/seven/templates/page.html.twig
MBP:drupal user$ git status
# On branch issue_77245
# Changes not staged for commit:
# (use "git add ..." to update what will be committed)
# (use "git checkout -- ..." to discard changes in working directory)
#
# modified: core/misc/announce.js
# modified: core/modules/system/system.module
# modified: core/modules/system/templates/page.html.twig
# modified: core/themes/bartik/templates/page.html.twig
# modified: core/themes/seven/templates/page.html.twig
#
# Untracked files:
# (use "git add ..." to include in what will be committed)
#
# core-js-status-messages-77245-33.patch
# core/modules/system/system.module.orig
# sites/default/files/
# sites/default/settings.php
no changes added to commit (use "git add" and/or "git commit -a")
I've exhausted my current level of skills. Hope this helps.
Comment #35
nod_The important part is the testing. For git as long as the test bot doesn't complain it's all good.
Comment #36
sarav.din33 CreditAttribution: sarav.din33 commentedOnce i apply #33 using following command,
In Terminal:
git apply core-js-status-messages-77245-33.patch
My patch file is in my root folder. Its named as "core-js-status-messages-77245-33.patch"
I got the following error:
error: patch failed: core/misc/announce.js:16
error: core/misc/announce.js: patch does not apply
Is there any mistake in unix command?
Comment #37
Wim Leers#36: No, Drupal 8 has just changed so much already that the patch no longer is applicable. It needs to be rerolled. Hence setting to "needs work".
Comment #38
sarav.din33 CreditAttribution: sarav.din33 commented#33 Patch rerolled. Refer (https://drupal.org/patch/reroll)
Comment #41
nod_#38: core-js-status-messages-77245-38.patch queued for re-testing.
Comment #43
nod_reroll
Comment #48
rteijeiro CreditAttribution: rteijeiro commentedRe-rolled.
Comment #49
dealancer CreditAttribution: dealancer commentedMessaging functionality works fine for me, but I have not tested screen reading yet.
Comment #50
nod_Patch is good to go, pinged morten about adding empty div everywhere.
Comment #51
mortendk CreditAttribution: mortendk commentedCan we please not use ID's if they are not absolutely extremely nessesary - they make the css work further down the road harder.
please dont use id's unless its absolutely nessesary, id to make the life of the css harder.
maybe a class="drupalsystem--messages" instead
Im generally not happy for having empty divs floating around unless theres a value inside of em. if we can test on {{ messages }} and test if its empty its fine with me even that its a bit cluttered
bartik is its own monster (that the frontend team will take on later based on the principles of d8 theming) anyways please dont add more id's in use a class like drupalsystem--messages instead
Comment #52
jessebeach CreditAttribution: jessebeach commentedThis should be the only drupal system messages div on the page, so for the purposes of JavaScript, having an ID makes finding it easier. The document keeps a list of ID'ed elements on the page and looking them up is very fast.
For the purposes of styling, I agree, we shouldn't be using the ID. I don't see any CSS in this patch, so it's not introducing any ID-keyed styling.
Comment #53
jessebeach CreditAttribution: jessebeach commentedThe messages.js file is missing the file doc block.
This is a copy-paste block of comment from announce.js. It should be updated.
Comment #54
rteijeiro CreditAttribution: rteijeiro commentedI will fix it ;)
Comment #55
rteijeiro CreditAttribution: rteijeiro commentedI guess this patch contains all @mortendk and @jessebeach suggestions. Tried to comment the function but I guess it's too verbose. I accept more suggestions regarding that :)
Re-rolled with the latest changes and updated page.html.twig for Seven too.
Also I have a question about the return of Drupal.theme.message function:
return '<div class="messages messages--' + type + '">' + message + '</div>';
It includes a new div so I'm not sure if we should update it according to @mortendk suggestions.
Comment #56
nod_You can't put the if messages. The element has to be on the page all the time, othewise JS can't find it and the whole thing can't work.
Comment #57
jessebeach CreditAttribution: jessebeach commentedrteijeiro, I'm not sure how you're suggesting to update this div. Can you elaborate?
Comment #58
jessebeach CreditAttribution: jessebeach commentedrteijeiro, I'm not sure how you're suggesting to update this div. Can you elaborate?
Comment #59
rteijeiro CreditAttribution: rteijeiro commented@nod_: Ok, I will fix it :'(
@jessebeach: I mean include the "drupalsystem--messages" class suggested by @mortendk instead the "messages" class.
Comment #60
mortendk CreditAttribution: mortendk commentedurgh just rmemebered the updated name conversions for css classes
the classname should be prefixed with a js- (js-drupalmessages) that will tell the themers to stay away from messing iwth that class & follow our standards (https://drupal.org/node/1887918#separate-concerns)
Comment #61
rteijeiro CreditAttribution: rteijeiro commented@mortendk: The js-drupalmessages class should be in the tpl div or in the div returned by Drupal.theme.message function in the message.js file?
I will try to ping you in IRC in order to get this issue fixed ;)
Comment #62
nod_Talked some more with mortendk, here is the reroll.
This patch adds a (usually empty)
<div data-drupal-messages>
on all pages for all themes to be able to print errors and warnings from the JS (to finally fix #1232416: Drupal alerts "An AJAX HTTP request terminated abnormally" during normal site operation, confusing site visitors/editors).I did not touch the classes/ids or anything because it's purely a JS patch. To mess with the markup a follow-up is needed, as long as the data- attribute is still around, the JS will work regardless of what happens to the markup/classes/ids.
The patch also fixes a bad use of debounce in
announce.js
.Comment #63
rteijeiro CreditAttribution: rteijeiro commentedIt looks good. Patch applies well and it creates the div placeholder for messages.
Maybe RTBC now?
Comment #64
seutje CreditAttribution: seutje commentedLooks like this breaks the default priority, making it default to "undefined".
Also, the initial implementation didn't seem to follow the spec, as that says that "off" is the default, not "polite".
ref: http://www.w3.org/TR/wai-aria/states_and_properties#aria-live
Also, I was under the impression the idea was to have the messages trigger the announce, otherwise it would be impossible for a11y users to know there was an error, wouldn't it?
Comment #65
nod_Making .message use .annonce is interesting. for now I just want whatever to close down the HTTP:0 issue
Comment #66.0
rteijeiro CreditAttribution: rteijeiro commentedupdate for #62 patch
Comment #67
nod_rerolled to fixed the polite thing raised by seutje.
Comment #72
Wim LeersThe patch in #67 simply does not include
message.js
, hence the test failures.Comment #73
rteijeiro CreditAttribution: rteijeiro commentedThanks @Win Leers for the help :)
Added message.js file to #67 patch
Comment #74
jibranExtra white space.
Comment #75
javisr CreditAttribution: javisr commentedremove whitespace commented in #74
Comment #76
idflood CreditAttribution: idflood commentedTested the patch in #75 by calling the following javascript from the chrome dev tool:
This worked beautifully and added the message to the page (tested with bartik, stark and seven themes). The patch also applies cleanly so maybe this can be marked RTBC.
Comment #77
bannockree CreditAttribution: bannockree commentedI read through all the comments, and while I didn't see any specifics on what needed manual testing, it appears that adequate manual testing has been done, so I'm removing the "needs manual testing" tag. Please put it back if I'm wrong!
Comment #78
nod_Ah yes manual testing was in #76. Because no code is using it yet, needs to be triggered manually :)
RTBC per #76.
Comment #79
Wim LeersI'm sorry, there are a bunch of nitpicks left:
Missing file-level docs.
2 newlines, should probably be 1.
Incorrect wrapping: more of the text fits on the first line.
Docs missing.
Docs missing.
I *think* that we also want docs for this.
Comment #80
idflood CreditAttribution: idflood commentedThis patch should fix the nitpicks described in #79. However there are certainly better comments to add than what I have written.
Comment #84
Wim Leerss/Display/Displays/
Parameter types missing
Inconsistent with other JS theme functions in core.
Extraneous empty line in the middle.
Comment #86
idflood CreditAttribution: idflood commentedThanks @Wim Leers for the quick review.
I'm not sure about the new @return but I found this in toolbar.js and dropbuttons.js.
Comment #87
Wim LeersThanks, looks good now! :)
Comment #89
nod_This is a reroll because the indentation standard changed for JavaScript files. No need for commit credit because of this reroll.
Comment #90
jibranReroll seems same as last patch so back to RTBC then.
Comment #91
droplet CreditAttribution: droplet commentedfew questions:
- Why no functions to remove messages posted by Drupal.message?
- Why not filter the undefined messages.
eg:
- What if there's a lightbox windows. How to display messages there?
- Should it "throw new Error" that block whole scripts from being executed?
- It will be more useful if debouncedProcessMessages() can be triggered via events.
Comment #93
nod_Nothing to remove messages because I don't want this script to be complicated. The current errors we get from PHP can't be removed, you have to reload to page to get them to disapear. This is intented to display ajax errors (as you can see by the dependency), nothing else in core. If we give the ability to remove messages it's a lot more complex to handle, there are UX concerns and that always takes time to solve.
The lightbox question is a good point. Didn't think of that.
The throw won't stop anything else from executing. We catch attach behaviors is wrapped in a try/catch, that won't prevent anything else from running.
About events not sure it's very useful. Instead of
Drupal.message()
we'd call$().trigger('message', 'mytext');
? Events are not the fastest thing ever, we add a dep on jQuery and I don't see how it'd be better. Do you have something in mind?Here is a reroll to prevent undefined messages to show up.
Comment #94
nod_Comment #95
droplet CreditAttribution: droplet commentedIt would be more important to have a function to remove the message then. Even an UI changes with "Close" button.
Imagine there's a uploader that only allow to upload JPG and 100kb of the max size. And then you uploaded a PNG.
And then you upload a JPG and files size larger than 100
Now, you have 2 error messages. Do you still upload a wrong type ??
Eg. we could register a function to remove the message after 10s...
if it accepts selectors, it could reuse on other modules, eg. Using on tabledrag to display message (tableDragChangedWarning)
And I think we can remove the behaviors. and setup it on first message call.
Comment #97
lanchez CreditAttribution: lanchez commentedLooked a bit into this and it needs to be at least converted to use libraries.yml. I can look more into it tomorrow.
Comment #98
rteijeiro CreditAttribution: rteijeiro commentedComment #99
lanchez CreditAttribution: lanchez commentedThe message adding is going to break after console div is removed in this issue https://www.drupal.org/node/2213583 . The messages could be probably added before region-content or after main-content link?
Also now with core.libraries.yml the js needs to be added as dependency to other script to be included everywhere. Which one should it be? I didn't make a patch yet, but the content would be pretty much this in core.libraries.yml:
drupal.message:
version: VERSION
js:
misc/message.js: {}
dependencies:
- core/drupal
- core/drupal.debounce
Comment #100
LewisNymanComment #101
heddnIs this still being worked on for 8.0 or is it bumped to 8.1 now?
Comment #102
Wim LeersThis related issue landed some time ago: #2289917: Convert "messages" page element into blocks.
Comment #103
heddnComment #104
nod_I would like to have it in 8.0.x but it needs someone to work on it.
Comment #105
googletorp CreditAttribution: googletorp as a volunteer commentedThis is basically a reroll of #94.
The patch from is so old, that I won't try to actually make an interdiff.txt. The JS from the patch is untouched, the changes is the "new" way of defining a library, attaching it to the system_messages and changes to new templates, since system message has changed a lot since the patch from a year ago.
Comment #106
googletorp CreditAttribution: googletorp as a volunteer commentedComment #108
googletorp CreditAttribution: googletorp as a volunteer commentedWe shouldn't attached the drupal.message library by default, also fixes some JSLint issues.
Comment #109
droplet CreditAttribution: droplet commentedIt's more than reroll. @see #95.
Comment #110
googletorp CreditAttribution: googletorp as a volunteer commentedRegarding #95
I don't believe that having the messages disappear after a certain amount of time, is a good idea, since we don't know how complex and how many messages will appear, and thus how long they should be on the page.
I don't see that message.js will have any sensible way of determine which messages should be removed, when. We could add a function to remove all messages generated by message.js or provide a context or something similar to that you could remove all validation errors for a specific form upon resubmitting an ajax form. Then it would be up to the scripts invoking the messages, to handle the removal when it makes sense.
Behaviors provides a nice error handling, if we don't have use then, we would need to code our own handling of a case where we don't have a place to put messages.
Comment #111
googletorp CreditAttribution: googletorp as a volunteer commentedI've added the concept of context, so it's possible to specify where messages are coming from. I've added a method to remove a messages of a certain type/context, though this could be done manually as well.
This should handle the concerns from #95.
It still uses behaviors as I believe this is the best option we have atm.
Comment #112
droplet CreditAttribution: droplet commented- On maintenance mode, upload a file
(same problem on unpatch)Comment #113
googletorp CreditAttribution: googletorp as a volunteer commented@droplet what we are making is a framework, the patch itself only makes the framework available - it's not actually used anywhere (yet).
Comment #114
googletorp CreditAttribution: googletorp as a volunteer commentedTo test this
$build['#attached'] = ['library' => ['core/drupal.message']];
somewhere, see patch #105 for more info (this was removed, since we don't want to load a lot of javascript by default on pages)Drupal.message.add('the message', 'the type status/warning/error, 'optional context')
Comment #117
mgiffordComment #118
lokapujyaDo these messages go into the block mentioned in #102?
Comment #119
mgiffordJust a re-roll.
Comment #120
star-szrComment #121
tic2000 CreditAttribution: tic2000 at Intellix commentedThe last patch misses message.js
Comment #122
andypostComment #123
kostyashupenkoRe-rolled patch 111 https://www.drupal.org/node/77245#comment-9922432
Comment #124
andypost#type=messages element should add this library
Comment #125
Wim Leers+1 for #124.
Why no dependency on
core/drupal.announce
?This would be a regression today. So, if you do this, then we should add this to
classy.info.yml
:Comment #126
tic2000 CreditAttribution: tic2000 at Intellix commentedIs this really addressing the issue? The announce part is good, because it reads the text, so it doesn't matter where on the page the action was initiated from.
The text is added to the top of the page and the top of the page may not be in view. Imagine this comment form using it. I submit through AJAX and the confirmation is all at the top. Sure in the case of comments you can get feedback by prepending the message to the form or adding the comment in it's place. But you have situations where this is not possible (the action is initiated from a table cell, that cell may be to narrow to display a message; or a subscribe form in the footer, you don't want a message to brake the footer layout, you just want a small message appear informing the user the subscription was successful). Something like https://material.angularjs.org/latest/demo/toast
Comment #128
mgiffordComment #129
lokapujyaRerolled.
#126: Yeah, but isn't that for contrib to do?
Comment #131
jibranWe can use jQuery selector here.
Let's rename n,nl to better helpful name.
Comment #132
joginderpc CreditAttribution: joginderpc at Srijan | A Material+ Company commentedUpdates following things as given in previous comments #131.
+++ b/core/misc/message.js
@@ -0,0 +1,104 @@
+ messagesElement = document.querySelector('[data-drupal-messages]');
We can use jQuery selector here.
+++ b/core/misc/message.js
@@ -0,0 +1,104 @@
+ message, n, nl;
Please review.
Comment #134
jibranmessage.js is missing from the patch.
Comment #135
mgiffordI'm tagging this for accessibility as it's required to get inline form errors as a fully fledged part of Core.
Comment #138
andrewmacpherson CreditAttribution: andrewmacpherson as a volunteer and at Annertech commentedThe patch from #132 needs a re-roll, today's test says it fails to apply.
Comment #139
BarisW CreditAttribution: BarisW at LimoenGroen commentedOn it
Comment #140
BarisW CreditAttribution: BarisW at LimoenGroen commentedHere is a re-roll. I've also re-added the messages.js file that was missing in patch #132.
Comment #142
hitesh-jain CreditAttribution: hitesh-jain at Acquia commentedComment #143
Manuel Garcia CreditAttribution: Manuel Garcia as a volunteer and at Appnovation commentedComment #144
hitesh-jain CreditAttribution: hitesh-jain at Acquia commentedPatched against 8.3.x branch.
Comment #145
joelpittetTrying to fix the twig template, the indentation went a bit wonky and div conditional went missing for the closing div.
Also undid the context removal but I don't think that's needed for this patch.
Bigpipe test should fail because the removal of the library, what's the reason behind that in the classy template?
Comment #147
droplet CreditAttribution: droplet commentedIs that intended to remove the JS in #140 and above patches..
the blocker is #91
I agreed with #126 also. We could jump out of the box. Here's an JS lib we can use:
http://codeseven.github.io/toastr/demo.html
Comment #148
joelpittet@droplet, good catch, it likely was a mistake because it wasn't mentioned. I've added it back into the latest patch.
Also probably blocked a bit on changing Classy markup which is API.
Comment #151
mgiffordJust wanted to encourage someone to write tests for this patch so we can hopefully meet this deadline:
https://www.drupal.org/node/2504847#comment-11750733
Comment #152
dmsmidtAdding my thoughts about message visibility and toast in #126 and #147.
I agree that when, for example, you are scrolled down and a message appears at the top of the page they are not really accessible.
This can however be addressed when we get Inline Form Errors in core (#2504847: [meta] Roadmap for stabilizing Inline Form Errors module (IFE)).
What we are addressing here is that we have a central place to put the messages with JS, and keep them there.
That is a small enough change, and can later be extended with things like toasts.
Let's do things in small enough steps so that we can at least go on.
The above also covers @droplet's concern in #91.
Comment #154
tedbowOk trying to get this going again.
I was working on #2773601: Display "You are now in edit mode" prompt when user enters edit mode but hope we can get this done first so that issue can just use the core messages library.
I correct some eslint errors in messages.js. Also a couple logic errors.
Also had to update \Drupal\Core\Render\Element\StatusMessages::renderMessages because it was not showing the place holder if there were no messages.
I also add a test. But it is failing for me now. Not sure why.
If you enable the test module js_message_test you can see the show and remove message links. The module works for me but test doesn't. Not sure why
Comment #156
GrandmaGlassesRopeManannouncements.reverse().forEach()
Set
announcements
back to an empty array at the end.string
string
Capture this selector and store outside the behavior.
array.forEach()
string
string
string
Update JSDoc format for object/key descriptions.
string
Comment #157
tedbow@drpal thanks for the review!
1,2 I think are out of scope :(
6. had to use messages.reverse().forEach() to keep message order
fixed all the rest.
Also in Drupal.theme.message there is no need for the context parameter.
Got JsMessageTest passing it was missing a library dependency in the test module.
The other tests that are failing I think are because of the changes to \Drupal\Core\Render\Element\StatusMessages::renderMessages but I haven't had time to look at that yet.
Comment #159
GrandmaGlassesRopeManstring
string
In addition to checking that text is a string, should we throw an error if text is not passed it, or is not actually a string?
No need to pass messages.
It might be nice to have the ability to remove all messages of a given context regardless of type.
Comment #160
tedbowDo want give the option to specify the element where the messages should go?
In #2785047: In Outside In mode, form validation messages should appear in the off-canvas tray, not the main page I would like to just the new messages library but it will not work because the messages div will not be on the tray.
Then we wouldn't want to do this on attach but when I message is added to check if container is available.
Here we could add containerSelector which would default to '[data-drupal-messages]'.
I think beyond the Settings Tray module any interaction in a dialog is going to run into this same problem. I think upcoming Media work will need this ability because the browser will be in a dialog.
Comment #161
tedbow@drupal thanks for review in #159
1-2 fixed
3. Won't
if (typeof text === 'string') {
not be true if it wasn't passed. I just added an else here and threw an error.4. fixed
5. Yes I think this could be good. If a module wants to remove all messages it added but not other modules they could use context.
I added this and added test coverage.
Comment #163
tedbowJust test fixes.
BigPipe test will still fail. Looking into that.
Comment #164
Wim LeersWhy would
classy/messages
no longer be necessary?Comment #165
Wim LeersThis changed the markup for status messages. BigPipe's expectations therefore need to be updated as well.
This fixes the "no-js" BigPipe fail, and part of the other BigPipe fail.
Comment #166
Wim LeersBecause this asset library is no longer being attached in the template, that's another BigPipe expectation we need to update: when BigPipe is using JS, it no longer needs to update the AJAX page state nor load the CSS file in this asset library.
I am posting this fix separately (from #165) because I'm not at all convinced that removing that asset library is correct. So then it's easy to revert this change.
Finally, if this change is correct, then you will need to expand BigPipe's test coverage with a case where it is explicitly loading some CSS or JS. Because this is effectively reducing BigPipe's test coverage.
Comment #169
Pavan B S CreditAttribution: Pavan B S at Valuebound commentedLIne exceeding 80 characters
Line exceeding 80 characters
Fixed coding standard error in the patch, please give me suggestion if i am wrong
Comment #171
tedbow@Pavan B S thanks for the patch but you have a bunch of unrelated files in there.
Re #164 I think this is mistake. I can confirm with the library the regular messages are not theme correctly.
Ok added back "classy/messages" library.
Update BigPipeTest
Comment #173
tedbowOk so this implements the ability to send messages to different divs. See my idea in #160
This will be needed for the Settings Tray module.
Comment #174
tedbowUpdate summary.
Right now Drupal.message.add() does not use Drupal.announce. I think it should right?
Comment #175
tedbowOk. so this calls Drupal.annouce() inside of Drupal.message.add().
It seems like every on screen message should be "announced" for screen readers but maybe I don't know the idea behind it.
@todo add test coverage is this is the correct behaviour.
Comment #177
nod_Been a while since I checked this issue :p
I'm not happy about adding a jquery dependency for this script. There are no events involved, I don't see the need for it. When we first wrote announce.js es6 wasn't nowhere near a possibility. We could make those array processing more modern. Patch incoming.
Comment #178
GrandmaGlassesRopeManHere is a slight refactor. I talked with @tedbow and this skips the work in #175.
Comment #179
GrandmaGlassesRopeManComment #180
nod_All right, simplified the JS.
Made a few changes in the test js file to show how it can be used but no tests have been updated to pass.
There is an issue with the HTML, we should have a template for status wrapper and status message. To let themes add the data-drupal-messages attribute where they want. It shouldn't be in classy like that. Anyway if the js looks good we can look at the tests.
Comment #181
nod_Oh and
Drupal.message()
expects an HTMLElement, no selector.Comment #183
tedbow@nod_ do you know why this patch contains changes to this file? It seems unrelated to the messages changes.
Comment #184
GrandmaGlassesRopeManid
,nth-clild
, arrays of both or just a single typeComment #186
nod_Looking at the interdiff. Could you keep the queryselectorall and instead of select+remove in the foreach build an array of selectors (map would work better than foreach). Would help readability.
The separation of select and remove in separate steps was on purpose.
Comment #187
GrandmaGlassesRopeManInterdiff is between the patch in #180.
Comment #188
GrandmaGlassesRopeManInterdiff is between the patch in #180.Poor internet at DDD.Comment #189
tedbowSince this will be array of selectors at this point for each "message" should we change the name to removeSelectors?
Agree with @nod_ that it is more readable seperatable
I really don't see a use case for specify the nth child message.
Presumably there would be JS from multiple modules calling messageAdd(). How would any 1 module know which index their messages were. They could easily know the order of their messages but they would not know if another module set a message in between theirs.
It seems like they would have actually inspect the DOM to know the order of the messages. If they are inspecting the DOM anyways why would they not just read the data-drupal-message attribute to get the string index?
Comment #190
GrandmaGlassesRopeManAddressed the feedback in #189.
Comment #191
tedbow@drpal thanks
That is much more readable to me.
Just want clarify for anyone readying through that in #190 @drpal removed the ability to remove the nth child message as was asking for in #189.3
Comment #192
tedbowI think this is re my comment in #191
Comment #193
nod_Thanks for all the tests :)
Few things before commit: In message.js
We could do better for docs of the main entry point of this new API.
s/%/@/
Here I'd prefer
Array.isArray()
.I'm wondering if we could simplify the api and not expose
messageWrapper
at all. Why would we have that in the api, It's passed to Drupal.message to begin with? I know it might be a bit different from our older apis but I'd like to start making conscious choices.Comment #194
GrandmaGlassesRopeManSome minor fixes from #193.
I removed
messageWrapper
from the exposed response from the constructor which should simplify everything.Comment #196
tedbowThis patch just reverts this change. The add and remove methods will not work if this is removed.
Since how this API is used is you call Drupal.message() and receive by an object with the methods on it.
Then the add and remove methods both need
this.element
so they can manipulate it.I think we can all agree this is better ;)
I found another problem though.
I was testing manually in Bartik.
I forgot you need the test theme to make Javascript on the test module js_message_test.js to work.
So I was clicking the links that should make the messages appear in the div with
data-drupal-messages-other
The message where appearing in the default message div because
data-drupal-messages-other
didn't exist.Took me a second to figure out what was going on.
document.querySelector(divSelector)
was returning null because the element wasn't on that page.But here when
messageWrapper
is null it will calldocument.querySelector(defaultMessageWrapperSelector);
.The message will then appear in the default messages div.
I think it would be better to throw an error in this case.
Should we be worrying about that?
Comment #197
nod_I wanted to get rid of the use of
this
too, replacethis.element
withmessageWrapper
and it'll work we shouldn't add stuff just because.If it fails and the error is not helpful, we should fix it. Let's check that if messageWrapper is not undefined
messageWrapper.nodeType
exists and equals to 1, that way we know we have a DOM Node of some kind. Might need to add this check all over the place too, to avoid surprises. But that's for another issue.Comment #198
tedbowWrote this before I saw @nod_'s comment in #197
So I think the problem I mentioned in #196 I think is something that we should check for. Because Javascript code easily be written wrong to get the call to
Drupal.message()
but messages still would be output to the screen just in the default messages div rather than what is expected.For example in both:
Drupal.message(document.querySelector('#one-character-off'));
and
Drupal.message($('#one-character-off')[0]);
No error will be thrown and the messages will be display in the default messages div which is not the intention.
This could fix both cases:
You have to check for
null
becausedocument.querySelector('#one-character-off')
will sendnull
$('#one-character-off')[0]
will sendundefined
but you can't simply check forundefined
because sending no argument will also maketypeof messageWrapper === 'undefined'
so you have to check forarguments.length === 1
I think the point of adding these extra checks is not to babysit bad calls but not write messages to the wrong div.
thoughts? is this overkill?
Comment #199
tedbowre #197
Yeah whoops fixed this. Also removed doc comment that was referring to it that was never removed.
data-selector
attribute soWas actually sending
null
asmessageWrapper
unintentionally.I think this makes the point that extra check is actually necessary.
Comment #200
andypostComment #201
nod_Js supporting the tests has some issues.
I'm also adding a clear method to the message object.
Comment #202
dmsmidtWas about to review, but I'll wait for nod_'s changes.
Comment #203
nod_Let's see how it goes.
In the test JS messages indexes were stepping over each other and made it easy to have unremovable messages on the page.
Comment #204
nod_Comment #205
dmsmidtPlease educate me on why messageWrapper and messages need to be checked again? Can't we do:
Comment #206
nod_lol yeah you're right, my mistake.
Comment #208
nod_Turns out, Array.from isn't supported by IE 11, back to for loop.
Fixed tests and comments from #205
Comment #209
nod_Touched the IS a bit. It'd be quite something to fix an 11 years old issue…
Comment #210
nod_Comment #211
mgifford@nod_ I like your comment in #5, 5 years ago :)
Comment #212
dmsmidt11 years, wow, let's do this!
Added another issue from Inline Form Errors to the IS.
Comment #213
dmsmidtI'm currently reviewing code and testing with a screen reader.
Comment #214
dmsmidtFirst of all what a great progress! I'm so happy to see this and immediately want to start experimenting with toast messages for example (in contrib) :-p.
Some remarks:
This can now be removed.
Needs to say what happens now. Like: "Render the messages or an empty messages container div which can be used by the JavaScript messages API."
And it would be great to improve the docblock as well so that @return and the description show there will always be a container.
Nit: remove empty line
Nit: Add empty line
Nit: missing comma
Nit: missing comma
All changes to announce.js seem out of scope. We can keep this patch much simpler that way. Although the changes look logical, we should do that in a separate issue. My tests without these changes work just as well!
We should however improve it a bit. Currenlty it is unclear what type of message was added. I propose we by default first tell the type of message (error, status, warning) and then the actual message.
Checked here:
https://www.w3.org/TR/wai-aria/states_and_properties#aria-live
Let's keep polite as a default (see announce.js).
And only set the priority to assertive on 'warnings' and 'errors'. This way, if devs introduce their own status (like a notice) it won't be so aggressive by default.
Can we rename 'messages' to 'index', this is much more understandable for me.
We need some before/after images for this.
This makes it impossible to use a custom generated index. Allowing custom generated indexes opens up a lot of possibilities in contrib. And may be needed for Inline Form Errors.
I think we should add the possibility to add a (custom or generated) index (data-drupal-message) via drupal_set_message().
Comment #215
dmsmidtUpdate IS: relationship with drupal.announce() is clear now.
Comment #216
nod_missing the dependency on the message css library too
Comment #217
GrandmaGlassesRopeManannouce.js
for this patch, which could be posted in a new issue.Comment #218
GrandmaGlassesRopeManI'm sorry for breaking
announce()
. Everything else should still apply.Comment #219
GrandmaGlassesRopeManSee #218
Comment #220
dmsmidtThat is looking much better, thanks @drpal.
#13 in a separate issue seems legit.
However from checking the interdiff in #217 I think you misunderstood my accesibility goal.
The "// Check this" line should be removed, and we can keep the
options.priority = 'assertive
part, but changetype !== 'status'
into(type === 'warning' || type === 'error')
. This way all other types will be polite.Also
Drupal.announce(options.priority);
doesn't sound to friendly or helpful and doesn't get announced with the same priority as the actual message. Can't we just usetype
as a starter?Comment #221
GrandmaGlassesRopeMan@dmsmidt
Yep, totally my fault here. We should now be announcing the type of the upcoming message at the same priority as the message itself.
Comment #222
GrandmaGlassesRopeManComment #225
tedbowPretty sure this will need to be re-rolled because this was reverted #2853509-16: Don't render status messages if there are no messages but also include their assets if there might be
Retesting to last patch to confirm it no longer applies.
Comment #227
dmsmidt@drpal, sorry for all the iterations, a11y is better now, but we can still improve.
Custom announce messages are currently never read out loud due to
if (options.announce !== '') {
.Also let's not separately announce the type, it sounds funny/weird (yes I tried), I would concat it to the message like so:
type + ': '+ message
. But.. we should also make it possible to translate it, and then it becomes much more work, we would need a mapping of type => "read out loud version of type" and then we would like that on the server side generated messages as well (reminder: we could use#status_headings
for that).So let's remove announcing type from this patch and make a follow up (just like #217-13).
Furthermore #214-2 is not solved, comments/dockblock needs update.
@_nod, not sure how we should fix the messages.css dependency in Classy and Bartik.
We add
css/components/messages.css
to the Classy and Bartik libraries base library and remove all{{ attach_library('classy/messages') }}
. Or we have to overwriteDrupal.theme.message
in the themes and add it there?We are getting somewhere, woot!
Comment #228
GrandmaGlassesRopeMan@dmsmidt
Haha, don't worry about it.
I think the changes in
#214-2
are out of scope right now since we don't actually need to make any changes to this file. I also removed the announcement of the message type.Comment #229
dmsmidtI did some more checks and saw that I missed another thing in previous reviews:
The aria-label is missing. It is present on server-side generated messages. The
#status_headings
inStatusMessages::renderMessages()
should somehow be usable by the Message API.But before we start refactoring this we should wait on #2853509: Don't render status messages if there are no messages but also include their assets if there might be, it's critical and changes the way
StatusMessages::renderMessages()
works again. But it'll also make sure we always have message styling.Comment #230
nod_There is more work needed on the js side no need to hold things off
Comment #231
nod_Added a message.select method to the api, put back the announce method like it was before, possibility to disable announce was a feature. Added all the attributes and structure of PHP's messages, that should help a11y.
Potential issues with error messages, since both the announce and the message itself could trigger, hence reading twice the error.
Comment #233
GrandmaGlassesRopeManWe can just check that the length exists, not that it equals 0.
Maybe we can return a
boolean
or throw an error in this case.Do we want to make sure that
options.annouce
is a string?I'm not sure these are needed anymore?
Comment #234
dmsmidt@nod_ #231, ah my bad about the announce message. Now I understand, if you explicitly send an empty string the announcement will be skipped. Drpal's third point makes sense: check if it is a string as well. If option.announce is FALSE it would read the default message right? That feels strange.
Comment #235
nod_Reroll.
NO || (YES && YES)
is clearer thanNO || (YES && NO)
.( edit ) I guess false should be taken care of too. No strong feelings either way.
Comment #237
GrandmaGlassesRopeMan@nod_
Good points on the JS. I fixed the out of date tests.
Comment #238
alexpottThis isn't going to work if there are no messages on the page.
I think rather than adding this is .html.twig files we should consider adding it in \Drupal\Core\Render\Element\StatusMessages::renderMessages() that way we can ensure that there is something for javascript to find to add messages regardless of what someone does in the .html.twig files for custom themes etc.
Doing this will also mean that this change is compatible with #2853509: Don't render status messages if there are no messages but also include their assets if there might be
Comment #239
nod_doesn't apply and #238 needs addressing
Comment #240
pk188 CreditAttribution: pk188 at OpenSense Labs commentedComment #242
pk188 CreditAttribution: pk188 at OpenSense Labs commentedComment #244
droplet CreditAttribution: droplet commentedshould rewrite into ES6 Class.
some basic things:
do not pass in selectors?
It doesn't work and do not take the options if I read the source code correctly.
methods: add / remove / select / clear should apply to same messageWrapper
To imagine one page has 2 messages area
- a bit odd to assign index back to option;
- and index should be ID I think;
- Imagine you adding 10 messages and remove 2 randomly. which one is index 2?
- To consider using [data-drupal-message-id="adopt-backend-pre-set-message"]
Comment #245
GrandmaGlassesRopeManA bit of a refactor from #244. Still needs to address #238.2
-
Drupal.message
is now an ES6 class.-
Drupal.message
constructor expects just a HTML element, not a selector.-
options.index
is nowoptions.id
to better reflect what it actually is.Comment #246
GrandmaGlassesRopeManComment #247
GrandmaGlassesRopeManAccidently included the sourcemap. When #2880004: Improve (again) ES6 helper scripts lands we shouldn't have this problem.
Comment #248
droplet CreditAttribution: droplet commentedOK. Any reason?
Just few thoughts:
Put `type` into `options`
-----------------
- If we passing in `options.id`, we should not add prefix to it.
- Should we checking the `ID === String`?
- I think we can add [drupal-message-type]
- Math.random isn't safe enough
------------------
.map(i => `[data-drupal-message~="${i}"]`)
we can't use `~=`. For example: "App" matches "App" and "Apple"
------------------
------------------
Should we add a handy replace mode? Most of the time, we only display a single message.
------------------
In Drupal, we usually display the Message from backend. If a module does this:
How can I get the instance?
THANKS!
Comment #249
GrandmaGlassesRopeManComment #250
GrandmaGlassesRopeMan- function signature for
message.add()
now accepts just two arguments,message
, andoptions
which contains astatus
key.- adjustments to id creation logic.
math.random
isn't great, but I'm not sure we're going to hit a duplicate key within reason.- message theme functions now has two data attributes,
data-drupal-message-id
anddata-drupal-message-type
- documentation updates to better clarify what's actually being passed to a function.
@droplet
I wanted to simplify the constructor, handling the ability to pass a selector string and an HTML element felt a bit unnecessary. About,
new Drupal.message();
. Unless a module specifically exposes it's instance ofDrupal.message()
, it will only be available to itself.Comment #251
nod_Wait a second, why do we have a class all of a sudden? I really do no want classes anywhere in our code. And for the moment it'll introduce a concistency problem. Most if not all our Drupal API don't need to use
new
. If we start going for classes I really want more discussion that sneaking that in there.Because if you allow a selector, you'll need to allow a context to select from because not everyone might want to select from
document.querySelector()
. It makes our code more consistent, less magic.drupal_set_message
API. But I don't care that much it really depends on how people use it.~=
that works for me, When I try, "App" doesn't select "Apple", it does an exact match, not a substring match (like ^= does)The module has to deal with it. Same as
Drupal.dialog()
,Drupal.ajax()
(notice how there are nonew *
to use those API too).So I'd expect: no classes (because that need at least some discussion+change notice), one data attribute, using
~=
.Comment #252
droplet CreditAttribution: droplet commentedNot really. We have Class everywhere already. Just usually we don't call it directly but in *.attach() and from PHP.
Drupal.tableDrag is one of the examples.
I think 2 types is more clear and better for themers. Or we just drop `type` and use the `class` instead. If there's no BC problem, I'd recommend move style to [data-attr] also.
I see your point but it's not handy.
Ahh Alright. But
App matches "App Apple"
Apple matches "App Apple"
Comment #253
GrandmaGlassesRopeManPhew, this was a can of worms I didn't want to open.
- Since classes are basically syntactical sugar over JavaScript's existing prototype, I don't see this as being a bad idea. If this issue is with
new
, we can abstract that away, but I wouldn't recommend it.- Having two distinct data attributes makes sense to me. There's two distinct bits of information, let's make those accessible.
- I thought
^=
was a starts-with match?- I agree with keeping a replace method to another issue. This is already 10 years old.
Comment #254
droplet CreditAttribution: droplet commentedOK. The main structure is fine.
One bad drawback is we can't make methods to Private scope in an elegant way. We may have to add @internal or prefix with _ temporarily.
It will land in Babel soon I bet:
http://thejameskyle.com/javascripts-new-private-class-fields.html
I don't like to mix ids with error type and filter from it but well... not a very bad idea. So now, we make a implicit code standard on message ids:
errorType-customMessage
(and [data-drupal-message-type] is useless then)
Do we support custom error types anyway?
(it won't allow using `status|warning|error` as prefix on custom type)
some comments needs work.
the remaining thing is: "A way to get the message status/instances" (we can do it in a follow-up I think)
Comment #255
dmsmidtComment #256
tedbowOk this patch does a few things
1. Adds a $messagesSelector parameter \Drupal\FunctionalJavascriptTests\Core\JsMessageTest::assertCurrentMessages. This function was not actually check to see if the message were in the right container. Though /js_message_test.js we were assigning to different containers the test would have passed either way. because assertCurrentMessages() we found the messages by
$this->getSession()->getPage()->findAll('css', '.messages')
This didn't take into account the container.
2. Fixes a problem where if you added a message like
defaultMessageArea.add('Msg-id-no-status', {id: 'my-special-id'});
The message would not have a status.
This was because the add() signature was
add(message, options = { type: 'status' })
So if options was provided but didn't have a status then the default status would not be assign.
At @drpal suggestion I first tried:
options = Object.assign({ type: 'status' }, options);
While this work when tested the tst page manually and no errors shown in the console at when clicking all buttons. This did throw a JS error when running the tests.
I am not sure why but I did restart phantom to make sure it wasn't some cache issue.
The patch uses hasOwnProperty() check and works both manually and in the test.
3. changes Message.announce to a static function.
Comment #257
droplet CreditAttribution: droplet commentedPossible in ES6:
add(message, { type = 'status' } = {})
@see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operat...
Comment #258
GrandmaGlassesRopeMan@droplet
Since we're not passing status separately anymore (part of the options object), I don't think that makes sense.
Comment #260
dawehnerShould we document here that the template should check whether messages exists or not?
This is a a weird class name. "Message", I would have expect it to be a single Message, but in fact it holds multiple messages. What about using "Messages" instead?
Are we okay of not supporting the $repeat parameter of drupal_set_message? I guess the fact that JS depends on time, two equal messages aren't no longer the same, but I wanted to mention that here.
I have a hard time seeing where type is used. Maybe you want to have a selectByType method
This , here is quite weird. Is this really part of your CS?
Reading up about alert on https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Tec... the role is on the h2 instead of a wrapper around it. Does that matter?
Comment #261
GrandmaGlassesRopeMan@dawehner Thanks!
#260.2 - Lets just make this a class expression, done.
#260.3 - I think so for now. It's a new api.
#260.4 - I think it was a documentation leftover, I cleaned it up.
#260.5 - Yes, trailing comma.
#260.6 - Maybe @dmsmidt can answer this.
Comment #262
dmsmidtI'll try to test later, but a quick glance shows me that in case of an error message we read the message twice. Once through
Drupal.announce()
and once due to the addition of an element withrole=alert
inDrupal.theme.message
. In the announce version we have a higher priority for both warnings and errors. In the theme we only read out messages of type error. Also, in the announce version we don't announce the error type, which we agreed we should.Anyhow, seems to need work.
Nit: add period to end of sentence.
Comment #263
GrandmaGlassesRopeMan- An attempt at refactoring
Drupal.theme.message
.Comment #264
dawehnerOne thing, and this might be a minor detail, which confused me a bit is that this is basically a dom only api. There is no way to get an array of messages somehow, so you could do something about it. Maybe the usecases are limited, but I would have expected to have that capability in a new API we design from scratch. Any thoughts about that?
Comment #266
GrandmaGlassesRopeMan- Fixes a mistake with inserting HTML elements.
- #264 - You should be able to construct an array of messages by fetching them from the DOM yourself. I'm not sure if there's value in storing message data on the instance of
Drupal.message
, but maybe a followup?Comment #267
GrandmaGlassesRopeManComment #268
dawehnerI don't feel really confident to approve this patch.
Damnit, test coverage actually helps.
Agreed
🔧 This line jump of the comment makes it really hard to read :(
❓ On top of that I'm a bit confused why we have to support multiple indexes both using an array and using a string with spaces, but maybe I'm missing something obvious.
Note: I'm following emoji code ... https://gist.github.com/pfleidi/4422a5cac5b04550f714f1f886d2feea
Comment #269
GrandmaGlassesRopeMan- Cleans up sketchy comment placement mentioned in #268. 👍
- Removes string manipulation methods on indexes within
select
method. 👍Comment #270
GrandmaGlassesRopeMan- no sourcemap 🤦♂️
Comment #271
dawehner🙃 Typo in Constuct
❌ Wait, do we include source mappings by default?
Comment #272
GrandmaGlassesRopeMan@dawehner Yep, no source maps are included by default. You'll need to run
yarn run watch:js-dev
if you want source maps. I had accidentally included it in #269 but quickly realized that for #270.- Fixed spelling mistake in #271.
Comment #273
dawehnerThank you @drpal. It would be great if one of the two other JS maintainers @droplet or @nod_ could sign this patch off.
Comment #274
star-szrIf the
<div data-drupal-messages>
element is required for this to work, then we should be updating Stable too (we're already updating Classy). This markup change may be slightly disruptive but probably acceptable.Also, I'm not seeing much discussion about performance since this rolls back the big change in #2853509: Don't render status messages if there are no messages but also include their assets if there might be.
Didn't #2853509: Don't render status messages if there are no messages but also include their assets if there might be remove the need for this line since it's now always included via classy.info.yml?
Comment #275
tedbowAdded
stable/templates/misc/status-messages.html.twig
to stable/templates/misc/status-messages.html.twigRe performance using @alexpott's idea here #2853509-22: Don't render status messages if there are no messages but also include their assets if there might be about not including the actual template if there are no messages from the server just a div place holder. This works but there must be some CSS difference because there is not padding at the top of the message in Bartik. That will need to be fixed.
Removed
{{ attach_library('classy/messages') }}
, yes not needed anymore.Comment #277
tedbowSome test fixes
I didn't mean to leave in the inner div here. This cause the ErrorHandler test.
I think removing these lines remove a return character in the response which broke the BigPipeTest. Remove the return character from the test expectation.
Comment #278
tedbowThe only thing I see remaining is the difference in padding(or margin) to message when there is no message from the server
JS Message
Server message
adding CSS tag.
Comment #279
tedbowOk I figured out what the difference in #278
Server site messages at least in Bartik are not rendered directly under
<div data-drupal-messages>
but within an inner div that has the classmessages__wrapper
.So the current patch actually doesn't target that inner div that server-side messages are rendered into which causes the margin problem.
We could just update our placeholder StatusMessages::renderMessages():
But then we would take way the advantage of having a template in the first place because whatever we put in this placeholder would have to match what is in the theme's
status-messages.html.twig
file.So working with @drpal we figured out that we need to actually create this inner div on the client side but in a way that can be way that can be overwritten by a theme.
Furthermore if no selector is passed to the
Drupal.message
we need the default target to be the inner div if it already exists(there was message from the server) and to create it if it doesn't exist.The other thing that this means if you want to target the default messages container you can't just pass inner div element because it might not exist. So for target the default contain you should not pass an argument to the
Drupal.message
constructor. I updated the test js to reflect this.Comment #280
GrandmaGlassesRopeMan- Fixes comments and adds some more documentation.
Comment #282
GrandmaGlassesRopeMan-
null
is still a value. need to passundefined
for the default param assignment to trigger.Comment #283
droplet CreditAttribution: droplet commented** I haven't done a full review.
#282,
document.querySelector returns null if no found.
Comment #284
GrandmaGlassesRopeMan@dawehner,
This shouldn't ever return
null
, unless you've adjusted the template, then you should override this method.It only mattered here, because we wanted to trigger the default param behavior.
Comment #286
Wim Leers@drpal asked me to look at the assertions in the BigPipe test coverage that assert whitespace.
Comment #287
Wim LeersDid some git+issue queue archeology. The test coverage with whitespace assertions was added in #2469431-210: BigPipe for auth users: first send+render the cheap parts of the page, then the expensive parts. That just imported the contrib BigPipe module though. The actual issue where this test coverage was added is therefore a contrib issue: #2675670: BigPipe response delivery test coverage with JS enabled & disabled (BigPipe + HtmlResponseBigPipeSubscriber).
#2675670 does not state explicit reasons for asserting the whitespace. But the reasons are clear now:
$this->assertRaw()
), in the case oftestBigPipeNoJS()
($status_messages->embeddedHtmlResponse
)testBigPipe()
($status_messages->embeddedAjaxResponseCommands
)I don't see a good alternative for them. For the first, one could argue it should just compare it as HTML (easier said than done, but possible). For the second… there is no good way to compare the expected JSON with the received JSON.
I think the answer is actually pretty simple: just update the test cases' expectations. It's extremely rare for us to change the rendered HTML for something like status messages. So needing to update these assertion expectations this one time is okay, and an acceptable cost.
Comment #288
chr.fritschJust a reroll
Comment #289
webchick@drpal gave me an overview of this patch today. This looks like a great addition to help with the kinds of responsive JavaScript UIs we want to do, both now [Settings Tray] and in the future. As a result, escalating this to "major" because without a central API for this I can quickly see Media Library + Settings Tray + Layout Builder + whatever doing their own thing here.
As part of the walkthrough, he showcased this UI, which is part of the test:
This demonstrates that adding/removing various types of status messages functions, both page-level and local-level scope, which is awesome. I had asked about accessibility, and he pointed me to the place in the code where
Drupal.announce()
is called on these, so we seem to be covered on that basis as well.I notice up in #251 that @nod_ was pushing back on making this a class with all the ES6 fanciness. With the ENORMOUS caveat that my JavaScript knowledge could fit inside here: || this does seem consistent with the way that we've gone about adding new APIs to the PHP part of Drupal; for example, the Migrate system doesn't use hooks, it uses Symfony Events because that's the New World Order™. While it introduces some inconsistency, it also means we don't add more legacy code to clean up later.
However, it seems like it'd be good to get @nod_'s sign-off on this patch's approach, if possible. So assigning to him. It looks like this patch has been pretty stalled for a couple of months, and it'd be a nice addition to 8.5 if we could swing it.
Comment #290
nod_I'm fine with ES6 class now. One thing I'd like to point out is that I tried to keep functions in Drupal.theme to return strings only. Theme functions shouldn't be dependent on the DOM (i know some old ones are but can't get rid of them easily). That way if someone wants to swap Drupal.theme with some other templating language it won't be an issue. And a theme function named "createMessageInternalWrapper" just doesn't sound like a theme function :p
Patch doesn't work in firefox:
TypeError: wrapper is null
atmessage.js:88:9
.Comment #291
GrandmaGlassesRopeManComment #292
GrandmaGlassesRopeMan@nod_ - An interesting point. I agree that
Drupal.theme.createMessageInternalWrapper
is not the best name. Both of the theme functions do try and make some assumptions based on the state of the DOM, and compute some output. This is especially difficult in this scenario due to the fact that messages could be rendered on the server, and we want to add messages to the default location.Additionally, while I couldn't replicate any issues in Firefox directly, it does point out a case where we did not proactively error early enough.
Comment #293
GrandmaGlassesRopeMan- A slight revision to theme function names. From
createMessageInternalWrapper
tomessageInternalWrapper
Comment #294
GrandmaGlassesRopeManComment #295
tedbowRegarding @nod_ comment in # I think this would better if this were not a theme funciton. It seems different from what `Drupal.theme` functions are currently used for.
Also it would still be overridable if it was `Drupal.message.messageInternalWrapper`
Other than that it looks good to RTBC!
Comment #296
GrandmaGlassesRopeMan- #295.1 - 👍
Comment #297
tedbow@drpal looks good
RTBC 🎉
Comment #299
tedbow#296 is getting unrelated DrupalCI errors like
Retesting
Comment #300
tedbowtests passed
Comment #301
nod_Thanks for moving some things out of Drupal.theme. It's overdue and we're on page #2 so that's a RTBC from me too :) thanks a lot for pushing this over the finish line.
If future me complains again about Drupal.theme not returning a string here is some working code:
Comment #303
GrandmaGlassesRopeManLooks like a random failure from ci.
Comment #305
tedbowBuild time issue with DrupalCI
Comment #307
jibranComment #309
jibranComment #310
lauriiiShould we throw an exception if an invalid message type is provided?
Also, it would be better to do the assertion before this function, to ensure that any overrides of this function wouldn't have to be able to handle invalid message types.
We are not allowed to make changes to markup in Classy and Stable themes. We can make exceptions to this case by case basis but it seems like the current approach is too risky.
Instead of wrapping the old message, could we add a new div as a sibling for the messages?
Maybe something like this would work:
Comment #311
GrandmaGlassesRopeMan- #310.1 - This makes sense. In
message.add()
we can check that message type is valid and throw an error if an invalid type is used.- #310.2 - I don't really think that this is a particularly risky decision. Only in the case of a message provided to browser from the backend are we wrapping it, and only the actual message section.
Comment #312
dmsmidtMay I kindly note that this still is a blocker for Inline Form Errors #2876321: Update inline form errors summary after form validation with AJAX, however the current version of this API won't be able to manage a mix of server side and client side generated messages. By moving forward with #310.2 I fear this becomes even more difficult in the future.
Comment #313
lauriiiThanks @drpal, the changes look great!
I thought more about this after #311 and #312 and I think we should proceed with the current solution given that there's downsides on the solution I proposed on #310. There's more risk involved with wrapping existing divs compared to adding new siblings but compared to many other kinds of changes, it is still one of the changes with least risk involved. This is also supported by the fact that @Cottser didn't hold particular concerns about this approach on his review #274.
Another concern that I have now, is that there are many overrides of this template that won't have this new wrapper. I suggest that we add the wrapper forcefully outside the template like we've done in the settings_tray module.
Comment #314
GrandmaGlassesRopeMan@lauriii - Great! One thing to take into consideration is that unless you include this library, and create a new instance of the message class, nothing happens. Additionally whenever you're creating that new instance, you can specify a dom node as a destination for those messages. If you've overridden the template, and another module expects something (the default destination), then we throw an error, which I think is pretty appropriate behavior.
Comment #315
lauriii@drpal sorry for a late reply. This makes sense. The error indeed should be enough to guide users how to get the JS messages working.
It would be great to create another, more specific change record for this template change to suggest themers adding this change before they even see the error.
Comment #316
GrandmaGlassesRopeManHere is the additional change record to help themers with this, https://www.drupal.org/node/2935209
Comment #317
dawehnerCould we hide this empty DIV by default using js-hide or so?
This is an error. I don't think we need to make this translatable.
What about using getMessageTypeLabels?
Again, I don't see why this needs to be translated
NITPICK: There is one space missing here :P
Comment #318
GrandmaGlassesRopeMan@dawehner Thanks!
- #317.1 - I think this div may not always be empty if the server has rendered some messages.
- #317.2 - This makes sense to me. I checked and we are only translating one other JavaScript error.
- #317.3 - 👍
- #317.4 - See #2.
- #317.5 - Fixed. I wonder if this is something we can enforce with eslint?
Comment #319
dawehnerGood question. I had a look at https://eslint.org/docs/rules/valid-jsdoc and there was nothing obvious there.
Could we somehow hide it at least for the empty case? Maybe I'm talking nonsense here.
Comment #320
dawehner@drpal and myself talked about it quickly in slack and agreed for #317.1 to postpone to a followup.
Comment #321
GrandmaGlassesRopeMan🎉™️
Comment #322
alexpottNice - still not loading up the entire rendering system with twig for no messages. +1
I was wondering if we hadn't considered putting
<div data-drupal-messages>
inside the block in core/themes/classy/templates/misc/status-messages.html.twigThat would mean core/themes/bartik/templates/status-messages.html.twig wouldn't have to change and neither would any other theme that had extended classy in the same way.
It would mean an extra div in places though.
Comment #323
tedbow@alexpott I think you form forgot to use
<code>
around<div data-drupal-messages>
so it didn't show up in the commentBy looking at the html source of the comment I think what @alexpott meant to put was:
Comment #324
alexpott@tedbow yep you're right - sorry - I've fixed the comment.
Comment #325
dawehnerRe #322
There are certainly advantages of your proposal, but I'm wondering whether having a div hanging around and not being changable by themes, would be a bad thing.
Comment #326
alexpottIsn't it changeable themers? - just don't use the (twig)block. I think we should err on the side of everyone getting the messages and if themers want to customise this then they need to do it in full knowledge that drupal needs a
<div data-drupal-messages>
in order to work as expected.Comment #327
tedbowI agree with #326 in that which try to make sure as many themes automatically get the JS messages as possible without any changes.
If we keep this change does there need to be updates to this change record? https://www.drupal.org/node/2935209 ?
Comment #329
lauriiiI'm not sure if I understand the reason behind moving the wrapper inside the block? It seems like this actually has reverse effect compared to what #326 states. Now if developers want to extend this template and override the block, they will have to remember to include the wrapper inside the block unless they use
{{ parent() }}
.The change in #318 for Bartik is redundant and there's duplicate Drupal messages wrapper.
Comment #330
alexpott@lauriii if we put the wrapper in classy's
status-messages.html.twig
then anything that extends classy gets js message support with no changes if they have copied Bartik. If we don't put it there then every theme that uses classy and extendsstatus-messages.html.twig
will need to be changed. I think adding the div to classy is part of the promise to classy - ie. to continue working with minimal changes to your theme.If people override
status-messages.html.twig
and don't use{{ parent() }}
they are going to include the<div data-drupal-messages>
no matter what we do.Comment #331
alexpottIgnore me in #330. @lauriii is correct. We should go back to #318 but without the changes to Bartik's
status-messages.html.twig
- Bartik is only replacing the inner block - that's how extends works. I should have read the manual. https://twig.symfony.com/doc/2.x/tags/extends.htmlComment #332
tedbowHere is patch that does
Comment #333
alexpottSo all I think we need to do is update the change record with something about how extends works and when you are going to need to do something.
Comment #334
GrandmaGlassesRopeMan- tests pass
- change record updated, https://www.drupal.org/node/2935209
- 👍
Comment #335
lauriiiWe have to do this change also for Umami theme now that it has landed.
We should move these selectors to the end of the file after the RTL rule, so that the LTR and RTL rules are grouped together.
We can also remove the .messages__wrapper from the selectors.
Comment #336
tedbow#335 fixed both
Comment #337
samuel.mortensonI have concerns about relying on this markup in a JS API. Many themes (ex: Bootstrap, Drupal8 Zymphonies Theme, and AdaptiveTheme) have overridden status-messages.html.twig and would all need updated if this change got in.
I can think of two ways to address this:
1) Since we're already outputting a fallback in
\Drupal\Core\Render\Element\StatusMessages::renderMessages
- why not remove all the template changes and always output the empty div after the normal status messages?2) We could have a fallback in JS, so that instead of an
Error
being thrown when[data-drupal-messages]
is not present, we append that div somewhere on the page. Not sure how we would determine where that should go.Comment #338
tedbow@samuel.mortenson I see your concerns about themes having to be updated. Also if a site used a custom theme and they overrode this template they would need to update there theme. That would be very hard to tell how common that is.
So I chatted with @drpal about this and think we have solution that works kind of like your suggestion in #337.1
So there are benefits to have the messages in the same div has your server-side messages if any that is why we were adding the changes to the templates status-messages.html.twig. But also this template will not be used if there are no server-side messages.
The current approach in #336 was to output
<div data-drupal-messages></div>
if there were no server-side messages.But of course that does lead to the problem that if
status-messages.html.twig
and doesn't update this template after this API is addedSo this patch instead of adding code>
if there were no server-side messages it always adds
<div data-drupal-messages-fallback class="visually-hidden"></div>
whether there are server-side messages or not.Then in
message.es6.js
default message container is being used and it doesn't exist then it changes thedata-drupal-messages-fallback
into thedata-drupal-messages
div by replacing the attributes and remove thevisually-hidden
class.This way:
status-messages.html.twig
or want to update it can have there server-side and client-side messages in the same wrapperdata-drupal-messages
div somewhere else they can. As long it is on the page somewhere thendata-drupal-messages-fallback
div will not be used.Comment #339
GrandmaGlassesRopeManAnother change, which is not clearly highlighted in @tedbow notes is the change for when we figure out
messageWrapper
. Previously this happened when a new instance ofDrupal.message
was created, however due to template possibly not being rendered (bigpipe?) this caused some issues. Now, themessageWrapper
location is figured out right before the first message is added to the page.Comment #340
alexpottThis seems like a really good idea. A very nice BC layer. It'd be good to have a test for it.
One thought is that
visually-hidden
is probably the wrong class. I thinkhidden
is the correct class. Since this is meant to be hidden from all users not just those that can see.Comment #341
tedbow@alexpott good catch! changing to use
hidden
classComment #342
droplet CreditAttribution: droplet commentedI'd remove the
data-drupal-messages-fallback
and introduce an option for target wrapperselector: "[data-drupal-messages]"
.If it's really needed, another option for
autoCreateWrapper: bool
. But I perferred:Allow to change the wrapper HTML:
It sorted one of the blockers in my early comments. It may has
[data-drupal-messages]
in the Modal & background but we only send message to Modal..etc. And our code usingdocument.querySelector
that only catch first element. First In, First Win.Comment #343
tedbow@droplet
There is already option to pick a target per instance of
Drupal.message
. We only use only use[data-drupal-messages]
if no selector is specified. @seecore/modules/system/tests/modules/js_message_test/js/js_message_test.js
for an example of using different target.Unless there is very very good reason not to I think we should add the BC layer that
data-drupal-messages-fallback
gives usSo if a theme like Bootstrap, Drupal8 Zymphonies Theme, or AdaptiveTheme as @samuel.mortenson mentioned in #337 did not update there templates they would always see the messages not a warning that the messages could not be displayed. Core goes out of its way to make sure that server-side messages via
\Drupal\Core\Render\Element\StatusMessages::renderMessages
are always placed on the page even if the "status message" block is intentionally deleted from the page. I think we should follow this same pattern here no matter if the theme was update or not the messages should show up on the page.This especially important because we would introducing this in minor version of Drupal(8.6 hopefully 🙏). This is of course if we think messages that are created with this JS API our as important as server-side message which I think they are.
Comment #344
droplet CreditAttribution: droplet commentedWhat's the main reason that must do in server-side but not client-side? I believe the client-side script will benefit for React & JS 3rd parties API binding for a long-term.
Comment #345
tedbowThe server response has to provide some indication of where the messages should appear in the markup of the page. That is all this doing. Also nothing is stopping the theme from putting the messages in another location. All the theme would have to do is put the
data-drupal-messages
attribute somewhere on the page via JS or PHP.Yes that is fine long term. But I don't think we should wait on that to happen before we create simple API for Javascript message. Again this is API. we can expand it or change how the internals work later.
Comment #346
GrandmaGlassesRopeMan🚀
Comment #347
andrewmacpherson CreditAttribution: andrewmacpherson as a volunteer and at Annertech commentedHow much testing has been done with actual assistive technology? I've seen screen readers have been mentioned a few times, but some of the comments sound like assumptions which would need manual testing to confirm.
I think the way Drupal.announce() is being used here is a bit ambitious. For example it looks like we could be are adding a new
role=alert
region AND calling Drupal.announce() - I expect that will lead to messages being announced twice.I'm not sure how to carry out manual testing. Would anyone mind walking me though the code, say in a Google Hangout or similar?
@dmsmidt - I see you did some screen reader testing in #214. Can you recall if you tested a situation where several messages were displayed? The static messages we have at the moment group all errors inside one
role=alert
wrapper, for example. I'm curious as to what happens when an extra error message is added when there is already an existing error message. Browsers seem to differ in the way they handlearia-atomic
andaria-relevant
- I think they provide different defaults.Update:
role=alert
has an implicitaria-atomic=true
. That means when a live region changes, it's supposed to read the entire live region. If multiple error messages are being added one at a time to a singlerole=alert
wrapper things code get verbose quickly.I see the patch has some test modules, and the tests have a mention of multiple-error, so that's encouraging. I'll try using the test modules for manual testing with some screen readers.
Comment #348
andrewmacpherson CreditAttribution: andrewmacpherson as a volunteer and at Annertech commentedrole="contentinfo"
is definitely wrong. There's an issue to fix this for static messages too (where?).contentinfo
is supposed to be for information about the document as a whole, not status updates. It's a landmark role, and there should only be one such region per page. It's intended to serve the same purpose as a top-level HTML footer element.role=status
is the appropriate role. Likerole=alert
it is an ARIA live region. It's possible that we might not needDrupal.announce()
at all if we employrole=status
correctly instead ofcontentinfo
.Update: I couldn't find the issue about static messages, so I filed #2942404: Messages should have role=status instead of role=contentinfo.
Comment #349
GrandmaGlassesRopeMan@andrewmacpherson
I made a minor change here, github.com/mattgrill/drupal, if you want to test this.
Comment #350
alexpott@andrewmacpherson I've added a how to test section to the issue summary.
Comment #351
GrandmaGlassesRopeManThis is the changes that I posted in #349, but as a patch!
@andrewmacpherson - If you want to review this in realtime, let me know. I can be available whenever.
Comment #352
andrewmacpherson CreditAttribution: andrewmacpherson as a volunteer and at Annertech commentedI did some manual testing of patch #351 with a couple of screen readers and various browsers.
/js_message_test_link
are very confusing to follow in a screen reader. As in, the specimen message content. We have buttons, invisible headings, roles, and message content which all contain various combinations of "error", "status", "message", "warning" and numbers. Manual testing would be much easier if the messages had some content apart from these. Maybe if the messages were all about different farmyard animals, or something, they'd be easier to follow in manual testing.<div role="status">
for every message, and then it nests an additionalrole="alert"
inside this for error messages. This might confuse assistive technology, but I'm not certain of that. I am certain that this isn't the right way to use these roles though. An element withrole="status"
has an implicitaria-live="polite"
, while an element withrole="alert"
gets an implicitaria-live="assertive"
. Nesting assertive inside of polite doesn't make sense. Instead, the message wrapper DIV should get a role of "status" or "alert".drupal.message.announce()
is used, or the fact that different numbers of aria-live regions are being created in short succession, or browser support for aria-live regions, or whatever. In any case it needs more testing. I tried ChromeVox, WIndow Eyes, and NVDA, in combination with IE11, Firefox 52-esr, and Chrome 65. Haven't tried JAWS, iOS VoiceOver, or MacOS VoiceOver yet.Comment #353
dmsmidt@andrew, I must say, fabulous testing and explanations.
#1 got me hooked, more animals in core thus seem to be legit!
#4-7: What do you propose? For sure the heading elements should be limited.
#8: Would be great if you could find a pattern, or at least provide us with the way we could most likely reproduce that issue.
Comment #354
andrewmacpherson CreditAttribution: andrewmacpherson as a volunteer and at Annertech commentedI'm still thinking about this.
One idea is to stop adding the headings in the JS behaviour. Instead, put a visually-hidden heading "status messages" before the
{{ messages }}
in the template.Pros:
- no risk of introducing a heading with the wrong level
- doesn't proliferate headings with duplicate text
- avoids changing document outline after the page loaded.
Cons:
- if there are no messages, we have a heading with no relevant content after it. That might not be too bad though. If I found a heading saying messages, but there were none, would I be confused, or is that clear enough to understand? We could mitigate it by managing a fallback "no messages", so a user can find "status messages, heading 2, no messages".
Comment #355
tedbow#352
1. Made the message texts somewhat more whimsical and unique. No farm animals, I am not that clever.
2. fixed now only the wrapper as a
role
attribute.3. done in 2)
4. H2s We were trying to make the client side messages have similar markup structure to messages that are render on the server. Bartik's message structure is going to come from
core/themes/classy/templates/misc/status-messages.html.twig
. This will true for any theme that extends classy and doesn't override the template.core/themes/stable/templates/misc/status-messages.html.twig
also uses h2s.themes/bootstrap/templates/system/status-messages.html.twig
for some reason uses h4s.So in most sites the server side messages will have these H2 headings.
Should we worry about attempting to match the server-side message structure? We can't change
stable
theme template. I assume if the current markup is bad for accessibility we could change the markup classy.Maybe the nature of client side messages in that they will appear after the page is loaded and that they may appear in various locations on the page means that they are different enough and should not have to match the server-side messages markup.
If we want the server-side and client side message markup structure should be the same, as much as possible, then I think we should keep the current structure with the H2s. If the H2 should not be there then they probably shouldn't be there regardless of whether it is server-side or client-side message and we should remove them both after this issue in a follow-up.
If there is no reason for server-side and client side message markup structure to be the same then we can remove the H2's here. but I would like feedback on this first.
6.
This patch removes the
role
attribute on H2 so that should not be an issue.For other points see 4) here.
7. So maybe this means we shouldn't have H2's at all the client-side.
8. I think it may be problem with
Drupal.announce
. I made a test module https://github.com/tedbow/annouce_testerJust enable and goto
/annouce_tester/announce
It will call
Drupal.announce
10x very quickly.If this is problem with
Drupal.announce
we can file a follow up.Comment #357
GrandmaGlassesRopeMan- correct constructor case,
Drupal.message()
->Drupal.Message()
- cleanup test code
- fix tests from #355
-
removeAll
method is removed.select
andremove
are singularComment #358
tedbowI think changing select/rmoeve to only use 1 message id is good change makes the code much simpler.
I played around the test code it will still be super simple for custom to Javascript to select/remove multiple messages if they have an array of message ids.
This is also is good to remove super simple just call multiple times.
Thanks for adding the es6 version of the test js code!
These changes look good they are only update the text in tests to match the change in the test JS code I added in #355
I would say this is RTBC.
I think we could have 2 follow ups
#355.4 should we remove h2 for messages for both server-side and client-side messages.
#355.6 does Drupal.announce work when calling multiple times quickly.
Comment #359
lauriiiThe latest patch has lots of unrelated changes
Comment #360
GrandmaGlassesRopeMan- matt learns how to copy/paste.
Comment #361
lauriiiThis certainly starts to look better. Here's few more comments after doing an extensive review on the patch.
I'm wondering if the
::getMessageTypeLabels
should be extended to support this use case.Also, is there use case for setting the priority outside of the message type?
I guess this comment is outdated since we are not using the options for removing messages again (only the options.id).
This comment could be more explicit than saying that it works as "sort of tag for message deletion".
Should we just say empty string?
We should at least remove the word unique from the documentation since Math.random() isn't unique.
Nit pick: what do you think, would this function be easier to read if we destructured the option properties as well?
s/messageWraper/messageWrapper
This could be also customized in the template. We should add mention in the change record that if they've customized this part in their template, they might want to override the theme function as well.
Just leaving a note here: I assume the reason for this change is that some text editors automatically fix indentation when you add the wrapping div. This has been indented like this to have correct indentations in the outputted markup. IMHO we should prioritize readability of template files over markup output so I'm fine with this change.
Nitpick: missing a period.
Looks like all of the accessibility feedback has been addressed, but would be great to get a sign off from the topic maintainers. Also, we should open a follow-up for the h2 issue.
Comment #362
GrandmaGlassesRopeManAlright,
#361.1 - I'm not sure.
#361.2 - Fixed. This was confusing anyways.
#361.3 - Fixed.
#361.4 - Fixed.
#361.5 - Fixed.
pseudo-random
#361.6 - Fixed. Yes!
#361.7 - Fixed
#361.8 - We can add a note about this in the change record.
#361.9 - 👍
#361.10 - Fixed.
Comment #363
GrandmaGlassesRopeManComment #365
tacituseu CreditAttribution: tacituseu commentedUnrelated failure.
Comment #366
andrewmacpherson CreditAttribution: andrewmacpherson as a volunteer and at Annertech commentedI need to take this patch for another round of manual testing. Last time I tried it wasn't very good. There were confusing headings, and parts of the message weren't announced, and it wasn't always clear that there were multiple messages being announced, and some announcements differed from the content of the visible message. The message status level wasn't conveyed. I thought it was a messy mix of all sorts of roles, headings, implicit live regions AND Drupal.announce().
The headings are a VERY big concern - let's address them here please.
Comment #367
lauriiiDiscussion from Slack:
So I think based on that we cannot move the heading issue to a follow-up.
Comment #368
chr.fritschNot sure if this is an issue that should be addressed here, but I noticed it when I played around with the buttons on /js_message_test_link.
So clicking on "Add multiple 'error' and one 'status'" and then on "Remove multiple" doesn't remove all the messages.
Comment #369
GrandmaGlassesRopeMan@chr.fritsch -
Add multiple 'error' and one 'status'
is used with theRemove 'error' type
button. Additionally all of this is test code.Comment #370
GrandmaGlassesRopeManComment #371
mgiffordI'm trying to figure out how to test this for accessibility. If it's an API, I don't know how it affects what is presented to the DOM.
If I can get some guidance here it would be useful. I'd like to see this in Core, but am not a JS person.
Comment #372
lauriii@mgifford you are right that we are only adding an API in this patch. You can test this by following the instructions in the issue summary 🙂
Comment #374
DuaelFrHi there,
Congratulations for the great job done here and all the dedication it needed to get to this point!
I made an "a11y-minded" code review. I really like the way you used
Drupal.announce()
to manage the addition of a new message. I appreciate the fact we can set a different message for screen reader users. Good job here!I don't know why the patch does not already provide a
CommandInterface
implementation to use this new API but I trust you people (and I don't really have the time to read all the previous comments).I can't make a real life test as I still don't have a proper screen reader installed but I can't see why this would not work as expected. I hope someone with a screen reader can jump in to finish this review and push it to RTBC soon :)
Kudos for everyone!
Comment #375
GrandmaGlassesRopeManComment #377
andrewmacpherson CreditAttribution: andrewmacpherson as a volunteer and at Annertech commentedThe H2 headings still need to be removed.
Comment #378
phenaproximaReroll against 8.7.x.
Comment #380
phenaproximaDiscussed with @drpal today, and we figured out why AjaxTest fails (although TBH I'm not sure how it has ever worked), although JsMessageTest is still broken (for reasons that are not related, although I'm not sure if the test is wrong, or the code). Patch forthcoming.
What we discovered in looking at this patch is that adding the fallback message area to the StatusMessages render element will not work. That element is automatically prepended to most AJAX responses delivered by the form system, which means every form AJAX response will return a fallback messages area! That's no good.
So I suggested an alternate approach -- let's revert the changes to the StatusMessages element, and add the fallback message area to the SystemMessageBlock plugin's output. That way, it will be rendered at least once in most themes (I can't imagine too many instances where you'd never want to show the messages block), but not more than once under most circumstances.
Comment #381
DuaelFrI've seen projects where the SystemMessageBlock were disabled. If not already anticipated, please consider testing the existence of the area before trying to write in :)
Comment #382
lauriiiI discussed with @phenaproxima about this issue and we agreed that adding the fallback in
Drupal\Core\Render\Element\StatusMessages
doesn't lead to the right behavior since it could be used for rendering messages out of the context ofDrupal\system\Plugin\Block\SystemMessagesBlock
. Since the wanted behavior is that the JS messages are attached to theDrupal\system\Plugin\Block\SystemMessagesBlock
, we could just render the fallback in that block directly. In that case we have to explicitly add a fallback for the element inDrupal\block\Plugin\DisplayVariant\BlockPageVariant
, which is fine.Comment #383
phenaproximaThis oughta do the trick. A quick summary of the changes:
Comment #385
lauriiiThank you @phenaproxima 🤩
I think this should be somewhere else than the render element since there's no connection between these two.
Should we set weight for this element as well so that it would be rendered at the same location as the other status messages?
Comment #386
Wim Leers#383 changed where the fallback is added. Now the updated BigPipe test expectations are wrong. That’s also why
BlockPageVariantTest
fails. Looks pretty simple to fix! :)Comment #387
tim.plunkettI would rather see this as a flag set on the render array, like
'#include_fallback' => TRUE,
And then use a #pre_render to actually include it.
This would also address the #weight issue @lauriii mentions.
Comment #388
phenaproximaOkay; I removed the fallback() method and implemented an #include_fallback flag on the render element (defaults to FALSE to maintain backwards compatibility). The variants, and SystemMessagesBlock, set #include_fallback to TRUE.
Let's see if this passes the tests.
Comment #390
tim.plunkettThe token changed from _HAdUpwWmet0TOTe2PSiJuMntExoshbm1kh2wQzzzAA to EBaaW0Ackt8KfI-t1xwsNY4hd3CsCxNyTZLB3t0f71k, that's not a problem.
The problem is that there is a second instance of StatusMessages::renderMessages added to the page, and the count of placeholders is therefore wrong.
I think this a real bug, not just a wonkiness of BigPipeTest. And I think it's unrelated to the difference between the flag or the dedicated call.
Note that the token change may just be necessitated by this additional instance, and might need to be reverted if the bug is fixed.
Comment #391
tim.plunkett@phenaproxima thinks there should be a second placeholder. Not so sure myself, but if that's okay then this should pass.
Comment #394
phenaproximaTrying a slightly different approach, starting from #388.
The thing is -- there is no good reason for the fallback area to ever be rendered with a placeholder, BigPipe or no BigPipe. It's completely static markup; all the dynamic stuff takes place on the client side, by design. So I changed generatePlaceholder() such that, if #include_fallback is truthy, the fallback area will be rendered immediately, alongside the placeholder, rather than as part of the placeholdered content.
In the interest of full disclosure: this does have the side effect of changing the output of generatePlaceholder(). However, I don't know if we consider render arrays built by internal pre-render callbacks to be part of Drupal's API, so I don't know if this has BC implications (I doubt it, but I thought I'd mention it).
I ran all the tests locally which broke in #388, and they all passed. Fingers crossed, then.
Comment #395
phenaproximaAdded a change record describing the new #include_fallback property: https://www.drupal.org/node/3002643
Comment #396
NickDickinsonWildeOne thing that I'm unclear if it is the desired behaviour:
If there is a *non* JS rendered status message, it isn't removable - to easily see, just run a cache clear while on
/js_message_test_link
.One thing that concerns me as a sometime themer - anyone using a Bartik based child theme, if they've customized messaged div padding/margin will likely have to adjust it; should this at least have a CR? (Due to the changes in
/core/themes/bartik/css/components/messages.css
.Other than those two concerns RTBC
Comment #397
phenaproximaYeah...that's unfortunate, but so far there's no way in core to dismiss a message. But there should be, and if I'm not imagining things, I think there's already an issue open for that. Implementing it here would be out of scope, though.
@lauriii is the authoritative word on this, but if my memory is correct, I believe that Bartik is considered "internal" and not meant to be extended by themers. Meaning that we can safely change its CSS in this patch. Classy and Stable, on the other hand, are base themes and they generally cannot be changed until Drupal 9.
Comment #398
NickDickinsonWildeThen unless @lauriii sees a problem there +1 RTBC
Comment #399
adriancid@phenaproxima I see this on the patch.
Add a newline at the end of the file
The new line is missing here too.
Comment #400
tim.plunkettThose are generated files. Not fixable here.
This approach is much better and I'm glad to see it fixed the tests
Comment #401
andrewmacpherson CreditAttribution: andrewmacpherson as a volunteer and at Annertech commentedAccessibility concerns from earlier comments haven't been addressed, and I've found a few new ones. I think I have a better understanding of this now.
role="status"
androle="alert"
are implicit live regions per the ARIA spec, but we're using them in conjunction with the live region fromdrupal.announce()
, and that's where things are getting messy.role="alert"
won't cause them to be announced. There are known quirks in browser support, and the ARIA spec itself isn't clear on how they should behave. For some breowsers you need explicit aria-live properties. I've seen some encouraging approaches where an empty<div role="alert"></div>
is injected first, and then populated with the message text as a separate step, so the browser effectively sees a change in the live region content.Drupal.announce()
for the messages. It's good for conveying stuff that is otherwise only apparent visually (e.g. the module page - "3 results in the modified list"), but using it to echo text which is visible on screen isn't really what we intended it for.Drupal.announce()
, then indicating the message type in the theme function.I think we can leave the aria-live stuff to follow-up issues. It's going to be tricky to get it good across a range of browser/OS/AT combinations. Would it be a good idea to mark the API as internal initially? So far nothing is actually using it, this patch just adds the API.
Comment #402
andrewmacpherson CreditAttribution: andrewmacpherson as a volunteer and at Annertech commentedThe aria-live mappings are off, this is something new I found. We have 3 message types (status, warning, error) and we map them to polite/assertive in aria-live. But we're doing it inconsistently.
In
Drupal.Message.announce()
...But this doesn't match the roles used in
Drupal.theme.message()
...role="alert"
, implicitlyaria-live="assertive"
role="status"
, implicitlyaria-live="polite"
role="status"
, implicitlyaria-live="polite"
In
Drupal.theme.tabbleDragChangedWarning()
, we already have a warning (amber) message marked up with the alert role (assertive)...TODO: I suggest we treat "error" and "warning" as assertive/alert. Should be an easy patch update in this issue, to make these consistent.
Comment #403
andrewmacpherson CreditAttribution: andrewmacpherson as a volunteer and at Annertech commentedQuestion: does this API allow messages to be injected literally anywhere, or does it require a pre-arranged wrapper region? I can see we have such regions in the test module, but I'm not clear if the API requires it.
It relates to the headings problem. I think it will be better to recommend a heading for the region where messages are added, which is much less disruptive than one heading per message.
Comment #404
GrandmaGlassesRopeMan#401.1 - fixed
#401.2 - sure, if you create the followup we can fix it after.
#402.1 - fixed
#403.1 - yes, you can create your own destination for messages and fill it with as many different message types that you want.
Comment #406
phenaproximaLet's see if this fixes it.
Comment #408
dmsmidtAfter reading the change record in https://www.drupal.org/node/3002643, I'm worried it will be a lot more difficult to fix #2876321: Update inline form errors summary after form validation with AJAX.
In that case there will be a server side rendered message showing the summary of all inline form errors. After fixing one of the errors, and if that form element is resubmitted via AJAX, the summary will be wrong (for example a required file). With the current approach it will be much more difficult to make it possible in a follow up to update server side rendered messages with this API without breaking BC. I know it is out of scope of this issue to mix SSR messages and CSR messages, but we should at least not make it too difficult.
Comment #409
phenaproxima@dmsmidt, I don't understand why this would cause a server-side problem. Under normal circumstances, the fallback area is not rendered in a status_messages element unless the #include_fallback switch is specifically set to true (it's false by default). In other words, 99% of the time, the status_messages element's behavior is unchanged by this patch. Can you provide an example or code path demonstrating how this would break inline form errors?
Comment #410
dmsmidt@phenaproxima, I hope I'm mistaken, but let me elaborate a bit.
I'm not saying this patch wil break any current behavior and certainly not interfere with server side rendering.
Initially my thought was that this client side API would be able to interact/modify the already (server side) rendered messages shown on a page. Because that is needed to change the inline form error summary. That summary is on the top of the page and is generated on the server side. Once a user fixes a problem in the form, and the error is resolved, we cannot use this current API approach to modify the summary via the client side. I was oké with this first to just get a basic API in and then in a follow up work on the interaction between SSR and CSR messages. I just read up on recent changes and see the JS API will use a completely separate fallback area. My fear is that this separation will make it more difficult to work towards a situation that the JS message API and the current system messages API will work together without BC breaks or lots of workarounds. Is this more clear?
Comment #411
phenaproximaThis should fix the tests.
Comment #412
phenaproxima@dmsmidt, I discussed your concerns with @alexpott. We agreed that this can still be committed as-is, because intermixing server-rendered messages and client-rendered messages is out of scope for this patch. True, BC makes this trickier, but we need to comply with the policy because Drupal 8. :) We can and probably should open a follow-up issue to investigate what it would take to "expose" server-rendered messages to the client-side API. But it's not really part of the work being done here, and doesn't need to block commit.
So, if someone will re-RTBC, I think this could potentially land soon.
Removing the "Needs manual testing" tag, because we have automated tests.
Comment #413
starshapedLooks good to me! Setting to RTBC.
Comment #414
GrandmaGlassesRopeManThis looks really good, 👍 from me.
I attached a small interdiff with some minor documentation changes,
object
toclass
. This probably shouldn't block this from getting in, but for correctness sake I wanted to add it.Comment #415
GrandmaGlassesRopeManSo... yeah, here is the interdiff.
Comment #416
andrewmacpherson CreditAttribution: andrewmacpherson as a volunteer and at Annertech commentedThe H2 headings have not been removed - I've asked for this several times already in previous comments, and it looks like I'm being ignored.They are highly disruptive to the page structure, and inserting them dynamically seriously undermines any other efforts which authors have made to achieve a sensible heading structure on their page. The H2 injected here doesn't just apply to the error message - When a H2 heading is introduced, it acts as a heading for ALL content following it, until the next H1 or H2. So if a page makes sensible use of H3 to H6 (e.g. "billing details" and "shipping details" as H3's), those are effectively re-parented by an error message which doesn't apply to them.This issue is NOT getting past the accessibility gate while those headings are still there.Update (5 mins later): very sorry, I made a mistake, looking at the wrong diffs, and this comment was written in haste. The changes in #404 DO remove the injected H2-per-message. The remaining H2's in the patch are part of the pre-arranged message region.
The thing I blocked it on HAS been addressed. Other a11y concerns noted in earlier comments (a) can be left to some easy follow-ups, or (b) are harder problems relating to inconsistent support for aria-live regions in browsers, OS accessibility APIs, and AT.
Comment #417
andrewmacpherson CreditAttribution: andrewmacpherson as a volunteer and at Annertech commentedback to rtbc
Comment #418
GrandmaGlassesRopeManComment #419
lauriiiFound unnecessary line change and extra whitespace which I have removed in this patch. I also applied the interdiff from #415. Just running the tests to make sure the tests are still passing since this change contains a minor change in the rendered output.
Also removing the needs accessibility review based on #416.
Comment #420
lauriiiUpdating commit credit
Comment #422
lauriiiThank you everyone who has worked on this issue during the last 12 years. 🙏 This issue was opened over 4 years before I created my Drupal.org account. 😳 Committed 280995f and pushed to 8.7.x. 🥳 Thanks! ✨
Comment #423
nod_wow, so happy to see this land. Thanks!
Comment #424
dmsmidt@phenaproxima thanks for taking my comment seriously and making a deliberative descision to move forward.
Great job everybody! I'm very interested in how this will be used in practice.
Comment #426
xjmSince this fix required a change to our stable base themes, we'll list it in the release notes since it is a small BC break for themes.
Comment #427
joegl CreditAttribution: joegl commentedhttps://www.drupal.org/project/drupal/issues/3053838
What's the proper thing to do now when there is an empty messages block in its own region? Why does it make sense to render an empty block in the first place? On upgrade a lot of our sites look screwy because the region is being rendered when there's nothing in it. From an HTML/CSS perspective this feels wrong.
Apologies if this is not the correct place to post. I came here from https://www.drupal.org/node/3002643
Comment #428
joegl CreditAttribution: joegl commentedTrying to follow-up on this:
Isn't this kind of anti-drupal? I don't understand why always rendering an empty div is seen as desirable, as we are currently having problems with entire regions being rendered with no content in them, because of the empty messages div (see linked issue). It seems inappropriate, but it could also be due to a bug I'm not aware of it (I plead ignorance here).
Comment #429
TerranRich CreditAttribution: TerranRich commentedHow do we utilize this functionality? Whenever I try to call
new Drupal.Message()
on an existing Drupal 8 site, it just throws an error aboutDrupal.Message
not being a valid constructor. Is there something that needs to be enabled/configured?Comment #430
Taiger CreditAttribution: Taiger commented@TerranRich you need to add the drupal.message library because it is not included by default.
For example:
There many ways to add a library: https://www.drupal.org/docs/8/modules/libraries-api-8x/using-libraries-a...