1import { Browser } from '../utility/browser.js'; 2import YoutubePlayer from './youtubePlayer.js'; 3(() => { 4 const config = { 5 // selector 6 dialogInnerSelector: '.fn-dialog__inner', 7 dialogContentSelector: '.fn-dialog__content', 8 dialogContentInnerSelector: '.fn-dialog__contentInner', 9 closeButtonSelector: '.fn-dialog__closeButton', 10 dialogVideoIframeSelector: '.fn-dialogVideo', 11 }; 12 // å dialog ã®ç¶æ 管ç 13 const players = new WeakMap(); 14 const initPromises = new WeakMap(); 15 // ã¤ãã³ããã¤ã³ã管çï¼ã¤ãã³ãã®éè¤ç»é²ãé²ãï¼ 16 const boundDialogs = new WeakSet(); 17 // videoId æ½åº 18 const extractVideoId = (src) => { 19 try { 20 const url = new URL(src); 21 const match = url.pathname.match(/\/embed\/([^/?#]+)/); 22 return match?.[1] ?? ''; 23 } 24 catch { 25 // URLã§ãªããã°ç©ºæåãè¿ã 26 return ''; 27 } 28 }; 29 const ensureOriginParam = (iframe) => { 30 const src = iframe.getAttribute('src'); 31 if (!src) 32 return; 33 try { 34 const url = new URL(src); 35 // enablejsapi ããªããã°ä½ãããªãï¼å¿µã®ããï¼ 36 if (url.searchParams.get('enablejsapi') !== '1') 37 return; 38 // ãã§ã« origin ãããã°ä½ãããªã 39 if (url.searchParams.has('origin')) 40 return; 41 url.searchParams.set('origin', window.location.origin); 42 // åãã¼ããçºçãããããä¸åº¦æ¶ãã¦ããåã»ãã 43 iframe.removeAttribute('src'); 44 iframe.setAttribute('src', url.toString()); 45 } 46 catch { 47 // ç¡å¹ãª URL ã®å ´åã¯ä½ãããªã 48 } 49 }; 50 // ãã¤ã¢ãã°ã®iframeãããã¬ã¤ã¤ã¼ãåæåï¼å¿ è¦ãªæã ãï¼ 51 const ensurePlayer = async (dialog, iframe) => { 52 // ãã§ã«ã¤ã³ã¹ã¿ã³ã¹æ¸ã¿ãªããããè¿ã 53 const existing = players.get(dialog); 54 if (existing) 55 return existing; 56 ensureOriginParam(iframe); 57 const src = iframe.getAttribute('src') ?? ''; 58 const videoId = extractVideoId(src); 59 if (!videoId) { 60 return null; 61 } 62 if (!iframe.id) { 63 const dialogId = dialog.id || 'dialog'; 64 iframe.id = `yt-${dialogId}`; 65 } 66 const player = new YoutubePlayer(iframe.id, videoId); 67 players.set(dialog, player); 68 // è¤æ°åã®ä¸¦è¡åæåãé²ããã Promise ãå ±æ 69 const init = player.init(); 70 initPromises.set(dialog, init); 71 try { 72 await init; 73 } 74 catch { 75 players.delete(dialog); 76 initPromises.delete(dialog); 77 return null; 78 } 79 return player; 80 }; 81 const setDialog = (element) => { 82 // 対å¿ããdialogã®idãåå¾ 83 const dialogId = element.dataset.dialogTarget; 84 if (!dialogId || dialogId === '') 85 return; 86 const dialog = document.querySelector(`#${dialogId}`); 87 const dialogInner = dialog?.querySelector(config.dialogInnerSelector); 88 const dialogContent = dialog?.querySelector(config.dialogContentSelector); 89 const dialogContentInner = dialog?.querySelector(config.dialogContentInnerSelector); 90 const closeButtons = dialog?.querySelectorAll(config.closeButtonSelector); 91 const videoIframe = dialog?.querySelector(config.dialogVideoIframeSelector); 92 if (!dialog || !closeButtons?.length) 93 return; 94 /** ã¹ã¯ãã¼ã«ãå¿ è¦ãªå ´åã«ã®ã¿ããã©ã¼ã«ã¹ç§»åç¨tabindexãä»ä¸ */ 95 const setTabindex = () => { 96 if (!dialogContent || !dialogContentInner) 97 return; 98 if (dialogContentInner.scrollHeight > dialogContent.clientHeight) { 99 dialogContent.setAttribute('tabindex', '0'); 100 } 101 else { 102 dialogContent.removeAttribute('tabindex'); 103 } 104 }; 105 /** ãã¤ã¢ãã°ãéãå¦ç */ 106 const showDialog = async () => { 107 if (dialog.open) 108 return; 109 dialog.setAttribute('tabindex', '-1'); 110 if (dialog.classList.contains('js-tc-widget')) { 111 dialog.show(); 112 document.documentElement.style.overflow = 'hidden'; 113 } 114 else { 115 dialog.showModal(); 116 } 117 dialog.focus({ preventScroll: true }); 118 requestAnimationFrame(() => { 119 setTabindex(); 120 }); 121 // YouTube åçå¶å¾¡ 122 if (videoIframe) { 123 // åæå Promise åå¾ 124 let initP = initPromises.get(dialog); 125 if (!initP) { 126 initP = (async () => { 127 await ensurePlayer(dialog, videoIframe); 128 })(); 129 initPromises.set(dialog, initP); 130 } 131 // åæåå®äºãå¾ ã¤ 132 await initP; 133 // åæåå¾ã«ãã¬ã¤ã¤ã¼ãåå¾ãã¦æä½ 134 const player = players.get(dialog); 135 if (player) { 136 player.seekTo(0, true); 137 // Safari SPï¼iOSï¼ã¯å®å ¨ã«åçããªãï¼YouTube å´ä»æ§ã®æ¢ç¥ãã°å¯¾å¿ï¼2åç®ããåæã«autoplayã試è¡ã
137®ããï¼ 138 if (Browser.isIOS()) { 139 player.stop(); 140 return; 141 } 142 // Safari PC 㯠autoplay ãããã¯åé¿ã®ãã setTimeout 143 if (Browser.isSafariPC()) { 144 setTimeout(() => player.play(), 0); 145 return; 146 } 147 // Chromeãä»ãã©ã¦ã¶ 148 player.play(); 149 } 150 } 151 }; 152 /** ãã¤ã¢ãã°ãéããå¦ç */ 153 const hideDialog = () => { 154 if (!dialog.open) 155 return; 156 if (dialog.classList.contains('js-tc-widget')) { 157 dialog.close(); 158 document.documentElement.style.overflow = ''; 159 } 160 else { 161 dialog.close(); 162 } 163 // YouTube 忢 164 const player = players.get(dialog); 165 if (player) { 166 player.stop(); 167 player.seekTo(0, true); 168 } 169 }; 170 /** ã¤ãã³ãè¨å® */ 171 const bindEvents = () => { 172 element.addEventListener('click', async (event) => { 173 event.preventDefault(); 174 // å ã«éãï¼UIããããã¯ããªãï¼ 175 await showDialog(); 176 }); 177 // ãã¤ã¢ãã°èªä½ã®ã¤ãã³ãã¯ä¸åº¦ã®ã¿ 178 if (boundDialogs.has(dialog)) 179 return; 180 // èæ¯ã¯ãªãã¯ã§éãã 181 dialogInner?.addEventListener('click', (event) => { 182 if (event.target === dialogInner) { 183 hideDialog(); 184 } 185 }); 186 // éãããã¿ã³ã§éãã 187 closeButtons.forEach((closeButton) => { 188 closeButton.addEventListener('click', hideDialog); 189 }); 190 // ãã¼ãã¦ã³ã¤ãã³ããç»é² 191 dialog.addEventListener('keydown', (event) => { 192 if (event.key === 'Escape') { 193 event.preventDefault(); 194 hideDialog(); 195 } 196 }); 197 // Esc ãªã© close æã確å®ã«åæ¢ 198 dialog.addEventListener('close', () => { 199 const player = players.get(dialog); 200 if (player) { 201 player.stop(); 202 initPromises.delete(dialog); 203 } 204 }); 205 boundDialogs.add(dialog); 206 }; 207 bindEvents(); 208 }; 209 const elements = document.querySelectorAll('.js-dialogButton'); 210 if (elements.length === 0) 211 return; 212 elements.forEach((element) => { 213 setDialog(element); 214 }); 215})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.