PageSourceSearch

https://travel.historictownsofamerica.com/wp-content/plugins/yatra…/js/video-player.js?ver=3.0.15.1789496072

js historictownsofamerica.com collected 2026-09-25 00:02:24 UTC 6,603 bytes, 226 lines download raw bytes

1/**
2 * Yatra Video Player Module
3 * Reusable video player for YouTube and other video sources
4 * 
5 * @package Yatra
6 * @version 1.0.0
7 */
8
9(function() {
10  'use strict';
11
12  // Translation helper. Same shim as tour-viewer.js — resolves
13  // through wp.i18n when available, falls back to identity otherwise.
14  // Call sites must pass `'yatra'` so wp i18n make-pot --domain=yatra
15  // picks them up (see tour-viewer.js for the full rationale).
16  var __ = (window.wp && window.wp.i18n && window.wp.i18n.__)
17    ? function (text, domain) { return window.wp.i18n.__(text, domain || 'yatra'); }
18    : function (text) { return text; };
19
20  class YatraVideoPlayer {
21    constructor() {
22      this.modal = null;
23      this.iframe = null;
24      this.currentVideo = null;
25      this.init();
26    }
27
28    init() {
29      // Nothing is built here on purpose. The modal markup used to be
30      // injected into <body> as soon as this script loaded — on every
31      // page, including ones with no video. It is now created on the
32      // first play() call, so pages that never play a video never get
33      // the extra DOM.
34    }
35
36    /**
37     * Build the modal once, on first use.
38     */
39    ensureModal() {
40      if (this.modal) {
41        return;
42      }
43      this.createModal();
44      this.attachEventListeners();
45    }
46
47    createModal() {
48      // Check if modal already exists
49      if (document.getElementById('yatra-video-player-modal')) {
50        this.modal = document.getElementById('yatra-video-player-modal');
51        this.iframe = document.getElementById('yatra-video-player-iframe');
52        return;
53      }
54
55      // Pre-compute the translated label OUT of the template literal
56      // so makepot extracts it reliably (see tour-viewer.js note).
57      var closeVideoLabel = __('Close Video', 'yatra');
58
59      // Create modal HTML
60      const modalHTML = `
61        <div id="yatra-video-player-modal" class="yatra-video-player-modal" style="display: none;">
62          <div class="yatra-video-player-overlay"></div>
63          <div class="yatra-video-player-content">
64            <button type="button" class="yatra-video-player-close" aria-label="${closeVideoLabel}">
65              <svg width="24" height="24" fill="none" stroke="currentColor" viewBox="0 0 24 24">
66                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
67              </svg>
68            </button>
69            <div class="yatra-video-player-wrapper">
70              <iframe id="yatra-video-player-iframe" 
71                      width="100%" 
72                      height="100%" 
73                      frameborder="0" 
74                      allowfullscreen 
75                      allow="autoplay; encrypted-media; picture-in-picture">
76              </iframe>
77            </div>
78          </div>
79        </div>
80      `;
81
82      // Append to body
83      document.body.insertAdjacentHTML('beforeend', modalHTML);
84      
85      this.modal = document.getElementById('yatra-video-player-modal');
86      this.iframe = document.getElementById('yatra-video-player-iframe');
87    }
88
89    attachEventListeners() {
90      // Close button
91      const closeBtn = this.modal.querySelector('.yatra-video-player-close');
92      if (closeBtn) {
93        closeBtn.addEventListener('click', () => this.close());
94      }
95
96      // Overlay click to close
97      const overlay = this.modal.querySelector('.yatra-video-player-overlay');
98      if (overlay) {
99        overlay.addEventListener('click', () => this.close());
100      }
101
102      // ESC key to close
103      document.addEventListener('keydown', (e) => {
104        if (e.key === 'Escape' && this.modal.style.display === 'flex') {
105          this.close();
106        }
107      });
108    }
109
110    /**
111     * Play a video
112     * @param {Object} video - Video object with url, embed_url, video_id, title
113     */
114    play(video) {
115      if (!video || !video.url) {
116        console.error('YatraVideoPlayer: Invalid video object');
117        return;
118      }
119
120      
121      this.currentVideo = video;
122      this.ensureModal();
123      
124      // Determine the embed URL
125      let embedUrl = '';
126      
127      if (video.embed_url) {
128        // Use provided embed URL
129        embedUrl = video.embed_url;
130      } else if (video.video_id) {
131        // YouTube video ID provided
132        embedUrl = `https://www.youtube.com/embed/${video.video_id}?autoplay=1&rel=0`;
133      } else if (video.url.includes('youtube.com') || video.url.includes('youtu.be')) {
134        // Extract YouTube video ID from URL
135        const videoId = this.extractYoutubeVideoId(video.url);
136        if (videoId) {
137          embedUrl = `https://www.youtube.com/embed/${videoId}?autoplay=1&rel=0`;
138        }
139      } else if (video.url.includes('vimeo.com')) {
140        // Vimeo video
141        const vimeoId = video.url.split('/').pop();
142        embedUrl = `https://player.vimeo.com/video/${vimeoId}?autoplay=1`;
143      } else {
144        // Direct video URL
145        embedUrl = video.url;
146      }
147
148      
149      
150      
151
152      // Add load event handlers for debugging
153      this.iframe.onload = () => {
154        
155      };
156      
157      this.iframe.onerror = (error) => {
158        console.error('YouTube iframe failed to load:', error);
159      };
160      
161      // Set iframe source
162      
163      this.iframe.src = embedUrl;
164      
165      // Verify iframe src was set
166      setTimeout(() => {
167        
168        
169      }, 100);
170      
171      // Show modal
172      this.open();
173    }
174
175    /**
176     * Extract YouTube video ID from various URL formats
177     * @param {string} url - YouTube URL
178     * @returns {string|null} Video ID or null
179     */
180    extractYoutubeVideoId(url) {
181      const patterns = [
182        /youtube\.com\/watch\?v=([^&]+)/,
183        /youtube\.com\/embed\/([^?]+)/,
184        /youtu\.be\/([^?]+)/,
185        /youtube\.com\/v\/([^?]+)/,
186        /youtube\.com\/shorts\/([^?&]+)/
187      ];
188      
189      for (const pattern of patterns) {
190        const match = url.match(pattern);
191        if (match) {
192          return match[1];
193        }
194      }
195      
196      return null;
197    }
198
199    open() {
200      
201      
202      this.modal.style.display = 'flex';
203      document.body.style.overflow = 'hidden';
204      
205    }
206
207    close() {
208      if (!this.modal) {
209        return; // never opened on this page
210      }
211      this.modal.style.display = 'none';
212      document.body.style.overflow = '';
213      
214      // Stop video playback by clearing iframe src
215      this.iframe.src = '';
216      this.currentVideo = null;
217    }
218  }
219
220  // Create global instance
221  window.YatraVideoPlayer = new YatraVideoPlayer();
222  
223  // Log successful initialization
224  
225
226})();

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.