Created
March 4, 2021 16:56
-
-
Save firestar300/a5d670357811dfaccf791f3c8613ac07 to your computer and use it in GitHub Desktop.
Transform native YouTube video player into a custom HTML markup
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.video { | |
position: relative; | |
display: block; | |
padding-bottom: 56.25%; | |
margin-bottom: 1rem; | |
img, | |
iframe, | |
&__play { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
} | |
img { | |
object-fit: cover; | |
} | |
&__play { | |
&::before { | |
@include pseudo__content; | |
position: absolute; | |
top: 50%; | |
left: 50%; | |
z-index: 10; | |
width: 88px; | |
height: 88px; | |
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 130 130'%3E%3Ccircle cx='65' cy='65' r='65' fill='%23fff' opacity='.3'/%3E%3Cpath fill='%23fff' fill-rule='evenodd' d='M45.6 47v36l38.8-18-38.8-18z' clip-rule='evenodd'/%3E%3C/svg%3E"); | |
background-size: 100% 100%; | |
transform: translate(-50%, -50%); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const $ = jQuery | |
class AbstractDomElement { | |
constructor(element, options) { | |
let oldInstance | |
// provide an explicit spaceName to prevent conflict after minification | |
// MaClass.nameSpace = 'MaClass' | |
this.constructor.nameSpace = this.constructor.nameSpace || this.constructor.name | |
const nameSpace = this.constructor.nameSpace | |
// if no spacename beapi, create it - avoid futur test | |
if (!element.beapi) { | |
element.beapi = {} | |
} | |
oldInstance = element.beapi[nameSpace] | |
if (oldInstance) { | |
console.warn( | |
'[AbstractDomElement] more than 1 class is initialised with the same name space on :', | |
element, | |
oldInstance | |
) | |
oldInstance._isNewInstance = false | |
return oldInstance | |
} | |
this._element = element | |
this._settings = $.extend(true, {}, this.constructor.defaults, options) | |
this._element.beapi[nameSpace] = this | |
this._isNewInstance = true | |
} | |
isNewInstance() { | |
return this._isNewInstance | |
} | |
destroy() { | |
this._element.beapi[this.constructor.nameSpace] = undefined | |
return this | |
} | |
static init(element, options) { | |
foreach(element, (el) => { | |
new this(el, options) | |
}) | |
return this | |
} | |
static hasInstance(element) { | |
const el = getDomElement(element) | |
return el && el.beapi && !!el.beapi[this.nameSpace] | |
} | |
static getInstance(element) { | |
const el = getDomElement(element) | |
return el && el.beapi ? el.beapi[this.nameSpace] : undefined | |
} | |
static destroy(element) { | |
this.foreach(element, (el) => { | |
if (el.beapi && el.beapi[this.nameSpace]) { | |
el.beapi[this.nameSpace].destroy() | |
} | |
}) | |
return this | |
} | |
static foreach(element, callback) { | |
foreach(element, (el) => { | |
if (el.beapi && el.beapi[this.nameSpace]) { | |
callback(el) | |
} | |
}) | |
return this | |
} | |
static initFromPreset() { | |
const preset = this.preset | |
let selector | |
for (selector in preset) { | |
this.init(selector, preset[selector]) | |
} | |
return this | |
} | |
static destroyFromPreset() { | |
const preset = this.preset | |
let selector | |
for (selector in preset) { | |
this.destroy(selector) | |
} | |
return this | |
} | |
} | |
// ---- | |
// utils | |
// ---- | |
function foreach(element, callback) { | |
const el = getDomElements(element) | |
let i | |
for (i = 0; i < el.length; i++) { | |
if (callback(el[i]) === false) break | |
} | |
} | |
function getDomElements(element) { | |
return typeof element === 'string' ? document.querySelectorAll(element) : element.length >= 0 ? element : [element] | |
} | |
function getDomElement(element) { | |
return getDomElements(element)[0] | |
} | |
// ---- | |
// export | |
// ---- | |
export default AbstractDomElement |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import AbstractDomElement from './AbstractDomElement' | |
/** | |
* Video Class | |
* @author Milan Ricoul | |
*/ | |
class Video extends AbstractDomElement { | |
constructor(element, options) { | |
var instance = super(element, options) | |
// avoid double init : | |
if (!instance.isNewInstance()) { | |
return instance | |
} | |
this.displayEmbed = this.displayEmbed.bind(this) | |
this.init() | |
} | |
/** | |
* Initialization | |
* @author Milan Ricoul | |
*/ | |
init() { | |
const el = this._element | |
this.wrapper = el | |
if (el.getAttribute('data-youtube-url')) { | |
this.embedUrl = el.getAttribute('data-youtube-url') | |
el.removeAttribute('data-youtube-url') | |
} else if (el.querySelector('iframe[src*="https://www.youtube.com/embed/"]')) { | |
this.embedUrl = el.querySelector('iframe[src*="https://www.youtube.com/embed/"]').getAttribute('src') | |
} else if (el.tagName === 'IFRAME') { | |
this.embedUrl = el.getAttribute('src') | |
const parent = el.parentNode | |
const width = el.getAttribute('width') | |
this.wrapper = document.createElement('div') | |
this.wrapper.classList.add('video') | |
this.wrapper.insertAdjacentHTML( | |
'afterbegin', | |
`<img data-sizes="auto" data-src="https://i.ytimg.com/vi/${this.youtubeParser( | |
this.embedUrl | |
)}/hqdefault.jpg" class="lazyload"/>` | |
) | |
parent.appendChild(this.wrapper) | |
parent.removeChild(el) | |
// Apply width of the former iframe | |
if (typeof width !== 'undefined') { | |
parent.style.maxWidth = `${width}px` | |
} | |
} else { | |
return false | |
} | |
console.log(this._settings) | |
this.wrapper.insertAdjacentHTML( | |
'afterbegin', | |
` | |
<button type="button" class="video__play btn btn--txt" aria-label="Lire la vidéo"> | |
<span class="sr-only">Lire la vidéo</span> | |
</button> | |
` | |
) | |
this.wrapper.querySelector('.video__play').addEventListener('click', this.displayEmbed) | |
} | |
/** | |
* Display video embed | |
* @author Milan Ricoul | |
*/ | |
displayEmbed() { | |
this.wrapper.innerHTML = ` | |
<iframe src="${ | |
this.embedUrl.includes('?') ? `${this.embedUrl}&autoplay=1&rel=0` : `${this.embedUrl}?autoplay=1&rel=0` | |
}" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> | |
` | |
} | |
/** | |
* Get the YouTube id from an url | |
* @param {String} url YouTube url | |
* @returns {String} | |
*/ | |
youtubeParser(url) { | |
var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/ | |
var match = url.match(regExp) | |
return match && match[7].length === 11 ? match[7] : false | |
} | |
} | |
Video.defaults = {} | |
Video.preset = { | |
'.video': {}, | |
'iframe[src*="https://www.youtube.com/embed/"]': {}, | |
} | |
export default Video |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment