PageSourceSearch

https://www.smilesolutions.com.au/wp-content/plugins/block-library…/view.js?ver=6bfc07b95ed4cfa6f245

js smilesolutions.com.au collected 2026-10-02 19:57:43 UTC 24,143 bytes, 631 lines download raw bytes

vendor: 112 bytes, lines 1-5
1/******/ (() => { // webpackBootstrap
2/******/ 	"use strict";
3/******/ 	var __webpack_modules__ = ({
4
5/***/ "./s
5rc/common/animations/parrallaxImages.js":
6/*!**************************************************!*\
7  !*** ./src/common/animations/parrallaxImages.js ***!
8  \**************************************************/
9/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
10
11__webpack_require__.r(__webpack_exports__);
12/* harmony export */ __webpack_require__.d(__webpack_exports__, {
13/* harmony export */   parallaxImages: () => (/* binding */ parallaxImages)
14/* harmony export */ });
15// Add parallax effect to images
16const parallaxImages = wrapper => {
17  wrapper.forEach(wrapper => {
18    const images = wrapper.querySelectorAll("img");
19    if (images.length > 0) {
20      images.forEach(img => {
21        scrollSmoother.effects(img, {
22          speed: "auto"
23        });
24      });
25    }
26  });
27};
28
29/***/ })
29
30
31/******/ 	});
32/************************************************************************/
33/******/ 	// The module cache
34/******/ 	var __webpack_module_cache__ = {};
35/******/ 	
36/******/ 	// The require function
37/******/ 	function __webpack_require__(moduleId) {
38/******/ 		// Check if module is in cache
39/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
40/******/ 		if (cachedModule !== undefined) {
41/******/ 			return cachedModule.exports;
42/******/ 		}
43/******/ 		// Create a new module (and put it into the cache)
44/******/ 		var module = __webpack_module_cache__[moduleId] = {
45/******/ 			// no module.id needed
46/******/ 			// no module.loaded needed
47/******/ 			exports: {}
48/******/ 		};
49/******/ 	
50/******/ 		// Execute the module function
51/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
52/******/ 	
53/******/ 		// Return the exports of the module
54/******/ 		return module.exports;
55/******/ 	}
56/******/ 	
57/************************************************************************/
58/******/ 	/* webpack/runtime/define property getters */
59/******/ 	(() => {
60/******/ 		// define getter functions for harmony exports
61/******/ 		__webpack_require__.d = (exports, definition) => {
62/******/ 			for(var key in definition) {
63/******/ 				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
64/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
65/******/ 				}
66/******/ 			}
67/******/ 		};
68/******/ 	})();
69/******/ 	
70/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
71/******/ 	(() => {
72/******/ 		__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
73/******/ 	})();
74/******/ 	
75/******/ 	/* webpack/runtime/make namespace object */
76/******/ 	(() => {
77/******/ 		// define __esModule on exports
78/******/ 		__webpack_require__.r = (exports) => {
79/******/ 			if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
80/******/ 				Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
81/******/ 			}
82/******/ 			Object.defineProperty(exports, '__esModule', { value: true });
83/******/ 		};
84/******/ 	})();
85/******/ 	
86/************************************************************************/
87var __webpack_exports__ = {};
88// This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.
89(() => {
90/*!*************************************************!*\
91  !*** ./src/staggered-media-and-content/view.js ***!
92  \*************************************************/
93__webpack_require__.r(__webpack_exports__);
94/* harmony import */ var _common_animations_parrallaxImages_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../common/animations/parrallaxImages.js */ "./src/common/animations/parrallaxImages.js");
95/**
96 * Use this file for JavaScript code that you want to run in the front-end
97 * on posts/pages that contain this block.
98 *
99 * When this file is defined as the value of the `viewScript` property
100 * in `block.json` it will be enqueued on the front end of the site.
101 *
102 * Example:
103 *
104 * ```js
105 * {
106 *   "viewScript": "file:./view.js"
107 * }
108 * ```
109 *
110 * If you're not making any changes to this file because your project doesn't need any
111 * JavaScript running in the front-end, then you should delete this file and remove
112 * the `viewScript` property from `block.json`.
113 *
114 * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#view-script
115 */
116
117
118function ensureYoutubeAPIReady() {
119  return new Promise((resolve, reject) => {
120    if (window.YT && window.YT.Player) {
121      return resolve();
122    }
123    let otherYoutubeReadyCb = null;
124    if (typeof window.onYouTubeIframeAPIReady !== "undefined") {
125      otherYoutubeReadyCb = window.onYouTubeIframeAPIReady;
126    }
127    window.onYouTubeIframeAPIReady = () => {
128      otherYoutubeReadyCb && otherYoutubeReadyCb();
129      resolve();
130    };
131    let script = document.createElement("script");
132    script.id = "youtube-iframe-script";
133    script.src = "https://www.youtube.com/iframe_api";
134    let firstScriptTag = document.getElementsByTagName("script")[0];
135    firstScriptTag.parentNode.insertBefore(script, firstScriptTag);
136  });
137}
138function ensureVimeoAPIReady() {
139  return new Promise((resolve, reject) => {
140    if (window.Vimeo && window.Vimeo.Player) {
141      return resolve();
142    }
143    let script = document.createElement("script");
144    script.id = "vimeo-iframe-script";
145    script.src = "https://player.vimeo.com/api/player.js";
146
147    // Set up onload event handler
148    script.onload = () => {
149      // Check if the necessary objects are now available
150      if (window.Vimeo && window.Vimeo.Player) {
151        resolve();
152      } else {
153        reject(new Error("Vimeo API script loaded, but Vimeo or Vimeo.Player is still not available"));
154      }
155    };
156
157    // Set up onerror event handler
158    script.onerror = () => {
159      reject(new Error("Error loading Vimeo API script"));
160    };
161    let firstScriptTag = document.getElementsByTagName("script")[0];
162    firstScriptTag.parentNode.insertBefore(script, firstScriptTag);
163  });
164}
165const removePosterAndOverlay = video => {
166  const poster = video.querySelector(".staggered-media-and-content-video__poster");
167  const overlay = video.querySelector(".staggered-media-and-content-video__overlay");
168  if (poster) {
169    poster.style.opacity = 0;
170    poster.style.pointerEvents = "none";
171  }
172  if (overlay) {
173    overlay.style.opacity = 0;
174    overlay.style.pointerEvents = "none";
175  }
176};
177const enterKeyPressPlay = (video, play) => {
178  const playButton = video.querySelector(".staggered-media-and-content-video__overlay-icon");
179  if (playButton) {
180    playButton.addEventListener("keydown", e => {
181      if (e.key === "Enter") {
182        removePosterAndOverlay(video);
183        play();
184      }
185    });
186  }
187};
188const handleIframeVideos = () => {
189  const videoCollection = document.getElementsByClassName("staggered-media-and-content-video__stacking-grid");
190  if (videoCollection) {
191    const videoArray = Array.from(videoCollection);
192    ensureYoutubeAPIReady().then(() => {
193      for (let i = 0; i < videoArray.length; i++) {
194        const videoItem = videoArray[i];
195        // Check if the current videoItem has the class 'source-video-youtube'
196        if (videoItem.dataset.videoType === "video-youtube") {
197          // If the class is found, run the function and stop the loop
198          videoArray.forEach((video, i) => {
199            // events if youtube video is loaded
200            const frame = video.getElementsByTagName("iframe");
201            if (frame.length) {
202              if (video.dataset.videoType === "video-youtube") {
203                frame[0].style.pointerEvents = "none";
204                let playAfterReady = false;
205                let isPlayerReady = false;
206                const player = new YT.Player(frame[0], {
207                  events: {
208                    onReady: () => {
209                      isPlayerReady = true;
210                      if (playAfterReady) {
211                        player.playVideo();
212                      }
213                    },
214                    onStateChange: e => {
215                      if (e.target.getPlayerState() === 1) {
216                        frame[0].style.visibility = "visible";
217                        frame[0].style.pointerEvents = "auto";
218                        removePosterAndOverlay(video);
219                      }
220                      if (video.dataset.loop === "true" && e.target.getPlayerState() === 0) {
221                        player.playVideo();
222                      }
223                    }
224                  }
225                });
226                function handlePlay() {
227                  if (!isPlayerReady) {
228                    playAfterReady = true;
229                  } else {
230                    player.playVideo();
231                  }
232                }
233                enterKeyPressPlay(video, handlePlay);
234                if (video.dataset.autoplay === "true") {
235                  handlePlay();
236                }
237                video.addEventListener("click", () => {
238                  handlePlay();
239                });
240              }
241            }
242          });
243          break;
244        }
245      }
246    });
247    for (let i = 0; i < videoArray.length; i++) {
248      const videoItem = videoArray[i];
249      // Check if the current videoItem has the class 'source-video-vimeo'
250      if (videoItem.dataset.videoType === "video-vimeo") {
251        // If the class is found, run the function and stop the loop
252        ensureVimeoAPIReady().then(() => {
253          videoArray.forEach((video, i) => {
254            // events if Vimeo video is loaded
255            const frame = video.getElementsByTagName("iframe");
256            if (frame.length) {
257              if (video.dataset.videoType === "video-vimeo") {
258                frame[0].onload = function () {
259                  ensureVimeoAPIReady().then(() => {
260                    const player = new Vimeo.Player(frame[0]);
261                    const play = () => {
262                      player.play();
263                    };
264                    const poster = video.querySelector(".staggered-media-and-content-video__poster");
265                    const overlay = video.querySelector(".staggered-media-and-content-video__overlay");
266                    if (poster) {
267                      poster.addEventListener("click", () => {
268                        play();
269                      });
270                    }
271                    if (overlay) {
272                      overlay.addEventListener("click", () => {
273                        play();
274                      });
275                    }
276                    enterKeyPressPlay(video, play);
277                    player.on("play", () => {
278                      removePosterAndOverlay(video);
279                    });
280                  });
281                };
282              }
283            }
284          });
285        });
286        break;
287      }
288    }
289  }
290};
291const handleLocalVideos = () => {
292  const fullWidthVideoBlocks = document.querySelectorAll(".wp-block-block-builder-by-arc-staggered-media-and-content");
293  fullWidthVideoBlocks.forEach(block => {
294    const video = block.querySelector(".staggered-media-and-content__local-video");
295    const playButton = block.querySelector(".staggered-media-and-content-video__overlay");
296    const stackingGrid = block.querySelector(".staggered-media-and-content-video__stacking-grid");
297    if (video) {
298      const play = () => {
299        video.play();
300      };
301      const poster = block.querySelector(".staggered-media-and-content-video__poster");
302      const overlay = block.querySelector(".staggered-media-and-content-video__overlay");
303      if (poster) {
304        if (stackingGrid.dataset.controls === "true") {
305          video.controls = false;
306        }
307        poster.addEventListener("click", () => {
308          if (stackingGrid.dataset.controls === "true") {
309            video.controls = true;
310          }
311          play();
312        });
313      }
314      if (overlay) {
315        overlay.addEventListener("click", () => {
316          if (stackingGrid.dataset.controls === "true") {
317            video.controls = true;
318          }
319          play();
320        });
321      }
322      if (playButton) {
323        playButton.addEventListener("keydown", e => {
324          if (e.key === "Enter") {
325            if (stackingGrid.dataset.controls === "true") {
326              video.controls = true;
327            }
328            removePosterAndOverlay(video);
329            play();
330          }
331        });
332      }
333      video.addEventListener("playing", function () {
334        removePosterAndOverlay(block);
335      });
336    }
337  });
338};
339
340// Position caption absolutely at bottom of image using Y position
341const positionCaptions = () => {
342  const imageContainers = document.querySelectorAll(".staggered-media-and-content__image");
343  const TABLET_MAX = 1025; // Match $tablet-max breakpoint
344
345  const updateCaptionPosition = (imageContainer, isInitial = false) => {
346    // Find caption as child of image container
347    const caption = imageContainer.querySelector(".staggered-media-and-content__caption");
348    const img = imageContainer.querySelector("img");
349    if (caption && img) {
350      const isMobile = window.innerWidth < TABLET_MAX;
351      if (isMobile) {
352        // For mobile/tablet: move caption outside image container to avoid overflow hidden
353        const columnOne = imageContainer.closest(".staggered-media-and-content__column-one");
354        if (!columnOne) return;
355
356        // Check if caption is already moved outside
357        if (caption.parentElement === imageContainer) {
358          // Move caption to be sibling of image container
359          imageContainer.parentNode.insertBefore(caption, imageContainer.nextSibling);
360        }
361
362        // Set column-one to relative positioning if not already
363        columnOne.style.position = "relative";
364
365        // Calculate image container bottom position relative to column-one
366        const imageContainerRect = imageContainer.getBoundingClientRect();
367        const columnRect = columnOne.getBoundingClientRect();
368        const imageContainerBottom = imageContainerRect.bottom - columnRect.top;
369        caption.style.position = "absolute";
370        caption.style.top = `${imageContainerBottom + 20}px`;
371        caption.style.left = "0";
372        caption.style.width = "100%";
373        caption.style.minHeight = "fit-content";
374
375        // Update column-one height to account for caption
376        setTimeout(() => {
377          const captionRect = caption.getBoundingClientRect();
378          const updatedColumnRect = columnOne.getBoundingClientRect();
379          const captionBottom = captionRect.bottom - updatedColumnRect.top;
380          const currentColumnHeight = columnOne.offsetHeight;
381          if (captionBottom > currentColumnHeight) {
382            columnOne.style.minHeight = `${captionBottom}px`;
383          }
384        }, 0);
385      } else {
386        // For desktop: keep caption inside image container
387        // Move caption back inside if it was moved out
388        const columnOneDesktop = imageContainer.closest(".staggered-media-and-content__column-one");
389        if (columnOneDesktop && caption.parentElement !== imageContainer) {
390          imageContainer.appendChild(caption);
391        }
392
393        // Set image container to relative positioning if not already
394        imageContainer.style.position = "relative";
395
396        // Calculate image element's bottom position relative to image container
397        const imageRect = img.getBoundingClientRect();
398        const containerRect = imageContainer.getBoundingClientRect();
399        const imageBottomY = imageRect.bottom - containerRect.top;
400        caption.style.position = "absolute";
401        caption.style.top = `${imageBottomY + 20}px`;
402        caption.style.left = "0";
403        caption.style.width = "100%";
404        caption.style.height = "fit-content";
405
406        // Update column-one height to account for caption on desktop
407        if (columnOneDesktop) {
408          setTimeout(() => {
409            const captionRect = caption.getBoundingClientRect();
410            const columnRect = columnOneDesktop.getBoundingClientRect();
411            const captionBottom = captionRect.bottom - columnRect.top;
412            const currentColumnHeight = columnOneDesktop.offsetHeight;
413            if (captionBottom > currentColumnHeight) {
414              columnOneDesktop.style.minHeight = `${captionBottom}px`;
415            }
416          }, 0);
417        }
418      }
419
420      // Fade in up animation after position is calculated
421      if (isInitial && typeof gsap !== "undefined" && typeof ScrollTrigger !== "undefined" && !caption.dataset.animated) {
422        // Set initial state
423        gsap.set(caption, {
424          opacity: 0,
425          y: 30
426        });
427
428        // Create fade-in-up animation with ScrollTrigger
429        var tl = gsap.timeline({
430          scrollTrigger: {
431            trigger: caption,
432            start: "top 99%",
433            end: "bottom 10%",
434            toggleActions: "play none none none"
435          }
436        });
437        tl.to(caption, {
438          duration: 1,
439          opacity: 1,
440          y: 0,
441          ease: "power2.out"
442        });
443
444        // Refresh ScrollTrigger after positioning is complete (longer delay for mobile DOM manipulation)
445        setTimeout(() => {
446          if (typeof ScrollTrigger !== "undefined") {
447            ScrollTrigger.refresh();
448          }
449        }, isMobile ? 200 : 100);
450
451        // Mark as animated to prevent re-animating
452        caption.dataset.animated = "true";
453      }
454    }
455  };
456
457  // Initial positioning with fade-in animation
458  imageContainers.forEach(imageContainer => {
459    updateCaptionPosition(imageContainer, true);
460  });
461
462  // Update on scroll and resize
463  const updateAllCaptions = () => {
464    imageContainers.forEach(imageContainer => {
465      updateCaptionPosition(imageContainer);
466    });
467  };
468
469  // Use ScrollTrigger to update on scroll
470  if (typeof ScrollTrigger !== "undefined") {
471    ScrollTrigger.addEventListener("refresh", updateAllCaptions);
472  }
473
474  // Also listen to window resize
475  window.addEventListener("resize", updateAllCaptions);
476
477  // Use requestAnimationFrame for smooth constant updates during scroll
478  let ticking = false;
479  const onScroll = () => {
480    if (!ticking) {
481      window.requestAnimationFrame(() => {
482        updateAllCaptions();
483        ticking = false;
484      });
485      ticking = true;
486    }
487  };
488  window.addEventListener("scroll", onScroll, {
489    passive: true
490  });
491
492  // Also update constantly using requestAnimationFrame loop
493  const constantUpdate = () => {
494    updateAllCaptions();
495    requestAnimationFrame(constantUpdate);
496  };
497  requestAnimationFrame(constantUpdate);
498};
499
500// initialize gsap animations
501const gsapMediaAndContentAnimations = () => {
502  const wrappers = document.querySelectorAll(".wp-block-create-block-staggered-media-and-content");
503  const stickyImage = wrapper => {
504    const image = wrapper.querySelector(".staggered-media-and-content__image");
505    const video = wrapper.querySelector(".staggered-media-and-content__video");
506    const backgroundImage = wrapper.querySelector(".staggered-media-and-content__background-image");
507    if (wrapper && (image || video || backgroundImage)) {
508      // Create ScrollTrigger instance to pin the image
509      ScrollTrigger.create({
510        trigger: wrapper,
511        start: "top top",
512        end: "bottom bottom",
513        pin: image || video,
514        pinSpacing: false,
515        onUpdate: () => {
516          // Update caption position when scroll trigger updates using Y position
517          const imageContainer = wrapper.querySelector(".staggered-media-and-content__image");
518          if (imageContainer) {
519            const columnOne = imageContainer.closest(".staggered-media-and-content__column-one");
520            if (!columnOne) return;
521
522            // Find caption - could be inside image container or as sibling on mobile
523            const caption = imageContainer.querySelector(".staggered-media-and-content__caption") || columnOne.querySelector(".staggered-media-and-content__caption");
524            const img = imageContainer.querySelector("img");
525            if (caption && img) {
526              const TABLET_MAX = 1025; // Match $tablet-max breakpoint
527              const isMobile = window.innerWidth < TABLET_MAX;
528              if (isMobile) {
529                // For mobile/tablet: position based on image container relative to column-one
530                const imageContainerRect = imageContainer.getBoundingClientRect();
531                const columnRect = columnOne.getBoundingClientRect();
532                const imageContainerBottom = imageContainerRect.bottom - columnRect.top;
533                const imageHeight = imageContainerRect.height;
534
535                // Position at image bottom - 40% of image height
536                const topPosition = imageContainerBottom - imageHeight * 0.4;
537                caption.style.top = `${topPosition}px`;
538                caption.style.minHeight = "fit-content";
539
540                // Update column-one height to account for caption
541                setTimeout(() => {
542                  const captionRect = caption.getBoundingClientRect();
543                  const updatedColumnRect = columnOne.getBoundingClientRect();
544                  const captionBottom = captionRect.bottom - updatedColumnRect.top;
545                  const currentColumnHeight = columnOne.offsetHeight;
546                  if (captionBottom > currentColumnHeight) {
547                    columnOne.style.minHeight = `${captionBottom}px`;
548                  }
549                }, 0);
550              } else {
551                // For desktop: position at image bottom Y + 20px
552                const imageRect = img.getBoundingClientRect();
553                const containerRect = imageContainer.getBoundingClientRect();
554                const imageBottomY = imageRect.bottom - containerRect.top;
555                caption.style.top = `${imageBottomY + 20}px`;
556
557                // Update column-one height to account for caption
558                setTimeout(() => {
559                  const captionRect = caption.getBoundingClientRect();
560                  const updatedColumnRect = columnOne.getBoundingClientRect();
561                  const captionBottom = captionRect.bottom - updatedColumnRect.top;
562                  const currentColumnHeight = columnOne.offsetHeight;
563                  if (captionBottom > currentColumnHeight) {
564                    columnOne.style.minHeight = `${captionBottom}px`;
565                  }
566                }, 0);
567              }
568            }
569          }
570        }
571      });
572
573      // Add parallax scrolling effect to background image
574      if (backgroundImage) {
575        gsap.set(backgroundImage, {
576          y: "40%"
577        });
578        gsap.to(backgroundImage, {
579          y: "-10%",
580          ease: "none",
581          scrollTrigger: {
582            trigger: wrapper,
583            start: "top 100%",
584            end: "bottom 105%",
585            scrub: true
586          }
587        });
588      }
589    }
590  };
591
592  // media query to prevent animations from running on wrong different screen sizes
593  let mm = gsap.matchMedia();
594  const breakPoint = 1025;
595
596  // Desktop: sticky image animation
597  mm.add({
598    isDesktop: `(min-width: ${breakPoint}px)`,
599    isMobile: `(max-width: ${breakPoint - 1}px)`
600  }
600, context => {
601    if (context.conditions.isDesktop) {
602      wrappers.forEach(wrapper => {
603        stickyImage(wrapper);
604      });
605    } else if (context.conditions.isMobile) {
606      (0,_common_animations_parrallaxImages_js__WEBPACK_IMPORTED_MODULE_0__.parallaxImages)(wrappers);
607    }
608  });
609};
610
611// Main initialization function
612const initStaggeredMediaAndContent = () => {
613  // Run all initialization functions in correct order
614  handleIframeVideos();
615  handleLocalVideos();
616  positionCaptions(); // Run BEFORE GSAP animations
617  gsapMediaAndContentAnimations();
618};
619
620// Initialize based on document ready state
621if (document.readyState === "loading") {
622  document.addEventListener("DOMContentLoaded", initStaggeredMediaAndContent);
623} else {
624  // Document already loaded, initialize immediately with slight delay
625  setTimeout(initStaggeredMediaAndContent, 0);
626}
627})();
628
629/******/ })()
630;
631//# sourceMappingURL=view.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.