'global/window'에서 창 가져오기;
'글로벌/문서'에서 문서 가져오기;
'../utils/merge-options'에서 mergeOptions 가져오기;
'../utils/url'에서 {getAbsoluteURL} 가져오기;
/**
* 이 함수는 무언가가 있을 때 소스 세트를 실행하는 데 사용됩니다.
* `mediaEl.load()`가 호출되는 것과 유사합니다. 다음을 통해 소스를 찾으려고 시도합니다.
* `src` 속성과 `< 원천> ` 요소. 그런 다음 `sourceset`을 실행합니다.
* 찾은 소스 또는 알 수 없는 경우 빈 문자열. 할 수 없다면
* 소스를 찾으면 `sourceset`이 실행되지 않습니다.
*
* @param {Html5} 기술
* sourceset이 설정된 기술 객체
*
* @return {부울}
* 소스 세트가 실행되지 않으면 false를 반환하고 그렇지 않으면 true를 반환합니다.
*/
const sourcesetLoad = (기술) => {
const el = tech.el();
// `el.src`가 설정되어 있으면 해당 소스가 로드됩니다.
if (el.hasAttribute('src')) {
tech.triggerSourceset(el.src);
true를 반환합니다.
}
/**
* 미디어 요소에 src 속성이 없기 때문에 소스 요소를 사용합니다.
* 소스 선택 알고리즘 구현. 이는 비동기식으로 발생하며
* 대부분의 경우 소스가 둘 이상인 경우 어떤 소스가 나올지 알 수 없습니다.
* 소스 선택 알고리즘을 다시 구현하지 않고 로드됩니다. 이때 우리는
* 그렇게 할 것입니다. 하지만 여기에서 처리하는 세 가지 특별한 경우가 있습니다.
*
* 1. 소스가 없으면 `sourceset`을 실행하지 마십시오.
* 2. 하나뿐인 경우`< 원천> ` 우리의 `src`인 `src` 속성/속성을 가진 `
* 삼. 하나 이상인 경우 `< 원천> ` 그러나 그들 모두는 동일한 `src` URL을 가지고 있습니다.
* 그것이 우리의 src가 될 것입니다.
*/
const sources = tech.$$('소스');
const srcUrls = [];
let src = '';
// 소스가 없으면 소스셋을 실행하지 않음
if (!소스.길이) {
거짓을 반환합니다.
}
// 유효한/중복되지 않은 소스 요소만 계산
에 대한 (하자 i = 0; i < 출처.길이; i++) {
const url = 소스[i].src;
만약 (URL && srcUrls.indexOf(url) === -1) {
srcUrls.push(url);
}
}
// 유효한 소스가 없습니다.
if (!srcUrls.length) {
거짓을 반환합니다.
}
// 유효한 소스 요소 URL은 하나만 있습니다.
// 사용
if (srcUrls.length === 1) {
src = srcUrls[0];
}
tech.triggerSourceset(src);
true를 반환합니다.
};
/**
* 브라우저용 `innerHTML` 디스크립터 구현
* 가지고 있지 않은 것.
*/
const innerHTMLDescriptorPolyfill = Object.defineProperty({}, 'innerHTML', {
얻다() {
return this.cloneNode(true).innerHTML;
},
집합(v) {
// innerHTML을 사용할 더미 노드를 만듭니다.
const dummy = document.createElement(this.nodeName.toLowerCase());
// innerHTML을 제공된 값으로 설정
dummy.innerHTML = v;
// 더미에서 노드를 보유할 문서 조각을 만듭니다.
const docFrag = document.createDocumentFragment();
// innerHTML에 의해 생성된 모든 노드를 dummy에 복사합니다.
// 문서 조각으로
동안 (dummy.childNodes.length) {
docFrag.appendChild(dummy.childNodes[0]);
}
// 콘텐츠 제거
this.innerText = '';
// 이제 우리는
// 문서 조각. 이것이 innerHTML이 수행하는 방식입니다.
window.Element.prototype.appendChild.call(this, docFrag);
// 그런 다음 innerHTML의 setter가 수행할 결과를 반환합니다.
this.innerHTML을 반환합니다.
}
});
/**
* 우선 순위 목록이 주어진 속성 설명자를 가져오고
* 얻을 속성.
*/
const getDescriptor = (우선 순위, 소품) => {
let 설명자 = {};
에 대한 (하자 i = 0; i < 우선순위.길이; i++) {
디스크립터 = Object.getOwnPropertyDescriptor(priority[i], prop);
if (설명자 && 디스크립터.세트 && 디스크립터.get) {
부서지다;
}
}
descriptor.enumerable = 참;
설명자.구성 가능 = 참;
반환 설명자;
};
const getInnerHTMLDescriptor = (기술) => getDescriptor([
tech.el(),
window.HTMLMediaElement.prototype,
창.요소.프로토타입,
innerHTMLDescriptorPolyfill
], 'innerHTML');
/**
* 동기식으로 알 수 있도록 브라우저 내부 기능 패치
* `인 경우< 원천> `가 미디어 요소에 추가되었습니다. 왠지 이
* 미디어 요소가 준비되었고 소스가 없는 경우 `sourceset`을 발생시킵니다.
* 다음과 같은 경우에 발생합니다.
* - 페이지가 방금 로드되었으며 미디어 요소에 소스가 없습니다.
* - 미디어 요소가 모든 소스에서 비워진 다음 `load()`가 호출되었습니다.
*
* 지원되는 경우 다음 기능/속성을 패치하여 이를 수행합니다.
*
* - `append()` - `를 추가하는 데 사용할 수 있습니다.< 원천> ` 요소를 미디어 요소로
* - `appendChild()` - `를 추가하는 데 사용할 수 있습니다.< 원천> ` 요소를 미디어 요소로
* - `insertAdjacentHTML()` - `를 추가하는 데 사용할 수 있습니다.< 원천> ` 요소를 미디어 요소로
* - `innerHTML` - `를 추가하는 데 사용할 수 있습니다.< 원천> ` 요소를 미디어 요소로
*
* @param {Html5} 기술
* sourceset이 설정되는 기술 개체입니다.
*/
const firstSourceWatch = 함수(기술) {
const el = tech.el();
// firstSourceWatch가 두 번 설정되지 않았는지 확인합니다.
if (el.resetSourceWatch_) {
반품;
}
오래된 const = {};
const innerDescriptor = getInnerHTMLDescriptor(tech);
const appendWrapper = (appendFn) => (...인수) => {
const retval = appendFn.apply(el, args);
sourcesetLoad(기술);
반환 반환;
};
['append', 'appendChild', 'insertAdjacentHTML'].forEach((k) => {
if (!el[k]) {
반품;
}
// 이전 함수 저장
old[k] = 엘[k];
// 소스가 있는 경우 소스 세트로 이전 함수를 호출합니다.
// 로드됨
el[k] = appendWrapper(old[k]);
});
Object.defineProperty(el, 'innerHTML', mergeOptions(innerDescriptor, {
세트: appendWrapper(innerDescriptor.set)
}));
el.resetSourceWatch_ = () => {
el.resetSourceWatch_ = null;
Object.keys(old).forEach((k) => {
el[k] = 이전[k];
});
Object.defineProperty(el, 'innerHTML', innerDescriptor);
};
// 첫 번째 소스 세트에서 변경 사항을 되돌려야 합니다.
tech.one('sourceset', el.resetSourceWatch_);
};
/**
* 브라우저용 `src` 디스크립터 구현
* 가지고 있지 않은 것.
*/
const srcDescriptorPolyfill = Object.defineProperty({}, 'src', {
얻다() {
if (this.hasAttribute('src')) {
return getAbsoluteURL(window.Element.prototype.getAttribute.call(this, 'src'));
}
반품 '';
},
집합(v) {
window.Element.prototype.setAttribute.call(this, 'src', v);
v를 반환합니다.
}
});
const getSrcDescriptor = (기술) => getDescriptor([tech.el(), window.HTMLMediaElement.prototype, srcDescriptorPolyfill], 'src');
/**
* `Html5` 기술에서 `sourceset` 처리 설정. 이 기능
* 다음 요소 속성/기능을 패치합니다.
*
* - `src` - `src`가 설정되는 시점을 결정합니다.
* - `setAttribute()` - `src`가 설정되는 시기 결정
* - `load()` - 소스 선택 알고리즘을 다시 트리거하고
* 원인 소스셋.
*
* `sourceset` 지원을 추가하거나 `load()` 중에 소스가 없는 경우
* `firstSourceWatch`에 나열된 기능도 패치합니다.
*
* @param {Html5} 기술
* 패치할 기술
*/
const setupSourceset = 기능(기술) {
if (!tech.featuresSourceset) {
반품;
}
const el = tech.el();
// sourceset이 두 번 설정되지 않았는지 확인합니다.
if (el.resetSourceset_) {
반품;
}
const srcDescriptor = getSrcDescriptor(tech);
const oldSetAttribute = el.setAttribute;
const oldLoad = el.load;
Object.defineProperty(el, 'src', mergeOptions(srcDescriptor, {
설정: (v) => {
const retval = srcDescriptor.set.call(el, v);
// 여기서 getter를 사용하여 src에 설정된 실제 값을 가져옵니다.
tech.triggerSourceset(el.src);
반환 반환;
}
}));
el.setAttribute = (n, v) => {
const retval = oldSetAttribute.call(el, n, v);
if ((/src/i).test(n)) {
tech.triggerSourceset(el.src);
}
반환 반환;
};
엘로드 = () => {
const retval = oldLoad.call(el);
// 로드가 호출되었지만 실행할 소스가 없는 경우
// 소스셋을 켭니다. 우리는 소스 추가를 감시해야 합니다.
// 미디어 요소가
// 소스가 없습니다
if (!sourcesetLoad(tech)) {
tech.triggerSourceset('');
firstSourceWatch(기술);
}
반환 반환;
};
if (el.currentSrc) {
tech.triggerSourceset(el.currentSrc);
} 그렇지 않으면 (!sourcesetLoad(tech)) {
firstSourceWatch(기술);
}
el.resetSourceset_ = () => {
el.resetSourceset_ = null;
el.load = oldLoad;
el.setAttribute = oldSetAttribute;
Object.defineProperty(el, 'src', srcDescriptor);
if (el.resetSourceWatch_) {
el.resetSourceWatch_();
}
};
};
기본 setupSourceset 내보내기;