PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.16
Yatra – Travel Booking & Tour Operator Software v3.0.16
3.0.16 3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 All 84 releases
yatra / assets / js / video-player.js

video-player.js in Yatra – Travel Booking & Tour Operator Software 3.0.16, at assets/js/video-player.js

227 lines 6.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 })();
227