Last active
April 22, 2022 15:09
-
-
Save husseyexplores/470e7a55034bb721fef486f716f90e49 to your computer and use it in GitHub Desktop.
[Stamped Rating Badge] Custom element Api fallback
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
<script> | |
!function(){let t=document.getElementById("stamped-main-widget");let e=!1,a=["scroll","mousedown","wheel","DOMMouseScroll","mousewheel","keyup","touchmove"];function r(){e=!1}function i(i){if(!t)return;let n=t.getAttribute("data-offset")||1,o=t.getAttribute("data-offset-mobile")||1,d=i||t.getAttribute("data-animation-duration"),c=window.innerWidth<768?Number(o):Number(n);!function(t,i){const n=document.scrollingElement||document.documentElement,o=n.scrollTop,d=t-o,c=+new Date;e=!0,a.forEach(t=>{document.documentElement.addEventListener(t,r)}),function l(){if(!e)return;const s=+new Date-c;var u,m,p;n.scrollTop=parseInt((u=s,m=o,p=d,(u/=i/2)<1?p/2*u*u+m:-p/2*(--u*(u-2)-1)+m)),s<i?requestAnimationFrame(l):(n.scrollTop=t,e=!1,a.forEach(t=>{document.documentElement.removeEventListener(t,r)}))}()}(function(t){let e=t.getBoundingClientRect();return{top:e.top+window.scrollY,left:e.left+window.scrollX}}(t).top-c,d||700)}function n(t){return t&&"stamped-rating-badge"===t.localName&&t.hasAttribute("data-revalidate")}function o(t){const e=t instanceof NodeList?Array.from(t).filter(n):Array.isArray(t)?t.filter(n):n(t)?t:Array.from(document.querySelectorAll("stamped-rating-badge[data-revalidate]"));if(!e.length)return Promise.resolve([]);const a=e.reduce((t,a,r)=>{let i=a.getAttribute("data-product-id");return i?t[i]=a:e.splice(r,1),t},{}),r=e[0],i=r.getAttribute("data-stamped-api-key"),o=r.getAttribute("data-stamped-sid");if(!i||!o)return console.warn("`apiKey` or `sId` is missing..."),Promise.resolve([]);const d=e.map(t=>t.getAttribute("data-product-id"));return(c={apiKey:i,sId:o,productIds:d},fetch("https://stamped.io/api/widget/badges",{method:"POST",headers:{accept:"application/json","content-type":"application/json"},body:JSON.stringify({apiKey:c.apiKey,sId:c.sId,productIds:c.productIds.map(t=>({productId:t}))})}).then(t=>t.json())).then(t=>(t.forEach(t=>{!function(t,e){if(!t||!e)return;t.querySelectorAll("[data-rating]").forEach(t=>{t.style.setProperty("--rating",e.rating)});let a=e.count,r=1===a?"review":0===a?"Write a review":"reviews";t.querySelectorAll("[data-rating-count]").forEach(t=>{t.setAttribute("data-rating-count",e.count),t.textContent=(0===a?"":a)+" "+r}),t.removeAttribute("data-revalidate"),"true"===t.getAttribute("aria-hidden")&&a>0&&(t.removeAttribute("aria-hidden"),t.style.display="")}(a[t.productId],t)}),t));var c}window.StampedScrollToMainWidget=i,window.StampedCustomRatingBadgesFetch=o,o(),t&&document.querySelectorAll("[data-scroll-to-main-widget]").forEach(e=>{!function(e){e.hasAttribute("data-scroll-to-main-widget")&&e.addEventListener("click",function(){let a=e.getAttribute("data-main-widget-collapse-el"),r=e.getAttribute("data-main-widget-collapse-trigger"),n=e.getAttribute("data-main-widget-collapse-open-class");if(a&&n){let e=t.closest(a),i=e&&e.querySelector(r);e&&(e.classList.contains(n)||i&&i.classList.contains(n)||(i||e).click())}i()})}(e)})}(); | |
</script> | |
{%- comment -%} | |
<script> | |
;(function () { | |
let MAIN_WIDGET_EL = document.getElementById('stamped-main-widget') | |
function isMobile() { | |
return window.innerWidth < 768 | |
} | |
function absoluteOffset(element) { | |
let rect = element.getBoundingClientRect() | |
return { top: rect.top + window.scrollY, left: rect.left + window.scrollX } | |
} | |
// t = current time | |
// b = start value | |
// c = change in value | |
// d = duration | |
function easeInOutQuad(t, b, c, d) { | |
t /= d / 2 | |
if (t < 1) return (c / 2) * t * t + b | |
t-- | |
return (-c / 2) * (t * (t - 2) - 1) + b | |
} | |
let isAnimating = false | |
let events = [ | |
'scroll', | |
'mousedown', | |
'wheel', | |
'DOMMouseScroll', | |
'mousewheel', | |
'keyup', | |
'touchmove', | |
] | |
function stopAnimationFn() { | |
isAnimating = false | |
} | |
function animateScrollTo(to, duration) { | |
const doc = document.scrollingElement || document.documentElement, | |
start = doc.scrollTop, | |
change = to - start, | |
startDate = +new Date() | |
isAnimating = true | |
events.forEach(event => { | |
document.documentElement.addEventListener(event, stopAnimationFn) | |
}) | |
function animateScroll() { | |
if (!isAnimating) return | |
const currentDate = +new Date() | |
const currentTime = currentDate - startDate | |
doc.scrollTop = parseInt( | |
easeInOutQuad(currentTime, start, change, duration), | |
) | |
if (currentTime < duration) { | |
requestAnimationFrame(animateScroll) | |
} else { | |
doc.scrollTop = to | |
isAnimating = false | |
events.forEach(event => { | |
document.documentElement.removeEventListener(event, stopAnimationFn) | |
}) | |
} | |
} | |
animateScroll() | |
} | |
function StampedScrollToMainWidget(duration) { | |
if (!MAIN_WIDGET_EL) { | |
return | |
} | |
let desktopOffset = MAIN_WIDGET_EL.getAttribute('data-offset') || 1 | |
let mobileOffset = MAIN_WIDGET_EL.getAttribute('data-offset-mobile') || 1 | |
let _duration = | |
duration || MAIN_WIDGET_EL.getAttribute('data-animation-duration') | |
let offset = isMobile() ? Number(mobileOffset) : Number(desktopOffset) | |
animateScrollTo( | |
absoluteOffset(MAIN_WIDGET_EL).top - offset, | |
_duration || 700, | |
) | |
} | |
window.StampedScrollToMainWidget = StampedScrollToMainWidget | |
// StampedScrollToMainWidget(4000) | |
//- --------------------------------------------------- | |
//- --------------------------------------------------- | |
//- --------------------------------------------------- | |
/** | |
* | |
* @param el {HTMLElement} | |
*/ | |
function addScrollToMainWidgetListener(el) { | |
let scrollToMainWidget = el.hasAttribute('data-scroll-to-main-widget') | |
if (!scrollToMainWidget) { | |
return | |
} | |
el.addEventListener('click', function () { | |
let collapseQs = el.getAttribute('data-main-widget-collapse-el') | |
let collapseTriggerQs = el.getAttribute( | |
'data-main-widget-collapse-trigger', | |
) | |
let openClass = el.getAttribute('data-main-widget-collapse-open-class') | |
if (collapseQs && openClass) { | |
let collapseEl = MAIN_WIDGET_EL.closest(collapseQs) | |
let collapseTrigger = | |
collapseEl && collapseEl.querySelector(collapseTriggerQs) | |
if (collapseEl) { | |
let isOpen = | |
collapseEl.classList.contains(openClass) || | |
(collapseTrigger && collapseTrigger.classList.contains(openClass)) | |
if (!isOpen) { | |
;(collapseTrigger || collapseEl).click() | |
} | |
} | |
} | |
StampedScrollToMainWidget() | |
}) | |
} | |
function fetchStampedRating(options) { | |
return fetch('https://stamped.io/api/widget/badges', { | |
method: 'POST', | |
headers: { | |
accept: 'application/json', | |
'content-type': 'application/json', | |
}, | |
body: JSON.stringify({ | |
apiKey: options.apiKey, | |
sId: options.sId, | |
productIds: options.productIds.map(id => ({ productId: id })), | |
}), | |
}).then(r => r.json()) | |
} | |
/** | |
* | |
* @param element {HTMLElement} | |
* @param reviewJson | |
* @returns | |
*/ | |
function updateRatingDom(element, reviewJson) { | |
if (!element || !reviewJson) return | |
element.querySelectorAll('[data-rating]').forEach(el => { | |
el.style.setProperty('--rating', reviewJson.rating) | |
}) | |
let count = reviewJson.count | |
let ratingText = | |
count === 1 ? 'review' : count === 0 ? 'Write a review' : 'reviews' | |
element.querySelectorAll('[data-rating-count]').forEach(el => { | |
el.setAttribute('data-rating-count', reviewJson.count) | |
el.textContent = (count === 0 ? '' : count) + ' ' + ratingText | |
}) | |
element.removeAttribute('data-revalidate') | |
let isHidden = element.getAttribute('aria-hidden') === 'true' | |
if (isHidden && count > 0) { | |
element.removeAttribute('aria-hidden') | |
element.style.display = '' | |
} | |
} | |
function isRevalidateableNode(node) { | |
return ( | |
node && | |
node.localName === 'stamped-rating-badge' && | |
node.hasAttribute('data-revalidate') | |
) | |
} | |
/** | |
* | |
* @param {badges | badges[] | NodeList<badges> | undefined} Rating badge node(s). | |
* @returns | |
*/ | |
function fixRatingBadges(badges) { | |
const ratingBadges = | |
badges instanceof NodeList | |
? Array.from(badges).filter(isRevalidateableNode) | |
: Array.isArray(badges) | |
? badges.filter(isRevalidateableNode) | |
: isRevalidateableNode(badges) | |
? badges | |
: Array.from( | |
document.querySelectorAll('stamped-rating-badge[data-revalidate]'), | |
) | |
if (!ratingBadges.length) { | |
return Promise.resolve([]) | |
} | |
const ratingBadgesLookup = ratingBadges.reduce((acc, el, index) => { | |
let pid = el.getAttribute('data-product-id') | |
if (pid) { | |
acc[pid] = el | |
} else { | |
ratingBadges.splice(index, 1) | |
} | |
return acc | |
}, {}) | |
const firstEl = ratingBadges[0] | |
const apiKey = firstEl.getAttribute('data-stamped-api-key') | |
const sId = firstEl.getAttribute('data-stamped-sid') | |
if (!apiKey || !sId) { | |
console.warn('`apiKey` or `sId` is missing...') | |
return Promise.resolve([]) | |
} | |
const productIds = ratingBadges.map(el => | |
el.getAttribute('data-product-id'), | |
) | |
return fetchStampedRating({ apiKey, sId, productIds }).then(list => { | |
list.forEach(ratingJson => { | |
updateRatingDom(ratingBadgesLookup[ratingJson.productId], ratingJson) | |
}) | |
return list | |
}) | |
} | |
window.StampedCustomRatingBadgesFetch = fixRatingBadges | |
fixRatingBadges() | |
if (MAIN_WIDGET_EL) { | |
document.querySelectorAll('[data-scroll-to-main-widget]').forEach(el => { | |
addScrollToMainWidgetListener(el) | |
}) | |
} | |
})() | |
</script> | |
{%- endcomment -%} | |
<script> | |
;(function() { | |
function callback(mutations, obs) { | |
let addedNodes = [] | |
mutations.forEach(mut => { | |
if (mut.type == 'childList' && mut.addedNodes.length > 0) { | |
mut.addedNodes.forEach(n => { | |
if (n && n.querySelector) { | |
addedNodes.push(n) | |
} | |
}) | |
} | |
}) | |
let uniqBadges = new Set() | |
addedNodes.forEach(node => { | |
if (!node || !node.querySelectorAll) return | |
let badges = node.querySelectorAll('stamped-rating-badge[data-revalidate]') | |
if (!badges.length) return | |
badges.forEach(badge => { | |
uniqBadges.add(badge) | |
}) | |
}) | |
if (StampedCustomRatingBadgesFetch) { | |
StampedCustomRatingBadgesFetch(Array.from(uniqBadges)) | |
} | |
} | |
// if (observer) observer.disconnect() | |
let observer = new MutationObserver(callback) | |
observer.observe(document.body, { | |
childList: true, | |
subtree: true, | |
}) | |
})() | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment