3 exports.__esModule = true;
5 var _dom = require('./utils/dom');
7 var Dom = _interopRequireWildcard(_dom);
9 var _fn = require('./utils/fn');
11 var Fn = _interopRequireWildcard(_fn);
13 var _component = require('./component');
15 var _component2 = _interopRequireDefault(_component);
17 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
19 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
21 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
23 function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
25 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
26 * @file modal-dialog.js
30 var MODAL_CLASS_NAME = 'vjs-modal-dialog';
34 * The `ModalDialog` displays over the video and its controls, which blocks
35 * interaction with the player until it is closed.
37 * Modal dialogs include a "Close" button and will close when that button
38 * is activated - or when ESC is pressed anywhere.
43 var ModalDialog = function (_Component) {
44 _inherits(ModalDialog, _Component);
47 * Create an instance of this class.
49 * @param {Player} player
50 * The `Player` that this class should be attached to.
52 * @param {Object} [options]
53 * The key/value store of player options.
55 * @param {Mixed} [options.content=undefined]
56 * Provide customized content for this modal.
58 * @param {string} [options.description]
59 * A text description for the modal, primarily for accessibility.
61 * @param {boolean} [options.fillAlways=false]
62 * Normally, modals are automatically filled only the first time
63 * they open. This tells the modal to refresh its content
64 * every time it opens.
66 * @param {string} [options.label]
67 * A text label for the modal, primarily for accessibility.
69 * @param {boolean} [options.temporary=true]
70 * If `true`, the modal can only be opened once; it will be
71 * disposed as soon as it's closed.
73 * @param {boolean} [options.uncloseable=false]
74 * If `true`, the user will not be able to close the modal
75 * through the UI in the normal ways. Programmatic closing is
78 function ModalDialog(player, options) {
79 _classCallCheck(this, ModalDialog);
81 var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
83 _this.opened_ = _this.hasBeenOpened_ = _this.hasBeenFilled_ = false;
85 _this.closeable(!_this.options_.uncloseable);
86 _this.content(_this.options_.content);
88 // Make sure the contentEl is defined AFTER any children are initialized
89 // because we only want the contents of the modal in the contentEl
90 // (not the UI elements like the close button).
91 _this.contentEl_ = Dom.createEl('div', {
92 className: MODAL_CLASS_NAME + '-content'
97 _this.descEl_ = Dom.createEl('p', {
98 className: MODAL_CLASS_NAME + '-description vjs-offscreen',
99 id: _this.el().getAttribute('aria-describedby')
102 Dom.textContent(_this.descEl_, _this.description());
103 _this.el_.appendChild(_this.descEl_);
104 _this.el_.appendChild(_this.contentEl_);
109 * Create the `ModalDialog`'s DOM element
112 * The DOM element that gets created.
116 ModalDialog.prototype.createEl = function createEl() {
117 return _Component.prototype.createEl.call(this, 'div', {
118 className: this.buildCSSClass(),
121 'aria-describedby': this.id() + '_description',
122 'aria-hidden': 'true',
123 'aria-label': this.label(),
129 * Builds the default DOM `className`.
132 * The DOM `className` for this object.
136 ModalDialog.prototype.buildCSSClass = function buildCSSClass() {
137 return MODAL_CLASS_NAME + ' vjs-hidden ' + _Component.prototype.buildCSSClass.call(this);
141 * Handles `keydown` events on the document, looking for ESC, which closes
144 * @param {EventTarget~Event} e
145 * The keypress that triggered this event.
151 ModalDialog.prototype.handleKeyPress = function handleKeyPress(e) {
152 if (e.which === ESC && this.closeable()) {
158 * Returns the label string for this modal. Primarily used for accessibility.
161 * the localized or raw label of this modal.
165 ModalDialog.prototype.label = function label() {
166 return this.options_.label || this.localize('Modal Window');
170 * Returns the description string for this modal. Primarily used for
174 * The localized or raw description of this modal.
178 ModalDialog.prototype.description = function description() {
179 var desc = this.options_.description || this.localize('This is a modal window.');
181 // Append a universal closeability message if the modal is closeable.
182 if (this.closeable()) {
183 desc += ' ' + this.localize('This modal can be closed by pressing the Escape key or activating the close button.');
192 * @fires ModalDialog#beforemodalopen
193 * @fires ModalDialog#modalopen
195 * @return {ModalDialog}
196 * Returns itself; method can be chained.
200 ModalDialog.prototype.open = function open() {
202 var player = this.player();
205 * Fired just before a `ModalDialog` is opened.
207 * @event ModalDialog#beforemodalopen
208 * @type {EventTarget~Event}
210 this.trigger('beforemodalopen');
213 // Fill content if the modal has never opened before and
214 // never been filled.
215 if (this.options_.fillAlways || !this.hasBeenOpened_ && !this.hasBeenFilled_) {
219 // If the player was playing, pause it and take note of its previously
221 this.wasPlaying_ = !player.paused();
223 if (this.options_.pauseOnOpen && this.wasPlaying_) {
227 if (this.closeable()) {
228 this.on(this.el_.ownerDocument, 'keydown', Fn.bind(this, this.handleKeyPress));
231 player.controls(false);
233 this.el().setAttribute('aria-hidden', 'false');
236 * Fired just after a `ModalDialog` is opened.
238 * @event ModalDialog#modalopen
239 * @type {EventTarget~Event}
241 this.trigger('modalopen');
242 this.hasBeenOpened_ = true;
248 * If the `ModalDialog` is currently open or closed.
250 * @param {boolean} [value]
251 * If given, it will open (`true`) or close (`false`) the modal.
254 * the current open state of the modaldialog
258 ModalDialog.prototype.opened = function opened(value) {
259 if (typeof value === 'boolean') {
260 this[value ? 'open' : 'close']();
266 * Closes the modal, does nothing if the `ModalDialog` is
269 * @fires ModalDialog#beforemodalclose
270 * @fires ModalDialog#modalclose
272 * @return {ModalDialog}
273 * Returns itself; method can be chained.
277 ModalDialog.prototype.close = function close() {
279 var player = this.player();
282 * Fired just before a `ModalDialog` is closed.
284 * @event ModalDialog#beforemodalclose
285 * @type {EventTarget~Event}
287 this.trigger('beforemodalclose');
288 this.opened_ = false;
290 if (this.wasPlaying_ && this.options_.pauseOnOpen) {
294 if (this.closeable()) {
295 this.off(this.el_.ownerDocument, 'keydown', Fn.bind(this, this.handleKeyPress));
298 player.controls(true);
300 this.el().setAttribute('aria-hidden', 'true');
303 * Fired just after a `ModalDialog` is closed.
305 * @event ModalDialog#modalclose
306 * @type {EventTarget~Event}
308 this.trigger('modalclose');
310 if (this.options_.temporary) {
318 * Check to see if the `ModalDialog` is closeable via the UI.
320 * @param {boolean} [value]
321 * If given as a boolean, it will set the `closeable` option.
324 * Returns the final value of the closable option.
328 ModalDialog.prototype.closeable = function closeable(value) {
329 if (typeof value === 'boolean') {
330 var closeable = this.closeable_ = !!value;
331 var close = this.getChild('closeButton');
333 // If this is being made closeable and has no close button, add one.
334 if (closeable && !close) {
336 // The close button should be a child of the modal - not its
337 // content element, so temporarily change the content element.
338 var temp = this.contentEl_;
340 this.contentEl_ = this.el_;
341 close = this.addChild('closeButton', { controlText: 'Close Modal Dialog' });
342 this.contentEl_ = temp;
343 this.on(close, 'close', this.close);
346 // If this is being made uncloseable and has a close button, remove it.
347 if (!closeable && close) {
348 this.off(close, 'close', this.close);
349 this.removeChild(close);
353 return this.closeable_;
357 * Fill the modal's content element with the modal's "content" option.
358 * The content element will be emptied before this change takes place.
360 * @return {ModalDialog}
361 * Returns itself; method can be chained.
365 ModalDialog.prototype.fill = function fill() {
366 return this.fillWith(this.content());
370 * Fill the modal's content element with arbitrary content.
371 * The content element will be emptied before this change takes place.
373 * @fires ModalDialog#beforemodalfill
374 * @fires ModalDialog#modalfill
376 * @param {Mixed} [content]
377 * The same rules apply to this as apply to the `content` option.
379 * @return {ModalDialog}
380 * Returns itself; method can be chained.
384 ModalDialog.prototype.fillWith = function fillWith(content) {
385 var contentEl = this.contentEl();
386 var parentEl = contentEl.parentNode;
387 var nextSiblingEl = contentEl.nextSibling;
390 * Fired just before a `ModalDialog` is filled with content.
392 * @event ModalDialog#beforemodalfill
393 * @type {EventTarget~Event}
395 this.trigger('beforemodalfill');
396 this.hasBeenFilled_ = true;
398 // Detach the content element from the DOM before performing
399 // manipulation to avoid modifying the live DOM multiple times.
400 parentEl.removeChild(contentEl);
402 Dom.insertContent(contentEl, content);
404 * Fired just after a `ModalDialog` is filled with content.
406 * @event ModalDialog#modalfill
407 * @type {EventTarget~Event}
409 this.trigger('modalfill');
411 // Re-inject the re-filled content element.
413 parentEl.insertBefore(contentEl, nextSiblingEl);
415 parentEl.appendChild(contentEl);
422 * Empties the content element. This happens anytime the modal is filled.
424 * @fires ModalDialog#beforemodalempty
425 * @fires ModalDialog#modalempty
427 * @return {ModalDialog}
428 * Returns itself; method can be chained.
432 ModalDialog.prototype.empty = function empty() {
434 * Fired just before a `ModalDialog` is emptied.
436 * @event ModalDialog#beforemodalempty
437 * @type {EventTarget~Event}
439 this.trigger('beforemodalempty');
440 Dom.emptyEl(this.contentEl());
443 * Fired just after a `ModalDialog` is emptied.
445 * @event ModalDialog#modalempty
446 * @type {EventTarget~Event}
448 this.trigger('modalempty');
453 * Gets or sets the modal content, which gets normalized before being
454 * rendered into the DOM.
456 * This does not update the DOM or fill the modal, but it is called during
459 * @param {Mixed} [value]
460 * If defined, sets the internal content value to be used on the
461 * next call(s) to `fill`. This value is normalized before being
462 * inserted. To "clear" the internal content value, pass `null`.
465 * The current content of the modal dialog
469 ModalDialog.prototype.content = function content(value) {
470 if (typeof value !== 'undefined') {
471 this.content_ = value;
473 return this.content_;
477 }(_component2['default']);
480 * Default options for `ModalDialog` default options.
487 ModalDialog.prototype.options_ = {
492 _component2['default'].registerComponent('ModalDialog', ModalDialog);
493 exports['default'] = ModalDialog;