PageSourceSearch

https://ftdes.net/wp-content/plugins/embedpress/assets/js/initplyr.js?ver=1761920615

js ftdes.net collected 2026-10-04 01:04:05 UTC 12,099 bytes, 316 lines download raw bytes

1/**
2 * Note: This is complex initialization, but it is necessary for Gutenberg and Elementor compatibility. There are some known issues in Gutenberg that require this complex setup.
3 */
4var playerInit = [];
5
6
7// Event listener for when the DOM content is loaded
8document.addEventListener('DOMContentLoaded', function () {
9
10
11  const overlayMask = document.createElement('div');
12  overlayMask.className = 'overlay-mask';
13
14
15  // Select all embed wrappers with the class 'ep-embed-content-wraper'
16  let embedWrappers = document.querySelectorAll('.ep-embed-content-wraper');
17
18  // Initialize the player for each embed wrapper
19  embedWrappers.forEach(wrapper => {
20    initPlayer(wrapper);
21  });
22
23  // Mutation observer to detect any changes in the DOM
24  const observer = new MutationObserver(mutations => {
25    mutations.forEach(mutation => {
26      const addedNodes = Array.from(mutation.addedNodes);
27      addedNodes.forEach(node => {
28        traverseAndInitPlayer(node);
29      });
30    });
31  });
32
33  // Start observing changes in the entire document body and its subtree
34  observer.observe(document.body, { childList: true, subtree: true });
35
36  // Recursive function to traverse the DOM and initialize the player for each embed wrapper
37  function traverseAndInitPlayer(node) {
38    if (node.nodeType === Node.ELEMENT_NODE && node.classList.contains('ep-embed-content-wraper')) {
39      initPlayer(node);
40    }
41
42    if (node.hasChildNodes()) {
43      node.childNodes.forEach(childNode => {
44        traverseAndInitPlayer(childNode);
45      });
46    }
47  }
48
49
50});
51
52
53// Function to initialize the player for a given wrapper
54function initPlayer(wrapper) {
55  const playerId = wrapper.getAttribute('data-playerid');
56
57  // Get the options for the player from the wrapper's data attribute
58  let options = document.querySelector(`[data-playerid='${playerId}']`)?.getAttribute('data-options');
59
60
61
62  if (!options) {
63    return false;
64  }
65
66  // Parse the options string into a JSON object
67  if (typeof options === 'string') {
68    try {
69      options = JSON.parse(options);
70    } catch (e) {
71      return;
72    }
73  } else {
74    return;
75  }
76
77
78  if (!options.poster_thumbnail) {
79    wrapper.style.opacity = "1";
80  }
81
82  // Create DOM elements from the icon strings
83  const pipPlayIconElement = document.createElement('div');
84  pipPlayIconElement.className = 'pip-play';
85  pipPlayIconElement.innerHTML = '<svg width="20" height="20" viewBox="-0.15 -0.112 0.9 0.9" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin" class="jam jam-play"><path fill="#fff" d="M.518.357A.037.037 0 0 0 .506.306L.134.08a.039.039 0 0 0-.02-.006.038.038 0 0 0-.038.037v.453c0 .007.002.014.006.02a.039.039 0 0 0 .052.012L.506.37A.034.034 0 0 0 .518.358zm.028.075L.174.658A.115.115 0 0 1 .017.622.109.109 0 0 1 0 .564V.111C0 .05.051 0 .114 0c.021 0 .042.006.06.017l.372.226a.11.11 0 0 1 0 .189z"/></svg>';
86  pipPlayIconElement.style.display = 'none';
87
88
89  const pipPauseIconElement = document.createElement('div');
90  pipPauseIconElement.className = 'pip-pause';
91  pipPauseIconElement.innerHTML = '<svg fill="#fff" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 2.5 2.5" xml:space="preserve"><path d="M1.013.499 1.006.5V.499H.748a.054.054 0 0 0-.054.054v1.394c0 .03.024.054.054.054h.266a.054.054 0 0 0 .054-.054V.553a.054.054 0 0 0-.054-.054zm.793 1.448V.553a.054.054 0 0 0-.054-.054L1.745.5V.499h-.258a.054.054 0 0 0-.054.054v1.394c0 .03.024.054.054.054h.265a.054.054 0 0 0 .054-.054z"/></svg>';
92
93  const pipCloseElement = document.createElement('div');
94  pipCloseElement.className = 'pip-close';
95  pipCloseElement.innerHTML = '<svg width="20" height="20" viewBox="0 0 0.9 0.9" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M.198.198a.037.037 0 0 1 .053 0L.45.397.648.199a.037.037 0 1 1 .053.053L.503.45l.198.198a.037.037 0 0 1-.053.053L.45.503.252.701A.037.037 0 0 1 .199.648L.397.45.198.252a.037.037 0 0 1 0-.053z" fill="#fff"/></svg>';
96
97  // Check if the player has not been initialized for this wrapper
98  if (playerId && !wrapper.classList.contains('plyr-initialized')) {
99
100
101    let selector = `[data-playerid='${playerId}'] .ose-embedpress-responsive`;
102
103
104    if (options.self_hosted && options.hosted_format === 'video') {
105      selector = `[data-playerid='${playerId}'] .ose-embedpress-responsive video`;
106    }
107    else if (options.self_hosted && options.hosted_format === 'audio') {
108      selector = `[data-playerid='${playerId}'] .ose-embedpress-responsive audio`;
109      wrapper.style.opacity = "1";
110    }
111
112
113    // Set the main color of the player
114    document.querySelector(`[data-playerid='${playerId}']`).style.setProperty('--plyr-color-main', options.player_color);
115    document.querySelector(`[data-playerid='${playerId}'].custom-player-preset-1, [data-playerid='${playerId}'].custom-player-preset-3, [data-playerid='${playerId}'].custom-player-preset-4`)?.style.setProperty('--plyr-range-fill-background', '#ffffff');
116
117    // Set the poster thumbnail for the player
118    if (document.querySelector(`[data-playerid='${playerId}'] iframe`)) {
119      document.querySelector(`[data-playerid='${playerId}'] iframe`).setAttribute('data-poster', options.poster_thumbnail);
120    }
121    if (document.querySelector(`[data-playerid='${playerId}'] video`)) {
122      document.querySelector(`[data-playerid='${playerId}'] video`).setAttribute('data-poster', options.poster_thumbnail);
123    }
124
125    // Define the controls to be displayed
126    const controls = [
127      'play-large',
128      options.restart ? 'restart' : '',
129      options.rewind ? 'rewind' : '',
130      'play',
131      options.fast_forward ? 'fast-forward' : '',
132      'progress',
133      'current-time',
134      'duration',
135      'mute',
136      'volume',
137      'captions',
138      'settings',
139      options.pip ? 'pip' : '',
140      'airplay',
141      options.download ? 'download' : '',
142      options.fullscreen ? 'fullscreen' : '',
143
144    ].filter(control => control !== '');
145
146    // Detect if we're on iOS
147    const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
148
149    // Detect if this is a YouTube video
150    const isYouTube = document.querySelector(`[data-playerid='${playerId}'] iframe[src*="youtube"]`) !== null;
151
152    // For iOS YouTube videos, we need to use fallback fullscreen instead of native
153    // because webkitEnterFullscreen() doesn't work on iframes
154    const shouldUseFallbackFullscreen = isIOS && isYouTube;
155
156
157
158    // Create a new Plyr player instance with the specified options and controls
159    const player = new Plyr(selector, {
160      controls: controls,
161      seekTime: 10,
162      poster: options.poster_thumbnail,
163      storage: {
164        enabled: true,
165        key: 'plyr_volume'
166      },
167      displayDuration: true,
168      tooltips: { controls: options.player_tooltip, seek: options.player_tooltip },
169      hideControls: options.hide_controls,
170      // iOS fullscreen configuration - use fallback for YouTube on iOS
171      fullscreen: {
172        enabled: options.fullscreen !== false,
173        fallback: true,
174        iosNative: !shouldUseFallbackFullscreen // Disable iosNative for YouTube on iOS
175      },
176      // Enable playsinline for iOS devices to allow custom controls
177      playsinline: true,
178      youtube: {
179        ...(options.autoplay && { autoplay: options.autoplay }),
180        ...(options.start && { start: options.start }),
181        ...(options.end && { end: options.end }),
182        ...(options.rel && { rel: options.rel }),
183        ...(options.fullscreen && { fs: options.fullscreen })
184      },
185      vimeo: {
186        byline: false,
187        portrait: false,
188        title: false,
189        speed: true,
190        transparent: false,
191        controls: false,
192        ...(options.t && { t: options.t }),
193        ...(options.vautoplay && { autoplay: options.vautoplay }),
194        ...(options.autopause && { autopause: options.autopause }),
195        ...(options.dnt && { dnt: options.dnt }),
196      }
197    });
198
199    playerInit[playerId] = player;
200
201
202    // iOS YouTube fullscreen fix: Ensure iframe has proper attributes
203    if (shouldUseFallbackFullscreen) {
204      const iframe = document.querySelector(`[data-playerid='${playerId}'] iframe[src*="youtube"]`);
205      if (iframe) {
206        // Ensure the iframe allows fullscreen
207        iframe.setAttribute('allowfullscreen', '');
208        iframe.setAttribute('webkitallowfullscreen', '');
209        iframe.setAttribute('mozallowfullscreen', '');
210
211        // Add iOS-specific class for styling
212        iframe.classList.add('ios-youtube-iframe');
213
214        // Listen for fullscreen events to handle iOS-specific behavior
215        player.on('enterfullscreen', () => {
216          // Force viewport meta tag update for better fullscreen experience
217          const viewport = document.querySelector('meta[name="viewport"]');
218          if (viewport) {
219            const originalContent = viewport.getAttribute('content');
220            viewport.setAttribute('data-original-content', originalContent);
221            viewport.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover');
222          }
223        });
224
225        player.on('exitfullscreen', () => {
226          // Restore original viewport meta tag
227          const viewport = document.querySelector('meta[name="viewport"]');
228          if (viewport && viewport.hasAttribute('data-original-content')) {
229            viewport.setAttribute('content', viewport.getAttribute('data-original-content'));
230            viewport.removeAttribute('data-original-content');
231          }
232        });
233      }
234    }
235
236
237
238    // Mark the wrapper as initialized
239    wrapper.classList.add('plyr-initialized');
240
241    const posterElement = wrapper.querySelector('.plyr__poster');
242
243    if (posterElement) {
244      const interval = setInterval(() => {
245        if (posterElement && posterElement.style.backgroundImage) {
246          wrapper.style.opacity = '1';
247          clearInterval(interval);
248        }
249      }, 200);
250
251    }
252
253  }
254
255  // Check for the existence of the player's pip button at regular intervals
256  const pipInterval = setInterval(() => {
257
258    let playerPip = document.querySelector(`[data-playerid="${playerId}"] [data-plyr="pip"]`);
259    if (playerPip) {
260      clearInterval(pipInterval);
261
262      let options = document.querySelector(`[data-playerid="${playerId}"]`).getAttribute('data-options');
263
264      options = JSON.parse(options);
265      if (!options.self_hosted) {
266
267        const iframeSelector = document.querySelector(`[data-playerid="${playerId}"] .plyr__video-wrapper`);
268
269        // Add click event listener to toggle the pip mode
270        playerPip.addEventListener('click', () => {
271          iframeSelector.classList.toggle('pip-mode');
272
273          let parentElement = iframeSelector.parentElement;
274          while (parentElement) {
275            parentElement.style.zIndex = '9999';
276            parentElement = parentElement.parentElement;
277          }
278
279        });
280
281
282
283        if (options.pip) {
284          iframeSelector.appendChild(pipPlayIconElement);
285          iframeSelector.appendChild(pipPauseIconElement);
286          iframeSelector.appendChild(pipCloseElement);
287          const pipPlay = document.querySelector(`[data-playerid="${playerId}"] .plyr__video-wrapper .pip-play`);
288          const pipPause = document.querySelector(`[data-playerid="${playerId}"] .plyr__video-wrapper .pip-pause`);
289          const pipClose = document.querySelector(`[data-playerid="${playerId}"] .plyr__video-wrapper .pip-close`);
290
291          pipClose.addEventListener('click', () => {
292            iframeSelector.classList.remove('pip-mode');
293          });
294
295
296          iframeSelector.addEventListener('click', () => {
297            const ariaPressedValue = document.querySelector(`[data-playerid="${playerId}"] .plyr__controls [data-plyr="play"]`).getAttribute('aria-pressed');
298
299            if (ariaPressedValue === 'true') {
300              pipPause.style.display = 'none';
301              pipPlay.style.display = 'flex';
302            } else {
303              pipPlay.style.display = 'none';
304              pipPause.style.display = 'flex';
305            }
306          });
307
308        }
309
310
311      }
312    }
313
314  }, 200);
315
316}

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.