1/** 2 * Ported from https://github.com/paulirish/lite-youtube-embed 3 * 4 * A lightweight vimeo embed. Still should feel the same to the user, just MUCH faster to initialize and paint. 5 * 6 * Thx to these as the inspiration 7 * https://storage.googleapis.com/amp-vs-non-amp/youtube-lazy.html 8 * https://autoplay-youtube-player.glitch.me/ 9 * 10 * Once built it, I also found these: 11 * https://github.com/ampproject/amphtml/blob/master/extensions/amp-youtube (ðð) 12 * https://github.com/Daugilas/lazyYT 13 * https://github.com/vb/lazyframe 14 */ 15class LiteVimeo extends HTMLElement { 16 constructor () { 17 super(); 18 // TODO: support dynamically setting the attribute via attributeChangedCallback 19 } 20 21 connectedCallback () { 22 // Gotta encode the untrusted value 23 // https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#rule-2---attribute-escape-before-inserting-untrusted-data-into-html-common-attributes 24 this.videoId = encodeURIComponent(this.getAttribute('videoid')); 25 26 this.secret = encodeURIComponent(this.getAttribute('h')); 27 28 let playBtn = this.querySelector('.ltv-playbtn'); 29 30 /** 31 * Lo, the vimeo placeholder image! (aka the thumbnail, poster image, etc) 32 * We have to use the Vimeo API. 33 */ 34 let { width, height } = getThumbnailDimensions(this.getBoundingClientRect()); 35 const devicePixelRatio = window.devicePixelRatio || 1; 36 width *= devicePixelRatio; 37 height *= devicePixelRatio; 38 39 // let thumbnailUrl = `https://lite-vimeo-embed.now.sh/thumb/${this.videoId}`; 40 // thumbnailUrl += `.${canUseWebP() ? 'webp' : 'jpg'}`; 41 // thumbnailUrl += `?mw=${width}&mh=${height}&q=${devicePixelRatio > 1 ? 70 : 85}`; 42 43 // this.style.backgroundImage = `url("${thumbnailUrl}")`; 44 45 if (!playBtn) { 46 const playBtn = document.createElement('button'); 47 playBtn.type = 'button'; 48 playBtn.classList.add('ltv-playbtn'); 49 this.appendChild(playBtn); 50 } 51 playBtn.removeAttribute('href'); 52 53 // On hover (or tap), warm up the TCP connections we're (likely) about to use. 54 this.addEventListener('pointerover', LiteVimeo._warmConnections, { 55 once: true 56 }); 57 58 // Once the user clicks, add the real iframe and drop our play button 59 // TODO: In the future we could be like amp-youtube and silently swap in the iframe during idle time 60 // We'd want to only do this for in-viewport or near-viewport ones: https://github.com/ampproject/amphtml/pull/5003 61 this.addEventListener('click', () => this._addIframe()); 62 } 63 64 // // TODO: Support the the user changing the [videoid] attribute 65 // attributeChangedCallback() { 66 // } 67 68 /** 69 * Begin pre-connecting to warm up the iframe load 70 * Since the embed's network requests load within its iframe, 71 * preload/prefetch'ing them outside the iframe will only cause double-downloads. 72 * So, the best we can do is warm up a few connections to origins that are in the critical path. 73 * 74 * Maybe `<link rel=preload as=document>` would work, but it's unsupported: http://crbug.com/593267 75 * But TBH, I don't think it'll happen soon with Site Isolation and split caches adding serious complexity. 76 */ 77 static _warmConnections () { 78 if (LiteVimeo.preconnected) return; 79 80 // The iframe document and most of its subresources come right off player.vimeo.com 81 addPrefetch('preconnect', 'https://player.vimeo.com'); 82 // Images 83 addPrefetch('preconnect', 'https://i.vimeocdn.com'); 84 // Files .js, .css 85 addPrefetch('preconnect', 'https://f.vimeocdn.com'); 86 // Metrics 87 addPrefetch('preconnect', 'https://fresnel.vimeocdn.com'); 88 89 LiteVimeo.preconnected = true; 90 } 91 92 _addIframe () { 93 const iframeHTML = ` 94<iframe width="640" height="360" frameborder="0" 95 allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen 96 src="https://player.vimeo.com/video/${this.videoId}?h=${this.secret}
96&autoplay=1" 97></iframe>`; 98 this.insertAdjacentHTML('beforeend', iframeHTML); 99 this.classList.add('ltv-activated'); 100 } 101} 102// Register custome element 103customElements.define('lite-vimeo', LiteVimeo); 104 105/** 106 * Add a <link rel={preload | preconnect} ...> to the head 107 */ 108function addPrefetch(kind, url, as) { 109 const linkElem = document.createElement('link'); 110 linkElem.rel = kind; 111 linkElem.href = url; 112 if (as) { 113 linkElem.as = as; 114 } 115 linkElem.crossorigin = true; 116 document.head.appendChild(linkElem); 117} 118 119function canUseWebP() { 120 var elem = document.createElement('canvas'); 121 122 if (elem.getContext && elem.getContext('2d')) { 123 // was able or not to get WebP representation 124 return elem.toDataURL('image/webp').indexOf('data:image/webp') === 0; 125 } 126 127 // very old browser like IE 8, canvas not supported 128 return false; 129} 130 131/** 132 * Get the thumbnail dimensions to use for a given player size. 133 * 134 * @param {Object} options 135 * @param {number} options.width The width of the player 136 * @param {number} options.height The height of the player 137 * @return {Object} The width and height 138 */ 139function getThumbnailDimensions({ width, height }) { 140 let roundedWidth = width; 141 let roundedHeight = height; 142 143 // If the original width is a multiple of 320 then we should 144 // not round up. This is to keep the native image dimensions 145 // so that they match up with the actual frames from the video. 146 // 147 // For example 640x360, 960x540, 1280x720, 1920x1080 148 // 149 // Round up to nearest 100 px to improve cacheability at the 150 // CDN. For example, any width between 601 pixels and 699 151 // pixels will render the thumbnail at 700 pixels width. 152 if (roundedWidth % 320 !== 0) { 153 roundedWidth = Math.ceil(width / 100) * 100; 154 roundedHeight = Math.round((roundedWidth / width) * height); 155 } 156 157 return { 158 width: roundedWidth, 159 height: roundedHeight 160 }; 161}
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.