Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Release] Stage to Main #2821

Merged
merged 9 commits into from
Sep 5, 2024
4 changes: 4 additions & 0 deletions libs/blocks/global-navigation/global-navigation.css
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,10 @@ header.global-navigation {
background-color: var(--feds-background-link--hover);
}

.feds-utilities .unav-comp-profile .secondary-button{
line-height: inherit;
}

#feds-googleLogin {
position: absolute;
top: 100%;
Expand Down
4 changes: 2 additions & 2 deletions libs/blocks/global-navigation/global-navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -322,15 +322,15 @@ class Gnav {
isDesktop.addEventListener('change', closeAllDropdowns);
}, 'Error in global navigation init', 'errorType=error,module=gnav');

ims = async () => loadIms()
ims = async () => (window.adobeIMS?.initialized ? this.imsReady() : loadIms()
.then(() => this.imsReady())
.catch((e) => {
if (e?.message === 'IMS timeout') {
window.addEventListener('onImsLibInstance', () => this.imsReady());
return;
}
lanaLog({ message: 'GNAV: Error with IMS', e, tags: 'errorType=info,module=gnav' });
});
}));

decorateTopNav = () => {
this.elements.mobileToggle = this.decorateToggle();
Expand Down
7 changes: 5 additions & 2 deletions libs/blocks/merch/merch.js
Original file line number Diff line number Diff line change
Expand Up @@ -364,14 +364,16 @@ async function openExternalModal(url, getModal) {
});
}

const isInternalModal = (url) => /\/fragments\//.test(url);

