Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modal Dialog #2668

Closed
wants to merge 36 commits into from
Closed

Modal Dialog #2668

wants to merge 36 commits into from

Conversation

misteroneill
Copy link
Member

This PR introduces two new components to video.js: CloseButton and ModalDialog with tests.

The general idea is to strike a balance between assumptions of how a modal should work - e.g., you want a "close" button or you only want to define the contents once - and flexibility.

At Brightcove, there are five plugins (both open and closed source) which individually define some kind of a modal. Every one in slightly and subtly different; so, part of the goal is that this can work for all those while anticipating potential needs of other plugin authors.

Much of the flexibility comes from adding hooks to important lifecycle events: fill, empty, open, close. This allows things like event binding to happen when users want - for example, it might make sense to bind events on "modalfill" so we are sure the DOM is in place.

@misteroneill
Copy link
Member Author

This is a WIP, but I'm opening a PR to start gathering feedback and spark discussion as to whether or not this belongs in video.js proper.

@pam
Copy link

pam commented Oct 2, 2015

Tests failed. Automated cross-browser testing via Sauce Labs and Travis CI shows that the JavaScript changes in this pull request are: BUSTED

Commit: 369f3d86c6a886ed2b54e2cbfd0d41ede8d8ea74
Build details: https://travis-ci.org/pam/video.js/builds/83376989

(Please note that this is a fully automated comment.)

@pam
Copy link

pam commented Oct 2, 2015

Tests failed. Automated cross-browser testing via Sauce Labs and Travis CI shows that the JavaScript changes in this pull request are: BUSTED

Commit: a7d18b45223b141b929b6096ae22a82a7d5d3d7c
Build details: https://travis-ci.org/pam/video.js/builds/83376481

(Please note that this is a fully automated comment.)

@pam
Copy link

pam commented Oct 2, 2015

Tests failed. Automated cross-browser testing via Sauce Labs and Travis CI shows that the JavaScript changes in this pull request are: BUSTED

Commit: d2988f2bfd8550e2bfda3f27aa27d407e770d556
Build details: https://travis-ci.org/pam/video.js/builds/83392382

(Please note that this is a fully automated comment.)

@pam
Copy link

pam commented Oct 2, 2015

Tests failed. Automated cross-browser testing via Sauce Labs and Travis CI shows that the JavaScript changes in this pull request are: BUSTED

Commit: 3a08ded21093aed904f3b3e7bb258ef65805563f
Build details: https://travis-ci.org/pam/video.js/builds/83391230

(Please note that this is a fully automated comment.)


$gradient-start: rgba(0, 0, 0, 0.8);
$gradient-stop: rgba(255, 255, 255, 0);
background: $gradient-start;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should move into a mixin.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. 👍

@heff
Copy link
Member

heff commented Oct 3, 2015

This touches on our strategy for UI components in plugins moving forward, which doesn't necessarily need to be solved here but will impact it.

I think we need to strongly define how plugins should be accessing UI components to use/extend them. It's totally inefficient for plugins to be pulling in entire copies of video.js as a dependency to get at a component. One step forward might be to break out UI components into their own repos/projects, which is something we've talked about either way, but even then it seems really inefficient to have a plugin compile Component along with itself, when another copy of Component will already be in the page with Video.js.

It sounds like peer dependencies are taking a big step forward in npm@3. Are they a viable option yet?

As far as this issue is concerned, if we go the route of having copies of components compiled with plugins, then I don't think it makes sense to pull this into core. If only because we might be moving all other components out.

If we go the route of saying plugins should use the copies included in video.js then a modal does seem like a root-level UI component, and we could probably justify it just because we could use it for the internal error display. If it weren't for that we'd be deciding if Video.js should include UI components just for what it uses internally, or if it should include additional general purpose UI components for the sake of plugins. I think I would lean towards the former in that case.

@gkatsev
Copy link
Member

gkatsev commented Oct 4, 2015

It's totally inefficient for plugins to be pulling in entire copies of video.js as a dependency to get at a component.

This is only really an issue if npm plus a packing system like browserify is not used. npm will auto-dedupe packages and if the end-user uses videojs and plugins from npm, you only include one version of video.js.

One step forward might be to break out UI components into their own repos/projects

One solution is to release each component into a separate repo. Then plugins can require just what they need. Basically, we can have a concept of component-plugins and have all the built-in videojs components be those themselves. This probably would need a pretty major rework to the API and how things work. But might be a good thing in the end. Maybe this plus redefined plugin API can be The Next Big Thing™ for videojs.

it seems really inefficient to have a plugin compile Component along with itself, when another copy of Component will already be in the page with Video.js.

