PageSourceSearch

https://elizabethfiend.com/blog/wp-content/plugins/nextgen-gallery…/galleria.nextgen_pro_lightbox.js?ver=4.2.1

js elizabethfiend.com collected 2026-10-10 01:36:06 UTC 91,692 bytes, 1,612 lines download raw bytes

1(function($) {
2
3
4    var add_nggpl_theme = function() {
5
6        Galleria.addTheme({
7            name: 'nextgen_pro_lightbox',
8            author: 'Imagely',
9            version: 2.0,
10            defaults: {
11                debug: false,
12                responsive: true,
13                carousel: true,
14                thumbnails: 'lazy',
15                fullscreen: false,
16                trueFullscreen: false,
17                fullscreenDoubleTap: false,
18                maxScaleRatio: 1
19            },
20            init: function(options) {
21                var self = this;
22                Galleria.requires(1.41, 'This version of the NextGEN Pro Lightbox theme requires Galleria 1.4.1 or later');
23
24                $.nplModal('log', 'theme initialization', {
25                    options: options
26                });
27
28                // Some objects have aip variables - animation-in-progress - and are used to make jQuery animations smoother
29                var methods = {
30                    sidebar: {
31                        _is_open: false,
32                        _type: '',
33                        is_open: function(state) {
34                            if (typeof state !== 'undefined') {
35                                this._is_open = state;
36                            } else {
37                                return this._is_open;
38                            }
39                        },
40                        toggle: function(type) {
41                            $.nplModal('log', 'theme sidebar.toggle()', {
42                                type: type
43                            });
44                            if (this.is_open() && type === this.get_type()) {
45                                this.close();
46                            } else {
47                                this.open(type);
48                            }
49                        },
50                        open: function(type) {
51                            $.nplModal('log', 'theme sidebar.open()', {
52                                type: type
53                            });
54
55                            $('#npl_wrapper').addClass('npl-sidebar-open npl-sidebar-overlay-open');
56
57                            this.render(type);
58                            methods.sidebar.is_open(true);
59
60                            var state = $.nplModal('get_state');
61                            state.sidebar = type;
62
63                            $.nplModal(
64                                'router.navigate',
65                                $.nplModal('get_setting', 'router_slug')
66                                + '/' + state.slug
67                                + '/' + state.image_id
68                                + '/' + type,
69                                true
70                            );
71
72                            self.resize();
73                            self.trigger('npl_sidebar_opened');
74                        },
75                        close: function() {
76                            $.nplModal('log', 'theme sidebar.close()');
77
78                            $('#npl_wrapper').removeClass('npl-sidebar-open npl-sidebar-overlay-open');
79
80                            methods.sidebar.is_open(false);
81
82                            var state = $.nplModal('get_state');
83                            state.sidebar = null;
84                            $.nplModal(
85                                'router.navigate',
86                                $.nplModal('get_setting', 'router_slug')
87                                + '/' + state.slug
88                                + '/' + state.image_id,
89                                true
90                            );
91
92                            self.resize();
93                            self.trigger('npl_sidebar_closed');
94                        },
95                        render: function(type) {
96                            $.nplModal('log', 'theme sidebar.render()', {
97                                type: type
98                            });
99
100                            // switching to another sidebar type; flash the overlay
101                            if (type !== this.get_type()) {
102                                this._type = type;
103                                $.nplModal('get_state').sidebar = type;
104                            }
105
106                            methods.sidebars[type].render(methods.galleria.get_current_image_id());
107                            methods.sidebars[type].init();
108                        },
109                        get_type: function() {
110                            return this._type;
111                        },
112                        events: {
113                            bind: function() {
114                                $.nplModal('log', 'theme sidebar.events.bind()');
115                                $('#npl_content').on('npl_sidebar_rendered', this.rendered);
116                                $('#npl_sidebar_toggle').on('click', function() {
117                                    methods.sidebar.close();
118                                });
119                            },
120                            rendered: function() {
121                                $.nplModal('log', 'theme sidebar.events.rendered()');
122
123                                // This is hidden except for narrow viewports by default, allows phone users to remember what photo they are 'on'
124                                $('#nggpl-sidebar-thumbnail-img').attr('src', self.getData(self.getIndex()).image);
125                            }
126                        }
127                    },
128                    sidebars: {
129                        datacache: {
130                            _cache: [],
131                            _current_image_ndx: null,
132                            _last_image_ndx: null,
133
134                            events: {
135                                bind: function() {
136                                    $.nplModal('log', 'theme sidebars.datacache.events.bind()');
137                                    self.bind('loadstart', this.loadstart);
138                                },
139
140                                // Used to track which direction users are navigating in so we can intelligently
141                                // pre-load sidebar data in advance of the image being selected
142                                loadstart: function() {
143                                    $.nplModal('log', 'theme sidebars.datacache.events.image()');
144                                    // Initial value at startup
145                                    if (methods.sidebars.datacache._current_image_ndx === null) {
146                                        methods.sidebars.datacache._last_image_ndx = methods.sidebars.datacache._current_image_ndx = self.getIndex();
147                                    } else {
148                                        // Store the current index and shift the old value
149                                        methods.sidebars.datacache._last_image_ndx = methods.sidebars.datacache._current_image_ndx;
150                                        methods.sidebars.datacache._current_image_ndx = self.getIndex();
151                                    }
152                                }
153                            },
154
155                            get_carousel_navigation_direction: function() {
156                                if (this._current_image_ndx === this._last_image_ndx) {
157                                    return 'same';
158                                } else {
159                                    if (this._last_image_ndx === 0 && this._current_image_ndx === (self.getDataLength() - 1)) {
160                                        return 'left';
161                                    } else if (this._current_image_ndx === 0 && this._last_image_ndx === (self.getDataLength() -1)) {
162                                        return 'right';
163                                    } else {
164                                        return (this._current_image_ndx < this._last_image_ndx) ? 'left' : 'right';
165                                    }
166                                }
167                            },
168
169                            // because the .length operator isn't accurate
170                            get_cache_size: function() {
171                                var size = this._cache.length;
172
173                                $.nplModal('log', 'theme sidebars.comments.get_cache_size()', {
174                                    result: size
175                                });
176
177                                return size;
178                            },
179
180                            // returns the image-id field of the first preceeding image found whose comments aren't cached
181                            get_prev_uncached_image_id: function(id, step) {
182                                step = step || 0;
183                                var prev_image_id = self.getData(self.getPrev(methods.galleria.get_index_from_id(id) - step)).image_id;
184                                if (this._cache[prev_image_id] && this.get_cache_size() < self.getDataLength()) {
185                                    prev_image_id = this.get_prev_uncached_image_id(prev_image_id);
186                                }
187
188                                $.nplModal('log', 'theme sidebars.comments.get_prev_uncached_image_id()', {
189                                    id: id,
190                                    result: prev_image_id
191                                });
192
193                                return prev_image_id;
194                            },
195
196                            // returns the image-id field of the first following image found whose comments aren't cached
197                            get_next_uncached_image_id: function(id, step) {
198                                step = step || 0;
199                                var next_image_id = self.getData(self.getNext(methods.galleria.get_index_from_id(id) + step)).image_id;
200                                if (this._cache[next_image_id] && this.get_cache_size() < self.getDataLength()) {
201                                    next_image_id = this.get_next_uncached_image_id(next_image_id);
202                                }
203
204                                $.nplModal('log', 'theme sidebars.comments.get_next_uncached_image_id()', {
205                                    id: id,
206                                    result: next_image_id
207                                });
208
209                                return next_image_id;
210                            },
211
212                            // expanded request method: adds first pre-ceding and following uncached id to the request
213                            expanded_request: function(id, finished) {
214                                $.nplModal('log', 'theme sidebars.comments.expanded_request()', {
215                                    id: id
216                                });
217
218                                var id_array = (id instanceof Array) ? id : id.toString().split(',');
219
220                                // a single ID was requested, so inject some extras so they can be cached in advance
221                                if (id_array.length === 1) {
222                                    var key = id_array[0];
223                                    var prev = this.get_prev_uncached_image_id(key);
224                                    var next = this.get_next_uncached_image_id(key);
225                                    if (!this._cache[prev]) {
226                                        this._cache[prev] = 'Placeholder stub';
227                                        id_array.unshift(prev);
228                                    }
229                                    if (!this._cache[next] && prev !== next && id !== next) {
230                                        this._cache[next] = 'Placeholder stub';
231                                        id_array.push(next);
232                                    }
233                                }
234
235                                id_array = this.sort_uniq(id_array);
236                                this.request(id_array, 0, finished);
237                            },
238
239                            // handles the HTTP request to load comments & cache the results
240                            request: function(id, page, finished) {
241                                $.nplModal('log', 'theme sidebars.comments.request()', {
242                                    id: id,
243                                    page: page
244                                });
245
246                                var myself = this; // self is taken
247                                var postdata = {
248                                    type: 'image',
249                                    page: page,
250                                    id: id.join(','),
251                                    from: window.parent.location.toString(),
252                                };
253                                if ($.nplModal('get_setting', 'lang', false)) {
254                                    postdata.lang = $.nplModal('get_setting', 'lang');
255                                }
256
257                                $.ajax({
258                                    url: photocrati_ajax.rest_url + '
258nggpro/v1/Galleria/GetSidebarData',
259                                    method: 'POST',
260                                    beforeSend: function (xhr) {
261                                        xhr.setRequestHeader('X-WP-Nonce', window.nextgen_pro_lightbox_authentication.nonce);
262                                    },
263                                    xhrFields: {
264                                        withCredentials: true
265                                    },
266                                    data: postdata,
267                                    success: function(data) {
268                                        $.nplModal('log', 'theme sidebars.comments.request() response', {
269                                            response: data
270                                        });
271
272                                        if (typeof(data) !== 'object') {
273                                            data = JSON.parse(data);
274                                        }
275                                        for (var ndx in data) {
276                                            myself._cache[ndx] = data[ndx];
277                                        }
278                                        if (typeof finished === 'function') {
279                                            finished(data);
280                                        }
281                                    }
282                                });
283                            },
284
285                            // find and load the next un-cached results
286                            load_more: function(id) {
287                                $.nplModal('log', 'theme sidebars.comments.load_more()', {
288                                    id: id
289                                });
290
291                                if (methods.nplModal.is_nextgen_gallery()
292                                    &&  $.nplModal('get_setting', 'enable_routing', false)
293                                    &&  $.nplModal('get_setting', 'enable_comments', false)) {
294                                    var precache_ids = [];
295
296                                    var direction = methods.sidebars.datacache.get_carousel_navigation_direction();
297                                    var count = 3;
298
299                                    // Retrieve X images in the same direction the user is navigating
300                                    for (var i = 0; i <= count; i++) {
301                                        if (direction === 'left') {
302                                            var uncached_id = this.get_prev_uncached_image_id(id, i);
303                                        } else {
304                                            var uncached_id = this.get_next_uncached_image_id(id, i);
305                                        }
306
307                                        // Push the recently found IDs to this._cache so they can't be included again
308                                        if (!this._cache[uncached_id]) {
309                                            this._cache[uncached_id] = 'Placeholder stub';
310                                            precache_ids.push(uncached_id);
311                                        }
312                                    }
313
314                                    precache_ids = this.sort_uniq(precache_ids);
315
316                                    if (precache_ids.length !== 0) {
317                                        this.expanded_request(precache_ids);
318                                    }
319                                }
320                            },
321
322                            sort_uniq: function(ids) {
323                                return ids.sort().filter(function(item, pos, ary) {
324                                    return !pos || item !== ary[pos - 1];
325                                })
326                            },
327
328                            get_cache_by_id: function(id) {
329                                return this._cache[id];
330                            }
331                        },
332                        comments: {
333                            // called after render(), initialize logic & events
334                            init: function() {
335                                $.nplModal('log', 'theme sidebars.comments.init()');
336
337                                if ($('#nggpl-comments-wrapper').length !== 1) { return; }
338
339                                // jquery's .val() fails with hidden fields
340                                var origin_url = document.getElementById("ngg_comment_origin_url");
341                                if (typeof origin_url !== 'undefined' && origin_url !== null) {
342                                    origin_url.value = window.location.href.toString();
343                                }
344
345                                // It is much faster to change the target attribute globally here than through WP hooks
346                                $('#npl_sidebar').find('a').each(function() {
347                                    if ($(this).attr('id') === 'nggpl-comment-logout') {
348                                        $(this).attr('href', $(this).attr('href') + '?redirect_to=' + window.location.toString());
349                                    } else {
350                                        $(this).attr('target', '_blank');
351                                    }
352                                });
353
354                                $('#nggpl-respond-form').on('submit', function (event) {
355                                    event.preventDefault();
356                                    var commentstatus = $('#nggpl-comment-status');
357                                    $('#npl_wrapper').addClass('npl-sidebar-overlay-open');
358                                    $.ajax({
359                                        type: $(this).attr('method'),
360                                        url: $(this).attr('action'),
361                                        data: $(this).serialize(),
362                                        dataType: 'json',
363                                        success: function (data) {
364                                            if (data.success === true) {
365                                                $('#nggpl-comment').val('');
366                                                $('#nggpl-comments-title').val('');
367                                                var image_id = methods.galleria.get_current_image_id();
368                                                methods.sidebars.datacache.expanded_request(image_id, function() {
369                                                    methods.sidebar.render(methods.sidebars.comments.get_type(), image_id);
370                                                });
371                                            } else {
372                                                commentstatus.addClass('error')
373                                                    .html(data);
374                                                $('#npl_wrapper').removeClass('npl-sidebar-overlay-open');
375                                            }
376                                        },
377                                        complete: function (jqXHR, status) {
378                                        },
379                                        error: function (jqXHR) {
380                                            commentstatus.addClass('error').html(jqXHR.responseText);
381                                            $('#npl_wrapper').removeClass('npl-sidebar-overlay-open');
382                                        }
383                                    });
384                                });
385
386                                $("#npl_sidebar .nggpl-button, #nggpl-comment-form-wrapper input[type='submit']").each(function() {
387                                    var $this = $(this);
388                                    $this.css({
389                                        'color': $.nplModal('get_setting', 'sidebar_button_color'),
390                                        'background-color': $.nplModal('get_setting', 'sidebar_button_background')
391                                    });
392                                });
393
394                                // handles 'Reply' links
395                                $('.nggpl-reply-to-comment').on('click', function(event) {
396                                    event.preventDefault();
397                                    // all that wordpress needs is the comment_parent value
398                                    $('#nggpl-comment_parent').val($(this).data('comment-id'));
399                                    $('#nggpl-comment-reply-status').removeClass('hidden');
400
401                                    // IE has issues setting focus on invisible elements. Be wary
402                                    $('#nggpl-commentform').find(':input').filter(':visible').first().trigger('focus');
403                                    $('#npl_sidebar').scrollTop($('#nggpl-comments-bottom').offset().top);
404                                });
405
406                                // handles "cancel reply" link
407                                $('#nggpl-comment-reply-status a').on('click', function(event) {
408                                    event.preventDefault();
409                                    $('#nggpl-comment_parent').val('0');
410                                    $('#nggpl-comment-reply-status').addClass('hidden');
411                                });
412
413                                // handles comment AJAX pagination
414                                $('#nggpl-comment-nav-below a').on('click', function(event) {
415                                    event.preventDefault();
416                                    $('#npl_wrapper').addClass('npl-sidebar-overlay-open');
417                                    var page_id = $(this).data('page-id');
418                                    methods.sidebars.datacache.request(
419                                        [methods.galleria.get_current_image_id()],
420                                        page_id,
421                                        function() {
422                                            methods.sidebar.render('comments', methods.galleria.get_current_image_id());
423                                        }
424                                    );
425                                });
426
427                                self.trigger('npl_sidebar_rendered');
428
429                                if (methods.nplModal.is_nextgen_gallery()
430                                    &&  $.nplModal('get_setting', 'enable_routing', false)
431                                    &&  $.nplModal('get_setting', 'enable_sharing', false)) {
432                                    $('#nggpl-comments-image-share-icons').removeClass('disabled');
433                                    methods.share_icons.create(
434                                        '#nggpl-comments-image-share-icons',
435                                        methods.icons.get_overlay_color()
436                                    );
437                                }
438
439                                methods.sidebars.comments.wait_for_image_to_reveal();
440                            },
441
442                            wait_for_image_to_reveal: function() {
443                                if (!methods.sidebars.comments.events.between_loadstart_and_finish) {
444                                    $('#npl_wrapper').removeClass('npl-sidebar-overlay-open');
445                                } else {
446                                    methods.sidebars.comments.events.waiting_for_image_to_load = true;
447                                }
448                            },
449
450                            // returns the display area content from cache
451                            render: function(id) {
452                                $.nplModal('log', 'theme sidebars.comments.render()', {
453                                    id: id
454                                });
455
456                                var cache = methods.sidebars.datacache.get_cache_by_id(id);
457
458                                if (!cache) {
459                                    $('#npl_wrapper').addClass('npl-sidebar-overlay-open');
460                                    methods.sidebars.datacache.expanded_request(id, function() {
461                                        cache = methods.sidebars.datacache.get_cache_by_id(id);
462                                        $('#npl_sidebar').html(cache.comments['rendered_view']);
463                                        methods.sidebars.comments.init();
464                                    });
465                                } else if (cache === 'Placeholder stub') {
466                                    $('#npl_wrapper').addClass('npl-sidebar-overlay-open');
467                                    var interval = setInterval(function() {
468                                        cache = methods.sidebars.datacache.get_cache_by_id(id);
469                                        if (cache !== 'Placeholder stub') {
470                                            $('#npl_sidebar').html(cache.comments['rendered_view']);
471                                            methods.sidebars.comments.init();
472                                            clearInterval(interval);
473                                        }
474                                    }, 250);
475                                } else {
476                                    $('#npl_sidebar').html(cache.comments['rendered_view']);
477                                    $('#npl_wrapper').removeClass('npl-sidebar-overlay-open');
478                                }
479                            },
480
481                            get_type: function() {
482                                return 'comments';
483                            },
484
485                            events: {
486                                waiting_for_image_to_load: false,
487                                between_loadstart_and_finish: false,
488
489                                bind: function() {
490                                    $.nplModal('log', 'theme sidebars.comments.events.bind()');
491
492                                    if (methods.nplModal.is_nextgen_gallery()
493                                    &&  $.nplModal('get_setting', 'enable_routing', false)
494                                    &&  $.nplModal('get_setting', 'enable_comments', false)
495                                    &&  !methods.nplModal.is_random_source()) {
496                                        self.bind('loadstart', this.loadstart);
497                                        self.bind('npl_init', this.npl_init);
498                                        self.bind('npl_init_keys', this.npl_init_keys);
499                                        self.bind('image', this.image);
500                                    }
501                                },
502
503                                npl_init: function() {
504                                    $.nplModal('log', 'theme sidebars.comments.events.npl_init()');
505
506                                    // Adds comment toolbar button
507                                    var comment_button = $('<i/>')
508                                        .addClass('nggpl-toolbar-button-comment fa fa-comment')
509                                        .attr({'title': $.nplModal('get_setting', 'i18n').toggle_social_sidebar});
510                                    methods.thumbnails.register_button(
511                                        comment_button,
512                                        function(event) {
513                                            methods.sidebar.toggle(methods.sidebars.comments.get_type());
514                                            event.preventDefault();
515                                        }
516                                    );
517                                },
518
519                                image: function() {
520                                    methods.sidebars.comments.events.between_loadstart_and_finish = false;
521
522                                    if (methods.sidebars.comments.events.waiting_for_image_to_load) {
523                                        methods.sidebars.comments.events.waiting_for_image_to_load = false;
524                                        $('#npl_wrapper').removeClass('npl-sidebar-overlay-open');
525                                    }
526                                },
527
528                                _loadstart_run_once: false,
529                                loadstart: function(e) {
530                                    $.nplModal('log', 'theme sidebars.comments.events.npl_init_complete()');
531
532                                    methods.sidebars.comments.events.between_loadstart_and_finish = true;
533
534                                    if (methods.nplModal.is_nextgen_gallery() && !methods.sidebars.comments._loadstart_run_once) {
535                                        // possibly display the comments sidebar at startup
536                                        if (($.nplModal('get_state').sidebar && $.nplModal('get_state').sidebar === methods.sidebars.comments.get_type())
537                                        ||  $.nplModal('get_setting', 'display_comments')) {
538                                            methods.sidebar.open(methods.sidebars.comments.get_type());
539                                        }
540                                        methods.sidebars.comments._loadstart_run_once = true;
541                                    } else if (methods.nplModal.is_nextgen_gallery()
542                                           &&  $.nplModal('get_setting', 'enable_routing', false)
543                                           &&  $.nplModal('get_setting', 'enable_comments', false)) {
544                                            // updates the sidebar
545                                            methods.sidebars.datacache.load_more(methods.galleria.get_current_image_id());
546                                            if (methods.sidebar.is_open() && methods.sidebar.get_type() === methods.sidebars.comments.get_type()) {
547                                                methods.sidebar.render(methods.sidebars.comments.get_type());
548                                            }
549                                    }
550                                },
551
552                                npl_init_keys: function() {
553                                    $.nplModal('log', 'theme sidebars.comments.events.npl_init_keys()');
554                                    var input_types = methods.galleria.get_keybinding_exclude_list();
555                                    if (methods.nplModal.is_nextgen_gallery()
556                                    &&  $.nplModal('get_setting', 'enable_routing', false)
557                                    &&  $.nplModal('get_setting', 'enable_comments', false))
558                                    {
559                                        self.attachKeyboard({
560                                            // spacebar
561                                            32: function () {
562                                                if (!$(document.activeElement).is(input_types)) {
563                                                    methods.sidebar.toggle(methods.sidebars.comments.get_type());
564                                                }
565                                            }
566                                        });
567                                    }
568                                }
569                            }
570                        }
571                    },
572                    thumbnails: {
573                        is_open: function() {
574                            return !$('#npl_wrapper').hasClass('npl-carousel-closed');
575                        },
576                        toggle: function() {
577                            $.nplModal('log', 'theme thumbnails.toggle()');
578
579                            if (this.is_open()) {
580                                this.close();
581                            } else {
582                                this.open();
583                            }
584                        },
585                        open: function() {
586                            $.nplModal('log', 'theme thumbnails.open()');
587
588                            $('#npl_wrapper').removeClass('npl-carousel-closed');
589                            $('.galleria-dock-toggle-container i').toggleClass('fa-angle-up fa-angle-down');
590                            $('.galleria-dock-toggle-container').find('[data-fa-i2svg]').toggleClass('fa-angle-up fa-angle-down');
591                            $(window).trigger('resize');
592                        },
593                        close: function() {
594                            $.nplModal('log', 'theme thumbnails.close()');
595
596                            $('#npl_wrapper').addClass('npl-carousel-closed');
597                            $('.galleria-dock-toggle-container i').toggleClass('fa-angle-up fa-angle-down');
598                            $('.galleria-dock-toggle-container').find('[data-fa-i2svg]').toggleClass('fa-angle-up fa-angle-down');
599                            $(window).trigger('resize');
600                        },
601                        adjust_container: function() {
602                            $.nplModal('log', 'theme thumbnails.adjust_container()');
603                            // Important: this must be delayed for a short while after Galleria.resize() is invoked to allow
604                            // Galleria to finish repositioning itself and prevent possible race scenario.
605                            setTimeout(function() {
606                                var available_width = self.$('thumbnails-container').width()
607                                    - self.$('nextgen-buttons').width()
608                                    - self.$('thumb-nav-left').width()
609                                    - self.$('thumb-nav-right').width();
610                                if (available_width <= (70 * 4)) {
611                                    self.$('container').addClass('nggpl-carousel-too-small');
612                                } else {
613                                    self.$('container').removeClass('nggpl-carousel-too-small');
614                                }
615                            }, 250);
616                        },
617                        _buttons: [],
618                        register_button: function(button, callback) {
619                            $.nplModal('log', 'theme thumbnails.register_button()', {
620                                button: button
621                            });
622
623                            var wrapper = $('<span class="nggpl-button nggpl-toolbar-button"/>');
624                            if ($.nplModal('get_setting', 'icon_background_enabled', false)
625                            &&  $.nplModal('get_setting', 'icon_background_rounded', false)) {
626                                wrapper.addClass('nggpl-rounded');
627                            }
628                            wrapper.html(button);
629                            this._buttons.push(wrapper);
630                            $(self._dom.stage).append(wrapper);
631
632                            wrapper.on('click', function(event) {
633                                callback(event)
634                            });
635                        },
636                        get_registered_buttons: function() {
637                            $.nplModal('log', 'theme thumbnails.get_registered_buttons', {
638                                buttons: this._buttons
639                            });
640                            return this._buttons;
641                        },
642                        events: {
643                            bind: function() {
644                                $.nplModal('log', 'theme thumbnails.events.bind()');
645
646                                self.bind('loadfinish', methods.thumbnails.adjust_container);
647                                self.bind('loadfinish', this.loadfinish);
648                                self.bind('npl_sidebar_opened', methods.thumbnails.adjust_container);
649                                self.bind('npl_sidebar_closed', methods.thumbnails.adjust_container);
650                                self.bind('npl_init', this.npl_init);
651                                self.bind('npl_init_complete', this.npl_init_complete);
652
653                                // This prevents multiple handlers from running simultaneously, and multiple
654                                // events pile up when listening to 'resize' - only the last handler is invoked
655                                // if 250ms pass after the last triggering.
656                                methods.galleria.bind_once('resize', methods.thumbnails.adjust_container, 250);
657                            },
658                            npl_init: function() {
659                                $.nplModal('log', 'theme thumbnails.events.npl_init()');
660
661                                if ('numbers' === options.thumbnails) {
662                                    self.$('container').addClass('nggpl-carousel-numbers');
663                                    self.$('thumbnails-list').css('color', methods.icons.get_color());
664
665                                    // Because numeric entries have a different width than at startup we
666                                    // must manually invoke updateCarousel() here so that we don't start
667                                    // with the carousel in the wrong position
668                                    self.updateCarousel();
669
670                                } else if ('lazy' === options.thumbnails) {
671                                    // load all thumbnails, 10 at a time, until all have been retrieved
672                                    self.lazyLoadChunks(10);
673                                }
674
675                                self.$('thumbnails-container').css({background: $.nplModal('get_setting', 'carousel_background_color')});
676
677                                // create carousel next/prev links
678                                var next_thumbs_button = $('<i/>')
679                                    .addClass('fa fa-angle-right')
680                                    .css({color: methods.icons.get_color()});
681                                var prev_thumbs_button = $('<i/>')
682                                    .addClass('fa fa-angle-left')
683                                    .css({color: methods.icons.get_color()});
684                                $(self._dom.stage).append(next_thumbs_button);
685                                $(self._dom.stage).append(prev_thumbs_button);
686                                self.append({'thumb-nav-left': prev_thumbs_button});
687                                self.append({'thumb-nav-right': next_thumbs_button});
688
689                                // Create thumbnails-container toggle button
690                                self.addElement('dock-toggle-container');
691                                var dock_toggle_container = self.$('dock-toggle-container')
692                                    .css({background: $.nplModal('get_setting', 'carousel_background_color')});
693                                var dock_toggle_button = $('<i/>').addClass('fa fa-angle-down')
694                                    .css({color: $.nplModal('get_setting', 'carousel_text_color')});
695
696                                // the container was marked hidden by the parent wrapper, adjust the angle-icon accordingly
697                                if (!methods.thumbnails.is_open()) {
698                                    dock_toggle_button.toggleClass('fa-angle-up fa-angle-down');
699                                }
700
701                                $(self._dom.stage).append(dock_toggle_button);
702                                self.append({'dock-toggle-container': dock_toggle_button});
703                                dock_toggle_container.on('click', self.proxy(function() {
704                                    methods.thumbnails.toggle();
705                                }));
706
707                                // Add playback controls
708                                var play_button = $('<i/>')
709                                    .addClass('nggpl-toolbar-button-play fa fa-play')
710                                    .attr({'title': $.nplModal('get_setting', 'i18n').play_pause});
711                                if (this._playing) {
712                                    play_button.removeClass('fa-play').addClass('fa-pause');
713                                }
714                                methods.thumbnails.register_button(
715                                    play_button,
716                                    function(event) {
717                                        event.preventDefault();
718                                        self.playToggle();
719                                        var $target = $(event.currentTarget);
720                                        $target.find('i').toggleClass('fa-play fa-pause');
721                                        $target.find('[data-fa-i2svg]').toggleClass('fa-play fa-pause');
722                                    }
723                                );
724
725                                // add info controls; handles animation of both the info & dock-toggle-container divs
726                                var info_button = $('<i/>')
727                                    .addClass('nggpl-toolbar-button-info fa fa-info')
728                                    .attr({'title': $.nplModal('get_setting', 'i18n').toggle_image_info});
729                                methods.thumbnails.register_button(
730                                    info_button,
731                                    function(event) {
732                                        event.preventDefault();
733                                        methods.info.toggle();
734                                    }
735                                );
736                            },
737                            npl_init_complete: function() {
738                                $.nplModal('log', 'theme thumbnails.events.npl_init_complete()');
739
740                                var display_buttons = methods.thumbnails.get_registered_buttons();
741                                // assign all of our buttons a (possibly custom) color
742                                for (i = 0; i <= (display_buttons.length - 1); i++) {
743                                    display_buttons[i].css({
744                                        'color': methods.icons.get_color(),
745                                        'background-color': methods.icons.get_background()
746                                    });
747                                }
748                                self.addElement('nextgen-buttons');
749                                self.append({'nextgen-buttons': display_buttons});
750                                self.prependChild('thumbnails-container', 'nextgen-buttons');
751                                self.prependChild('info', 'dock-toggle-container');
752
753                                if (!$.nplModal('mobile.browser.any')) {
754                                    self.addIdleState(self.get('dock-toggle-button'), {opacity: 0});
755                                }
756                            },
757                            // Hide the parent lightbox's spinner
758                            _loadfinish_ran_once: false,
759                            loadfinish: function() {
760                                $.nplModal('log', 'theme thumbnails.events.loadfinish()');
761
762                                if (methods.thumbnails.events._loadfinish_ran_once) {
763                                    return;
764                                }
765
766                                $('#npl_spinner_container').addClass('hidden');
767                                methods.thumbnails.events._loadfinish_ran_once = true;
768                            }
769                        }
770                    },
771                    info: {
772                        is_open: function() {
773                            return $('#npl_wrapper').hasClass('npl-info-open');
774                        },
775
776                        toggle: function() {
777                            $.nplModal('log', 'theme info.toggle()');
778
779                            if (this.is_open()) {
780                                this.close();
781                            } else {
782                                this.open();
783                            }
784                        },
785
786                        open: function() {
787                            $.nplModal('log', 'theme info.open()');
788
789                            $('#npl_wrapper').addClass('npl-info-open');
790                        },
791
792                        close: function() {
793                            $.nplModal('log', 'theme info.close()');
794
795                            $('#npl_wrapper').removeClass('npl-info-open');
796                        },
797
798                        events: {
799                            bind: function() {
800                                $.nplModal('log', 'theme info.events.bind()');
801
802                                self.bind('npl_init', this.npl_init);
803                                self.bind('loadfinish', this.loadfinish);
804                            },
805
806                            npl_init: function() {
807                                $.nplModal('log', 'theme info.events.npl_init()');
808
809                                var needsnewparent = self.$('info').detach();
810                                self.$('thumbnails-container').append(needsnewparent);
811
812                                // Add social share icons to the infobar. ID is important, sidebars could add their own icons
813                                self.prependChild(
814                                    'info-text',
815                                    $('<div/>')
816                                        .attr('id', 'galleria-image-share-icons')
817                                        .attr('class', 'galleria-image-share-icons')
818                                );
819                                if (carousel_text_color = $.nplModal('get_setting', 'carousel_text_color')) {
820                                    self.$('info-title').css({color: carousel_text_color});
821                                    self.$('info-description').css({color: carousel_text_color});
822                                }
823                                self.$('info, info-text, info-title, info-description').css({background: $.nplModal('get_setting', 'carousel_background_color')});
824                            },
825
826                            _loadfinish_ran_once: false,
827                            loadfinish: function() {
828                                $.nplModal('log', 'theme info.events.loadfinish()');
829                                // anchors in our image captions / descriptions must have target=_blank
830                                self.$('info-title, info-description').find('a').each(function() {
831                                    $(this).attr('target', '_blank');
832                                    $(this).css('color', methods.icons.get_color());
833                                });
834
835                                methods.info.events._loadfinish_ran_once = true;
836                            }
837                        }
838                    },
839                    icons: {
840                        get_color: function() {
841                            return $.nplModal('get_setting', 'icon_color');
842                        },
843                        get_background: function() {
844                            var iconcolor = $.nplModal('get_setting', 'carousel_background_color');
845                            if ($.nplModal('get_setting', 'icon_background_enabled', false)) {
846                                iconcolor = $.nplModal('get_setting', 'icon_background');
847                            }
848                            return iconcolor;
849                        },
850                        get_overlay_color: function() {
851                            return $.nplModal('get_setting', 'overlay_icon_color');
852                        }
853                    },
854                    nplModal: {
855                        close: function() {
856                            $.nplModal('close_modal');
857                        },
858                        is_random_source: function() {
859                            var gallery = $.nplModal('get_gallery_from_id', $.nplModal('get_state').gallery_id);
860                            var result = ($.inArray(gallery.source, ['random', 'random_images']) !== -1);
861
862                            $.nplModal('log', 'theme nplModal.is_random_source()', {
863                                result: result
864                            });
865
866                            return result;
867                        },
868                        is_nextgen_gallery: function() {
869                            var retval = $.nplModal('get_state').gallery_id !== '!';
870
871                            $.nplModal('log', 'theme nplModal.is_nextgen_gallery()', {
872                                result: retval
873                            });
874
875                            return retval;
876                        },
877                        is_nextgen_widget: function() {
878                            var retval = false;
879                            var gallery = $.nplModal('get_gallery_from_id', $.nplModal('get_state').gallery_id);
880                            var slug = gallery.slug;
881                            if (slug) {
882                                retval = slug.indexOf('widget-ngg-images') !== -1;
883                            }
884
885                            $.nplModal('log', 'theme nplModal.is_nextgen_widget()', {
886                                result: retval
887                            });
888
889                            return retval;
890                        },
891                        events: {
892                            bind: function() {
893                                $.nplModal('log', 'theme nplModal.bind()');
894
895                                if (Galleria.IPAD || Galleria.IPHONE) {
896                                    self.$('container').addClass('nggpl-ios-browser');
897                                }
898
899                                // update the parent url when a new image has been chosen or the slideshow advances
900                                if (methods.nplModal.is_nextgen_gallery()) {
901                                    self.bind('image', this.image);
902                                }
903
904                                // handle updates to the current url once opened; most likely due to the back/forward button
905                                if (methods.nplModal.is_nextgen_gallery()
906                                &&  $.nplModal('get_setting', 'enable_routing', false)
907                                &&  $.nplModal('get_setting', 'enable_comments', false)) {
908                                    $('#npl_content').on('npl_url_handler', this.unhandled_url_change);
909                                }
910
911                                if ($.nplModal('get_setting', 'protect_images', false)) {
912                                    $('.galleria-image').on('dragstart', function(event) {
913                                        event.preventDefault();
914                                    });
915                                    self.bind('npl_init', this.npl_init);
916                                    self.bind('npl_init_complete', this.npl_init_complete);
917                                }
918
919                                jQuery('#npl_content').on('npl_closing', this.closing);
920                            },
921                            npl_init: function() {
922                                $.nplModal('log', 'theme nplModal.events.npl_init()');
923
924                                self.addElement('image-protection');
925                                document.oncontextmenu = function(event) {
926                                    event = event || window.event;
927                                    event.preventDefault();
928                                };
929                            },
930                            npl_init_complete: function() {
931                                $.nplModal('log', 'theme nplModal.events.npl_init_complete()');
932                                self.prependChild('images', 'image-protection');
933                            },
934                            _image_ran_once: false,
935                            image: function() {
936                                $.nplModal('log', 'theme nplModal.events.image()');
937                                if (methods.nplModal.events._image_ran_once) {
938                                    if (!methods.nplModal.is_random_source()) {
939                                        var image_id = self.getData(self.getIndex()).image_id;
940                                        var sidebar_string = methods.sidebar.is_open() ? '/' + methods.sidebar.get_type() : '';
941                                        var state = $.nplModal('get_state');
942                                        state.image_id = image_id;
943                                        $.nplModal('set_state', state);
944                                        if ($.nplModal('get_setting', 'enable_routing', false)) {
945                                            $.nplModal(
946                                                'router.navigate',
947                                                $.nplModal('get_setting', 'router_slug') + '/' + $.nplModal('get_state').slug + '/' + image_id + sidebar_string,
948                                                true
949                                            );
950                                        }
951                                    }
952                                }
953                                methods.nplModal.events._image_ran_once = true;
954                            },
955                            unhandled_url_change: function(event, state) {
956                                $.nplModal('log', 'theme nplModal.unhandled_url_change()', {
957                                    event: event,
958                                    state: state
959                                });
960                                for (var i = 0; i <= (self.getDataLength() - 1); i++) {
961                                    if (state.image_id === self.getData(i).image_id) {
962                                        self.show(i);
963                                    }
964                                }
965                                if (methods.sidebar.is_open() && state.sidebar == null) {
966                                    methods.sidebar.close();
967                                } else if (!methods.sidebar.is_open()
968                                       &&  typeof state.sidebar !== 'undefined'
969                                       &&  state.sidebar !== null) {
970                                    methods.sidebar.open(state.sidebar);
971                                }
972                            },
973                            closing: function() {
974                                // without this our bound keys will continue to activate even aften
975                                // Galleria.destroy() has been called and the container div emptied
976                                self.detachKeyboard();
977                            }
978                        }
979                    },
980                    galleria: {
981                        bind_once: function(event, callback, timeout) {
982                            var timer_id = undefined;
983                            window.addEventListener(event, function() {
984                                if (typeof timer_id === 'undefined') {
985                                    clearTimeout(timer_id);
986                                    timer_id = undefined;
987                                }
988                                timer_id = setTimeout(function() {
989                                    timer_id = undefined;
990                                    callback();
991                                }, timeout);
992                            });
993                        },
994                        get_displayed_gallery_setting: function(name, def) {
995                            var tmp = '';
996                            var gallery = $.nplModal('get_gallery_from_id', $.nplModal('get_state').gallery_id);
997                            if (gallery && typeof gallery.display_settings[name] !== 'undefined') {
998                                tmp = gallery.display_settings[name];
999                            } else {
1000                                tmp = def;
1001                            }
1002                            if (tmp === '1') tmp = true;
1003                            if (tmp === '0') tmp = false;
1004                            if (tmp === 1) tmp = true;
1005                            if (tmp === 0) tmp = false;
1006
1007                            $.nplModal('log', 'theme galleria.get_displayed_gallery_setting()', {
1008                                name: name,
1009                                result: tmp
1010                            });
1011
1012                            return tmp;
1013                        },
1014                        get_keybinding_exclude_list: function() {
1015                            return 'textarea, input';
1016                        },
1017                        get_current_image_id: function() {
1018                            return self.getData(self.getIndex()).image_id;
1019                        },
1020                        // returns the Galleria image-index based on the provided image id
1021                        get_index_from_id: function(id) {
1022                            var retval = null;
1023                            for (var i = 0; i <= (self.getDataLength() - 1); i++) {
1024                                if (id === self.getData(i).image_id) {
1025                                    retval = i;
1026                                }
1027                            }
1028                            return retval;
1029                        },
1030                        events: {
1031                            bind: function() {
1032                                $.nplModal('log', 'theme galleria.events.bind()');
1033                                self.bind('touchmove', this.touchmove);
1034                                self.bind('npl_init', this.npl_init);
1035                                self.bind('npl_init_keys', this.npl_init_keys);
1036                                self.bind('npl_init_complete', this.npl_init_complete);
1037                                self.bind('loadstart', this.loadstart);
1038                                self.bind('loadfinish', this.loadfinish);
1039                                $(window).on('resize orientationchange', this.browserchanged);
1040                            },
1041                            browserchanged: function() {
1042                                $.nplModal('log', 'theme galleria.events.browserchanged()');
1043                                setTimeout(function() {
1044                                    self.rescale();
1045                                }, 200);
1046                            },
1047                            npl_init: function() {
1048                                $.nplModal('log', 'theme galleria.events.npl_init()');
1049                                // for some reason this isn't an option that can be passed at startup
1050                                self.setPlaytime(($.nplModal('get_setting', 'slideshow_speed', 5) * 1000));
1051
1052                                // Create next / back links
1053                                var next_image_button = $('<i/>')
1054                                    .addClass('fa fa-angle-right')
1055                                    .css({color: methods.icons.get_overlay_color()});
1056                                var prev_image_button = $('<i/>')
1057                                    .addClass('fa fa-angle-left')
1058                                    .css({color: methods.icons.get_overlay_color()});
1059                                $(self._dom.stage).append(next_image_button);
1060                                $(self._dom.stage).append(prev_image_button);
1061                                self.append({'image-nav-left': prev_image_button});
1062                                self.append({'image-nav-right': next_image_button});
1063
1064                                self.$('counter').css({color: methods.icons.get_overlay_color()});
1065                            },
1066                            npl_init_keys: function() {
1067                                $.nplModal('log', 'theme galleria.events.npl_init_keys()');
1068                                var input_types = methods.galleria.get_keybinding_exclude_list();
1069                                self.attachKeyboard({
1070                                    left: function() {
1071                                        if (!$(document.activeElement).is(input_types)) {
1072                                            this.prev();
1073                                        }
1074                                    },
1075                                    right: function() {
1076                                        if (!$(document.activeElement).is(input_types)) {
1077                                            this.next();
1078                                        }
1079                                    },
1080                                    down: function() {
1081                                        if (!$(document.activeElement).is(input_types)) {
1082                                            methods.thumbnails.toggle();
1083                                        }
1084                                    },
1085                                    up: function() {
1086                                        if (!$(document.activeElement).is(input_types)) {
1087                                            methods.info.toggle();
1088                                        }
1089                                    },
1090                                    // escape key
1091                                    27: function(event) {
1092                                        event.preventDefault();
1093                                        methods.nplModal.close();
1094                                    }
1095                                });
1096                            },
1097                            npl_init_complete: function() {
1098                                $.nplModal('log', 'theme galleria.events.npl_init_complete()');
1099                                if (!$.nplModal('mobile.browser.any')) {
1100                                    self.addIdleState(self.get('counter'),            {opacity: 0});
1101                                    self.addIdleState(self.get('image-nav-left'),     {opacity: 0});
1102                                    self.addIdleState(self.get('image-nav-right'),    {opacity: 0});
1103                                }
1104                            },
1105                            touchmove: function(event) {
1106                                // prevent scrolling on elements without the 'scrollable' class
1107                                if (!$('.scrollable').has($(event.target)).length) {
1108                                    $.nplModal('log', 'theme galleria.events.touchmove() prevented scrolling');
1109                                    event.preventDefault();
1110                                }
1111                            },
1112                            loadstart: function(event) {
1113                                $.nplModal('log', 'theme galleria.events.loadstart()', {
1114                                    event: event
1115                                });
1116
1117                                if (!event.cached) {
1118                                    var button = $('#npl_button_close').find('i');
1119                                    button.removeClass('fa-times-circle');
1120                                }
1121                            },
1122                            loadfinish: function() {
1123                                $.nplModal('log', 'theme galleria.events.loadfinish()');
1124
1125                                var button = $('#npl_button_close').find('i');
1126                                button.addClass('fa-times');
1127                            }
1128                        }
1129                    },
1130                    share_icons: {
1131                        strip_html: function(html) {
1132                            var tmp = document.createElement('div');
1133                            tmp.innerHTML = html;
1134                            return tmp.textContent || tmp.innerText || "";
1135                        },
1136                        create: function(target, iconcolor) {
1137                            $.nplModal('log', 'theme share_icons.create()');
1138                            if (methods.nplModal.is_random_source()
1139                            ||  methods.nplModal.is_nextgen_widget()
1140                            ||  !methods.nplModal.is_nextgen_gallery()
1141                            ||  !$.nplModal('get_setting', 'enable_routing', false)) {
1142                                return false;
1143                            }
1144
1145                            var id = self.getData(self.getIndex()).image_id;
1146                            var data = self.getData(self.getIndex());
1147                            var url = encodeURIComponent(window.location.toString());
1148
1149                            var twitter_icon = $('<li/>').html(
1150                                $('<a/>', {'href': 'https://twitter.com/share?url=' + methods.share_icons.get_share_url(id, 'full'),
1151                                    'target': '_blank',
1152                                    'class': 'nggpl-comment-tweet-button',
1153                                    'title': $.nplModal('get_setting', 'i18n').share.twitter})
1154                                    .css({color: iconcolor})
1155                                    .html($('<i/>', {'class': 'fa-brands fa-square-x-twitter'}))
1156                            );
1157
1158                            var facebook_icon = $('<li/>').html(
1159                                $('<a/>', {
1160                                    'class': 'nggpl-comment-facebook-button',
1161                                    'title': $.nplModal('get_setting', 'i18n').share.facebook
1162                                }).css({color: iconcolor})
1163                                    .html($('<i/>', {'class': 'fa fa-facebook-square'}))
1164                            );
1165
1166                            if (typeof $.nplModal('get_setting', 'facebook_app_id') !== 'undefined') {
1167                                facebook_icon.on('click', function(event) {
1168                                    event.preventDefault();
1169                                    FB.ui({
1170                                        method: 'share',
1171                                        href: methods.share_icons.get_share_url(id, 'full'),
1172                                        link: window.location.toString()
1173                                    }, function(response){
1174                                        // Debug response (optional)
1175                                    });
1176                                });
1177                            } else {
1178                                var facebook_url = 'https://www.facebook.com/share.php';
1179                                facebook_url += '?u=' + encodeURIComponent(methods.share_icons.get_share_url(id, 'full'));
1180                                var anchor = facebook_icon.find('a');
1181                                anchor.attr('href', facebook_url);
1182                                anchor.attr('target', '_blank');
1183                            }
1184
1185                            var pinterest_url = encodeURIComponent(methods.share_icons.get_share_url(id, 'full'));
1186
1187                            // Pinterest restricts description length, and we must avoid making the request longer than browsers will allow
1188                            var summary = methods.share_icons.strip_html(data.description);
1189                            if (summary.length >= 446) {
1190                                summary = summary.substring(0, 492);
1191                                summary += '...';
1192                            }
1193
1194                            pinterest_url += '&url=' + url;
1195                            pinterest_url += '&media=' + data.image;
1196                            pinterest_url += '&description=' + summary;
1197                            var pinterest_icon = $('<li/>').html(
1198                                $('<a/>', {'href': 'http://pinterest.com/pin/create/button/?s=100' + pinterest_url,
1199                                    'target': '_blank',
1200                                    'class': 'nggpl-comment-pinterest-button',
1201                                    'title': $.nplModal('get_setting', 'i18n').share.pinterest})
1202                                    .css({color: iconcolor})
1203                                    .html($('<i/>', {'class': 'fa fa-pinterest-square'}))
1204                            );
1205
1206                            var icons = [twitter_icon, facebook_icon, pinterest_icon];
1207
1208                            target = $(target);
1209                            target.html('');
1210                            $('<ul/>').appendTo(target);
1211                            target.find('ul').append(icons);
1212                        },
1213                        get_share_url: function(id, named_size) {
1214                            if (typeof(named_size) === 'undefined') {
1215                                named_size = 'thumb';
1216                            }
1217
1218                            var gallery_id = $.nplModal('get_state').gallery_id;
1219                            var base_url = $.nplModal('get_setting', 'share_url')
1220                                .replace('{gallery_id}', gallery_id)
1221                                .replace('{image_id}', id)
1222                                .replace('{named_size}', named_size);
1223                            var site_url_link = $('<a/>').attr('href', $.nplModal('get_setting', 'wp_site_url'))[0];
1224                            var parent_link   = $('<a/>').attr('href', window.location.toString())[0];
1225                            var base_link     = $('<a/>').attr('href', base_url)[0];
1226
1227                            // check if site is in a sub-directory and shorten the prefix
1228                            if (parent_link.pathname.indexOf(site_url_link.pathname) >= 0) {
1229                                parent_link.pathname = parent_link.pathname.substr(site_url_link.pathname.length);
1230                            }
1231                            // shorten url by removing their common prefix
1232                            if (parent_link.pathname.indexOf(base_link.pathname) >= 0) {
1233                                parent_link.pathname = parent_link.pathname.substr(parent_link.pathname.length);
1234                            }
1235
1236                            // this is odd but it's just how the 'share' controller expects it
1237                            base_link.search = parent_link.search;
1238                            if (base_link.search.length > 0) {
1239                                base_link.search += '&';
1240                            }
1241                            base_link.search += 'uri=' + parent_link.pathname;
1242
1243                            $.nplModal('log', 'theme share_icons.get_share_url() result', {
1244                                id: id,
1245                                named_size: named_size,
1246                                result: base_link.href
1247                            });
1248
1249                            return base_link.href;
1250                        },
1251                        events: {
1252                            bind: function() {
1253                                $.nplModal('log', 'theme share_icons.events.bind()');
1254                                self.bind('loadfinish', this.loadfinish);
1255                                self.bind('npl_init', this.npl_init);
1256                            },
1257                            npl_init: function() {
1258                                if (typeof $.nplModal('get_setting', 'facebook_app_id') !== 'undefined') {
1259                                    if (typeof window.fbAsyncInit === 'undefined') {
1260                                        window.fbAsyncInit = function() {
1261                                            FB.init({
1262                                                appId: $.nplModal('get_setting', 'facebook_app_id'),
1263                                                autoLogAppEvents: true,
1264                                                xfbml: true,
1265                                                version: 'v2.12'
1266                                            });
1267                                        };
1268
1269                                        (function(d, s, id) {
1270                                            var js, fjs = d.getElementsByTagName(s)[0];
1271                                            if (d.getElementById(id)) { return; }
1272                                            js = d.createElement(s); js.id = id;
1273                                            js.src = "https://connect.facebook.net/en_US/sdk.js";
1274                                            fjs.parentNode.insertBefore(js, fjs);
1275                                        }(document, 'script', 'facebook-jssdk'));
1276                                    }
1277                                }
1278                            },
1279                            loadfinish: function() {
1280                                $.nplModal('log', 'theme share_icons.events.loadfinish()');
1281                                if (methods.nplModal.is_nextgen_gallery()
1282                                    &&  $.nplModal('get_setting', 'enable_routing', false)
1283                                    &&  $.nplModal('get_setting', 'enable_sharing', false)) {
1284                                    var iconcolor = $.nplModal('get_setting', 'carousel_text_color') ? $.nplModal('get_setting', 'carousel_text_color') : methods.icons.get_color();
1285                                    methods.share_icons.create(
1286                                        '#galleria-image-share-icons',
1287                                        iconcolor
1288                                    );
1289                                }
1290                            }
1291                        }
1292                    },
1293                    tiktok: {
1294                        cleanup: function() {
1295                            $('#npl_content .ngg-tiktok-container').remove();
1296                            $('#npl_content .ngg-tiktok-error').remove();
1297                            $('#npl_wrapper').removeClass('npl-tiktok-mode');
1298                        },
1299
1300                        handle_content: function(data) {
1301                            this.cleanup();
1302                            if (!data.tiktok_play_url && !data.tiktok_share_url) return;
1303
1304                            // Check if NextGEN_TikTok helper is available
1305                            if (typeof NextGEN_TikTok === 'undefined' || !NextGEN_TikTok.handle_content) {
1306                                console.warn('NextGEN_TikTok helper not available.');
1307                                return;
1308                            }
1309
1310                            $('#npl_wrapper').addClass('npl-tiktok-mode');
1311
1312                            var $img = $('#npl_content .galleria-image img:visible');
1313
1314                            NextGEN_TikTok.handle_content({
1315                                playUrl: data.tiktok_play_url,
1316                                shareUrl: data.tiktok_share_url,
1317                                container: $('#npl_content .galleria-stage'),
1318                                width: $img.width(),
1319                                height: $img.height(),
1320                            });
1321                        },
1322
1323                        events: {
1324                            bind: function() {
1325                                self.bind('loadstart', function() {
1326                                    methods.tiktok.cleanup();
1327                                });
1328                                self.bind('loadfinish', function(e) {
1329                                    var data = e.data || self.getData(self.getIndex());
1330                                    // Check if this is a TikTok video
1331                                    var isTikTok = (data.is_tiktok == 1 || data.is_tiktok == '1' || data.is_tiktok === true)
1332                                               || (data.tiktok_play_url || data.tiktok_share_url);
1333                                    if (isTikTok) {
1334                                        methods.tiktok.handle_content(data);
1335                                    }
1336                                });
1337                            }
1338                        }
1339                    },
1340                    video: {
1341                        cleanup: function() {
1342                            $('#npl_content .ngg-video-container').remove();
1343                            $('#npl_content .ngg-video-error').remove();
1344                            $('#npl_wrapper').removeClass('npl-video-mode');
1345                        },
1346
1347                        getVideoEmbedInfo: function(url, autoplay) {
1348                            if (!url || typeof url !== 'string') {
1349                                return { isEmbed: false, embedUrl: null, useIframe: false };
1350                            }
1351
1352                            var embedUrl = null;
1353                            var useIframe = false;
1354                            var isEmbed = false;
1355                            var autoplayParam = autoplay ? '1' : '0';
1356
1357                            var youtubeRegex = /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/;
1358                            var youtubeMatch = url.match(youtubeRegex);
1359                            if (youtubeMatch) {
1360                                embedUrl = 'https://www.youtube.com/embed/' + youtubeMatch[1] + '?autoplay=' + autoplayParam + '&rel=0';
1361                                useIframe = true;
1362                                isEmbed = true;
1363                            }
1364
1365                            var vimeoRegex = /(?:vimeo\.com\/)(?:.*\/)?(\d+)/;
1366                            var vimeoMatch = url.match(vimeoRegex);
1367                            if (vimeoMatch && !isEmbed) {
1368                                embedUrl = 'https://player.vimeo.com/video/' + vimeoMatch[1] + '?autoplay=' + autoplayParam;
1369                                useIframe = true;
1370                                isEmbed = true;
1371                            }
1372
1373                            var dailymotionRegex = /(?:dailymotion\.com\/(?:embed\/)?video\/|dai\.ly\/)([a-zA-Z0-9]+)/;
1374                            var dailymotionMatch = url.match(dailymotionRegex);
1375                            if (dailymotionMatch && !isEmbed) {
1376                                embedUrl = 'https://www.dailymotion.com/embed/video/' + dailymotionMatch[1] + '?autoplay=' + autoplayParam;
1377                                useIframe = true;
1378                                isEmbed = true;
1379                            }
1380
1381                            var twitchRegex = /(?:twitch\.tv\/videos\/|twitch\.tv\/)(\d+|[a-zA-Z0-9_]+)/;
1382                            var twitchMatch = url.match(twitchRegex);
1383                            if (twitchMatch && !isEmbed) {
1384                                var twitchId = twitchMatch[1];
1385                                var autoplayStr = autoplay ? 'true' : 'false';
1386                                if (/^\d+$/.test(twitchId)) {
1387                                    embedUrl = 'https://player.twitch.tv/?video=' + twitchId + '&autoplay=' + autoplayStr + '&parent=' + window.location.hostname;
1388                                } else {
1389                                    embedUrl = 'https://player.twitch.tv/?channel=' + twitchI
1389d + '&autoplay=' + autoplayStr + '&parent=' + window.location.hostname;
1390                                }
1391                                useIframe = true;
1392                                isEmbed = true;
1393                            }
1394
1395                            var videopressRegex = /(?:videopress\.com\/v\/|video\.wordpress\.com\/v\/)([a-zA-Z0-9]+)/;
1396                            var videopressMatch = url.match(videopressRegex);
1397                            if (videopressMatch && !isEmbed) {
1398                                embedUrl = 'https://videopress.com/embed/' + videopressMatch[1] + '?autoplay=' + autoplayParam;
1399                                useIframe = true;
1400                                isEmbed = true;
1401                            }
1402
1403                            var wistiaRegex = /(?:wistia\.com\/medias\/|wistia\.net\/embed\/)([a-zA-Z0-9]+)/;
1404                            var wistiaMatch = url.match(wistiaRegex);
1405                            if (wistiaMatch && !isEmbed) {
1406                                embedUrl = 'https://fast.wistia.net/embed/iframe/' + wistiaMatch[1] + '?autoplay=' + autoplayParam;
1407                                useIframe = true;
1408                                isEmbed = true;
1409                            }
1410
1411                            return {
1412                                isEmbed: isEmbed,
1413                                embedUrl: embedUrl,
1414                                useIframe: useIframe,
1415                                originalUrl: url
1416                            };
1417                        },
1418
1419                        handle_content: function(data) {
1420                            this.cleanup();
1421                            if (!data.video_link) return;
1422
1423                            $('#npl_wrapper').addClass('npl-video-mode');
1424
1425                            // Get video control properties from data
1426                            var isAutoplay = (data.is_video_autoplay == 1 || data.is_video_autoplay == '1' || data.is_video_autoplay === true);
1427                            var showControls = (data.show_video_controls == 1 || data.show_video_controls == '1' || data.show_video_controls === true);
1428                            var showPlayPause = (data.show_play_pause_controls == 1 || data.show_play_pause_controls == '1' || data.show_play_pause_controls === true);
1429
1430                            // Default to true if not specified
1431                            if (typeof data.is_video_autoplay === 'undefined') {
1432                                isAutoplay = true;
1433                            }
1434                            if (typeof data.show_video_controls === 'undefined') {
1435                                showControls = true;
1436                            }
1437
1438                            var $container = $('#npl_content .galleria-stage');
1439                            var $videoContainer = $('<div class="ngg-video-container"></div>');
1440
1441                            var videoInfo = this.getVideoEmbedInfo(data.video_link, isAutoplay);
1442                            var $videoElement;
1443
1444                            if (videoInfo.useIframe && videoInfo.embedUrl) {
1445                                // For iframe embeds, controls are handled by the platform
1446                                $videoElement = $('<iframe>', {
1447                                    src: videoInfo.embedUrl,
1448                                    frameborder: '0',
1449                                    allow: 'autoplay; fullscreen; picture-in-picture',
1450                                    allowfullscreen: true,
1451                                    webkitallowfullscreen: true,
1452                                    mozallowfullscreen: true
1453                                });
1454
1455                                if (!showControls && videoInfo.embedUrl.indexOf('youtube.com') !== -1) {
1456                                    videoInfo.embedUrl += (videoInfo.embedUrl.indexOf('?') === -1 ? '?' : '&') + 'controls=0';
1457                                    $videoElement.attr('src', videoInfo.embedUrl);
1458                                }
1459                            } else {
1460                                var videoAttrs = {
1461                                    playsinline: true,
1462                                    preload: 'auto'
1463                                };
1464
1465                                if (showControls) {
1466                                    videoAttrs.controls = true;
1467                                }
1468
1469                                if (isAutoplay) {
1470                                    videoAttrs.autoplay = true;
1471                                    videoAttrs.muted = true; // Required for autoplay in modern browsers
1472                                }
1473
1474                                $videoElement = $('<video>', videoAttrs);
1475                                $videoElement.attr('src', data.video_link);
1476
1477                                if (showPlayPause && !showControls) {
1478                                    var $playPauseBtn = $('<button>', {
1479                                        class: 'ngg-video-play-pause-btn',
1480                                        type: 'button',
1481                                        html: '<i class="fa fa-play"></i>'
1482                                    });
1483
1484                                    $playPauseBtn.on('click', function() {
1485                                        var video = $videoElement[0];
1486                                        if (video.paused) {
1487                                            video.play();
1488                                            $playPauseBtn.html('<i class="fa fa-pause"></i>');
1489                                        } else {
1490                                            video.pause();
1491                                            $playPauseBtn.html('<i class="fa fa-play"></i>');
1492                                        }
1493                                    });
1494
1495                                    $videoElement.on('play', function() {
1496                                        $playPauseBtn.html('<i class="fa fa-pause"></i>');
1497                                    });
1498
1499                                    $videoElement.on('pause', function() {
1500                                        $playPauseBtn.html('<i class="fa fa-play"></i>');
1501                                    });
1502
1503                                    $videoContainer.append($playPauseBtn);
1504                                }
1505
1506                                if (isAutoplay) {
1507                                    $videoElement.on('playing', function() {
1508                                        try {
1509                                            $videoElement.prop('muted', false);
1510                                        } catch (e) {
1511                                            console.debug('Could not unmute video automatically:', e);
1512                                        }
1513                                    });
1514
1515                                    setTimeout(function() {
1516                                        if ($videoElement[0] && $videoElement[0].paused) {
1517                                            $videoElement[0].play().catch(function(err) {
1518                                                console.warn('Video auto
1518play failed:', err);
1519                                            });
1520                                        }
1521                                    }, 100);
1522                                }
1523                            }
1524
1525
1526														// Size iframe to match lightbox image sizing behavior
1527														// Use responsive aspect ratio (16:9 default for most platforms)
1528														const aspectRatio = 16 / 9;
1529														const maxWidth = window.innerWidth * 0.9;
1530														const maxHeight = window.innerHeight * 0.9;
1531														let width = Math.min(maxWidth, 1080);
1532														let height = width / aspectRatio;
1533
1534														if (height > maxHeight) {
1535															height = maxHeight;
1536															width = height * aspectRatio;
1537														}
1538
1539														$videoContainer.css({
1540															width: width + "px",
1541															height: height + "px",
1542															maxWidth: "100%",
1543															maxHeight: "90vh"
1544														});
1545
1546                            $videoContainer.append($videoElement);
1547                            $container.append($videoContainer);
1548                        },
1549
1550                        events: {
1551                            bind: function() {
1552                                self.bind('loadstart', function() {
1553                                    methods.video.cleanup();
1554                                });
1555                                self.bind('loadfinish', function(e) {
1556                                    var data = e.data || self.getData(self.getIndex());
1557                                    // Check if this is a generic video (not TikTok)
1558                                    var isTikTok = (data.is_tiktok == 1 || data.is_tiktok == '1' || data.is_tiktok === true)
1559                                                || (data.tiktok_play_url || data.tiktok_share_url);
1560                                    var hasVideoLink = (data.is_video_link == 1 || data.is_video_link == '1' || data.is_video_link === true)
1561                                                   || (data.video_link && data.video_link.length > 0);
1562                                    if (!isTikTok && hasVideoLink) {
1563                                        methods.video.handle_content(data);
1564                                    }
1565                                });
1566                            }
1567                        }
1568                    }
1569                };
1570
1571                $.nplModal('log', 'theme initialization - about to bind events');
1572
1573                // Load our modules
1574                methods.galleria.events.bind();
1575                methods.nplModal.events.bind();
1576                methods.thumbnails.events.bind();
1577                methods.info.events.bind();
1578                methods.share_icons.events.bind();
1579                methods.sidebar.events.bind();
1580                methods.sidebars.datacache.events.bind();
1581                methods.sidebars.comments.events.bind();
1582                methods.tiktok.events.bind();
1583                methods.video.events.bind();
1584
1585                $.nplModal('log', 'theme initialization - done binding events');
1586
1587                $.nplModal('log', 'theme initialization - about to trigger npl_ready');
1588                $(self._target).trigger('npl_ready', {galleria_theme: self, methods: methods});
1589
1590                $.nplModal('log', 'theme initialization - about to trigger npl_init');
1591                self.trigger('npl_init');
1592
1593                $.nplModal('log', 'theme initialization - about to trigger npl_init_keys');
1594                self.trigger('npl_init_keys');
1595
1596                $.nplModal('log', 'theme initialization - about to trigger npl_init_complete');
1597                self.trigger('npl_init_complete');
1598            }
1599        });
1600    };
1601
1602    // In case this theme is enqueued before Galleria.js is loaded we
1603    // will periodically check if Galleria exists before calling
1604    // Galleria.addTheme()
1605    var interval = setInterval(function() {
1606        if (typeof window.Galleria !== 'undefined') {
1607            clearInterval(interval);
1608            add_nggpl_theme();
1609        }
1610    }, 10);
1611
1612}(jQuery));

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.