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

refactor(modules): minify code without losing readability #303

Merged
merged 4 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 56 additions & 56 deletions modules/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,99 +9,99 @@
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
export const getTargetValue = (element) => element.getAttribute('data-rum-target') || element.getAttribute('href')
|| element.currentSrc || element.getAttribute('src') || element.dataset.action || element.action;
export const getTargetValue = (el) => el.getAttribute('data-rum-target') || el.getAttribute('href')
|| el.currentSrc || el.getAttribute('src') || el.dataset.action || el.action;

export const targetSelector = (element) => {
export const targetSelector = (el) => {
try {
if (!element) return undefined;
let value = getTargetValue(element);
if (!value && element.tagName !== 'A' && element.closest('a')) {
value = getTargetValue(element.closest('a'));
if (!el) return undefined;
let v = getTargetValue(el);
if (!v && el.tagName !== 'A' && el.closest('a')) {
v = getTargetValue(el.closest('a'));
}
if (value && !value.startsWith('https://')) {
if (v && !v.startsWith('https://')) {
// resolve relative links
value = new URL(value, window.location).href;
v = new URL(v, window.location).href;
}
return value;
return v;
/* c8 ignore next 3 */
} catch (error) {
return null;
}
};

function walk(element, checkFn) {
if (!element || element === document.body || element === document.documentElement) {
function walk(el, checkFn) {
if (!el || el === document.body || el === document.documentElement) {
return undefined;
}
const checkValue = checkFn(element);
return checkValue || walk(element.parentElement, checkFn);
return checkFn(el) || walk(el.parentElement, checkFn);
}

function isDialog(element) {
function isDialog(el) {
// doing it well
if (element.tagName === 'DIALOG') return true;
if (el.tagName === 'DIALOG') return true;
// making the best of it
if (element.getAttribute('role') === 'dialog') return true;
if (element.getAttribute('role') === 'alertdialog') return true;
if (element.getAttribute('aria-modal') === 'true') return true;
if (el.getAttribute('role') === 'dialog') return true;
if (el.getAttribute('role') === 'alertdialog') return true;
if (el.getAttribute('aria-modal') === 'true') return true;
// doing it wrong
const computedStyle = window.getComputedStyle(element);
return (computedStyle && computedStyle.position === 'fixed' && computedStyle.zIndex > 100);
const cs = window.getComputedStyle(el);
return (cs && cs.position === 'fixed' && cs.zIndex > 100);
}

function isButton(element) {
if (element.tagName === 'BUTTON') return true;
if (element.tagName === 'INPUT' && element.getAttribute('type') === 'button') return true;
if (element.tagName === 'A') {
const classes = Array.from(element.classList);
function isButton(el) {
if (el.tagName === 'BUTTON') return true;
if (el.tagName === 'INPUT' && el.getAttribute('type') === 'button') return true;
if (el.tagName === 'A') {
const classes = Array.from(el.classList);
return classes.some((className) => className.match(/button|cta/));
}
return element.getAttribute('role') === 'button';
return el.getAttribute('role') === 'button';
}

function getSourceContext(element) {
if (element.closest('form')) {
return `form${element.id ? `#${element.id}` : ''}`;
function getSourceContext(el) {
if (el.closest('form')) {
return `form${el.id ? `#${el.id}` : ''}`;
}
const block = element.closest('.block[data-block-name]');
const block = el.closest('.block[data-block-name]');
if (block) return `.${block.getAttribute('data-block-name')}`;
if (walk(element, isDialog)) return 'dialog';
if (element.closest('nav')) return 'nav';
if (element.closest('header')) return 'header';
if (element.closest('footer')) return 'footer';
if (element.closest('aside')) return 'aside';
return (walk(element, (e) => e.id && `#${e.id}`));
if (walk(el, isDialog)) return 'dialog';
if (el.closest('nav')) return 'nav';
if (el.closest('header')) return 'header';
if (el.closest('footer')) return 'footer';
if (el.closest('aside')) return 'aside';
return (walk(el, (e) => e.id && `#${e.id}`));
}

function getSourceElement(element) {
if (element.closest('form') && Array.from(element.closest('form').elements).includes(element)) {
return (element.tagName.toLowerCase()
+ (['INPUT', 'BUTTON'].includes(element.tagName)
? `[type='${element.getAttribute('type') || ''}']`
function getSourceElement(el) {
const f = el.closest('form');
if (f && Array.from(f.elements).includes(el)) {
return (el.tagName.toLowerCase()
+ (['INPUT', 'BUTTON'].includes(el.tagName)
? `[type='${el.getAttribute('type') || ''}']`
: ''));
}
if (walk(element, isButton)) return 'button';
return element.tagName.toLowerCase().match(/^(a|img|video)$/) && element.tagName.toLowerCase();
if (walk(el, isButton)) return 'button';
return el.tagName.toLowerCase().match(/^(a|img|video)$/) && el.tagName.toLowerCase();
}

function getSourceIdentifier(element) {
if (element.id) return `#${element.id}`;
if (element.getAttribute('data-block-name')) return `.${element.getAttribute('data-block-name')}`;
return (element.classList.length > 0 && `.${element.classList[0]}`);
function getSourceIdentifier(el) {
if (el.id) return `#${el.id}`;
if (el.getAttribute('data-block-name')) return `.${el.getAttribute('data-block-name')}`;
return (el.classList.length > 0 && `.${el.classList[0]}`);
}
export const sourceSelector = (element) => {
export const sourceSelector = (el) => {
try {
if (!element || element === document.body || element === document.documentElement) {
if (!el || el === document.body || el === document.documentElement) {
return undefined;
}
if (element.getAttribute('data-rum-source')) {
return element.getAttribute('data-rum-source');
if (el.getAttribute('data-rum-source')) {
return el.getAttribute('data-rum-source');
}
const context = getSourceContext(element.parentElement) || '';
const elementName = getSourceElement(element) || '';
const identifier = getSourceIdentifier(element) || '';
return `${context} ${elementName}${identifier}`.trim() || `"${element.textContent.substring(0, 10)}"`;
const ctx = getSourceContext(el.parentElement) || '';
const name = getSourceElement(el) || '';
const id = getSourceIdentifier(el) || '';
return `${ctx} ${name}${id}`.trim() || `"${el.textContent.substring(0, 10)}"`;
/* c8 ignore next 3 */
} catch (error) {
return null;
Expand Down
77 changes: 39 additions & 38 deletions modules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,13 @@ import { fflags } from './fflags.js';
const { sampleRUM, queue, isSelected } = (window.hlx && window.hlx.rum) ? window.hlx.rum
/* c8 ignore next */ : {};

const formSubmitListener = (e) => sampleRUM('formsubmit', { target: targetSelector(e.target), source: sourceSelector(e.target) });

// eslint-disable-next-line no-use-before-define, max-len
const blocksMutationObserver = window.MutationObserver ? new MutationObserver(blocksMutationsCallback)
/* c8 ignore next */ : {};
const blocksMO = window.MutationObserver ? new MutationObserver(blocksMCB)
/* c8 ignore next */ : {}; // blocks mutation observer

// eslint-disable-next-line no-use-before-define, max-len
const mediaMutationObserver = window.MutationObserver ? new MutationObserver(mediaMutationsCallback)
/* c8 ignore next */ : {};
const mediaMO = window.MutationObserver ? new MutationObserver(mediaMCB)
/* c8 ignore next */ : {}; // media mutation observer

function trackCheckpoint(checkpoint, data, t) {
const { weight, id } = window.hlx.rum;
Expand Down Expand Up @@ -132,10 +130,10 @@ function addNavigationTracking() {
};

new PerformanceObserver((list) => list
.getEntries().map((entry) => navigate(
.getEntries().map((e) => navigate(
window.hlx.referrer || document.referrer,
entry.type,
entry.redirectCount,
e.type,
e.redirectCount,
)))
.observe({ type: 'navigation', buffered: true });
}
Expand All @@ -144,16 +142,16 @@ function addLoadResourceTracking() {
const observer = new PerformanceObserver((list) => {
try {
list.getEntries()
.filter((entry) => !entry.responseStatus || entry.responseStatus < 400)
.filter((entry) => window.location.hostname === new URL(entry.name).hostname)
.filter((entry) => new URL(entry.name).pathname.match('.*(\\.plain\\.html$|\\.json|graphql|api)'))
.forEach((entry) => {
sampleRUM('loadresource', { source: entry.name, target: Math.round(entry.duration) });
.filter((e) => !e.responseStatus || e.responseStatus < 400)
.filter((e) => window.location.hostname === new URL(e.name).hostname)
.filter((e) => new URL(e.name).pathname.match('.*(\\.plain\\.html$|\\.json|graphql|api)'))
.forEach((e) => {
sampleRUM('loadresource', { source: e.name, target: Math.round(e.duration) });
});
list.getEntries()
.filter((entry) => entry.responseStatus === 404)
.forEach((entry) => {
sampleRUM('missingresource', { source: entry.name, target: entry.hostname });
.filter((e) => e.responseStatus === 404)
.forEach((e) => {
sampleRUM('missingresource', { source: e.name, target: e.hostname });
});
/* c8 ignore next 3 */
} catch (error) {
Expand All @@ -163,24 +161,26 @@ function addLoadResourceTracking() {
observer.observe({ type: 'resource', buffered: true });
}

function activateBlocksMutationObserver() {
if (!blocksMutationObserver || blocksMutationObserver.active) {
// activate blocks mutation observer
function activateBlocksMO() {
if (!blocksMO || blocksMO.active) {
return;
}
blocksMutationObserver.active = true;
blocksMutationObserver.observe(
blocksMO.active = true;
blocksMO.observe(
document.body,
// eslint-disable-next-line object-curly-newline
{ subtree: true, attributes: true, attributeFilter: ['data-block-status'] },
);
}

function activateMediaMutationObserver() {
if (!mediaMutationObserver || mediaMutationObserver.active) {
// activate media mutation observer
function activateMediaMO() {
if (!mediaMO || mediaMO.active) {
return;
}
mediaMutationObserver.active = true;
mediaMutationObserver.observe(
mediaMO.active = true;
mediaMO.observe(
document.body,
// eslint-disable-next-line object-curly-newline
{ subtree: true, attributes: false, childList: true },
Expand All @@ -192,16 +192,16 @@ function getIntersectionObsever(checkpoint) {
if (!window.IntersectionObserver) {
return null;
}
activateBlocksMutationObserver();
activateMediaMutationObserver();
activateBlocksMO();
activateMediaMO();
const observer = new IntersectionObserver((entries) => {
try {
entries
.filter((entry) => entry.isIntersecting)
.forEach((entry) => {
observer.unobserve(entry.target); // observe only once
const target = targetSelector(entry.target);
const source = sourceSelector(entry.target);
.filter((e) => e.isIntersecting)
.forEach((e) => {
observer.unobserve(e.target); // observe only once
const target = targetSelector(e.target);
const source = sourceSelector(e.target);
sampleRUM(checkpoint, { target, source });
});
/* c8 ignore next 3 */
Expand Down Expand Up @@ -233,19 +233,19 @@ function addViewMediaTracking(parent) {
}

function addFormTracking(parent) {
activateBlocksMutationObserver();
activateMediaMutationObserver();
activateBlocksMO();
activateMediaMO();
parent.querySelectorAll('form').forEach((form) => {
form.removeEventListener('submit', formSubmitListener); // listen only once
form.addEventListener('submit', formSubmitListener);
form.addEventListener('submit', (e) => sampleRUM('formsubmit', { target: targetSelector(e.target), source: sourceSelector(e.target) }), { once: true });
});
}

function addObserver(ck, fn, block) {
return DEFAULT_TRACKING_EVENTS.includes(ck) && fn(block);
}

function blocksMutationsCallback(mutations) {
// blocks mutation observer callback
function blocksMCB(mutations) {
// block specific mutations
mutations
.filter((m) => m.type === 'attributes' && m.attributeName === 'data-block-status')
Expand All @@ -256,7 +256,8 @@ function blocksMutationsCallback(mutations) {
});
}

function mediaMutationsCallback(mutations) {
// media mutation observer callback
function mediaMCB(mutations) {
// media mutations
mutations
.forEach((m) => {
Expand Down
12 changes: 6 additions & 6 deletions modules/martech.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function addCookieConsentTracking(sampleRUM) {
return;
}

let consentMutationObserver;
let consentMO; // consent mutation observer
const trackShowConsent = () => {
const otsdk = document.querySelector('body > div#onetrust-consent-sdk');
if (otsdk) {
Expand All @@ -28,8 +28,8 @@ export function addCookieConsentTracking(sampleRUM) {
} else {
sampleRUM('consent', { source: 'onetrust', target: 'show' });
}
if (consentMutationObserver) {
consentMutationObserver.disconnect();
if (consentMO) {
consentMO.disconnect();
}
return true;
}
Expand All @@ -38,11 +38,11 @@ export function addCookieConsentTracking(sampleRUM) {

if (!trackShowConsent()) {
// eslint-disable-next-line max-len
consentMutationObserver = window.MutationObserver
consentMO = window.MutationObserver
? new MutationObserver(trackShowConsent)
: /* c8 ignore next */ null;
if (consentMutationObserver) {
consentMutationObserver.observe(
if (consentMO) {
consentMO.observe(
document.body,
// eslint-disable-next-line object-curly-newline
{ attributes: false, childList: true, subtree: false },
Expand Down
8 changes: 5 additions & 3 deletions modules/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,30 @@
* governing permissions and limitations under the License.
*/

const { href } = window.location;

export const urlSanitizers = {
/**
* Returns the full url.
* If no url is provided, it defaults to window.location.href.
* @param {string} url (default: window.location.href) The url to sanitize
* @returns {string} The sanitized url
*/
full: (url = window.location.href) => new URL(url).toString(),
full: (url = href) => new URL(url).toString(),
/**
* Returns the origin of the provided url.
* If no url is provided, it defaults to window.location.href.
* @param {string} url (default: window.location.href) The url to sanitize
* @returns {string} The sanitized url
*/
origin: (url = window.location.href) => new URL(url).origin,
origin: (url = href) => new URL(url).origin,
/**
* Returns the sanitized url: the origin and the path (no query params or hash)
* If no url is provided, it defaults to window.location.href.
* @param {string} url (default: window.location.href) The url to sanitize
* @returns {string} The sanitized url
*/
path: (url = window.location.href) => {
path: (url = href) => {
const u = new URL(url);
return `${u.origin}${u.pathname}`;
},
Expand Down
Loading