export async function openModal(e, url, offerType) {
e.preventDefault();
e.stopImmediatePropagation();
const { getModal } = await import('../modal/modal.js');
await import('../modal/modal.merch.js');
const offerTypeClass = offerType === OFFER_TYPE_TRIAL ? 'twp' : 'crm';
let modal;
if (/\/fragments\//.test(url)) {
if (isInternalModal(url)) {
const fragmentPath = url.split(/hlx.(page|live)/).pop();
modal = await openFragmentModal(fragmentPath, getModal);
} else {
Expand All @@ -398,7 +400,8 @@ export async function getModalAction(offers, options) {
const columnName = (offerType === OFFER_TYPE_TRIAL) ? FREE_TRIAL_PATH : BUY_NOW_PATH;
let url = checkoutLinkConfig[columnName];
if (!url) return undefined;
url = localizeLink(checkoutLinkConfig[columnName]);
url = isInternalModal(url)
? localizeLink(checkoutLinkConfig[columnName]) : checkoutLinkConfig[columnName];
return { url, handler: (e) => openModal(e, url, offerType) };
}

Expand Down
56 changes: 56 additions & 0 deletions libs/blocks/vimeo/vimeo.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,59 @@
position: relative;
padding-bottom: 56.25%;
}

lite-vimeo {
aspect-ratio: 16 / 9;
background-color: #000;
position: relative;
display: block;
contain: content;
background-position: center center;
background-size: cover;
cursor: pointer;
}

lite-vimeo > .ltv-playbtn {
font-size: 10px;
padding: 0;
width: 6.5em;
height: 4em;
background: rgb(23, 35, 34, 75%);
z-index: 1;
opacity: .8;
border-radius: .5em;
transition: opacity .2s ease-out, background .2s ease-out;
outline: 0;
border: 0;
cursor: pointer;
}

lite-vimeo:hover > .ltv-playbtn {
background-color: rgb(0, 173, 239);
opacity: 1;
}

lite-vimeo > .ltv-playbtn::before {
content: '';
border-style: solid;
border-width: 10px 0 10px 20px;
border-color: transparent transparent transparent #fff;
}

lite-vimeo > .ltv-playbtn,
lite-vimeo > .ltv-playbtn::before {
position: absolute;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
}

lite-vimeo.ltv-activated {
cursor: unset;
}

lite-vimeo.ltv-activated::before,
lite-vimeo.ltv-activated > .ltv-playbtn {
opacity: 0;
pointer-events: none;
}
89 changes: 72 additions & 17 deletions libs/blocks/vimeo/vimeo.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,80 @@
import { createIntersectionObserver, createTag, isInTextNode } from '../../utils/utils.js';
// part of the code is an optimized version of lite-vimeo-embed -> https://github.com/luwes/lite-vimeo-embed
import { replaceKey } from '../../features/placeholders.js';
import { createIntersectionObserver, createTag, getConfig, isInTextNode, loadLink } from '../../utils/utils.js';

export default function init(a) {
if (isInTextNode(a)) return;
const embedVimeo = () => {
const url = new URL(a.href);
let src = url.href;
if (url.hostname !== 'player.vimeo.com') {
const video = url.pathname.split('/')[1];
src = `https://player.vimeo.com/video/${video}?app_id=122963`;
}
const iframe = createTag('iframe', {
src,
style: 'border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;',
class LiteVimeo extends HTMLElement {
static preconnected = false;

connectedCallback() {
this.isMobile = navigator.userAgent.includes('Mobi');
this.videoId = this.getAttribute('videoid');
this.setupThumbnail();
this.setupPlayButton();
this.addEventListener('pointerover', LiteVimeo.warmConnections, { once: true });
this.addEventListener('click', this.addIframe);
}

static warmConnections() {
if (LiteVimeo.preconnected) return;
LiteVimeo.preconnected = true;
['player.vimeo.com',
'i.vimeocdn.com',
'f.vimeocdn.com',
'fresnel.vimeocdn.com',
].forEach((url) => loadLink(`https://${url}`, { rel: 'preconnect' }));
}

setupThumbnail() {
const { width, height } = this.getBoundingClientRect();
const roundedWidth = Math.min(Math.ceil(width / 100) * 100, 1920);
const roundedHeight = Math.round((roundedWidth / width) * height);

fetch(`https://vimeo.com/api/v2/video/${this.videoId}.json`)
.then((response) => response.json())
.then((data) => {
const thumbnailUrl = data[0]?.thumbnail_large?.replace(/-d_[\dx]+$/i, `-d_${roundedWidth}x${roundedHeight}`);
this.style.backgroundImage = `url("${thumbnailUrl}")`;

Check warning on line 36 in libs/blocks/vimeo/vimeo.js

View check run for this annotation

Codecov / codecov/patch

libs/blocks/vimeo/vimeo.js#L35-L36

Added lines #L35 - L36 were not covered by tests
})
.catch((e) => {
window.lana.log(`Error fetching Vimeo thumbnail: ${e}`, { tags: 'errorType=info,module=vimeo' });

Check warning on line 39 in libs/blocks/vimeo/vimeo.js

View check run for this annotation

Codecov / codecov/patch

libs/blocks/vimeo/vimeo.js#L39

Added line #L39 was not covered by tests
});
}

async setupPlayButton() {
const playBtnEl = createTag('button', {
type: 'button',
'aria-label': `${await replaceKey('play-video', getConfig())}`,
class: 'ltv-playbtn',
});
this.append(playBtnEl);
}

addIframe() {
if (this.classList.contains('ltv-activated')) return;
this.classList.add('ltv-activated');
const iframeEl = createTag('iframe', {
style: 'border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute; background-color: #000;',
frameborder: '0',
allow: 'autoplay; fullscreen; picture-in-picture',
allowfullscreen: 'true',
title: 'Content from Vimeo',
loading: 'lazy',
allow: 'accelerometer; fullscreen; autoplay; encrypted-media; gyroscope; picture-in-picture',
allowFullscreen: true,
src: `https://player.vimeo.com/video/${encodeURIComponent(this.videoId)}?autoplay=1&muted=${this.isMobile ? 1 : 0}`,
});
const wrapper = createTag('div', { class: 'embed-vimeo' }, iframe);
this.insertAdjacentElement('afterend', iframeEl);
iframeEl.addEventListener('load', () => iframeEl.focus(), { once: true });
this.remove();
}
}

export default async function init(a) {
if (isInTextNode(a)) return;
if (!customElements.get('lite-vimeo')) customElements.define('lite-vimeo', LiteVimeo);

const embedVimeo = () => {
const url = new URL(a.href);
const videoid = url.pathname.split('/')[url.hostname === 'player.vimeo.com' ? 2 : 1];
const liteVimeo = createTag('lite-vimeo', { videoid });
const wrapper = createTag('div', { class: 'embed-vimeo' }, liteVimeo);
a.parentElement.replaceChild(wrapper, a);
};

Expand Down
55 changes: 55 additions & 0 deletions libs/blocks/youtube/youtube.css
Original file line number Diff line number Diff line change
@@ -1 +1,56 @@
@import url('../../styles/iframe.css');

lite-youtube {
top: 0;
left: 0;
width: 100%;
height: 100%;
position: absolute;
cursor: pointer;
}

lite-youtube > .lty-playbtn {
display: block;
width: 68px;
height: 48px;
position: absolute;
cursor: pointer;
transform: translate3d(-50%, -50%, 0);
top: 50%;
left: 50%;
z-index: 1;
background-color: transparent;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 48"><path d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z" fill="red"/><path d="M45 24 27 14v20" fill="white"/></svg>');
filter: grayscale(100%);
transition: filter .1s cubic-bezier(0, 0, 0.2, 1);
border: none;
}

lite-youtube:hover > .lty-playbtn,
lite-youtube .lty-playbtn:focus {
filter: none;
}

lite-youtube.lyt-activated {
cursor: unset;
}

lite-youtube.lyt-activated::before,
lite-youtube.lyt-activated > .lty-playbtn {
opacity: 0;
pointer-events: none;
}

.lyt-visually-hidden {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}

.dark-background {
background-color: #000;
}
105 changes: 89 additions & 16 deletions libs/blocks/youtube/youtube.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,109 @@
import { createIntersectionObserver, isInTextNode } from '../../utils/utils.js';
// part of the code is an optimized version of lite-youtube-embed -> https://github.com/paulirish/lite-youtube-embed
import { createIntersectionObserver, createTag, isInTextNode, loadLink } from '../../utils/utils.js';

class LiteYTEmbed extends HTMLElement {
connectedCallback() {
this.isMobile = navigator.userAgent.includes('Mobi');
this.videoId = this.getAttribute('videoid');
const playBtnEl = createTag('button', { type: 'button', class: 'lty-playbtn' });
this.append(playBtnEl);
this.playLabel = this.getAttribute('playlabel') || 'Play';
this.style.backgroundImage = `url("https://i.ytimg.com/vi/${this.videoId}/hqdefault.jpg")`;
this.style.backgroundSize = 'cover';
this.style.backgroundPosition = 'center';
const playBtnLabelEl = createTag('span', { class: 'lyt-visually-hidden' });
playBtnLabelEl.textContent = this.playLabel;
playBtnEl.append(playBtnLabelEl);
this.addEventListener('pointerover', LiteYTEmbed.warmConnections, { once: true });
this.addEventListener('click', this.addIframe);
this.needsYTApiForAutoplay = navigator.vendor.includes('Apple') || this.isMobile;
}

static warmConnections() {
if (LiteYTEmbed.preconnected) return;
LiteYTEmbed.preconnected = true;
['www.youtube-nocookie.com',
'www.google.com',
'googleads.g.doubleclick.net',
'static.doubleclick.net',
].forEach((url) => loadLink(`https://${url}`, { rel: 'preconnect' }));
}

static loadYouTubeAPI() {
return new Promise((resolve) => {
if (window.YT?.Player) {
resolve();
return;
}

Check warning on line 37 in libs/blocks/youtube/youtube.js

View check run for this annotation

Codecov / codecov/patch

libs/blocks/youtube/youtube.js#L35-L37

Added lines #L35 - L37 were not covered by tests
const tag = createTag('script', { src: 'https://www.youtube.com/iframe_api' });
window.onYouTubeIframeAPIReady = resolve;
document.head.appendChild(tag);
});
}

async addIframe() {
if (this.classList.contains('lyt-activated')) return;

this.classList.add('lyt-activated');
const params = new URLSearchParams(this.getAttribute('params') || []);
params.append('autoplay', '1');
params.append('playsinline', '1');
if (this.isMobile) params.append('mute', '1');

if (this.needsYTApiForAutoplay) {
await LiteYTEmbed.loadYouTubeAPI();
await new Promise((resolve) => { window.YT.ready(resolve); });
// eslint-disable-next-line
new window.YT.Player(this, {
videoId: this.videoId,
playerVars: Object.fromEntries(params),
allow: 'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture',
allowfullscreen: true,
title: this.playLabel,
});

Check warning on line 63 in libs/blocks/youtube/youtube.js

View check run for this annotation

Codecov / codecov/patch

libs/blocks/youtube/youtube.js#L55-L63

Added lines #L55 - L63 were not covered by tests
} else {
const iframeEl = createTag('iframe', {
src: `https://www.youtube-nocookie.com/embed/${encodeURIComponent(this.videoId)}?${params.toString()}`,
allowFullscreen: true,
allow: 'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture',
title: this.playLabel,
});
this.insertAdjacentElement('afterend', iframeEl);
iframeEl.focus();
this.remove();
}
}
}

export default async function init(a) {
if (!customElements.get('lite-youtube')) customElements.define('lite-youtube', LiteYTEmbed);

export default function init(a) {
const embedVideo = () => {
if (isInTextNode(a) || !a.origin?.includes('youtu')) return;
const title = !a.textContent.includes('http') ? a.textContent : 'Youtube Video';
const searchParams = new URLSearchParams(a.search);
const id = searchParams.get('v') || a.pathname.split('/').pop();
searchParams.delete('v');
const src = `https://www.youtube.com/embed/${id}?${searchParams.toString()}`;
const embedHTML = `
<div class="milo-video">
<iframe src="${src}" class="youtube"
webkitallowfullscreen mozallowfullscreen allowfullscreen
allow="encrypted-media; accelerometer; gyroscope; picture-in-picture"
scrolling="no"
id="player-${id}"
title="${title}">
</iframe>
</div>`;
a.insertAdjacentHTML('afterend', embedHTML);
const liteYTElement = createTag('lite-youtube', { videoid: id, playlabel: title });

if (searchParams.toString()) liteYTElement.setAttribute('params', searchParams.toString());

const ytContainer = createTag('div', { class: 'milo-video dark-background' }, liteYTElement);
a.insertAdjacentElement('afterend', ytContainer);
a.remove();

if (document.readyState === 'complete') {
/* eslint-disable-next-line no-underscore-dangle */
// eslint-disable-next-line no-underscore-dangle
window._satellite?.track('trackYoutube');
} else {
document.addEventListener('readystatechange', () => {
if (document.readyState === 'complete') {
/* eslint-disable-next-line no-underscore-dangle */
// eslint-disable-next-line no-underscore-dangle

Check warning on line 101 in libs/blocks/youtube/youtube.js

View check run for this annotation

Codecov / codecov/patch

libs/blocks/youtube/youtube.js#L101

Added line #L101 was not covered by tests
window._satellite?.track('trackYoutube');
}
});
}
};

createIntersectionObserver({ el: a, callback: embedVideo });
}
Loading
Loading