Ultimately, we can't really support everything. For this, we might need to find the happy path (I recommend browserify+npm) and support that path fully. That doesn't mean we shouldn't support other ways too, but it could mean that payloads end up slightly larger because there isn't a good way of doing dedupes and stuff like that if we're supporting globals for everything. However, I guess plugins can be smarter and have different builds. One browserify build that requires everything and assumed the end-user also uses browserify (or webpack). One global build that assumes none of the dependencies are available and/or one global build that assumes all the dependencies will be available in the global scope.

It sounds like peer dependencies are taking a big step forward in npm@3. Are they a viable option yet?

Yes, seems like in npm 3, peer dependencies are finally not a hassle. However, with npm 3 also deduping everything by default, peer deps aren't as useful because plugins can just depend on videojs and the end-user who uses browserify themselves, can also just require them and then npm will dedupe videojs so you only end up with one videojs in your tree.

Also, npm is working on better front-end package managing. Maybe we should talk to them about what they're working on and what our needs are.

we could probably justify it just because we could use it for the internal error display

I think we should update the internal error display to use this modal dialog.

@misteroneill
Copy link
Member Author

It seems like the big concern here is that builds for plugins will have video.js bundled with them. I agree that should be avoided! I think @gkatsev is right that npm/browserify solves this problem. Although, I do wonder how it would work with multiple versions of video.js in its dependency tree (e.g. if plugin-a depends on video.js@5.1.x and plugin-b depends on video.js@5.0.x)?

I agree with both of you that the internal error display could be updated to use this; it justifies the inclusion in video.js proper in my mind. One of my main concerns was having UI components in video.js that were only there for plugin authors. The flip side of that introduced another concern: having a plugin whose only purpose was to provide blank-slate UI components. Sort of a meta-plugin. Perhaps that's not a bad thing. Any opinions on that?

@pam
Copy link

pam commented Oct 5, 2015

Tests failed. Automated cross-browser testing via Sauce Labs and Travis CI shows that the JavaScript changes in this pull request are: BUSTED

Commit: a9c21fdeb3cabf07843a7d3752989590806210a6
Build details: https://travis-ci.org/pam/video.js/builds/83708323

(Please note that this is a fully automated comment.)

@heff
Copy link
Member

heff commented Oct 5, 2015

npm de-duping is great but it's not a complete answer unfortunately

  • most people apparently still don't use any module bundler, and only 17% said browserify
  • most plugins in the wiki today don't have commonJS or requireJS support, including videojs-youtube and google's IMA3

If we were a full app framework we might be able to force stricter development pipelines on plugin authors and users, but video.js is a widget that's going to be dropped into a lot of existing pipelines, and using the independently compiled versions of plugins is gonna be the norm for a while.

If peer dependencies are better now it looks to me like they could support the best of both worlds. Are there still reasons why we wouldn't want to go that route?

@pam
Copy link

pam commented Oct 5, 2015

Tests failed. Automated cross-browser testing via Sauce Labs and Travis CI shows that the JavaScript changes in this pull request are: BUSTED

Commit: 5058f8bae9496b83ad1a8961c2a5df59a002d42a
Build details: https://travis-ci.org/pam/video.js/builds/83708501

(Please note that this is a fully automated comment.)

@misteroneill
Copy link
Member Author

I don't think anyone was suggesting forcing people into an npm/browserify workflow. Maybe I'm not clear on the problem. Plugins already depend on video.js (implicitly as a global); so, I'm not sure how this work would change that or how calling videojs.getComponent('ModalDialog') introduces issues that videojs.plugin('foo', foo) doesn't?

@pam
Copy link

pam commented Oct 5, 2015

Tests failed. Automated cross-browser testing via Sauce Labs and Travis CI shows that the JavaScript changes in this pull request are: BUSTED

Commit: c1cfd051d158b05cdfd81966a5febf565a596657
Build details: https://travis-ci.org/pam/video.js/builds/83746275

(Please note that this is a fully automated comment.)

@pam
Copy link

pam commented Oct 5, 2015

Tests failed. Automated cross-browser testing via Sauce Labs and Travis CI shows that the JavaScript changes in this pull request are: BUSTED

Commit: 0fb1999bbff661a1b479ea922db8c545ba76dfbc
Build details: https://travis-ci.org/pam/video.js/builds/83765023

(Please note that this is a fully automated comment.)

@pam
Copy link

pam commented Oct 5, 2015

Tests failed. Automated cross-browser testing via Sauce Labs and Travis CI shows that the JavaScript changes in this pull request are: BUSTED

Commit: 83a68f5b98941888d153c614e14c0f68e0702b09
Build details: https://travis-ci.org/pam/video.js/builds/83767966

(Please note that this is a fully automated comment.)

@heff
Copy link
Member

heff commented Oct 5, 2015

Check out videojs-dock as an example. It doesn't rely on Video.js as a global, and if you were to compile that for users looking to include it as a standalone js file next to video.js (not using browserify), it would include another copy of Video.js.

I may have jumped ahead, but that's what I assumed we meant by the npm workflow that doesn't rely on peer dependencies.

@gkatsev
Copy link
Member

gkatsev commented Oct 5, 2015

It actually does currently rely on videojs as a global. I use browserify-shim to shim it in so the code looks like it can be required. Also, not sure why I didn't use es6 module syntax there.

@heff
Copy link
Member

heff commented Oct 5, 2015

Oh wow, that's cool. I stand corrected.

* disposed as soon as it's closed, which is useful for one-off
* modals.
*
* @param {Boolean} [options.fillAlways=false]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Part of me wonders if this should be the default case and the "fill once" case should be the special case. The reason I went this way is that "fill once" is more conservative (fewer DOM changes, etc).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first glance Modal feels really complicated for what I think of as a box that displays text. I feel like it'd be nice if we could simplify it but I also don't understand all the use cases going into it. Do you think you could document the different use cases you're trying to solve for with the different options here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I can elaborate on it more in the PR description.

Both fillImmediately and openImmediately can probably go away. They were added pretty early on, but it's just as easy to do var m = new ModalDialog(); m.open();.

The slug option may also be a candidate for removal; though, it makes modifying the HTML class on a per-instance basis hard. Sub-classes can use buildCSSClass.

Another candidate for removal is the fillWith() function. Of course, it does allow developers to bypass the content() step entirely, which may be convenient, and it's only a few extra lines of code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another candidate for change would be to rename the open/close methods to show/hide (overriding/expanding on those methods of Component).

@pam
Copy link

pam commented Oct 5, 2015

Tests failed. Automated cross-browser testing via Sauce Labs and Travis CI shows that the JavaScript changes in this pull request are: BUSTED

Commit: ffc410b9c8c0c7174f80d361e817aa260442da37
Build details: https://travis-ci.org/pam/video.js/builds/83782570

(Please note that this is a fully automated comment.)

@gkatsev
Copy link
Member

gkatsev commented Oct 5, 2015

Also, what I was kind of suggesting is that we target global and browserify packaging. This should hopefully be relatively simple to do by using browserify to write the plugins. Then with various plugins like browserify-shim, we can produce two builds of the plugin. One of the builds is the "happy path" I was describing above which uses browserify and depends on video.js and that is what you get when you require the plugin. Otherwise, you get a build that assumes that videojs/deps are available in the global namespace and can be shimed using browserify-shim. Don't have any concrete examples of this, but I believe it should be possible to do relatively easily. I can give it a shot with the videojs-dock plugin when I get back from my conference.

@pam
Copy link

pam commented Oct 6, 2015

Tests failed. Automated cross-browser testing via Sauce Labs and Travis CI shows that the JavaScript changes in this pull request are: BUSTED

Commit: d4792b8c6f523b3ee13e5beb5a81ee5a7659cf07
Build details: https://travis-ci.org/pam/video.js/builds/83951157

(Please note that this is a fully automated comment.)

@pam
Copy link

pam commented Oct 6, 2015

Tests failed. Automated cross-browser testing via Sauce Labs and Travis CI shows that the JavaScript changes in this pull request are: BUSTED

Commit: 1f366f63ffc354bcbf5efd0078c48a56b6b2411d
Build details: https://travis-ci.org/pam/video.js/builds/83950845

(Please note that this is a fully automated comment.)

@pam
Copy link

pam commented Oct 6, 2015

Tests failed. Automated cross-browser testing via Sauce Labs and Travis CI shows that the JavaScript changes in this pull request are: BUSTED

Commit: 50c5241d927ee59066ac43e38cdf87524aee96f7
Build details: https://travis-ci.org/pam/video.js/builds/83975010

(Please note that this is a fully automated comment.)

@chemoish
Copy link
Member

chemoish commented Oct 7, 2015

+1 @gkatsev, interested in seeing that.

I currently have to shim video.js with webpack as well. However, video.js itself could also benefit from module loader packaging.

@pam
Copy link

pam commented Oct 7, 2015

Tests failed. Automated cross-browser testing via Sauce Labs and Travis CI shows that the JavaScript changes in this pull request are: BUSTED

Commit: d44816fc6edddc131165fa3535346926bcaa582e
Build details: https://travis-ci.org/pam/video.js/builds/84140951

(Please note that this is a fully automated comment.)

