Posted by xjm on November 27, 2012 at 4:34am
29 followers
| Project: | Drupal core |
| Version: | 8.x-dev |
| Component: | views.module |
| Category: | task |
| Priority: | critical |
| Assigned: | quicksketch |
| Status: | needs work |
| Issue tags: | accessibility, JavaScript, modal dialog, VDC |
Issue Summary
Followup to #1667742: Add abstracted dialog to core (resolves accessibility bug). We need to convert the Views modal to the new abstracted dialog. This will help resolve #1806308: Views' Javascript is not keyboard-usable once the updated, accessible version of jQuery UI is released.
Comments
#1
#2
#3
Working on it.
#4
It seems to be that larowlan is already working on that: http://drupal.org/node/1667742#comment-6700926
#5
So i think the way to implement is to introduce two new ajax commands:
dialogOpen($content)/dialogSet($content) and dialogClose() so custom ajax commands can control what's happening with the dialog.
Views needs this to implement it's custom logic when the dialog should be closed, and when you should just get another form.
#6
That might make sense, and I don't object to it if Views needs it. I removed it from the scope of #1667742: Add abstracted dialog to core (resolves accessibility bug), because it was not needed for confirmation forms, and I'm suspicious of adding APIs without use cases.
However, I also suspect that Views might be doing too much logic server-side. The evolution of Drupal's Ajax system was primarily driven by PHP programmers who dabble in JavaScript. There's nothing wrong with that (Drupal gets written by the people who show up), but our front-end developer community has grown and is continuing to grow, and there might be benefit to rethinking some of the separation of concerns. Whether we want dedicated Ajax commands for controlling dialog open/close or whether we want JavaScript making that determination based on higher-level data returned by the server is an example of that. I don't currently know what the best approach is for Views, and ultimately, it should get decided by the people who write and review the patch.
#7
It feels like it would make at least the code easier to read, as just imagine you want to add a new Form to the stack, and you would have to get this information from PHP into JS.
If we go with the ajax commands we certainly should get views converted converted first to new ajax command objects, see #1843224: Convert Views Ajax commands to new Ajax API, but we could work on the generic ajax commands in the meantime (doing now).
#8
This is the current work which adds a new ajax commando to open/close modals
#9
Since there's a patch, marking needs review.
#10
Yeah general review would be cool, but it's certainly not in the state of being strict-reviewable.
#11
Commands should be in dialog.ajax.js, dialog.js should only have the basic code to make dialog work, see #1863478: Split Dialog API and optional integration helpers into separate files. Actually, happy to dup the other one and include the change here.
#12
Frega wanted to work on getting ajax commandos for the dialog though it seems to be that he didn't had time recently,
let's see.
I think we should keep the other issue to make at least some progress.
#13
opened an actual issue to implement a proper API: #1870764: Add an ajax command which makes it easy to use the dialog API in complex cases
#14
Any progress on this? We added this dialog so that Views could use it and this critical bug has been open awhile now.
#15
Progress is certainly happening on the other issue, so let's postpone this issue first.
It's funny but sadly the dialog API was changed during the issue to not support the slightly more complicated usecase of views :(
This is the reason why we need the other issue first.
#16
So #1909144: Allow #ajax['dialog'] to contain options other than 'modal' was committed awhile ago.. I don't suppose that's enough to unblock this?
#17
Sadly not really, see #1870764: Add an ajax command which makes it easy to use the dialog API in complex cases. We not even need other options, but also proper ajax commands.
#18
Tagging
#19
This patch does a direct conversion of the current system based on #1870764-102: Add an ajax command which makes it easy to use the dialog API in complex cases. It should be a 100% conversion. It has a few nice improvements:
- Dialogs now reuse the existing commands for open/close. Previous commands for SetViewsForm and DismissForm removed.
- Dialogs are now draggable, since we're using the native jQuery UI header instead of making our own.
- Dialogs *could* be resizable, but since we auto-resize already I'm not sure if that's necessary.
- Lots of cruft code eliminated. Between this patch and the generic modal system, I think we're looking at a net reduction of code just through this abstraction. Of course other places in core will use modals too, so this individual reduction isn't too important.
Every situation I've tested works completely, but there are still a lot of areas for improvement:
- We could move the auto-resizing logic to /core/misc/dialog.js. Seems too useful to be part of Views only.
- We could move the theming of the dialog to system.base.css and system.theme.css. I like the Views-style theming of modals more than the default jQuery UI modals and it'd be nice if they looked the same everywhere.
- We could gut Views' custom form handling and use the approach being researched in #1944472: Add generic content handler for returning dialogs: utilize the router system to eliminate use of nojs/ajax in the paths and set up separate handlers for different versions of the page. (This will be a large undertaking, it'd probably be better to separate this problem).
- There's probably still more cruft code sitting around that no longer does anything that we need to remove. I tried to get all of it, but the Views architecture is so spread out it's hard to be sure that I got it all.
#20
The last submitted patch, views_convert_modals-1851414-19.patch, failed testing.
#21
Resize shouldn't be in dialog.js, playing around with it it it seems that the whole views code can be replaced by
Drupal.viewsUi.resizeDialog = function ($dialog, noShrink) {
"use strict";
var $ = jQuery;
if (!$dialog.length || $dialog.css('display') === 'none') {
return;
}
var windowWidth = $(window).width();
var maxWidth = parseInt(windowWidth * 0.85, 10);
var minWidth = parseInt(windowWidth * 0.6, 10);
$dialog.dialog('option', {
maxWidth: maxWidth,
minWidth: minWidth,
position: { my: "center", at: "center", of: window }
});
};
and it seems to be working just the same.
#22
Why not? It seems like a deficiency of jQuery UI that it doesn't have a built-in ability to keep the dialog centered while resizing the window. While I know you want to keep the dialog.js file "pure" as an HTML5 shim, I'm positive that any browser-native version of a dialog would have the ability to adjust when the window was resized (though exactly *how* it would adjust we can't tell, since there aren't any implementations yet).
That's not too surprising. I couldn't figure out why in the world that code was so complicated. It may be left over from the conversion to jQuery UI, where the old dialog system didn't have built-in calculations for "center". We should add a setTimeout() counter to prevent repeated calculations on scroll/resize too. While resizing you can easily end up with hundreds of calls in just a few seconds.
#23
We have a debounce function to limit the maddness with resize events.
As for the resizing and centering, the browsers will only use CSS to do that. if you have a
#dialogsomething {position:absolute;top:20%;left:20%;bottom:20%;right:20%;}that should work fine in browsers.Since jquery can't use CSS to do the sizing and all we're stuck with using their API to do it. and that's starting to be tying things down to jQuery UI more than i'm comfortable with.
One could argue that if we make the dialog resizable and draggable It doesn't make sense to keep the centering and resizing on window resize too.
#24
The re-sizing code seems good for re-use if the percentage of height and width, in addition to orientation were parameters rather than hard-coded since that seems to hard-coded to the Views UI specific use case.
#25
Yeah I agree. We could simply re-set the all the size and position settings on resize, just like #21 only with the user-provided values. Of course you'd want to be able to toggle this setting as it might not be appropriate for all situations. I think it would make sense to enable it by default, and have a disable toggle though by overloading the existing $options array (which currently is for jQuery UI options only).
Cool, I hadn't seen Drupal.debounce() before. It looks like toolbar library depends on drupal.debounce already, so there's a very high chance it'll be loaded on the page for administrators. Unfortunately since we'll be using dialogs in non-admin situations (i.e. WYSIWYG dialogs), this means an additional HTTP request when the dialog is first opened. Kind of unfortunate, but may be mitigated by other libraries adding debounce.js as a requirement at page-load time.
#26
.
#27
In practice, this doesn't work so well. The first problem is that jQuery UI Dialog doesn't support height in percentages, so you can't have a dialog that is "75%" height. Additionally, even if we convert these to pixels on resize, we end up cutting off the buttons at the bottom of the dialog when the window gets too small. The previous implementation always kept the buttons visible. #21's simplification has the same problems. jQuery UI has a dedicated "buttons" wrapper to prevent this kind of problem, but moving our buttons into that wrapper and still having our AJAX behaviors work is going to be tricky business.
#28
not that bad actually I've done it for ctools modal #1397370-6: Make modal.js use jQuery dialog (look for
// Transform submit in dialog buttons.in the patch) it's ugly but it works. Ideally we'd rewrite the JS ajax API so that it's more flexible and not tied to a DOM element so it's less workaround-ish.Yes for the height issue it's more complicated than #21, but it won't be more code than currently.
#29
Yeah I was thinking along the same lines as the only possible solution: hide the button in the original place and have the second button click the first one... Seems like a pretty good trick. I like that your version actually just reuses the existing labels too, that solves any translation problems. The theming for jQuery UI dialogs needs some work, the default CSS for their dialogs have slightly larger/rounder buttons than we use elsewhere in the Seven theme. However since this needs to affect the front-end too... we may want a dedicated stylesheet for dialog theming.
#30
I have another revision to this issue that is looking pretty good. Unfortunately all this moving files around requires some additional planning when making patches, which I didn't anticipate, so rolling a nice clean patch is will take me a bit. Here's an interdiff that includes most of the changes that will go on top of #19.
Changes:
- New /core/misc/dialog.theme.css file for general presentation CSS for dialogs.
- Removed almost all CSS from Seven and Views regarding dialogs. There's still a bit more to trim out.
- Images for dialogs (close.png, progress-small.gif) have been moved to /misc.
- Moved jquery.ui.dialog.patch.js into dialog.js, with a JS setting toggle to turn it off in the event that D8 ships with jQuery UI 1.9 and jQuery Update wants to undo the "patch". It doesn't seem like it would do any harm running on jQuery UI 1.10, but for cleanliness there's a way to turn it off. Because it fixes a general problem with dialogs, dialog.js is an appropriate place for it.
- Moved the resizing code into dialog.js. It works great but is kind of clunky (100x better than the previous version though). Again, because this is a general improvement to dialogs, it makes sense in dialog.js.
- Buttons are now placed in the jQuery UI dialog button area, which fixes issues with the buttons being hidden. I used a trick similar to _nod's suggestion in #28, but the new way we're handling AJAX makes this problem a bit easier than it had been in D7/Ctools. This code lives in jquery.ajax.js, since it's Drupal-implementation specific and for the most part only needed on AJAX-loaded forms.
A bug I noticed: The interface for filtering AND/OR groups is broken. There's some additional JS that needs to be updated in there.
I'll try to post a real reroll that can be applied directly and moves the files around properly tomorrow. I'm coming up on a busy week so I may not get back to this immediately. I think the new home for images/CSS/JS makes sense and is inline with our current patterns (though obviously adding 4 more files to /misc isn't ideal). Feedback about the locations of files and CSS and general review that can be done at this point would be appreciated.
#31
Oh, and regarding the jankiness of button presentation (previously we had a nice blue "primary button" in the dialog, now they're both gray), that problem already has its own issue in #1848292: Consolidate Seven button styles.
#32
For the resize i'd use the
dialog:*events instead of putting that in directly, that's why we have those events.I wouldn't be selecting
<button>elements to add them to the dialog buttons since #1719640: Use 'button' element instead of empty links.i got issues applying the patch over #19 So I guess I'll wait for your reroll to try it out. I like where it's going though.
#33
There is an issue for the OR dialog #1929070: Refactor views_ui_rearrange_filter_form to remove theme function for table rendering
#34
Is that true even when you apply it in CSS? As in:
.views-ui-dialog {height: 75%;
}
The dialog is after all a DOM element, so I don't get what jQuery UI does to remove CSS features from it.
#35
Hmm, well I suppose that may be true. If you set a height of "auto", jQuery UI dialogs won't set a specific height property at all, so you could control it with CSS. For some reason jQuery UI Dialogs discard percentage height values but pass through percentage width values
However one problem with CSS-only approach is that the dialog will *always* be that particular height. So a simple dialog that only needs 100px of height ends up displaying 75% of the height, resulting in a huge empty part of the dialog. So even if it's possible using CSS, we'll probably want to use a JS-based solution anyway. The current patch functionality really works pretty well, sorry I haven't rolled it properly so that it can be easily tested. I hope to get to it tonight.
#36
I'm incorrect. Of course you could use
height: auto; max-height: 75%;. That accommodates for everything. I'll try rerolling this without the current height component and do it all with CSS.#37
Here's a patch that is pretty much a straight reroll from #30, just combining the two patches (and the file renames) into a single patch that should be testable.
I experimented around with the resizing options quite a bit but I don't think a CSS-only solution is going to work in this situation (I hope I'm wrong). I struggled for quite a while trying to figure out how to do this, but this Views example is really much more complicated that it seems. The trouble is that we have areas inside the dialog that are not definable either in static pixel heights nor percentages. The top and bottom of the dialog show expand as needed to show all the text without scrolling, but the area in the middle needs to scroll the remaining space.
As far as a generic resizing solution goes, I think this is generally solvable through CSS-only after we update to jQuery UI 1.10. Our current version seems to have a bug in it that prevents the use of
position: fixed;on the dialog.I removed jquery.ui.dialog.patch.js, since it will be irrelevant after #1175830: Update to jQuery UI 1.10 so that Drupal dialogs can be tested for accessibility is committed.
Here's an image depicting the problem with the Views dialog. I'm thinking we might be able to solve it through a custom position callback... but I'm really not sure at this point what the best way to handle it is.

#38
This version moves the resizing code back to views-admin.js (but still trims it down to utilize jQuery UI and the new dialog API). Now that I'm certain we can do an always-centered modal dialog with CSS only (after updating to jQuery 1.10), the Views-dialog becomes a special-case rather than a universal problem. I didn't really like that resizing code anyway.
I removed a dozen "use strict" and jQuery assignments in this version, instead just wrapping the whole file in a jQuery/strict wrapper, as is typical of most JS files in Drupal, hence the bigger patch, but it's all more removals so that's probably a good thing.
#39
Haven't tested yet, but it looks great :)
Nice to have the resizing out of the general dialog and ajax code.
#40
The last submitted patch, views_convert_modals-1851414-38.patch, failed testing.
#41
Awesome!
Related: #1832862: Users feel overwhelmed by handler listings
#42
Thanks for working on this issue. Tested it manually and spotted some issues:
#43
Thanks @dawehner. I can also tack on several other problems:
- The "Selected" item is supposed to populate with the checkboxes you've selected, but it does not.
- The buttons are supposed to update their labels based on affecting the master vs. overridden displays.
I fiddled around with the jerkiness issue a little bit but haven't solved it yet. Part of the reason for the jerkiness is that this version uses the debounce.js file to add a 25ms delay. The previous version was firing on every scroll/resize event, which could be as frequent as 1-5ms. So by effect things will be slightly more jerky but not nearly so CPU consuming.
#44
#38: views_convert_modals-1851414-38.patch queued for re-testing.
#45
The last submitted patch, views_convert_modals-1851414-38.patch, failed testing.
#46
@nod_ and others interested in dialogs: I've incorporated a large chunk of this patch's code into #1879120: Use core dialogs rather than CKEditor dialogs, including the CSS cleanup, the porting of Views-style loading throbbers to the dialog CSS file, and the auto-centering code. If that patch lands first, this issue can be rerolled with a patch that is quite a bit smaller.