/**
* @file 모달-dialog.js
*/
import * as Dom from './utils/dom';
'./component'에서 컴포넌트 가져오기;
'글로벌/창'에서 창 가져오기;
'글로벌/문서'에서 문서 가져오기;
'키코드'에서 키코드 가져오기;
const MODAL_CLASS_NAME = 'vjs-modal-dialog';
/**
* `ModalDialog`는 동영상과 컨트롤 위에 표시되며
* 플레이어가 닫힐 때까지 플레이어와 상호 작용합니다.
*
* 모달 대화 상자에는 "닫기" 버튼이 포함되어 있으며 해당 버튼을 누르면 닫힙니다.
* 활성화 - 또는 ESC를 아무데나 눌렀을 때.
*
* @extends 컴포넌트
*/
클래스 ModalDialog 확장 구성 요소 {
/**
* 이 클래스의 인스턴스를 만듭니다.
*
* @param {플레이어} 플레이어
* 이 클래스가 연결되어야 하는 `Player`.
*
* @param {객체} [옵션]
* 플레이어 옵션의 키/값 저장소.
*
* @param {혼합} [options.content=정의되지 않음]
* 이 모달에 대한 맞춤형 콘텐츠를 제공합니다.
*
* @param {문자열} [옵션 설명]
* 주로 접근성을 위한 모달에 대한 텍스트 설명입니다.
*
* @param {부울} [options.fillAlways=false]
* 일반적으로 모달은 처음에만 자동으로 채워집니다.
* 그들은 열립니다. 이것은 모달에게 내용을 새로 고치도록 지시합니다.
* 열 때마다.
*
* @param {문자열} [옵션.레이블]
* 주로 접근성을 위한 모달용 텍스트 레이블입니다.
*
* @param {부울} [options.pauseOnOpen=true]
* 'true'인 경우 다음 시간에 재생하면 재생이 일시 중지됩니다.
* 모달이 열리고 닫히면 다시 시작됩니다.
*
* @param {부울} [옵션.임시=참]
* 'true'이면 모달을 한 번만 열 수 있습니다. 그것은 될 것이다
* 마감되는 대로 폐기합니다.
*
* @param {부울} [options.uncloseable=false]
* `true`이면 사용자가 모달을 닫을 수 없습니다.
* 일반적인 방법으로 UI를 통해. 프로그래밍 방식 종료는
* 여전히 가능합니다.
*/
생성자(플레이어, 옵션) {
super(플레이어, 옵션);
this.handleKeyDown_ = (e) => this.handleKeyDown(e);
this.close_ = (e) => this.close(e);
this.opened_ = this.hasBeenOpened_ = this.hasBeenFilled_ = 거짓;
this.closeable(!this.options_.uncloseable);
this.content(this.options_.content);
// 자식이 초기화된 후에 contentEl이 정의되었는지 확인합니다.
// contentEl에 있는 모달의 내용만 원하기 때문에
// (닫기 버튼과 같은 UI 요소가 아님).
this.contentEl_ = Dom.createEl('div', {
클래스 이름: `${MODAL_CLASS_NAME}-content`
}, {
역할: '문서'
});
this.descEl_ = Dom.createEl('p', {
className: `${MODAL_CLASS_NAME}-description vjs-control-text`,
id: this.el().getAttribute('aria-describedby')
});
Dom.textContent(this.descEl_, this.description());
this.el_.appendChild(this.descEl_);
this.el_.appendChild(this.contentEl_);
}
/**
* `ModalDialog`의 DOM 요소 생성
*
* @return {요소}
* 생성되는 DOM 요소.
*/
createEl() {
return super.createEl('div', {
className: this.buildCSSClass(),
탭 인덱스: -1
}, {
'aria-describedby': `${this.id()}_description`,
'aria-hidden': '참',
'아리아 라벨': this.label(),
'역할': '대화'
});
}
폐기() {
this.contentEl_ = null;
this.descEl_ = null;
this.previousActiveEl_ = null;
super.dispose();
}
/**
* 기본 DOM `className`을 빌드합니다.
*
* @return {문자열}
* 이 개체의 DOM `className`입니다.
*/
buildCSSClass() {
`${MODAL_CLASS_NAME} vjs-hidden ${super.buildCSSClass()}` 반환;
}
/**
* 이 모달의 레이블 문자열을 반환합니다. 주로 접근성에 사용됩니다.
*
* @return {문자열}
* 이 모달의 현지화 또는 원시 레이블.
*/
라벨() {
return this.localize(this.options_.label || '모달 창');
}
/**
* 이 모달에 대한 설명 문자열을 반환합니다. 주로 사용
* 접근성.
*
* @return {문자열}
* 이 모달의 현지화된 설명 또는 초기 설명입니다.
*/
설명() {
let desc = this.options_.description || this.localize('모달 창입니다.');
// 모달이 닫힐 수 있는 경우 범용 닫기 가능성 메시지를 추가합니다.
if (this.closeable()) {
desc += ' ' + this.localize('Esc 키를 누르거나 닫기 버튼을 활성화하여 이 모달을 닫을 수 있습니다.');
}
반환 설명;
}
/**
* 모달을 엽니다.
*
* @fires ModalDialog#beforemodalopen
* @fires ModalDialog#modalopen
*/
열려 있는() {
if (!this.opened_) {
const player = this.player();
/**
* `ModalDialog`가 열리기 직전에 실행됩니다.
*
* @event ModalDialog#beforemodalopen
* @type {이벤트대상~이벤트}
*/
this.trigger('beforemodalopen');
this.opened_ = 참;
// 모달이 이전에 열린 적이 없는 경우 콘텐츠를 채우고
// 채워진 적이 없습니다.
if (this.options_.fillAlways || !this.hasBeenOpened_ && !this.hasBeenFilled_) {
this.fill();
}
// 플레이어가 재생 중인 경우 일시 중지하고 이전
// 재생 상태.
this.wasPlaying_ = !player.paused();
if (this.options_.pauseOnOpen && this.wasPlaying_) {
player.pause();
}
this.on('keydown', this.handleKeyDown_);
// 컨트롤을 숨기고 활성화되었는지 확인합니다.
this.hadControls_ = player.controls();
player.controls(거짓);
this.show();
this.conditionalFocus_();
this.el().setAttribute('aria-hidden', 'false');
/**
* `ModalDialog`가 열린 직후에 시작됩니다.
*
* @event 모달대화상자#modalopen
* @type {이벤트대상~이벤트}
*/
this.trigger('modalopen');
this.hasBeenOpened_ = 참;
}
}
/**
* `ModalDialog`가 현재 열려 있거나 닫혀 있는지 여부.
*
* @param {부울} [값]
* 주어진 경우 모달을 열거나(`true`) 닫습니다(`false`).
*
* @return {부울}
* 모달 대화 상자의 현재 열린 상태
*/
열림(값) {
if (typeof 값 === '부울') {
이[값 ? '열기' : '닫기']();
}
반환 this.opened_;
}
/**
* 모달을 닫고 `ModalDialog`가
* 열려 있지 않음.
*
* @fires ModalDialog#beforemodalclose
* @fires ModalDialog#modalclose
*/
닫다() {
if (!this.opened_) {
반품;
}
const player = this.player();
/**
* `ModalDialog`가 닫히기 직전에 시작됩니다.
*
* @event ModalDialog#beforemodalclose
* @type {이벤트대상~이벤트}
*/
this.trigger('beforemodalclose');
this.opened_ = 거짓;
if (this.wasPlaying_ && this.options_.pauseOnOpen) {
플레이어.플레이();
}
this.off('키다운', this.handleKeyDown_);
if (this.hadControls_) {
player.controls(true);
}
this.hide();
this.el().setAttribute('aria-hidden', 'true');
/**
* `ModalDialog`가 닫힌 직후에 시작됩니다.
*
* @event 모달대화상자#modalclose
* @type {이벤트대상~이벤트}
*/
this.trigger('modalclose');
this.conditionalBlur_();
if (this.options_.temporary) {
this.dispose();
}
}
/**
* UI를 통해 `ModalDialog`를 닫을 수 있는지 확인하십시오.
*
* @param {부울} [값]
* 부울로 주어지면 `closeable` 옵션을 설정합니다.
*
* @return {부울}
* 닫을 수 있는 옵션의 최종 값을 반환합니다.
*/
닫기 가능(값) {
if (typeof 값 === '부울') {
const closeable = this.closeable_ = !!value;
let close = this.getChild('closeButton');
// 닫을 수 있게 만들고 닫기 버튼이 없으면 추가합니다.
if (닫을 수 있는 && !닫다) {
// 닫기 버튼은 모달의 자식이어야 합니다.
// 콘텐츠 요소이므로 일시적으로 콘텐츠 요소를 변경합니다.
const temp = this.contentEl_;
this.contentEl_ = this.el_;
닫기 = this.addChild('closeButton', {controlText: '모달 대화상자 닫기'});
this.contentEl_ = 임시;
this.on(닫기, '닫기', this.close_);
}
// 닫을 수 없게 만들고 닫기 버튼이 있으면 제거합니다.
if (!닫을 수 있는 && 닫다) {
this.off(닫기, '닫기', this.close_);
this.removeChild(닫기);
닫기.처리();
}
}
this.closeable_을 반환합니다.
}
/**
* 모달의 콘텐츠 요소를 모달의 "콘텐츠" 옵션으로 채웁니다.
* 이 변경 사항이 적용되기 전에 콘텐츠 요소가 비워집니다.
*/
채우다() {
this.fillWith(this.content());
}
/**
* 임의의 콘텐츠로 모달의 콘텐츠 요소를 채웁니다.
* 이 변경 사항이 적용되기 전에 콘텐츠 요소가 비워집니다.
*
* @fires ModalDialog#beforemodalfill
* @fires ModalDialog#modalfill
*
* @param {혼합} [내용]
* '콘텐츠' 옵션에 적용되는 것과 동일한 규칙이 적용됩니다.
*/
채우기(내용) {
const contentEl = this.contentEl();
const parentEl = contentEl.parentNode;
const nextSiblingEl = contentEl.nextSibling;
/**
* `ModalDialog`가 콘텐츠로 채워지기 직전에 시작됩니다.
*
* @event ModalDialog#beforemodalfill
* @type {이벤트대상~이벤트}
*/
this.trigger('beforemodalfill');
this.hasBeenFilled_ = 참;
// 수행하기 전에 DOM에서 콘텐츠 요소를 분리합니다.
// 라이브 DOM을 여러 번 수정하지 않도록 조작합니다.
parentEl.removeChild(contentEl);
this.empty();
Dom.insertContent(contentEl, 콘텐츠);
/**
* `ModalDialog`가 콘텐츠로 채워진 직후에 시작됩니다.
*
* @event 모달대화상자#modalfill
* @type {이벤트대상~이벤트}
*/
this.trigger('modalfill');
// 다시 채워진 콘텐츠 요소를 다시 삽입합니다.
경우 (nextSiblingEl) {
parentEl.insertBefore(contentEl, nextSiblingEl);
} else {
parentEl.appendChild(contentEl);
}
// 닫기 버튼이 대화 DOM에서 마지막인지 확인합니다.
const closeButton = this.getChild('closeButton');
if(닫기버튼) {
parentEl.appendChild(closeButton.el_);
}
}
/**
* 콘텐츠 요소를 비웁니다. 이것은 모달이 채워질 때마다 발생합니다.
*
* @fires ModalDialog#beforemodalempty
* @fires ModalDialog#modalempty
*/
비어 있는() {
/**
* `ModalDialog`가 비워지기 직전에 시작됩니다.
*
* @event ModalDialog#beforemodalempty
* @type {이벤트대상~이벤트}
*/
this.trigger('beforemodalempty');
Dom.emptyEl(this.contentEl());
/**
* `ModalDialog`가 비워진 직후에 시작됩니다.
*
* @event ModalDialog#modalempty
* @type {이벤트대상~이벤트}
*/
this.trigger('modalempty');
}
/**
* 정규화되기 전에 모달 콘텐츠를 가져오거나 설정합니다.
* DOM으로 렌더링됩니다.
*
* 이것은 DOM을 업데이트하거나 모달을 채우지는 않지만 호출되는 동안 호출됩니다.
* 그 과정.
*
* @param {혼합} [값]
* 정의된 경우에 사용할 내부 콘텐츠 값을 설정합니다.
* `fill`에 대한 다음 호출(들). 이 값은 정규화되기 전에
* 삽입. 내부 콘텐츠 값을 "지우려면" `null`을 전달합니다.
*
* @return {혼합}
* 모달 대화 상자의 현재 내용
*/
내용(값) {
if (값 유형 !== '정의되지 않음') {
this.content_ = 값;
}
this.content_를 반환합니다.
}
/**
* 이전에 플레이어에 포커스가 있는 경우 조건부로 모달 대화 상자에 포커스를 맞춥니다.
*
* @사적인
*/
conditionalFocus_() {
const activeEl = document.activeElement;
const playerEl = this.player_.el_;
this.previousActiveEl_ = null;
if (playerEl.contains(activeEl) || playerEl === activeEl) {
this.previousActiveEl_ = 활성 El;
this.focus();
}
}
/**
* 조건부로 요소를 흐리게 처리하고 마지막으로 초점을 맞춘 요소의 초점을 다시 맞춥니다.
*
* @사적인
*/
conditionalBlur_() {
if (this.previousActiveEl_) {
this.previousActiveEl_.focus();
this.previousActiveEl_ = null;
}
}
/**
* 키 다운 핸들러. 모달에 포커스가 있을 때 첨부됩니다.
*
* @listens 키다운
*/
handleKeyDown(이벤트) {
// 키다운이 모달 대화 상자 밖으로 도달하지 않도록 합니다.
event.stopPropagation();
if (keycode.isEventKey(이벤트, '탈출') && this.closeable()) {
event.preventDefault();
this.close();
반품;
}
// 탭 키가 아니면 일찍 종료
if (!keycode.isEventKey(event, 'Tab')) {
반품;
}
const focusableEls = this.focusableEls_();
const activeEl = this.el_.querySelector(':focus');
let focusIndex;
에 대한 (하자 i = 0; i < focusableEls.length; i++) {
if (activeEl === focusableEls[i]) {
focusIndex = i;
부서지다;
}
}
if (document.activeElement === this.el_) {
포커스 인덱스 = 0;
}
if (이벤트.쉬프트키 && 포커스 인덱스 === 0) {
focusableEls[focusableEls.length - 1].focus();
event.preventDefault();
} 그렇지 않으면 (!event.shiftKey && focusIndex === focusableEls.length - 1) {
focusableEls[0].focus();
event.preventDefault();
}
}
/**
* 모든 포커스 가능 요소 가져오기
*
* @사적인
*/
focusableEls_() {
const allChildren = this.el_.querySelectorAll('*');
return Array.prototype.filter.call(allChildren, (자식) => {
return ((window.HTMLAnchorElement의 하위 인스턴스 ||
window.HTMLAreaElement의 하위 인스턴스) && child.hasAttribute('href')) ||
((window.HTMLInputElement의 하위 인스턴스 ||
window.HTMLSelectElement의 자식 인스턴스 ||
window.HTMLTextAreaElement의 자식 인스턴스 ||
window.HTMLButtonElement의 하위 인스턴스) && !child.hasAttribute('비활성화됨')) ||
(window.HTMLIFrameElement의 하위 인스턴스 ||
window.HTMLObjectElement의 자식 인스턴스 ||
window.HTMLEmbedElement의 자식 인스턴스) ||
(자식.hasAttribute('tabindex') && child.getAttribute('tabindex') !== -1) ||
(child.hasAttribute('contenteditable'));
});
}
}
/**
* `ModalDialog` 기본 옵션에 대한 기본 옵션.
*
* @type {객체}
* @사적인
*/
ModalDialog.prototype.options_ = {
pauseOnOpen: 참,
임시: 사실
};
Component.registerComponent('ModalDialog', ModalDialog);
기본 ModalDialog 내보내기;