@fynd-design-engineering/fynd-one-v2 3.4.63 → 3.4.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accordians/dropdown.js +1 -95
- package/dist/accordians/index.js +1 -391
- package/dist/cms-listing/index.js +1 -24
- package/dist/filters/clear-search.js +1 -32
- package/dist/filters/konnect.js +1 -165
- package/dist/filters/show-count.js +1 -66
- package/dist/form/country-dropdown.css +1 -160
- package/dist/form/cs-gated-redirection.js +1 -40
- package/dist/form/download-file.js +1 -70
- package/dist/form/validation.css +1 -1019
- package/dist/form/validation.js +7 -10611
- package/dist/global/anchor-scroll.js +1 -174
- package/dist/global/auth.js +1 -87
- package/dist/global/chat.js +1 -185
- package/dist/global/console-links.js +1 -89
- package/dist/global/contact-popup.js +2 -83
- package/dist/global/css/in-page-embed.css +1 -1043
- package/dist/global/css/in-project-settings.css +1 -173
- package/dist/global/css/temp.css +1 -89
- package/dist/global/custom-bg-video.js +1 -40
- package/dist/global/footer-accordion.js +1 -44
- package/dist/global/lazy-loader.js +1 -135
- package/dist/global/loader.js +2 -166
- package/dist/global/media-card.js +1 -166
- package/dist/global/miscellaneous.js +1 -136
- package/dist/global/number-count.js +1 -82
- package/dist/global/popup-video.js +1 -276
- package/dist/global/progressive-scroll.js +1 -222
- package/dist/global/responsive-video.js +1 -321
- package/dist/global/style.css +1 -1065
- package/dist/global/video-card.js +1 -50
- package/dist/hacktimus/2025.js +1 -177
- package/dist/hacktimus/styles.css +1 -91
- package/dist/home/index.js +1 -17
- package/dist/marquee/index.js +1 -3104
- package/dist/marquee/marquee-swiper.js +1 -36
- package/dist/navigation/announcement/index.js +1 -5169
- package/dist/navigation/context-menu/index.js +1 -31
- package/dist/navigation/desktop/index.js +1 -4603
- package/dist/navigation/initialization.js +1 -602
- package/dist/navigation/main.js +1 -4911
- package/dist/navigation/mobile/index.js +1 -286
- package/dist/navigation/scroll/index.js +1 -62
- package/dist/navigation/secondary-navigation/index.js +1 -437
- package/dist/navigation/style.css +1 -154
- package/dist/navigation/temp.css +0 -2
- package/dist/navigation/theme.css +1 -69
- package/dist/navigation-v2/index.js +1 -4990
- package/dist/navigation-v2/styles.css +1 -233
- package/dist/others/feature-detail.js +1 -75
- package/dist/others/geolocation.js +1 -50
- package/dist/others/hero-aniamtion.js +1 -53
- package/dist/others/hero-india-animation-2.js +1 -70
- package/dist/others/hero-india-animation.js +1 -93
- package/dist/others/home-solution-tab.js +1 -115
- package/dist/others/storefront-chat/index.js +1 -487
- package/dist/others/storefront-chat/styles.css +1 -107
- package/dist/playbook-2026/hero-reveal.js +1 -47
- package/dist/playbook-2026/index.js +1 -536
- package/dist/playbook-2026/styles.css +1 -110
- package/dist/posthog-and-ga/attributes.js +1 -190
- package/dist/posthog-and-ga/main.js +1 -528
- package/dist/progressive-scroll/index.js +1 -147
- package/dist/quick-fix/reload.js +1 -22
- package/dist/seo/schema.js +1 -465
- package/dist/slider/freescroll.js +1 -34
- package/dist/test/sample.js +1 -15
- package/dist/testimonials/index.js +1 -2654
- package/dist/timeline/index.js +1 -160
- package/dist/timeline/style.css +1 -42
- package/dist/tracking/custom-id.js +1 -75
- package/dist/tracking/fill-form-fields.js +1 -238
- package/dist/tracking/form-tracker.js +1 -146
- package/dist/tracking/page-categories.js +1 -20
- package/dist/tracking/user-journey.js +1 -839
- package/dist/tracking/utm-links.js +1 -194
- package/dist/utils/sample.js +1 -17
- package/dist/validations/localhost.js +1 -221
- package/package.json +1 -1
|
@@ -1,222 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
(() => {
|
|
3
|
-
// bin/live-reload.js
|
|
4
|
-
if (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1") {
|
|
5
|
-
new EventSource(`${"http://localhost:3000"}/esbuild`).addEventListener(
|
|
6
|
-
"change",
|
|
7
|
-
() => location.reload()
|
|
8
|
-
);
|
|
9
|
-
} else {
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// src/global/progressive-scroll.ts
|
|
13
|
-
var GSAP = window.gsap;
|
|
14
|
-
var GSAPScrollTrigger = window.ScrollTrigger;
|
|
15
|
-
if (!GSAP || !GSAPScrollTrigger) {
|
|
16
|
-
console.warn(
|
|
17
|
-
"GSAP or ScrollTrigger is not available on window. Make sure they are loaded before this script."
|
|
18
|
-
);
|
|
19
|
-
} else {
|
|
20
|
-
GSAP.registerPlugin(GSAPScrollTrigger);
|
|
21
|
-
}
|
|
22
|
-
function moveElements(sourceSelector, targetSelector, warningMessage) {
|
|
23
|
-
const target = document.querySelector(targetSelector);
|
|
24
|
-
if (!target) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
const sources = document.querySelectorAll(sourceSelector);
|
|
28
|
-
if (sources.length === 0) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
sources.forEach((source) => {
|
|
32
|
-
try {
|
|
33
|
-
target.appendChild(source);
|
|
34
|
-
} catch (error) {
|
|
35
|
-
console.error("Error appending element", { source, target }, error);
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
function initScrollBlocks() {
|
|
40
|
-
moveElements(
|
|
41
|
-
"[fynd-sticky-source]",
|
|
42
|
-
"[fynd-sticky-target]",
|
|
43
|
-
"Warning: No element found with attribute fynd-sticky-target"
|
|
44
|
-
);
|
|
45
|
-
moveElements(
|
|
46
|
-
"[fynd-scroll-source]",
|
|
47
|
-
"[fynd-scroll-target]",
|
|
48
|
-
"Warning: No element found with attribute fynd-scroll-target"
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
function safeGetLocalStorageItem(key) {
|
|
52
|
-
try {
|
|
53
|
-
return window.localStorage.getItem(key);
|
|
54
|
-
} catch (error) {
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
function safeSetLocalStorageItem(key, value) {
|
|
59
|
-
try {
|
|
60
|
-
if (value === null) {
|
|
61
|
-
window.localStorage.removeItem(key);
|
|
62
|
-
} else {
|
|
63
|
-
window.localStorage.setItem(key, value);
|
|
64
|
-
}
|
|
65
|
-
} catch (error) {
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function initProgressiveScroll() {
|
|
69
|
-
const sections = document.querySelectorAll("[fynd-scroll-source]");
|
|
70
|
-
if (sections.length === 0) {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
let timeout;
|
|
74
|
-
let lastVisitedSection = null;
|
|
75
|
-
safeSetLocalStorageItem("lastVisitedSection", null);
|
|
76
|
-
function debouncedScrollTrigger(attributeValue) {
|
|
77
|
-
if (!attributeValue) {
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
if (timeout !== void 0) {
|
|
81
|
-
window.clearTimeout(timeout);
|
|
82
|
-
}
|
|
83
|
-
const scrollSections = document.querySelectorAll("[fynd-scroll-source]");
|
|
84
|
-
if (scrollSections.length === 0) return;
|
|
85
|
-
const first = scrollSections[0].getAttribute("fynd-scroll-source");
|
|
86
|
-
const last = scrollSections[scrollSections.length - 1].getAttribute(
|
|
87
|
-
"fynd-scroll-source"
|
|
88
|
-
);
|
|
89
|
-
const currentEl = document.querySelector(
|
|
90
|
-
`[fynd-scroll-source="${attributeValue}"]`
|
|
91
|
-
);
|
|
92
|
-
if (!currentEl) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
const currentVal = currentEl.getAttribute("fynd-scroll-source");
|
|
96
|
-
lastVisitedSection = safeGetLocalStorageItem("lastVisitedSection");
|
|
97
|
-
const currentNum = parseInt(currentVal || "", 10);
|
|
98
|
-
const firstNum = parseInt(first || "", 10);
|
|
99
|
-
const lastNum = parseInt(last || "", 10);
|
|
100
|
-
const lastVisitedNum = parseInt(lastVisitedSection || "", 10);
|
|
101
|
-
const atStart = currentNum === firstNum && lastVisitedNum === firstNum;
|
|
102
|
-
const atEnd = currentNum === lastNum && lastVisitedNum === lastNum;
|
|
103
|
-
if (atStart || atEnd) return;
|
|
104
|
-
timeout = window.setTimeout(() => {
|
|
105
|
-
updateStickyImage(attributeValue);
|
|
106
|
-
safeSetLocalStorageItem("lastVisitedSection", attributeValue);
|
|
107
|
-
}, 50);
|
|
108
|
-
}
|
|
109
|
-
sections.forEach((section) => {
|
|
110
|
-
const attr = section.getAttribute("fynd-scroll-source");
|
|
111
|
-
if (!attr) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
if (!GSAP || !GSAPScrollTrigger) return;
|
|
115
|
-
GSAPScrollTrigger.create({
|
|
116
|
-
trigger: section,
|
|
117
|
-
start: "top 50%",
|
|
118
|
-
end: "bottom 50%",
|
|
119
|
-
onEnter: () => debouncedScrollTrigger(attr),
|
|
120
|
-
onEnterBack: () => debouncedScrollTrigger(attr),
|
|
121
|
-
onLeave: () => debouncedScrollTrigger(attr),
|
|
122
|
-
onLeaveBack: () => debouncedScrollTrigger(attr)
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
function updateStickyImage(identifier) {
|
|
127
|
-
if (!identifier) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
const stickyImages = document.querySelectorAll("[fynd-sticky-source]");
|
|
131
|
-
if (stickyImages.length === 0) {
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
if (!GSAP) return;
|
|
135
|
-
GSAP.killTweensOf(stickyImages);
|
|
136
|
-
GSAP.set(stickyImages, { opacity: 0 });
|
|
137
|
-
const activeImage = document.querySelector(
|
|
138
|
-
`[fynd-sticky-source="${identifier}"]`
|
|
139
|
-
);
|
|
140
|
-
if (!activeImage) {
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
GSAP.to(activeImage, {
|
|
144
|
-
opacity: 1,
|
|
145
|
-
duration: 0.5,
|
|
146
|
-
ease: "power1.out"
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
function getScrollContainer() {
|
|
150
|
-
const containers = document.querySelectorAll("[fynd-scroll-container]");
|
|
151
|
-
if (containers.length === 0) {
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
if (!GSAP) return;
|
|
155
|
-
GSAP.to(containers, {
|
|
156
|
-
opacity: 1,
|
|
157
|
-
duration: 0.5,
|
|
158
|
-
ease: "power2.out",
|
|
159
|
-
delay: 0.5
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
function dynamiColorDesktop() {
|
|
163
|
-
const elements = document.querySelectorAll("[fynd-sticky-bg]");
|
|
164
|
-
if (elements.length === 0) {
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
elements.forEach((el) => {
|
|
168
|
-
const value = el.getAttribute("fynd-sticky-bg");
|
|
169
|
-
if (!value) {
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
const isHex = /^#([0-9A-F]{3}){1,2}$/i.test(value);
|
|
173
|
-
if (!isHex) {
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
el.style.backgroundColor = value;
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
function dynamicColorMobile() {
|
|
180
|
-
const element = document.querySelector("[fynd-sticky-bg]");
|
|
181
|
-
if (!element) {
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
const value = element.getAttribute("fynd-sticky-bg");
|
|
185
|
-
if (!value) {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
const isHex = /^#([0-9A-F]{3}){1,2}$/i.test(value);
|
|
189
|
-
if (!isHex) {
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
const cards = document.querySelectorAll("[fynd-card-bg-mobile]");
|
|
193
|
-
if (cards.length === 0) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
cards.forEach((c) => {
|
|
197
|
-
c.style.backgroundColor = value;
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
var desktopInitialized = false;
|
|
201
|
-
function handleResize() {
|
|
202
|
-
const width = window.innerWidth;
|
|
203
|
-
if (width > 991) {
|
|
204
|
-
if (!desktopInitialized) {
|
|
205
|
-
dynamiColorDesktop();
|
|
206
|
-
initScrollBlocks();
|
|
207
|
-
initProgressiveScroll();
|
|
208
|
-
getScrollContainer();
|
|
209
|
-
desktopInitialized = true;
|
|
210
|
-
}
|
|
211
|
-
} else {
|
|
212
|
-
dynamicColorMobile();
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
document.addEventListener("DOMContentLoaded", () => {
|
|
216
|
-
handleResize();
|
|
217
|
-
window.addEventListener("resize", () => {
|
|
218
|
-
handleResize();
|
|
219
|
-
});
|
|
220
|
-
});
|
|
221
|
-
})();
|
|
222
|
-
//# sourceMappingURL=progressive-scroll.js.map
|
|
1
|
+
"use strict";(()=>{var c=window.gsap,l=window.ScrollTrigger;!c||!l?console.warn("GSAP or ScrollTrigger is not available on window. Make sure they are loaded before this script."):c.registerPlugin(l);function y(t,e,r){let o=document.querySelector(e);if(!o)return;let i=document.querySelectorAll(t);i.length!==0&&i.forEach(n=>{try{o.appendChild(n)}catch(s){console.error("Error appending element",{source:n,target:o},s)}})}function v(){y("[fynd-sticky-source]","[fynd-sticky-target]","Warning: No element found with attribute fynd-sticky-target"),y("[fynd-scroll-source]","[fynd-scroll-target]","Warning: No element found with attribute fynd-scroll-target")}function b(t){try{return window.localStorage.getItem(t)}catch{return null}}function m(t,e){try{e===null?window.localStorage.removeItem(t):window.localStorage.setItem(t,e)}catch{}}function k(){let t=document.querySelectorAll("[fynd-scroll-source]");if(t.length===0)return;let e,r=null;m("lastVisitedSection",null);function o(i){if(!i)return;e!==void 0&&window.clearTimeout(e);let n=document.querySelectorAll("[fynd-scroll-source]");if(n.length===0)return;let s=n[0].getAttribute("fynd-scroll-source"),h=n[n.length-1].getAttribute("fynd-scroll-source"),u=document.querySelector(`[fynd-scroll-source="${i}"]`);if(!u)return;let E=u.getAttribute("fynd-scroll-source");r=b("lastVisitedSection");let d=parseInt(E||"",10),a=parseInt(s||"",10),f=parseInt(h||"",10),g=parseInt(r||"",10);d===a&&g===a||d===f&&g===f||(e=window.setTimeout(()=>{p(i),m("lastVisitedSection",i)},50))}t.forEach(i=>{let n=i.getAttribute("fynd-scroll-source");n&&(!c||!l||l.create({trigger:i,start:"top 50%",end:"bottom 50%",onEnter:()=>o(n),onEnterBack:()=>o(n),onLeave:()=>o(n),onLeaveBack:()=>o(n)}))})}function p(t){if(!t)return;let e=document.querySelectorAll("[fynd-sticky-source]");if(e.length===0||!c)return;c.killTweensOf(e),c.set(e,{opacity:0});let r=document.querySelector(`[fynd-sticky-source="${t}"]`);r&&c.to(r,{opacity:1,duration:.5,ease:"power1.out"})}function A(){let t=document.querySelectorAll("[fynd-scroll-container]");t.length!==0&&c&&c.to(t,{opacity:1,duration:.5,ease:"power2.out",delay:.5})}function L(){let t=document.querySelectorAll("[fynd-sticky-bg]");t.length!==0&&t.forEach(e=>{let r=e.getAttribute("fynd-sticky-bg");!r||!/^#([0-9A-F]{3}){1,2}$/i.test(r)||(e.style.backgroundColor=r)})}function T(){let t=document.querySelector("[fynd-sticky-bg]");if(!t)return;let e=t.getAttribute("fynd-sticky-bg");if(!e||!/^#([0-9A-F]{3}){1,2}$/i.test(e))return;let o=document.querySelectorAll("[fynd-card-bg-mobile]");o.length!==0&&o.forEach(i=>{i.style.backgroundColor=e})}var S=!1;function w(){window.innerWidth>991?S||(L(),v(),k(),A(),S=!0):T()}document.addEventListener("DOMContentLoaded",()=>{w(),window.addEventListener("resize",()=>{w()})});})();
|
|
@@ -1,321 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
(() => {
|
|
3
|
-
// bin/live-reload.js
|
|
4
|
-
if (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1") {
|
|
5
|
-
new EventSource(`${"http://localhost:3000"}/esbuild`).addEventListener(
|
|
6
|
-
"change",
|
|
7
|
-
() => location.reload()
|
|
8
|
-
);
|
|
9
|
-
} else {
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// src/global/responsive-video.ts
|
|
13
|
-
var RV_SELECTORS = {
|
|
14
|
-
wrapper: "[data-rv-wrapper]",
|
|
15
|
-
thumbnailDesktop: "[data-rv-thumbnail-desktop]",
|
|
16
|
-
thumbnailMobile: "[data-rv-thumbnail-mobile]"
|
|
17
|
-
};
|
|
18
|
-
var RV_ATTRS = {
|
|
19
|
-
hidden: "data-rv-hidden"
|
|
20
|
-
};
|
|
21
|
-
var RV_DEFAULTS = {
|
|
22
|
-
breakpoint: 992,
|
|
23
|
-
threshold: 0.25
|
|
24
|
-
};
|
|
25
|
-
var LOG_PREFIX = "[RVPlayer]";
|
|
26
|
-
function csvToArray(value) {
|
|
27
|
-
if (!value || !value.trim()) return [];
|
|
28
|
-
return value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
29
|
-
}
|
|
30
|
-
function parseSources(srcAttr, typeAttr, label, wrapperEl) {
|
|
31
|
-
const srcs = csvToArray(srcAttr);
|
|
32
|
-
const types = csvToArray(typeAttr);
|
|
33
|
-
if (srcs.length === 0) {
|
|
34
|
-
console.warn(`${LOG_PREFIX} No ${label} sources found on wrapper:`, wrapperEl);
|
|
35
|
-
return [];
|
|
36
|
-
}
|
|
37
|
-
if (types.length === 0) {
|
|
38
|
-
console.warn(`${LOG_PREFIX} No ${label} MIME types found on wrapper. Sources may not load correctly:`, wrapperEl);
|
|
39
|
-
}
|
|
40
|
-
if (srcs.length !== types.length) {
|
|
41
|
-
console.warn(
|
|
42
|
-
`${LOG_PREFIX} Mismatch: ${srcs.length} ${label} source(s) but ${types.length} type(s). Extra entries will be ignored:`,
|
|
43
|
-
wrapperEl
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
const srcLooksLikeMime = srcs.length > 0 && srcs.every((s) => /^(video|audio)\/\w+/.test(s));
|
|
47
|
-
const typeLooksLikeUrl = types.length > 0 && types.every((t) => /^https?:\/\//.test(t));
|
|
48
|
-
if (srcLooksLikeMime && typeLooksLikeUrl) {
|
|
49
|
-
console.warn(
|
|
50
|
-
`${LOG_PREFIX} Swapped ${label} attributes detected! data-rv-${label}-src contains MIME types and data-rv-${label}-type contains URLs. Auto-correcting:`,
|
|
51
|
-
wrapperEl
|
|
52
|
-
);
|
|
53
|
-
return types.map((url, i) => ({
|
|
54
|
-
src: url,
|
|
55
|
-
type: srcs[i] || ""
|
|
56
|
-
}));
|
|
57
|
-
}
|
|
58
|
-
return srcs.map((src, i) => ({
|
|
59
|
-
src,
|
|
60
|
-
type: types[i] || ""
|
|
61
|
-
}));
|
|
62
|
-
}
|
|
63
|
-
var RVPlayer = class {
|
|
64
|
-
constructor(wrapper) {
|
|
65
|
-
this.currentMode = null;
|
|
66
|
-
this.observer = null;
|
|
67
|
-
this.handlePlaying = () => {
|
|
68
|
-
this.setPostersHidden(true);
|
|
69
|
-
};
|
|
70
|
-
this.handleError = (e) => {
|
|
71
|
-
const target = e.target;
|
|
72
|
-
const tagName = target.tagName?.toLowerCase();
|
|
73
|
-
if (tagName === "source") {
|
|
74
|
-
const sourceEl = target;
|
|
75
|
-
console.warn(`${LOG_PREFIX} Failed to load source: "${sourceEl.src}" (${sourceEl.type || "no type"}):`, this.wrapper);
|
|
76
|
-
} else if (tagName === "video") {
|
|
77
|
-
const mediaError = target.error;
|
|
78
|
-
const errorMessages = {
|
|
79
|
-
1: "MEDIA_ERR_ABORTED \u2014 fetching was aborted",
|
|
80
|
-
2: "MEDIA_ERR_NETWORK \u2014 network error",
|
|
81
|
-
3: "MEDIA_ERR_DECODE \u2014 decoding error",
|
|
82
|
-
4: "MEDIA_ERR_SRC_NOT_SUPPORTED \u2014 source format not supported"
|
|
83
|
-
};
|
|
84
|
-
const message = mediaError ? errorMessages[mediaError.code] || `Unknown error (code ${mediaError.code})` : "Unknown error";
|
|
85
|
-
console.warn(`${LOG_PREFIX} Video error: ${message}:`, this.wrapper);
|
|
86
|
-
}
|
|
87
|
-
this.setPostersHidden(false);
|
|
88
|
-
};
|
|
89
|
-
this.wrapper = wrapper;
|
|
90
|
-
this.video = wrapper.querySelector("video");
|
|
91
|
-
this.posterDesktop = wrapper.querySelector(RV_SELECTORS.thumbnailDesktop);
|
|
92
|
-
this.posterMobile = wrapper.querySelector(RV_SELECTORS.thumbnailMobile);
|
|
93
|
-
if (!this.video) {
|
|
94
|
-
console.warn(`${LOG_PREFIX} No <video> element found inside wrapper. Skipping:`, wrapper);
|
|
95
|
-
this.config = { mobileSources: [], desktopSources: [], breakpoint: RV_DEFAULTS.breakpoint, threshold: RV_DEFAULTS.threshold };
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
this.enforceVideoAttributes();
|
|
99
|
-
if (!this.posterDesktop && !this.posterMobile) {
|
|
100
|
-
console.warn(`${LOG_PREFIX} No thumbnail images found. Users will see a black frame until video loads:`, wrapper);
|
|
101
|
-
} else {
|
|
102
|
-
if (!this.posterDesktop) {
|
|
103
|
-
console.warn(`${LOG_PREFIX} Missing [data-rv-thumbnail-desktop]. No fallback for desktop:`, wrapper);
|
|
104
|
-
}
|
|
105
|
-
if (!this.posterMobile) {
|
|
106
|
-
console.warn(`${LOG_PREFIX} Missing [data-rv-thumbnail-mobile]. No fallback for mobile:`, wrapper);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
const dataset = wrapper.dataset;
|
|
110
|
-
const breakpointRaw = parseInt(dataset.rvBreakpoint || "", 10);
|
|
111
|
-
const thresholdRaw = parseFloat(dataset.rvThreshold || "");
|
|
112
|
-
const breakpoint = Number.isFinite(breakpointRaw) && breakpointRaw > 0 ? breakpointRaw : RV_DEFAULTS.breakpoint;
|
|
113
|
-
const threshold = Number.isFinite(thresholdRaw) && thresholdRaw >= 0 && thresholdRaw <= 1 ? thresholdRaw : RV_DEFAULTS.threshold;
|
|
114
|
-
if (dataset.rvBreakpoint && breakpoint !== breakpointRaw) {
|
|
115
|
-
console.warn(`${LOG_PREFIX} Invalid breakpoint "${dataset.rvBreakpoint}". Using default (${RV_DEFAULTS.breakpoint}):`, wrapper);
|
|
116
|
-
}
|
|
117
|
-
if (dataset.rvThreshold && threshold !== thresholdRaw) {
|
|
118
|
-
console.warn(`${LOG_PREFIX} Invalid threshold "${dataset.rvThreshold}". Must be 0\u20131. Using default (${RV_DEFAULTS.threshold}):`, wrapper);
|
|
119
|
-
}
|
|
120
|
-
this.config = {
|
|
121
|
-
mobileSources: parseSources(dataset.rvMobileSrc, dataset.rvMobileType, "mobile", wrapper),
|
|
122
|
-
desktopSources: parseSources(dataset.rvDesktopSrc, dataset.rvDesktopType, "desktop", wrapper),
|
|
123
|
-
breakpoint,
|
|
124
|
-
threshold
|
|
125
|
-
};
|
|
126
|
-
this.init();
|
|
127
|
-
}
|
|
128
|
-
// ── Lifecycle ──────────────────────────────────────────
|
|
129
|
-
init() {
|
|
130
|
-
if (!this.video) return;
|
|
131
|
-
this.video.addEventListener("playing", this.handlePlaying);
|
|
132
|
-
this.video.addEventListener("error", this.handleError);
|
|
133
|
-
this.video.addEventListener("error", this.handleError, true);
|
|
134
|
-
this.applySources();
|
|
135
|
-
this.updatePosterVisibility();
|
|
136
|
-
this.observe();
|
|
137
|
-
}
|
|
138
|
-
destroy() {
|
|
139
|
-
if (this.observer) {
|
|
140
|
-
this.observer.disconnect();
|
|
141
|
-
this.observer = null;
|
|
142
|
-
}
|
|
143
|
-
if (this.video) {
|
|
144
|
-
this.video.removeEventListener("playing", this.handlePlaying);
|
|
145
|
-
this.video.removeEventListener("error", this.handleError);
|
|
146
|
-
this.video.removeEventListener("error", this.handleError, true);
|
|
147
|
-
this.video.pause();
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
// ── Event handlers (arrow fns to preserve `this`) ──────
|
|
151
|
-
/**
|
|
152
|
-
* Force muted, playsinline, loop, preload on the <video>.
|
|
153
|
-
* Webflow (and some CMSs) strip these attributes at publish time.
|
|
154
|
-
*/
|
|
155
|
-
enforceVideoAttributes() {
|
|
156
|
-
if (!this.video) return;
|
|
157
|
-
const required = [
|
|
158
|
-
{ attr: "muted", prop: "muted" },
|
|
159
|
-
{ attr: "playsinline" },
|
|
160
|
-
{ attr: "loop", prop: "loop" },
|
|
161
|
-
{ attr: "preload", value: "metadata" }
|
|
162
|
-
];
|
|
163
|
-
required.forEach(({ attr, prop, value }) => {
|
|
164
|
-
const hasAttr = this.video.hasAttribute(attr);
|
|
165
|
-
if (!hasAttr) {
|
|
166
|
-
console.warn(`${LOG_PREFIX} <video> missing "${attr}" \u2014 applying via JS:`, this.wrapper);
|
|
167
|
-
}
|
|
168
|
-
this.video.setAttribute(attr, value ?? "");
|
|
169
|
-
if (prop) {
|
|
170
|
-
this.video[prop] = true;
|
|
171
|
-
}
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
// ── Poster visibility ─────────────────────────────────
|
|
175
|
-
/** Ensure transition style is applied once on each poster */
|
|
176
|
-
initPosterStyles(img) {
|
|
177
|
-
if (img.dataset.rvStyled) return;
|
|
178
|
-
img.style.transition = "opacity 0.5s ease";
|
|
179
|
-
img.dataset.rvStyled = "true";
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Show the correct poster for the current viewport.
|
|
183
|
-
* Desktop poster hidden on mobile, mobile poster hidden on desktop.
|
|
184
|
-
* Called on init and on every resize/orientation change.
|
|
185
|
-
*/
|
|
186
|
-
updatePosterVisibility() {
|
|
187
|
-
const isMobile = window.innerWidth < this.config.breakpoint;
|
|
188
|
-
if (this.posterDesktop) {
|
|
189
|
-
this.initPosterStyles(this.posterDesktop);
|
|
190
|
-
this.posterDesktop.style.display = isMobile ? "none" : "block";
|
|
191
|
-
}
|
|
192
|
-
if (this.posterMobile) {
|
|
193
|
-
this.initPosterStyles(this.posterMobile);
|
|
194
|
-
this.posterMobile.style.display = isMobile ? "block" : "none";
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
setPostersHidden(hidden) {
|
|
198
|
-
const isMobile = window.innerWidth < this.config.breakpoint;
|
|
199
|
-
const activePoster = isMobile ? this.posterMobile : this.posterDesktop;
|
|
200
|
-
const inactivePoster = isMobile ? this.posterDesktop : this.posterMobile;
|
|
201
|
-
if (activePoster) {
|
|
202
|
-
this.initPosterStyles(activePoster);
|
|
203
|
-
activePoster.style.display = "block";
|
|
204
|
-
if (hidden) {
|
|
205
|
-
activePoster.style.opacity = "0";
|
|
206
|
-
activePoster.style.pointerEvents = "none";
|
|
207
|
-
activePoster.setAttribute(RV_ATTRS.hidden, "");
|
|
208
|
-
} else {
|
|
209
|
-
activePoster.style.opacity = "1";
|
|
210
|
-
activePoster.style.pointerEvents = "";
|
|
211
|
-
activePoster.removeAttribute(RV_ATTRS.hidden);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
if (inactivePoster) {
|
|
215
|
-
this.initPosterStyles(inactivePoster);
|
|
216
|
-
inactivePoster.style.display = "none";
|
|
217
|
-
inactivePoster.removeAttribute(RV_ATTRS.hidden);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
// ── Source management ─────────────────────────────────
|
|
221
|
-
applySources() {
|
|
222
|
-
if (!this.video) return;
|
|
223
|
-
const isMobile = window.innerWidth < this.config.breakpoint;
|
|
224
|
-
const mode = isMobile ? "mobile" : "desktop";
|
|
225
|
-
if (mode === this.currentMode) return;
|
|
226
|
-
this.currentMode = mode;
|
|
227
|
-
const sources = isMobile ? this.config.mobileSources : this.config.desktopSources;
|
|
228
|
-
if (sources.length === 0) {
|
|
229
|
-
console.warn(`${LOG_PREFIX} No ${mode} sources to apply. Video will not play:`, this.wrapper);
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
const existing = this.video.querySelectorAll("source");
|
|
233
|
-
existing.forEach((s) => s.remove());
|
|
234
|
-
sources.forEach(({ src, type }) => {
|
|
235
|
-
const sourceEl = document.createElement("source");
|
|
236
|
-
sourceEl.src = src;
|
|
237
|
-
if (type) sourceEl.type = type;
|
|
238
|
-
this.video.appendChild(sourceEl);
|
|
239
|
-
});
|
|
240
|
-
this.video.load();
|
|
241
|
-
this.setPostersHidden(false);
|
|
242
|
-
}
|
|
243
|
-
// ── Playback ──────────────────────────────────────────
|
|
244
|
-
safePlay() {
|
|
245
|
-
if (!this.video) return;
|
|
246
|
-
const playPromise = this.video.play();
|
|
247
|
-
if (playPromise && typeof playPromise.catch === "function") {
|
|
248
|
-
playPromise.catch((err) => {
|
|
249
|
-
if (err.name === "NotAllowedError") {
|
|
250
|
-
console.warn(`${LOG_PREFIX} Autoplay blocked by browser. Ensure video is muted:`, this.wrapper);
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
// ── IntersectionObserver ──────────────────────────────
|
|
256
|
-
observe() {
|
|
257
|
-
if (!this.video) return;
|
|
258
|
-
if (!("IntersectionObserver" in window)) {
|
|
259
|
-
console.warn(`${LOG_PREFIX} IntersectionObserver not supported. Video will autoplay immediately:`, this.wrapper);
|
|
260
|
-
this.safePlay();
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
this.observer = new IntersectionObserver(
|
|
264
|
-
(entries) => {
|
|
265
|
-
entries.forEach((entry) => {
|
|
266
|
-
if (entry.isIntersecting) {
|
|
267
|
-
this.safePlay();
|
|
268
|
-
} else {
|
|
269
|
-
this.video?.pause();
|
|
270
|
-
}
|
|
271
|
-
});
|
|
272
|
-
},
|
|
273
|
-
{ threshold: this.config.threshold }
|
|
274
|
-
);
|
|
275
|
-
this.observer.observe(this.video);
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
var RVManager = class {
|
|
279
|
-
constructor() {
|
|
280
|
-
this.instances = [];
|
|
281
|
-
this.resizeTimer = null;
|
|
282
|
-
this.init();
|
|
283
|
-
this.bindResize();
|
|
284
|
-
}
|
|
285
|
-
init() {
|
|
286
|
-
const wrappers = document.querySelectorAll(RV_SELECTORS.wrapper);
|
|
287
|
-
if (wrappers.length === 0) {
|
|
288
|
-
console.warn(`${LOG_PREFIX} No elements with [data-rv-wrapper] found on the page.`);
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
console.info(`${LOG_PREFIX} Initialising ${wrappers.length} video player(s).`);
|
|
292
|
-
wrappers.forEach((el) => {
|
|
293
|
-
this.instances.push(new RVPlayer(el));
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
bindResize() {
|
|
297
|
-
const handleResize = () => {
|
|
298
|
-
if (this.resizeTimer) clearTimeout(this.resizeTimer);
|
|
299
|
-
this.resizeTimer = setTimeout(() => {
|
|
300
|
-
this.instances.forEach((inst) => {
|
|
301
|
-
inst.applySources();
|
|
302
|
-
inst.updatePosterVisibility();
|
|
303
|
-
});
|
|
304
|
-
}, 150);
|
|
305
|
-
};
|
|
306
|
-
window.addEventListener("resize", handleResize);
|
|
307
|
-
window.addEventListener("orientationchange", handleResize);
|
|
308
|
-
}
|
|
309
|
-
/** Call to tear down all players (useful in SPA contexts) */
|
|
310
|
-
destroyAll() {
|
|
311
|
-
this.instances.forEach((inst) => inst.destroy());
|
|
312
|
-
this.instances = [];
|
|
313
|
-
}
|
|
314
|
-
};
|
|
315
|
-
if (document.readyState === "loading") {
|
|
316
|
-
document.addEventListener("DOMContentLoaded", () => new RVManager());
|
|
317
|
-
} else {
|
|
318
|
-
new RVManager();
|
|
319
|
-
}
|
|
320
|
-
})();
|
|
321
|
-
//# sourceMappingURL=responsive-video.js.map
|
|
1
|
+
"use strict";(()=>{var v={wrapper:"[data-rv-wrapper]",thumbnailDesktop:"[data-rv-thumbnail-desktop]",thumbnailMobile:"[data-rv-thumbnail-mobile]"},u={hidden:"data-rv-hidden"},d={breakpoint:992,threshold:.25},s="[RVPlayer]";function b(a){return!a||!a.trim()?[]:a.split(",").map(e=>e.trim()).filter(Boolean)}function m(a,e,t,i){let o=b(a),r=b(e);if(o.length===0)return console.warn(`${s} No ${t} sources found on wrapper:`,i),[];r.length===0&&console.warn(`${s} No ${t} MIME types found on wrapper. Sources may not load correctly:`,i),o.length!==r.length&&console.warn(`${s} Mismatch: ${o.length} ${t} source(s) but ${r.length} type(s). Extra entries will be ignored:`,i);let n=o.length>0&&o.every(l=>/^(video|audio)\/\w+/.test(l)),c=r.length>0&&r.every(l=>/^https?:\/\//.test(l));return n&&c?(console.warn(`${s} Swapped ${t} attributes detected! data-rv-${t}-src contains MIME types and data-rv-${t}-type contains URLs. Auto-correcting:`,i),r.map((l,p)=>({src:l,type:o[p]||""}))):o.map((l,p)=>({src:l,type:r[p]||""}))}var f=class{constructor(e){this.currentMode=null;this.observer=null;this.handlePlaying=()=>{this.setPostersHidden(!0)};this.handleError=e=>{let t=e.target,i=t.tagName?.toLowerCase();if(i==="source"){let o=t;console.warn(`${s} Failed to load source: "${o.src}" (${o.type||"no type"}):`,this.wrapper)}else if(i==="video"){let o=t.error,n=o?{1:"MEDIA_ERR_ABORTED \u2014 fetching was aborted",2:"MEDIA_ERR_NETWORK \u2014 network error",3:"MEDIA_ERR_DECODE \u2014 decoding error",4:"MEDIA_ERR_SRC_NOT_SUPPORTED \u2014 source format not supported"}[o.code]||`Unknown error (code ${o.code})`:"Unknown error";console.warn(`${s} Video error: ${n}:`,this.wrapper)}this.setPostersHidden(!1)};if(this.wrapper=e,this.video=e.querySelector("video"),this.posterDesktop=e.querySelector(v.thumbnailDesktop),this.posterMobile=e.querySelector(v.thumbnailMobile),!this.video){console.warn(`${s} No <video> element found inside wrapper. Skipping:`,e),this.config={mobileSources:[],desktopSources:[],breakpoint:d.breakpoint,threshold:d.threshold};return}this.enforceVideoAttributes(),!this.posterDesktop&&!this.posterMobile?console.warn(`${s} No thumbnail images found. Users will see a black frame until video loads:`,e):(this.posterDesktop||console.warn(`${s} Missing [data-rv-thumbnail-desktop]. No fallback for desktop:`,e),this.posterMobile||console.warn(`${s} Missing [data-rv-thumbnail-mobile]. No fallback for mobile:`,e));let t=e.dataset,i=parseInt(t.rvBreakpoint||"",10),o=parseFloat(t.rvThreshold||""),r=Number.isFinite(i)&&i>0?i:d.breakpoint,n=Number.isFinite(o)&&o>=0&&o<=1?o:d.threshold;t.rvBreakpoint&&r!==i&&console.warn(`${s} Invalid breakpoint "${t.rvBreakpoint}". Using default (${d.breakpoint}):`,e),t.rvThreshold&&n!==o&&console.warn(`${s} Invalid threshold "${t.rvThreshold}". Must be 0\u20131. Using default (${d.threshold}):`,e),this.config={mobileSources:m(t.rvMobileSrc,t.rvMobileType,"mobile",e),desktopSources:m(t.rvDesktopSrc,t.rvDesktopType,"desktop",e),breakpoint:r,threshold:n},this.init()}init(){this.video&&(this.video.addEventListener("playing",this.handlePlaying),this.video.addEventListener("error",this.handleError),this.video.addEventListener("error",this.handleError,!0),this.applySources(),this.updatePosterVisibility(),this.observe())}destroy(){this.observer&&(this.observer.disconnect(),this.observer=null),this.video&&(this.video.removeEventListener("playing",this.handlePlaying),this.video.removeEventListener("error",this.handleError),this.video.removeEventListener("error",this.handleError,!0),this.video.pause())}enforceVideoAttributes(){if(!this.video)return;[{attr:"muted",prop:"muted"},{attr:"playsinline"},{attr:"loop",prop:"loop"},{attr:"preload",value:"metadata"}].forEach(({attr:t,prop:i,value:o})=>{this.video.hasAttribute(t)||console.warn(`${s} <video> missing "${t}" \u2014 applying via JS:`,this.wrapper),this.video.setAttribute(t,o??""),i&&(this.video[i]=!0)})}initPosterStyles(e){e.dataset.rvStyled||(e.style.transition="opacity 0.5s ease",e.dataset.rvStyled="true")}updatePosterVisibility(){let e=window.innerWidth<this.config.breakpoint;this.posterDesktop&&(this.initPosterStyles(this.posterDesktop),this.posterDesktop.style.display=e?"none":"block"),this.posterMobile&&(this.initPosterStyles(this.posterMobile),this.posterMobile.style.display=e?"block":"none")}setPostersHidden(e){let t=window.innerWidth<this.config.breakpoint,i=t?this.posterMobile:this.posterDesktop,o=t?this.posterDesktop:this.posterMobile;i&&(this.initPosterStyles(i),i.style.display="block",e?(i.style.opacity="0",i.style.pointerEvents="none",i.setAttribute(u.hidden,"")):(i.style.opacity="1",i.style.pointerEvents="",i.removeAttribute(u.hidden))),o&&(this.initPosterStyles(o),o.style.display="none",o.removeAttribute(u.hidden))}applySources(){if(!this.video)return;let e=window.innerWidth<this.config.breakpoint,t=e?"mobile":"desktop";if(t===this.currentMode)return;this.currentMode=t;let i=e?this.config.mobileSources:this.config.desktopSources;if(i.length===0){console.warn(`${s} No ${t} sources to apply. Video will not play:`,this.wrapper);return}this.video.querySelectorAll("source").forEach(r=>r.remove()),i.forEach(({src:r,type:n})=>{let c=document.createElement("source");c.src=r,n&&(c.type=n),this.video.appendChild(c)}),this.video.load(),this.setPostersHidden(!1)}safePlay(){if(!this.video)return;let e=this.video.play();e&&typeof e.catch=="function"&&e.catch(t=>{t.name==="NotAllowedError"&&console.warn(`${s} Autoplay blocked by browser. Ensure video is muted:`,this.wrapper)})}observe(){if(this.video){if(!("IntersectionObserver"in window)){console.warn(`${s} IntersectionObserver not supported. Video will autoplay immediately:`,this.wrapper),this.safePlay();return}this.observer=new IntersectionObserver(e=>{e.forEach(t=>{t.isIntersecting?this.safePlay():this.video?.pause()})},{threshold:this.config.threshold}),this.observer.observe(this.video)}}},h=class{constructor(){this.instances=[];this.resizeTimer=null;this.init(),this.bindResize()}init(){let e=document.querySelectorAll(v.wrapper);if(e.length===0){console.warn(`${s} No elements with [data-rv-wrapper] found on the page.`);return}console.info(`${s} Initialising ${e.length} video player(s).`),e.forEach(t=>{this.instances.push(new f(t))})}bindResize(){let e=()=>{this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=setTimeout(()=>{this.instances.forEach(t=>{t.applySources(),t.updatePosterVisibility()})},150)};window.addEventListener("resize",e),window.addEventListener("orientationchange",e)}destroyAll(){this.instances.forEach(e=>e.destroy()),this.instances=[]}};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>new h):new h;})();
|