@widelab-nc/widelab 1.1.34 → 1.1.36
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/index.js +2 -2
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
- package/src/index.js +324 -114
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -260,6 +260,39 @@ if (infoBar) {
|
|
|
260
260
|
});
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
// Safe new version that uses the same classes and structure
|
|
266
|
+
window.customCursorTextUpdate = function(el) {
|
|
267
|
+
const cursorEl = document.querySelector('.custom_cursor_text');
|
|
268
|
+
if (!cursorEl) return;
|
|
269
|
+
|
|
270
|
+
const defaultText = cursorEl.dataset.default || '';
|
|
271
|
+
|
|
272
|
+
const getText = (node) =>
|
|
273
|
+
node.getAttribute('widecursortext') || node.getAttribute('wideCursorText') || '';
|
|
274
|
+
|
|
275
|
+
const activate = () => {
|
|
276
|
+
cursorEl.textContent = getText(el);
|
|
277
|
+
document.documentElement.classList.add('has-custom-cursor');
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
const maybeDeactivate = (ev) => {
|
|
281
|
+
const to = ev.relatedTarget;
|
|
282
|
+
// Don't deactivate if moving between elements that also use the custom cursor
|
|
283
|
+
if (to && to.closest && to.closest('[wide="customCursor"]')) return;
|
|
284
|
+
|
|
285
|
+
cursorEl.textContent = defaultText;
|
|
286
|
+
document.documentElement.classList.remove('has-custom-cursor');
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
el.addEventListener('pointerenter', activate);
|
|
290
|
+
el.addEventListener('pointerleave', maybeDeactivate);
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
|
|
263
296
|
// Hero animation on load
|
|
264
297
|
window.heroAnimationOnLoad = function(e) {
|
|
265
298
|
const videoMask = e.querySelector('.hero_headline_ract-mask');
|
|
@@ -627,6 +660,52 @@ window.reviewsSlider = function(e) {
|
|
|
627
660
|
});
|
|
628
661
|
}
|
|
629
662
|
|
|
663
|
+
// Partner slider
|
|
664
|
+
window.partnerSlider = function (e) {
|
|
665
|
+
// Keep the same querySelector for consistency with teamSlider
|
|
666
|
+
const teamList = e.querySelector('.team_collection_list');
|
|
667
|
+
|
|
668
|
+
// Initialize Splide with drag restored
|
|
669
|
+
const splide = new Splide(e, {
|
|
670
|
+
type: 'slide',
|
|
671
|
+
fixedWidth: '31.5%',
|
|
672
|
+
padding: { left: '2.5rem', right: 0 },
|
|
673
|
+
focus: 0,
|
|
674
|
+
gap: 0,
|
|
675
|
+
pagination: false,
|
|
676
|
+
omitEnd: true,
|
|
677
|
+
arrows: false,
|
|
678
|
+
drag: true, // restored dragging
|
|
679
|
+
easing: 'cubic-bezier(0.83, 0, 0.17, 1)',
|
|
680
|
+
snap: true,
|
|
681
|
+
classes: {
|
|
682
|
+
pagination: 'splide__pagination facts-pagination partner-bullets',
|
|
683
|
+
page: 'splide__pagination__page facts-page',
|
|
684
|
+
},
|
|
685
|
+
breakpoints: {
|
|
686
|
+
992: { fixedWidth: '40%', padding: { left: '1.75rem' }, drag: 'free', snap: false },
|
|
687
|
+
560: { fixedWidth: '75%', padding: { left: '1.375rem' }, drag: 'free', snap: false },
|
|
688
|
+
},
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
splide.mount();
|
|
692
|
+
|
|
693
|
+
// Removed: click-to-next handler
|
|
694
|
+
|
|
695
|
+
// GSAP in-view animation
|
|
696
|
+
gsap.from(e, {
|
|
697
|
+
scrollTrigger: {
|
|
698
|
+
trigger: e,
|
|
699
|
+
start: 'top bottom',
|
|
700
|
+
end: 'bottom bottom',
|
|
701
|
+
scrub: 1,
|
|
702
|
+
once: true,
|
|
703
|
+
},
|
|
704
|
+
x: '10%',
|
|
705
|
+
opacity: 0,
|
|
706
|
+
ease: 'linear',
|
|
707
|
+
});
|
|
708
|
+
};
|
|
630
709
|
// Element padding change on scroll
|
|
631
710
|
window.elementPaddingChange = function(e) {
|
|
632
711
|
gsap.to(e, {
|
|
@@ -967,149 +1046,251 @@ window.badgeColorChange = function(e) {
|
|
|
967
1046
|
});
|
|
968
1047
|
}
|
|
969
1048
|
|
|
1049
|
+
// Single entry you call from x-init
|
|
1050
|
+
window.clientFilters = function () {
|
|
1051
|
+
// Prevent double initialization if Alpine re-mounts
|
|
1052
|
+
if (window.__clientFiltersInitialized) return;
|
|
1053
|
+
window.__clientFiltersInitialized = true;
|
|
1054
|
+
|
|
1055
|
+
// --- Config ---
|
|
1056
|
+
const FIELDS = ["industry", "country", "services"];
|
|
1057
|
+
const SEL = {
|
|
1058
|
+
dropdown: '[fs-cmsfilter-element="dropdown"]',
|
|
1059
|
+
dropdownHolder: ".dropdown-holder",
|
|
1060
|
+
dropdownTitle: '[filters-clients_dropdown-field="tag-name-title"], .filters-clients_dropdown-field',
|
|
1061
|
+
tagNumber: '[fs-cmsfilter-element="tag-number"]',
|
|
1062
|
+
dynItem: ".w-dyn-item",
|
|
1063
|
+
checkboxWrap: ".w-checkbox",
|
|
1064
|
+
checkboxInput: 'input[type="checkbox"]',
|
|
1065
|
+
webflowChecked: "w--redirected-checked",
|
|
1066
|
+
fsActive: "fs-cmsfilter_active",
|
|
1067
|
+
listContainer: ".collection-list",
|
|
1068
|
+
count: ".count",
|
|
1069
|
+
crossIcon: ".cross-icon",
|
|
1070
|
+
clearButton: ".clear-button",
|
|
1071
|
+
activeDropdown: "active-dropdown",
|
|
1072
|
+
};
|
|
970
1073
|
|
|
971
|
-
//
|
|
972
|
-
|
|
973
|
-
function
|
|
1074
|
+
// --- Utils ---
|
|
1075
|
+
function $(s, ctx = document) { return ctx.querySelector(s); }
|
|
1076
|
+
function $all(s, ctx = document) { return Array.from(ctx.querySelectorAll(s)); }
|
|
1077
|
+
function debounce(fn, ms) { let t; return (...a)=>{clearTimeout(t); t=setTimeout(()=>fn(...a), ms);} }
|
|
1078
|
+
function textClean(el){ return (el?.textContent || "").trim(); }
|
|
1079
|
+
|
|
1080
|
+
// Wait until Finsweet cmsfilter is ready (query params applied, classes toggled)
|
|
1081
|
+
function waitForCmsFilter() {
|
|
1082
|
+
return new Promise((resolve) => {
|
|
1083
|
+
const w = window;
|
|
1084
|
+
w.fsAttributes = w.fsAttributes || [];
|
|
1085
|
+
// already initialized?
|
|
1086
|
+
try {
|
|
1087
|
+
const exists = (w.fsAttributes.instances || []).some(i => i.name === "cmsfilter");
|
|
1088
|
+
if (exists) return resolve();
|
|
1089
|
+
} catch(e){}
|
|
1090
|
+
w.fsAttributes.push(["cmsfilter", function(){ resolve(); }]);
|
|
1091
|
+
});
|
|
1092
|
+
}
|
|
974
1093
|
|
|
975
|
-
|
|
1094
|
+
// Remember original texts for labels and toggles
|
|
1095
|
+
function hydrateOriginalTexts() {
|
|
1096
|
+
FIELDS.forEach((field) => {
|
|
1097
|
+
$all(`span[fs-cmsfilter-field="${field}"]`).forEach((span) => {
|
|
1098
|
+
if (!span.dataset.originalText) {
|
|
1099
|
+
span.dataset.originalText = textClean(span);
|
|
1100
|
+
}
|
|
1101
|
+
});
|
|
1102
|
+
});
|
|
1103
|
+
$all(SEL.dropdownHolder).forEach((holder) => {
|
|
1104
|
+
const toggle = $(SEL.dropdownTitle, holder);
|
|
1105
|
+
if (toggle && !toggle.dataset.defaultText) {
|
|
1106
|
+
toggle.dataset.defaultText = textClean(toggle);
|
|
1107
|
+
}
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
976
1110
|
|
|
977
|
-
|
|
1111
|
+
// Count matching results per value and sort UI items by count
|
|
1112
|
+
function updateCheckboxCounts(excludeField = null) {
|
|
1113
|
+
FIELDS.forEach((field) => {
|
|
978
1114
|
if (field === excludeField) return;
|
|
979
1115
|
|
|
980
|
-
const
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
checkbox.dataset.originalText = originalText;
|
|
1116
|
+
const spans = $all(`span[fs-cmsfilter-field="${field}"]`);
|
|
1117
|
+
spans.forEach((span) => {
|
|
1118
|
+
const originalText = span.dataset.originalText || textClean(span);
|
|
1119
|
+
span.dataset.originalText = originalText;
|
|
985
1120
|
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
if (div
|
|
990
|
-
matchedCount++;
|
|
991
|
-
}
|
|
1121
|
+
// Count visible matches in results
|
|
1122
|
+
let matched = 0;
|
|
1123
|
+
$all(`div[fs-cmsfilter-field="${field}"]`).forEach((div) => {
|
|
1124
|
+
if (textClean(div) === originalText) matched++;
|
|
992
1125
|
});
|
|
993
1126
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
countSpan
|
|
998
|
-
|
|
1127
|
+
// Ensure "(n)" bubble
|
|
1128
|
+
let countSpan = span.nextElementSibling;
|
|
1129
|
+
if (!countSpan || !countSpan.classList.contains("count")) {
|
|
1130
|
+
countSpan = document.createElement("span");
|
|
1131
|
+
countSpan.className = "count";
|
|
1132
|
+
span.insertAdjacentElement("afterend", countSpan);
|
|
999
1133
|
}
|
|
1000
|
-
countSpan.textContent = `(${
|
|
1134
|
+
countSpan.textContent = `(${matched})`;
|
|
1001
1135
|
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
} else {
|
|
1006
|
-
parentDiv.classList.remove('empty-category');
|
|
1007
|
-
}
|
|
1136
|
+
// Toggle empty-category on dyn item
|
|
1137
|
+
const dyn = span.closest(SEL.dynItem);
|
|
1138
|
+
if (dyn) dyn.classList.toggle("empty-category", matched === 0);
|
|
1008
1139
|
});
|
|
1009
1140
|
|
|
1010
|
-
|
|
1141
|
+
// Sort items in this field's collection-list by count desc
|
|
1142
|
+
const anySpan = document.querySelector(`span[fs-cmsfilter-field="${field}"]`);
|
|
1143
|
+
if (anySpan) {
|
|
1144
|
+
const list = anySpan.closest(SEL.listContainer);
|
|
1145
|
+
if (list) {
|
|
1146
|
+
const items = Array.from(list.children);
|
|
1147
|
+
items.sort((a, b) => {
|
|
1148
|
+
const ca = parseInt((a.querySelector(SEL.count)?.textContent || "").replace(/[()]/g, "")) || 0;
|
|
1149
|
+
const cb = parseInt((b.querySelector(SEL.count)?.textContent || "").replace(/[()]/g, "")) || 0;
|
|
1150
|
+
return cb - ca;
|
|
1151
|
+
});
|
|
1152
|
+
items.forEach((it) => list.appendChild(it));
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1011
1155
|
});
|
|
1012
1156
|
}
|
|
1013
1157
|
|
|
1014
|
-
|
|
1158
|
+
// Collect selected label names within a dropdown holder
|
|
1159
|
+
function getSelectedNames(holder) {
|
|
1160
|
+
const labels = $all(`${SEL.dynItem} ${SEL.checkboxWrap}, ${SEL.checkboxWrap}`, holder);
|
|
1161
|
+
return labels
|
|
1162
|
+
.filter((label) => {
|
|
1163
|
+
if (label.classList.contains(SEL.fsActive)) return true; // Finsweet
|
|
1164
|
+
const wbox = label.querySelector(".w-checkbox-input");
|
|
1165
|
+
if (wbox && wbox.classList.contains(SEL.webflowChecked)) return true; // Webflow styled
|
|
1166
|
+
const input = label.querySelector(SEL.checkboxInput);
|
|
1167
|
+
return !!(input && input.checked); // Native
|
|
1168
|
+
})
|
|
1169
|
+
.map((label) => {
|
|
1170
|
+
const span = label.querySelector('[fs-cmsfilter-field]');
|
|
1171
|
+
return (span && (span.getAttribute('data-original-text') || textClean(span))) || "";
|
|
1172
|
+
})
|
|
1173
|
+
.filter(Boolean);
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
// Update dropdown button label (first selected + +N), class states and numeric tag
|
|
1177
|
+
function updateDropdownTitle(holder) {
|
|
1178
|
+
const toggle = $(SEL.dropdownTitle, holder);
|
|
1179
|
+
if (!toggle) return;
|
|
1180
|
+
|
|
1181
|
+
const defaults = toggle.dataset.defaultText || textClean(toggle);
|
|
1182
|
+
const names = getSelectedNames(holder);
|
|
1183
|
+
|
|
1184
|
+
// Persist "first selected" per dropdown (dataset)
|
|
1185
|
+
if (!holder.dataset.firstSelected) {
|
|
1186
|
+
holder.dataset.firstSelected = names[0] || "";
|
|
1187
|
+
} else if (names.length && !names.includes(holder.dataset.firstSelected)) {
|
|
1188
|
+
holder.dataset.firstSelected = names[0];
|
|
1189
|
+
} else if (!names.length) {
|
|
1190
|
+
holder.dataset.firstSelected = "";
|
|
1191
|
+
}
|
|
1015
1192
|
|
|
1016
|
-
|
|
1017
|
-
|
|
1193
|
+
let display = defaults;
|
|
1194
|
+
if (names.length === 1) {
|
|
1195
|
+
display = names[0];
|
|
1196
|
+
} else if (names.length > 1) {
|
|
1197
|
+
display = `${holder.dataset.firstSelected || names[0]} +${names.length - 1}`;
|
|
1198
|
+
}
|
|
1199
|
+
toggle.textContent = display;
|
|
1018
1200
|
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
const countB = parseInt((b.querySelector('.count')?.textContent || '').replace(/[()]/g, '')) || 0;
|
|
1022
|
-
return countB - countA;
|
|
1023
|
-
});
|
|
1201
|
+
holder.classList.toggle(SEL.activeDropdown, names.length > 0);
|
|
1202
|
+
toggle.classList.toggle(SEL.activeDropdown, names.length > 0);
|
|
1024
1203
|
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1204
|
+
const tagNum = $(SEL.tagNumber, holder);
|
|
1205
|
+
if (tagNum) {
|
|
1206
|
+
tagNum.textContent = names.length > 1 ? `+${names.length - 1}` : "";
|
|
1207
|
+
}
|
|
1028
1208
|
}
|
|
1029
1209
|
|
|
1030
|
-
|
|
1210
|
+
function updateAllDropdownTitles() {
|
|
1211
|
+
$all(SEL.dropdownHolder).forEach(updateDropdownTitle);
|
|
1212
|
+
}
|
|
1031
1213
|
|
|
1032
|
-
function
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1214
|
+
function toggleClearButton() {
|
|
1215
|
+
const anyActive = !!$(`.${SEL.activeDropdown}`);
|
|
1216
|
+
const btn = $(SEL.clearButton);
|
|
1217
|
+
if (btn) btn.style.display = anyActive ? "block" : "none";
|
|
1036
1218
|
}
|
|
1037
1219
|
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1220
|
+
// Unified UI refresh
|
|
1221
|
+
const refreshUI = debounce(function (excludeField = null) {
|
|
1222
|
+
updateCheckboxCounts(excludeField);
|
|
1223
|
+
updateAllDropdownTitles();
|
|
1224
|
+
toggleClearButton();
|
|
1225
|
+
}, 60);
|
|
1226
|
+
|
|
1227
|
+
// --- Event wiring (delegated & once) ---
|
|
1228
|
+
function bindEventsOnce() {
|
|
1229
|
+
// Clicks: checkbox labels, dropdown toggles, cross icons, clear button
|
|
1230
|
+
document.addEventListener("click", (e) => {
|
|
1231
|
+
const label = e.target.closest(SEL.checkboxWrap);
|
|
1232
|
+
if (label) {
|
|
1233
|
+
// Let Finsweet/Webflow toggle classes first
|
|
1234
|
+
setTimeout(() => {
|
|
1235
|
+
const span = label.querySelector('[fs-cmsfilter-field]');
|
|
1236
|
+
const field = span?.getAttribute('fs-cmsfilter-field') || null;
|
|
1237
|
+
refreshUI(field);
|
|
1238
|
+
}, 0);
|
|
1239
|
+
return;
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
const toggle = e.target.closest(SEL.dropdownTitle);
|
|
1243
|
+
if (toggle) {
|
|
1244
|
+
// After opening/closing or instant selections
|
|
1245
|
+
setTimeout(() => refreshUI(null), 120);
|
|
1246
|
+
return;
|
|
1044
1247
|
}
|
|
1045
|
-
});
|
|
1046
|
-
});
|
|
1047
1248
|
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1249
|
+
const cross = e.target.closest(SEL.crossIcon);
|
|
1250
|
+
if (cross) {
|
|
1251
|
+
setTimeout(() => refreshUI(null), 80);
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
const clear = e.target.closest(SEL.clearButton);
|
|
1256
|
+
if (clear) {
|
|
1257
|
+
setTimeout(() => refreshUI(null), 120);
|
|
1258
|
+
return;
|
|
1259
|
+
}
|
|
1051
1260
|
});
|
|
1052
|
-
});
|
|
1053
1261
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1262
|
+
// Any checkbox state change (keyboard/tap)
|
|
1263
|
+
document.addEventListener("change", (e) => {
|
|
1264
|
+
if (e.target && e.target.matches(SEL.checkboxInput)) {
|
|
1265
|
+
const span = e.target.closest('label')?.querySelector('[fs-cmsfilter-field]') ||
|
|
1266
|
+
e.target.closest(SEL.checkboxWrap)?.querySelector('[fs-cmsfilter-field]');
|
|
1267
|
+
const field = span?.getAttribute('fs-cmsfilter-field') || null;
|
|
1268
|
+
const holder = e.target.closest(SEL.dropdownHolder);
|
|
1269
|
+
if (holder) updateDropdownTitle(holder);
|
|
1270
|
+
refreshUI(field);
|
|
1271
|
+
}
|
|
1057
1272
|
});
|
|
1058
|
-
});
|
|
1059
1273
|
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1274
|
+
// Observe class mutations that might come from Finsweet
|
|
1275
|
+
const mo = new MutationObserver((muts) => {
|
|
1276
|
+
// If any class changed, softly refresh
|
|
1277
|
+
if (muts.some(m => m.type === "attributes" && m.attributeName === "class")) {
|
|
1278
|
+
refreshUI(null);
|
|
1279
|
+
}
|
|
1280
|
+
});
|
|
1281
|
+
mo.observe(document.body, { subtree: true, attributes: true, attributeFilter: ["class"] });
|
|
1066
1282
|
}
|
|
1067
|
-
toggleClearButton();
|
|
1068
|
-
const observer = new MutationObserver(toggleClearButton);
|
|
1069
|
-
|
|
1070
|
-
observer.observe(document.body, {
|
|
1071
|
-
childList: true,
|
|
1072
|
-
subtree: true,
|
|
1073
|
-
attributes: true,
|
|
1074
|
-
attributeFilter: ['class']
|
|
1075
|
-
});
|
|
1076
1283
|
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
const dropdownHolder = dropdown.closest('.dropdown-holder');
|
|
1086
|
-
const tagNumber = dropdown.querySelector('[fs-cmsfilter-element="tag-number"]');
|
|
1087
|
-
|
|
1088
|
-
if (checkedBoxes.length > 0) {
|
|
1089
|
-
// Check if firstCheckedText is still checked
|
|
1090
|
-
if (![...checkedBoxes].some(cb => cb.nextElementSibling.textContent.split('(')[0].trim() === firstCheckedText)) {
|
|
1091
|
-
// If not, set it to the current checkbox text without the count
|
|
1092
|
-
firstCheckedText = checkedBoxes[0].nextElementSibling.textContent.split('(')[0].trim();
|
|
1093
|
-
}
|
|
1094
|
-
titleField.textContent = firstCheckedText;
|
|
1095
|
-
dropdownHolder.classList.add('active-dropdown');
|
|
1096
|
-
} else {
|
|
1097
|
-
titleField.textContent = originalText;
|
|
1098
|
-
dropdownHolder.classList.remove('active-dropdown');
|
|
1099
|
-
firstCheckedText = null;
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
if (checkedBoxes.length > 1) {
|
|
1103
|
-
const numberText = `+${checkedBoxes.length - 1}`;
|
|
1104
|
-
tagNumber.textContent = numberText;
|
|
1105
|
-
} else {
|
|
1106
|
-
tagNumber.textContent = '';
|
|
1107
|
-
}
|
|
1108
|
-
});
|
|
1109
|
-
});
|
|
1284
|
+
// --- Boot ---
|
|
1285
|
+
waitForCmsFilter().then(() => {
|
|
1286
|
+
// Allow Finsweet to finish applying query param checks/classes
|
|
1287
|
+
setTimeout(() => {
|
|
1288
|
+
hydrateOriginalTexts();
|
|
1289
|
+
bindEventsOnce();
|
|
1290
|
+
refreshUI(null);
|
|
1291
|
+
}, 120);
|
|
1110
1292
|
});
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1293
|
+
};
|
|
1113
1294
|
// Filtering logic on Client's page
|
|
1114
1295
|
window.formatCounter = function() {
|
|
1115
1296
|
function format_number(x) {
|
|
@@ -1503,20 +1684,35 @@ window.initBentoRevealScrub = function (container) {
|
|
|
1503
1684
|
}
|
|
1504
1685
|
);
|
|
1505
1686
|
};
|
|
1506
|
-
|
|
1507
1687
|
window.initPartnerVideos = function (container) {
|
|
1508
1688
|
const items = Array.from(container.querySelectorAll('.partner_item'));
|
|
1509
1689
|
const vids = items.map(i => i.querySelector('video')).filter(Boolean);
|
|
1510
1690
|
|
|
1691
|
+
// Helper: pause all other videos
|
|
1511
1692
|
const pauseAll = (except) => {
|
|
1512
1693
|
vids.forEach(v => {
|
|
1513
1694
|
if (v !== except) {
|
|
1514
1695
|
v.pause();
|
|
1515
1696
|
v.muted = true;
|
|
1697
|
+
const parent = v.closest('.partner_item');
|
|
1698
|
+
if (parent) toggleIcons(parent, false);
|
|
1516
1699
|
}
|
|
1517
1700
|
});
|
|
1518
1701
|
};
|
|
1519
1702
|
|
|
1703
|
+
// Helper: toggle play/pause icons
|
|
1704
|
+
function toggleIcons(item, isPlaying) {
|
|
1705
|
+
const playIcon = item.querySelector('.is-play');
|
|
1706
|
+
const pauseIcon = item.querySelector('.is-pause');
|
|
1707
|
+
if (isPlaying) {
|
|
1708
|
+
if (playIcon) playIcon.style.display = 'none';
|
|
1709
|
+
if (pauseIcon) pauseIcon.style.display = 'block';
|
|
1710
|
+
} else {
|
|
1711
|
+
if (playIcon) playIcon.style.display = 'block';
|
|
1712
|
+
if (pauseIcon) pauseIcon.style.display = 'none';
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1520
1716
|
items.forEach((item) => {
|
|
1521
1717
|
const v = item.querySelector('video');
|
|
1522
1718
|
if (!v) return;
|
|
@@ -1527,17 +1723,29 @@ window.initPartnerVideos = function (container) {
|
|
|
1527
1723
|
v.setAttribute('playsinline', '');
|
|
1528
1724
|
v.playsInline = true;
|
|
1529
1725
|
|
|
1726
|
+
// Default state on init (show play icon)
|
|
1727
|
+
toggleIcons(item, false);
|
|
1728
|
+
|
|
1729
|
+
// Handle click (play/pause toggle)
|
|
1530
1730
|
item.addEventListener('click', () => {
|
|
1531
1731
|
if (v.paused) {
|
|
1532
1732
|
pauseAll(v);
|
|
1533
1733
|
v.muted = false;
|
|
1534
1734
|
v.play();
|
|
1735
|
+
toggleIcons(item, true);
|
|
1535
1736
|
} else {
|
|
1536
1737
|
v.pause();
|
|
1738
|
+
toggleIcons(item, false);
|
|
1537
1739
|
}
|
|
1538
1740
|
});
|
|
1741
|
+
|
|
1742
|
+
// Handle pause and ended (ensure icons reset)
|
|
1743
|
+
v.addEventListener('pause', () => toggleIcons(item, false));
|
|
1744
|
+
v.addEventListener('ended', () => toggleIcons(item, false));
|
|
1745
|
+
v.addEventListener('play', () => toggleIcons(item, true));
|
|
1539
1746
|
});
|
|
1540
1747
|
|
|
1748
|
+
// Pause videos when out of viewport
|
|
1541
1749
|
const rootEl =
|
|
1542
1750
|
document.querySelector('[data-scroll-root]') ||
|
|
1543
1751
|
document.querySelector('[data-smooth-scroll-root]') ||
|
|
@@ -1548,7 +1756,10 @@ window.initPartnerVideos = function (container) {
|
|
|
1548
1756
|
entries.forEach(({ isIntersecting, target }) => {
|
|
1549
1757
|
const v = target.querySelector('video');
|
|
1550
1758
|
if (!v) return;
|
|
1551
|
-
if (!isIntersecting)
|
|
1759
|
+
if (!isIntersecting) {
|
|
1760
|
+
v.pause();
|
|
1761
|
+
toggleIcons(target, false);
|
|
1762
|
+
}
|
|
1552
1763
|
});
|
|
1553
1764
|
},
|
|
1554
1765
|
{ root: rootEl, threshold: 0.25 }
|
|
@@ -1558,7 +1769,6 @@ window.initPartnerVideos = function (container) {
|
|
|
1558
1769
|
};
|
|
1559
1770
|
|
|
1560
1771
|
|
|
1561
|
-
|
|
1562
1772
|
// Case study - What's next interaction
|
|
1563
1773
|
window.whatsNext = function() {
|
|
1564
1774
|
const caseItem = document.querySelectorAll('.whats-next_links_item.is-case');
|