1(function () { 2 'use strict'; 3 4 // å½åç«ç¹æ è¯ï¼åå ¥ä¸è½½è®°å½ï¼åè¯ç§ç« JS éæ¹ä¸ºå¯¹åº sam_xx 5 var SITE_WEBSITE = 'sam_fr'; 6 7 var root = document.getElementById('sam-download-gate'); 8 if (!root) { 9 return; 10 } 11 12 var form = document.getElementById('sam-download-gate-form'); 13 var nameInput = document.getElementById('sam-download-gate-name'); 14 var emailInput = document.getElementById('sam-download-gate-email'); 15 var errorEl = document.getElementById('sam-download-gate-error'); 16 var submitBtn = document.getElementById('sam-download-gate-submit'); 17 var pendingUrls = []; 18 var pendingAction = null; 19 var mobileMq = window.matchMedia('(max-width: 1025px)'); 20 21 function t(key, fallback) { 22 var value = root.getAttribute(key); 23 return (value && value.trim()) || fallback; 24 } 25 26 function setEmailPlaceholder() { 27 if (!emailInput) { 28 return; 29 } 30 var pc = emailInput.getAttribute('data-placeholder-pc') || ''; 31 var mobile = emailInput.getAttribute('data-placeholder-mobile') || pc; 32 emailInput.placeholder = mobileMq.matches ? mobile.trim() : pc.trim(); 33 } 34 35 function showError(message) { 36 if (!errorEl) { 37 return; 38 } 39 errorEl.textContent = message || ''; 40 if (message) { 41 errorEl.removeAttribute('hidden'); 42 } else { 43 errorEl.setAttribute('hidden', ''); 44 } 45 } 46 47 function normalizeUrls(urls) { 48 if (typeof urls === 'string') { 49 urls = [urls]; 50 } 51 if (!Array.isArray(urls)) { 52 return []; 53 } 54 var seen = {}; 55 var result = []; 56 urls.forEach(function (url) { 57 var value = (url || '').trim(); 58 if (!value || value === '#' || value.indexOf('javascript:') === 0 || seen[value]) { 59 return; 60 } 61 seen[value] = true; 62 result.push(value); 63 }); 64 return result; 65 } 66 67 /** 68 * @param {string|string[]} urls ä¸è½½å°åï¼æ ç宿件æ¶å¯ä¼ 页颿 è¯ URL 69 * @param {{ onSuccess?: function }} [options] onSuccessï¼æäº¤æååæ§è¡ï¼å¦å¾è¡¨å¯¼åºï¼ï¼ä¸åèµ°æä»¶ä¸è½½ 70 */ 71 function openModal(urls, options) { 72 options = options || {}; 73 pendingAction = typeof options.onSuccess === 'function' ? options.onSuccess : null; 74 pendingUrls = normalizeUrls(urls); 75 if (!pendingUrls.length && pendingAction && options.fileUrl) { 76 pendingUrls = normalizeUrls(options.fileUrl); 77 } 78 if (!pendingUrls.length) { 79 pendingAction = null; 80 return; 81 } 82 if (nameInput) { 83 nameInput.value = ''; 84 } 85 if (emailInput) { 86 emailInput.value = ''; 87 } 88 showError(''); 89 setEmailPlaceholder(); 90 root.removeAttribute('hidden'); 91 root.setAttribute('aria-hidden', 'false'); 92 document.body.style.overflow = 'hidden'; 93 if (nameInput) { 94 nameInput.focus(); 95 } 96 } 97 98 function closeModal() { 99 root.setAttribute('hidden', ''); 100 root.setAttribute('aria-hidden', 'true'); 101 document.body.style.overflow = ''; 102 pendingUrls = []; 103 pendingAction = null; 104 showError(''); 105 if (submitBtn) { 106 submitBtn.disabled = false; 107 } 108 } 109 110 function isValidEmail(value) { 111 return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value); 112 } 113 114 function submitDownloadLead(payload) { 115 var apiUrl = (typeof Apis !== 'undefined' && Apis.storeDownloadRecord) ? Apis.storeDownloadRecord : ''; 116 if (!apiUrl) { 117 return Promise.reject(new Error(t('data-msg-submit-fail', 'Submit failed. Please try again.'))); 118 } 119 120 return fetch(apiUrl, { 121 method: 'POST', 122 headers: { 123 'Content-Type': 'application/json', 124 Accept: 'application/json' 125 }, 126 body: JSON.stringify({ 127 username: payload.name, 128 email: payload.email, 129 website: SITE_WEBSITE, 130 file_url: payload.file_urls[0], 131 file_urls: payload.file_urls, 132 landing_page: payload.page_url 133 }) 134 }).then(function (res) { 135 return res.json().then(function (data) { 136 if (!res.ok || !data || data.code != 200) { 137 var msg = data && data.msg ? data.msg : t('data-msg-submit-fail', 'Submit failed. Please try again.'); 138 throw new Error(typeof msg === 'string' ? msg : t('data-msg-submit-fail', 'Submit failed. Please try again.')); 139 } 140 return data; 141 }); 142 }); 143 } 144 145 function fileNameFromUrl(url) { 146 try { 147 var path = url.split('?')[0]; 148 var name = decodeURIComponent(path.substring(path.lastIndexOf('/') + 1)); 149 return name || 'download.pdf'; 150 } catch (e) { 151 return 'download.pdf'; 152 } 153 } 154 155 function clickDownloadLink(href, filename) { 156 var link = document.createElement('a'); 157 link.href = href; 158 link.setAttribute('download', filename || 'download.pdf'); 159 link.style.display = 'none'; 160 document.body.appendChild(link); 161 link.click(); 162 document.body.removeChild(link); 163 } 164 165 function downloadFile(url) { 166 var filename = fileNameFromUrl(url); 167 168 return fetch(url, { mode: 'cors', credentials: 'omit' }) 169 .then(function (response) { 170 if (!response.ok) { 171 throw new Error('Network response was not ok'); 172 } 173 return response.blob(); 174 }) 175 .then(function (blob) { 176 var objectUrl = URL.createObjectURL(blob); 177 clickDownloadLink(objectUrl, filename); 178 window.setTimeout(function () { 179 URL.revokeObjectURL(objectUrl); 180 }, 1500); 181 }) 182 .catch(function () { 183 var iframe = document.createElement('iframe'); 184 iframe.style.cssText = 'position:fixed;left:-9999px;width:1px;height:1px;opacity:0;pointer-events:none;'; 185 iframe.setAttribute('aria-hidden', 'true'); 186 iframe.src = url; 187 document.body.appendChild(iframe); 188 window.setTimeout(function () { 189 if (iframe.parentNode) { 190 iframe.parentNode.removeChild(iframe); 191 } 192 }, 60000); 193 }); 194 } 195 196 function downloadZip(urls) { 197 var apiUrl = (typeof Apis !== 'undefined' && Apis.downloadFilesZip) ? Apis.downloadFilesZip : ''; 198 if (!apiUrl) { 199 return Promise.reject(new Error('zip unavailable'));
200 } 201 202 return fetch(apiUrl, { 203 method: 'POST', 204 headers: { 205 'Content-Type': 'application/json', 206 Accept: 'application/json' 207 }, 208 body: JSON.stringify({ fileList: urls }) 209 }).then(function (res) { 210 var contentType = (res.headers.get('content-type') || '').toLowerCase(); 211 if (!res.ok || contentType.indexOf('application/zip') === -1) { 212 throw new Error('zip failed'); 213 } 214 return res.blob(); 215 }).then(function (blob) { 216 var objectUrl = URL.createObjectURL(blob); 217 clickDownloadLink(objectUrl, 'Samaterials-Download.zip'); 218 window.setTimeout(function () { 219 URL.revokeObjectURL(objectUrl); 220 }, 1500); 221 }); 222 } 223 224 function wait(ms) { 225 return new Promise(function (resolve) { 226 window.setTimeout(resolve, ms); 227 }); 228 } 229 230 function downloadFiles(urls) { 231 if (urls.length === 1) { 232 return downloadFile(urls[0]); 233 } 234 235 return downloadZip(urls).catch(function () { 236 var chain = Promise.resolve(); 237 urls.forEach(function (url) { 238 chain = chain.then(function () { 239 return downloadFile(url).then(function () { 240 return wait(400); 241 }); 242 }); 243 }); 244 return chain; 245 }); 246 } 247 248 document.addEventListener('click', function (event) { 249 var trigger = event.target.closest('.js-download-gate'); 250 if (trigger) { 251 event.preventDefault(); 252 var url = trigger.getAttribute('data-download-url') || trigger.getAttribute('href') || ''; 253 openModal(url); 254 return; 255 } 256 257 if (event.target.closest('[data-download-gate-close]')) { 258 closeModal(); 259 } 260 }); 261 262 document.addEventListener('keydown', function (event) { 263 if (event.key === 'Escape' && !root.hasAttribute('hidden')) { 264 closeModal(); 265 } 266 }); 267 268 if (form) { 269 form.addEventListener('submit', function (event) { 270 event.preventDefault(); 271 var name = (nameInput && nameInput.value || '').trim(); 272 var email = (emailInput && emailInput.value || '').trim(); 273 274 if (!name) { 275 showError(t('data-msg-name-required', 'Your Name is required')); 276 if (nameInput) { 277 nameInput.focus(); 278 } 279 return; 280 } 281 if (!email) { 282 showError(t('data-msg-email-required', 'Your Email is required')); 283 if (emailInput) { 284 emailInput.focus(); 285 } 286 return; 287 } 288 if (!isValidEmail(email)) { 289 showError(t('data-msg-email-invalid', 'Please enter a valid email address.')); 290 if (emailInput) { 291 emailInput.focus(); 292 } 293 return; 294 } 295 if (!pendingUrls.length) { 296 showError(t('data-msg-file-missing', 'Download file is missing.')); 297 return; 298 } 299 300 var payload = { 301 name: name, 302 email: email, 303 website: SITE_WEBSITE, 304 file_urls: pendingUrls.slice(), 305 page_url: window.location.href, 306 source: root.getAttribute('data-source') || '' 307 }; 308 309 if (submitBtn) { 310 submitBtn.disabled = true; 311 } 312 showError(''); 313 314 var urls = pendingUrls.slice(); 315 var action = pendingAction; 316 317 // å¾è¡¨ CSV/XLS çéå¨ãæäº¤ãç¹å»ç忥è°ç¨æ é触åä¸è½½ï¼ 318 // å¦å fetch ä¹åæµè§å¨ä¼ä¸¢æ user gestureï¼æ¦æª blob ä¸è½½ã 319 if (action) { 320 try { 321 action(); 322 } catch (err) { 323 showError(err && err.message ? err.message : t('data-msg-submit-fail', 'Submit failed. Please try again.')); 324 if (submitBtn) { 325 submitBtn.disabled = false; 326 } 327 return; 328 } 329 submitDownloadLead(payload) 330 .then(function () { 331 closeModal(); 332 }) 333 .catch(function (err) { 334 // æä»¶å¯è½å·²å¼å§ä¸è½½ï¼ä»æç¤ºæäº¤å¤±è´¥ï¼ä¾¿äºéè¯çèµ 335 showError(err && err.message ? err.message : t('data-msg-submit-fail', 'Submit failed. Please try again.')); 336 if (submitBtn) { 337 submitBtn.disabled = false; 338 } 339 }); 340 return; 341 } 342 343 submitDownloadLead(payload) 344 .then(function () { 345 return downloadFiles(urls); 346 }) 347 .then(function () { 348 closeModal(); 349 }) 350 .catch(function (err) { 351 showError(err && err.message ? err.message : t('data-msg-submit-fail', 'Submit failed. Please try again.')); 352 if (submitBtn) { 353 submitBtn.disabled = false; 354 } 355 }); 356 }); 357 } 358 359 window.SamDownloadGate = { 360 open: openModal 361 }; 362 363 setEmailPlaceholder(); 364 if (typeof mobileMq.addEventListener === 'function') { 365 mobileMq.addEventListener('change', setEmailPlaceholder); 366 } else if (typeof mobileMq.addListener === 'function') { 367 mobileMq.addListener(setEmailPlaceholder); 368 } 369})();
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.