PageSourceSearch

https://www.unila.ac.id/en/wp-content/plugins/video-popup/assets/js/videoPopup.js?ver=2.0.3

js unila.ac.id collected 2026-10-01 11:25:37 UTC 20,340 bytes, 578 lines download raw bytes

1/**
2 * Pure JavaScript Video Popup Library - Developed by Alobaidi.
3 * Core library that manages the popup display, video embedding, and all related functionality
4 * License: This library is exclusive to the Video Popup plugin for WordPress and must not be used separately or outside the plugin. Developed by Alobaidi.
5 * 
6 * @author   Alobaidi
7 * @version  2.0.3
8 */
9
10
11/**
12 * Main VideoPopup class
13 * Manages popup creation, video embedding and all popup behaviors
14 */
15class VideoPopup {
16    /**
17     * Initializes plugin with customizable options
18     * @param {Object} options Configuration options
19     */
20    constructor(options = {}) {
21        this.defaults = {
22            autoplay: this.validateBoolean(options.autoplay, true),
23            wrapClose: this.validateBoolean(options.wrapClose, false),
24            noCookie: this.validateBoolean(options.noCookie, false),
25            handleVars: this.validateBoolean(options.handleVars, false),
26            onPageLoad: this.validateBoolean(options.onPageLoad, false),
27            oplCookie: options.oplCookie || false,
28            debug: this.validateBoolean(options.debug, false)
29        };
30        
31        this.init();
32    }
33
34    /**
35     * Initializes event listeners
36     */
37    init() {
38        this.addClickListener();
39    }
40
41    /**
42     * Adds click event listeners to video links
43     */
44    addClickListener() {
45        document.querySelectorAll('a.vp-a, a.vp-s').forEach(link => {
46            link.addEventListener('click', async (e) => {
47
48                if ( link.classList.contains('vp-a') ) {
49                    e.preventDefault();
50                    link.blur();
51                    await this.openPopup(link, true);
52                }
53
54                else if ( link.classList.contains('vp-s') ) {
55                    e.preventDefault();
56                    link.blur();
57                    await this.openPopup(link, false);
58                }
59        
60            });
61        });
62    }
63
64    /**
65     * Validates boolean values with various formats
66     * @param {*} value Value to validate as boolean
67     * @param {boolean} defaultValue Default if invalid
68     * @return {boolean} Normalized boolean value
69     */
70    validateBoolean(value, defaultValue) {
71        if (value === undefined || value === null) return defaultValue;
72        
73        if (value === true || value === false) return value;
74        
75        if (value && typeof value === 'string') {
76            const cleanValue = value.trim().toLowerCase();
77            if (cleanValue === 'true' || cleanValue === '1') return true;
78            if (cleanValue === 'false' || cleanValue === '0') return false;
79        }
80        
81        if (typeof value === 'number') {
82            if (value === 1) return true;
83            if (value === 0) return false;
84        }
85        
86        return defaultValue;
87    }
88
89    /**
90     * Trims string values if they exist
91     * @param {*} value Value to trim if string
92     * @return {*} Trimmed value or original value
93     */
94    trimIfExists(value) {
95        if ( value && (typeof value === 'string' || typeof value === 'number') ) {
96            const trimmed = typeof value === 'string' ? value.trim() : value;
97            return trimmed === '' ? null : trimmed;
98        }
99        return value;
100    }
101
102    /**
103     * Opens popup with video content
104     * @param {HTMLElement} element Link element that was clicked
105     * @param {boolean} autoplay Whether video should autoplay
106     */
107    async openPopup(element, autoplay) {
108        const data = this.extractData(element);
109        const embedHTML = this.generateEmbed(data, autoplay);
110        await this.createPopup(embedHTML, data);
111    }
112
113    /**
114     * Sets cookie with expiration time
115     * @param {string} name Cookie name
116     * @param {number} days Days until expiration
117     */
118    setCookie(name, days) {
119        if ( !name || !days ) return;
120        const expirySec = Math.floor(Date.now() / 1000) + (days * 24 * 60 * 60);
121        const expiryDate = new Date(expirySec * 1000);
122        document.cookie = `${name}=${expirySec};expires=${expiryDate.toUTCString()};path=/`;
123    }
124
125    /**
126     * Checks if cookie exists
127     * @param {string} name Cookie name
128     * @return {boolean} True if cookie exists
129     */
130    getCookie(name) {
131        if ( !name ) return;
132        const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
133        return match ? true : false;
134    }
135
136    /**
137     * Removes cookie if it exists
138     * @param {string} name Cookie name
139     */
140    unsetCookie(name){
141        if ( !name ) return;
142        if ( this.getCookie(name) ) {
143            document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;
144        }
145    }
146
147    /**
148     * Extracts data attributes and settings from link element
149     * @param {HTMLElement} element Link element
150     * @return {Object} Extracted and validated data
151     */
152    extractData(element) {
153        const url = element.href;
154
155        let autoplay_status;
156        if ( element.classList.contains('vp-a') ) {
157            autoplay_status = 'true (vp-a class)';
158        } else if ( element.classList.contains('vp-s') ) {
159            autoplay_status = 'false (vp-s class)';
160        } else {
161            autoplay_status = 'the link are not contains vp-s or vp-a class!';
162        }
163
164        const noCookie = this.trimIfExists(element.getAttribute('data-cookie'));
165        const wrapClose = this.trimIfExists(element.getAttribute('data-wrap-c'));
166
167        return {
168            url: url,
169            noCookie: this.validateBoolean(noCookie, this.defaults.noCookie),
170            wrapClose: this.validateBoolean(wrapClose, this.defaults.wrapClose),
171
172            videoType: this.detectVideoType(url),
173            videoMimeType: this.getDirectVideoMimeType(url),
174
175            isAutoplay: autoplay_status,
176            mute: this.trimIfExists(element.getAttribute('data-mute')),
177
178            linkClasses: element.classList,
179            handleVars: this.defaults.handleVars,
180            onPageLoad: this.defaults.onPageLoad,
181            oplCookie: this.defaults.oplCookie
182        };
183    }
184
185    /**
186     * Generates appropriate embed code based on URL type
187     * @param {Object} data Video data object
188     * @param {boolean} autoplay Whether video should autoplay
189     * @return {string|number|null} HTML embed code or error indicator
190     */
191    generateEmbed(data, autoplay) {
192        const url = data.url ? data.url.trim() : null;
193        if ( !url ) return null;
194        
195        if (this.isYouTube(url)) {
196            return this.createYouTubeEmbed(url, data, autoplay);
197        } else if (this.isVimeo(url)) {
198            return this.createVimeoEmbed(url, data, autoplay);
199        } else if (this.isDirectVideo(url)) {
200            return this.createDirectVideoEmbed(url, data, autoplay);
201        }
202        
203        return 0;
204    }
205
206    /**
207     * Checks if URL is from YouTube
208     * @param {string} url URL to check
209     * @return {boolean} True if YouTube URL
210     */
211    isYouTube(url) {
212        return /youtube\.com|youtu\.be|youtube-nocookie\.com/i.test(url);
213    }
214
215    /**
216     * Checks if URL is from Vimeo
217     * @param {string} url URL to check
218     * @return {boolean} True if Vimeo URL
219     */
220    isVimeo(url) {
221        return /vimeo\.com/i.test(url);
222    }
223
224    /**
225     * Checks if URL is direct video file
226     * @param {string} url URL to check
227     * @return {boolean} True if direct video file
228     */
229    isDirectVideo(url) {
230        return /\.(mp4|webm)$/i.test(url);
231    }
232
233    /**
234     * Determines MIME type for direct video files
235     * @param {string} url Video URL
236     * @return {string|null} MIME type or null
237     */
238    getDirectVideoMimeType(url) {
239        if (/\.mp4$/i.test(url)) {
240            return 'video/mp4';
241        }
242        else if (/\.webm$/i.test(url)) {
243            return 'video/webm';
244        }
245        else {
246            return null;
247        }
248    }
249
250    /**
251     * Detects video provider type from URL
252     * @param {string} url Video URL
253     * @return {string|boolean} CSS class name for video type or false
254     */
255    detectVideoType(url) {
256        if (this.isYouTube(url)) {
257            return 'vp-video-type-youtube';
258        } 
259
260        else if (this.isVimeo(url)) {
261            return 'vp-video-type-vimeo';
262        } 
263
264        else if (this.isDirectVideo(url)) {
265            const getVideoMimeType = this.getDirectVideoMimeType(url);
266
267            if ( getVideoMimeType == 'video/mp4') {
268                return 'vp-video-type-mp4';
269            }
270            else if ( getVideoMimeType == 'video/webm' ) {
271                return 'vp-video-type-webm';
272            }
273            return null;
274        }
275
276        return false;
277    }
278
279    /**
280     * Extracts YouTube video ID from URL
281     * @param {string} url YouTube URL
282     * @return {string|null} Video ID or null
283     */
284    extractYouTubeId(url) {
285        const match = url.match(/(?:youtube\.com\/(?:watch\?v=|embed\/|v\/|shorts\/)|youtu\.be\/|youtube-nocookie\.com\/(?:watch\?v=|embed\/|v\/)|m\.youtube\.com\/watch\?v=)([^&\n?#]+)/);
286        return match ? match[1] : null;
287    }
288
289    /**
290     * Extracts Vimeo video ID from URL
291     * @param {string} url Vimeo URL
292     * @return {string|null} Video ID or null
293     */
294    extractVimeoId(url) {
295        const match = url.match(/vimeo\.com\/(?:channels\/[^\/]+\/|video\/)?(\d+)(?:\/|\?|$)/);
296        return match ? match[1] : null;
297    }
298
299    /**
300     * Creates YouTube embed HTML
301     * @param {string} url YouTube URL
302     * @param {Object} data Video settings
303     * @param {boolean} autoplay Whether video should autoplay
304     * @return {string|boolean|null} Embed HTML or false/null on error
305     */
306    createYouTubeEmbed(url, data, autoplay) {
307        if ( !url ) return null;
308
309        url = url.trim();
310        const videoId = this.extractYouTubeId(url);
311        if ( !videoId ) return false;
312
313        const youtubeDomain = data.noCookie === true || data.noCookie == 1 ? 'youtube-nocookie.com' : 'youtube.com';
314
315        let embedUrl = `https://www.${youtubeDomain}/embed/${videoId}?`;
316
317        embedUrl += `autoplay=${autoplay ? 1 : 0}`;
318
319        if (data.mute == 1) embedUrl += `&mute=1`;
320
321        return `<iframe src="${embedUrl}" frameborder="0" allow="autoplay; fullscreen"></iframe>`;
322    }
323
324    /**
325     * Creates Vimeo embed HTML
326     * @param {string} url Vimeo URL
327     * @param {Object} data Video settings
328     * @param {boolean} autoplay Whether video should autoplay
329     * @return {string|boolean|null} Embed HTML or false/null on error
330     */
331    createVimeoEmbed(url, data, autoplay) {
332        if ( !url ) return null;
333
334        url = url.trim();
335        const videoId = this.extractVimeoId(url);
336        if ( !videoId ) return false;
337
338        let embedUrl = `https://player.vimeo.com/video/${videoId}?`;
339
340        embedUrl += `autoplay=${autoplay ? 1 : 0}`;
341
342        if (data.mute == 1) embedUrl += `&muted=1`;
343        if (data.noCookie === true || data.noCookie == 1) embedUrl += `&dnt=1`;
344
345        return `<iframe src="${embedUrl}" frameborder="0" allow="autoplay; fullscreen"></iframe>`;
346    }
347
348    /**
349     * Creates direct video embed HTML
350     * @param {string} url Direct video URL
351     * @param {Object} data Video settings
352     * @param {boolean} autoplay Whether video should autoplay
353     * @return {string|boolean|null} Embed HTML or false/null on error
354     */
355    createDirectVideoEmbed(url, data, autoplay) {
356        if ( !url ) return null;
357
358        url = url.trim();
359
360        if ( !this.isDirectVideo(url) ) return false;
361
362        const autoplayAttr = autoplay ? ' autoplay' : '';
363        const mutedAttr = data.mute ? ' muted' : '';
364        
365        const getVideoMimeType = this.getDirectVideoMimeType(url) || 'video/mp4';
366        
367        return `<video${mutedAttr}${autoplayAttr}
367 controls playsInline controlslist="nodownload" disablePictureInPicture="true">
368                    <source src="${url}" type="${getVideoMimeType}">
369                    Your browser does not support the video tag.
370                 </video>`;
371    }
372
373    /**
374     * Removes any existing popup from the page
375     */
376    deleteCurrentPopup() {
377        const currentOldPopup = document.querySelector('.YouTubePopUp-Wrap');
378        if ( currentOldPopup ) {
379            currentOldPopup.remove();
380        }
381        
382        const currentPopup = document.querySelector('.vp-show');
383        if ( currentPopup ) {
384            currentPopup.classList.remove('vp-show');
385            currentPopup.remove();
386        }
387    }
388
389    /**
390     * Creates and displays the popup with video content
391     * @param {string} embedHTML HTML for video embed
392     * @param {Object} data Video settings
393     */
394    async createPopup(embedHTML, data) {
395        this.deleteCurrentPopup();
396
397        const popup = document.createElement('div');
398        const modalType = this.defaults.onPageLoad ? 'vp-modal vp-modal_type_onpageload' : 'vp-modal vp-modal_type_click';
399        popup.className = modalType;
400
401        const videoTypeClass = data.videoType ? ' ' + data.videoType : '';
402        const iframe = embedHTML ? embedHTML : '';
403        
404        popup.innerHTML = `
405            <div class="vp-container${videoTypeClass}">
406                <div class="vp-video" style="width: 800px; height: 450px;">
407                    <span class="vp-close"></span>
408                    ${iframe}
409                </div>
410            </div>
411        `;
412
413        const popupContainer = popup.querySelector('.vp-container');
414        document.body.appendChild(popup);
415
416        await new Promise(resolve => setTimeout(resolve, 30));
417        this.deleteCurrentPopup();
418        popup.classList.add('vp-show');
419        popup.focus();
420        data['iframe'] = iframe ? 'appear' : 'no iframe';
421
422        if ( this.defaults.onPageLoad && data.oplCookie ) {
423            const cookieName = data.oplCookie["name"];
424            const cookieDays = data.oplCookie["days"];
425            if ( cookieName && cookieDays ) {
426                this.setCookie(cookieName, parseInt(cookieDays));
427            }
428        }
429        
430        popup.addEventListener('click', async (e) => {
431            if ( data.wrapClose != 1 && data.wrapClose !== true ) {
432                if ( popup && e.target === popup ) {
433                    await this.closePopup();
434                }
435
436                if ( popupContainer && e.target === popupContainer ) {
437                    await this.closePopup();
438                }
439            }
440        });
441        
442        popup.querySelector('.vp-close').addEventListener('click', async () => {
443            await this.closePopup();
444        });
445
446        // Allows closing popup by ESC key
447        document.addEventListener('keydown', async (e) => {
448            const isShowPopup = document.querySelector('.vp-show'); // Current Popup
449            if ( e.key === 'Escape' && isShowPopup ) {
450                await this.closePopup();
451            }
452        });
453
454        this.debug(data);
455    }
456
457    /**
458     * Closes and removes the popup
459     */
460    async closePopup() {
461        const popup = document.querySelector('.vp-show');
462        if (popup) {
463            popup.classList.remove('vp-show');
464            await new Promise(resolve => setTimeout(resolve, 500));
465            popup.remove();
466        }
467    }
468
469    /**
470     * Outputs debug information to console
471     * @param {Object} data Debug data to display
472     */
473    debug(data) {
474        if ( !this.defaults.handleVars ) {
475            console.log("videoPopup.js: General options object not found. Will use default options.");
476        }
477
478        const debugLogTitle = this.defaults.onPageLoad ? 'Video Popup - On Page Load Modal Debug' : 'Video Popup Modal Debug';
479
480        if ( this.defaults.debug ) {
481            const videoURL =  data.url ? data.url.trim() : null;
482            if ( !videoURL ) {
483                console.log(`=== ${debugLogTitle} - Start ===`);
484                console.log('   No video URL! Please enter a video URL to display the debug result.');
485                console.log(`=== ${debugLogTitle} - End ===`);
486                console.log(''); // an empty line
487                return;
488            } 
489
490            console.log(`=== ${debugLogTitle} - Start ===`);
491            
492            console.log('Link Properties:');
493            for (const [key, value] of Object.entries(data)) {
494                if (key === 'oplCookie' && typeof value === 'object' && value !== null) {
495                    console.log(`   ${key}: {`);
496                    for (const [cookieKey, cookieValue] of Object.entries(value)) {
497                        console.log(`           ${cookieKey}: "${cookieValue}"`);
498                    }
499                    console.log(`       }`);
500                } else {
501                    console.log(`   ${key}: ${value}`);
502                }
503            }
504
505            console.log('Functions Status:');
506
507            console.log('   If YouTube Video:');
508                const isYouTubeResult = this.isYouTube(videoURL);
509                console.log(`      isYouTube: ${isYouTubeResult ? 'true' : isYouTubeResult}`);
510                const youtubeVideoId = this.extractYouTubeId(videoURL);
511                console.log(`      extractYouTubeId: ${youtubeVideoId ? `Works Good - ${youtubeVideoId}` : youtubeVideoId}`);
512                const youtubeEmbedResult = this.createYouTubeEmbed(videoURL, data, true);
513                console.log(`      createYouTubeEmbed: ${youtubeEmbedResult ? 'Works Good' : youtubeEmbedResult}`);    
514
515            console.log('   If Vimeo Video:');
516                const isVimeoResult = this.isVimeo(videoURL);
517                console.log(`      isVimeo: ${isVimeoResult ? 'true' : isVimeoResult}`);
518                const vimeoVideoId = this.extractVimeoId(videoURL);
519                console.log(`      extractVimeoId: ${vimeoVideoId ? `Works Good - ${vimeoVideoId}` : vimeoVideoId}`);
520                const vimeoEmbedResult = this.createVimeoEmbed(videoURL, data, true);
521                console.log(`      createVimeoEmbed: ${vimeoEmbedResult ? 'Works Good' : vimeoEmbedResult}`);
522
523            console.log('   If Direct Video:');
524                const isDirectVideoResult = this.isDirectVideo(videoURL);
525                console.log(`      isDirectVideo: ${isDirectVideoResult ? 'true' : isDirectVideoResult}`);
526                const directEmbedResult = this.createDirectVideoEmbed(videoURL, data, true);
527                console.log(`      createDirectVideoEmbed: ${directEmbedResult ? 'Works Good' : directEmbedResult}`);
528
529            const generateEmbedResult = this.generateEmbed(data, true);
530            console.log(`   generateEmbed: ${generateEmbedResult ? 'Works Good' : generateEmbedResult}`);
531
532            console.log(`=== ${debugLogTitle} - End ===`);
533            console.log(''); // an empty line
534        }
535    }
536}
537
538
539/**
540 * VideoPopupOnPageLoad class extends core popup functionality
541 * with specialized behavior for automatic page load display
542 * 
543 * @extends VideoPopup
544 */
545class VideoPopupOnPageLoad extends VideoPopup {
546    constructor(options = {}) {
547        super(options);
548    }
549
550    init(){}
551    
552    async closePopup() {
553        await super.closePopup();
554        delete this;
555    }
556}
557
558
559/**
560 * Auto-initialization when DOM is ready
561 * Creates VideoPopup instance with default or custom settings
562 */
563document.addEventListener('DOMContentLoaded', () => {
564    if ( typeof theVideoPopupGeneralOptions === 'undefined' ) {
565        new VideoPopup( { handleVars: false } );
566        return;
567    }
568
569    new VideoPopup({
570        autoplay: true,
571        onPageLoad: false,
572        oplCookie: false,
573        wrapClose: theVideoPopupGeneralOptions.wrap_close,
574        noCookie: theVideoPopupGeneralOptions.no_cookie,
575        handleVars: true,
576        debug: theVideoPopupGeneralOptions.debug
577    });
vendor: 3 bytes, line 578
578});

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.