@pam
Copy link

pam commented Oct 7, 2015

Tests failed. Automated cross-browser testing via Sauce Labs and Travis CI shows that the JavaScript changes in this pull request are: BUSTED

Commit: 6fcfd90dfb3cc7aaeb3b64d7e34796309c0abbbf
Build details: https://travis-ci.org/pam/video.js/builds/84142059

(Please note that this is a fully automated comment.)

This makes testing for the presence of multiple classes on a component a
little cleaner/simpler.
This improves modal accessibility by allowing a description element and
some additional updates to ARIA attributes.

Also, this removes the previously-added `assertElHasClasses` in favor of
a more comprehensive `assertEl` method on the test helpers object.
Also adds a number of methods to the DOM utility and lots of tests for
those. Simplifies the modal dialog component correspondingly.
@misteroneill misteroneill changed the title Modal Dialog - WIP Modal Dialog Oct 27, 2015
@misteroneill
Copy link
Member Author

@gkatsev Alright, this is ready for further review - particularly the last 4 commits. Note particularly the changes to utils/dom, which is where I landed with the content normalization. This should come in useful for all sorts of XSS-conscious content injection.

@gkatsev
Copy link
Member

gkatsev commented Oct 27, 2015

@pam retry


font-size: 1.2em; // 12px
line-height: 1.5; // 18px
padding: 30px;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably be in em as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the same thing originally (was 2.5em), but increasing the padding as the font-size increases looks bad.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. Also, rem is even less supported than em.

if (typeof value === 'string' && /\S/.test(value)) {
return document.createTextNode(value);
}
}).filter(value => value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the filter here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The map will only return nodes or undefined, so this removes the undefineds since they can't be inserted into the DOM.

@gkatsev
Copy link
Member

gkatsev commented Oct 28, 2015

Makes sense to fix the focus stuff later. I guess what we would want is to capture it only if the focus is already inside the player area but not otherwise? Something to think about.


player.controls(true);
this.hide();
this.el().setAttribute('aria-hidden', 'true');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering about what value this attribute should get since boolean attributes in HTML are checked via presence rather than value so it's customary to set their value to their name but seems like ARIA specifically looks for the value true.
Just wanted to call that out for others that care :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point @gkatsev!

ARIA doesn't follow HTML syntax, in fact it's a language with its own syntax which can be used within HTML (but also within other languages). The fact that HTML booleans are either false through their absence or true through presence which can be denoted as, e.g. selected="selected" is an SGML vs XML thing, whereas ARIA values may be booleans or true, false or undefined (as well as true/false/mixed!), so the syntax was defined differently.

Setting aria-* attributes otherwise is a syntax violation, but it's a tricky one to catch since HTML validators generally look at static pages rather than what the JavaScript is doing.

@gkatsev
Copy link
Member

gkatsev commented Oct 28, 2015

I wonder why pam hasn't run on this after the rebase...

@misteroneill
Copy link
Member Author

I think she gave up. 😈

}

.vjs-error .vjs-error-display:before {
content: 'X';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was this removed on purpose?
I would prefer to not change the look of the error display too much. Or at least, we still need something to make it noticeable as an error display and not just an uncloseable modal dialog.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. It looked totally broken with that style - it duplicates a lot of the style of the modal dialog.

I don't know what the "X" was about (I was guessing a "close" icon/button).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think just to signify an error.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, then I'll bring that back.

@gkatsev
Copy link
Member

gkatsev commented Oct 28, 2015

LGTM

@gkatsev gkatsev closed this in 51f1863 Oct 28, 2015
@misteroneill misteroneill deleted the modal-dialog branch October 28, 2015 17:36
@sethborg
Copy link
Contributor

I know this isn't the place for this but there's no where else to turn. Would someone mind posting some example code of how to use this new function? I can't find a single example on the internet.

@misteroneill
Copy link
Member Author

@sethborg No worries. There are ModalDialog API docs, but I agree that a more prose-based document would be helpful. I'll add an issue to create one. The absolute easiest way to create a modal is the createModal method of a Player:

// Get a reference to your player.
var player = videojs.getPlayers().yourPlayerId;

player.createModal('Hello, world!');

Note that if you want to populate it with HTML - and you probably do - you can pass a DOM element reference or a function that creates one:

player.createModal(function () {
  var content = document.createElement('h1');
  content.textContent = 'Hello, world!';
  return content;
});

Beyond this, the ModalDialog component exists as something that can be used to create more complex modals.

@sethborg
Copy link
Contributor

Oh this creates a modal dialog on the video player area. I was under the impression this allowed me to create a lightbox over the whole webpage with the video player in it. The API should clear that up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants