PageSourceSearch

https://elizabethfiend.com/blog/wp-content/plugins/nextgen-gallery…/DisplayTypes/Mosaic/main.js?ver=2.2.0

js elizabethfiend.com collected 2026-10-10 01:36:10 UTC 17,756 bytes, 417 lines download raw bytes

1// ngg_mosaic_methods does not use any jQuery so it can begin loading gallery images before
2// jQuery's init / window.ready is fired
3var ngg_mosaic_methods = {
4
5    high_dpi: false,
6
7    init: function() {
8        this.high_dpi = this.getDPIRatio() > 1;
9
10        _.each(document.getElementsByClassName('ngg-pro-mosaic-container'), function(self) {
11            var gallery_id = self.getAttribute('data-ngg-pro-mosaic-id');
12            var gallery = ngg_mosaic_methods.get_gallery(gallery_id);
13
14            const container = self.parentElement;
15            const styleName = 'firstload';
16
17            // Images in the template are deferred from loading until here
18            if (ngg_mosaic_methods.get_setting(gallery_id, 'lazy_load_enable', false, 'bool')) {
19                var initial_load = ngg_mosaic_methods.get_setting(gallery.ID, 'lazy_load_initial', 35, 'int');
20                gallery.mosaic_loaded = [];
21                _.each(
22                    gallery.images_list,
23                    function(image, index) {
24                        if (index < initial_load) {
25                            gallery.mosaic_loaded.push(image.image_id);
26                            self.appendChild(ngg_mosaic_methods.create_image(
27                                gallery,
28                                image,
29                                undefined,
30                                '1' === self.parentElement.dataset['firstloadEnabled']
31                            ));
32                        }
33                    }
34                );
35            } else {
36                _.each(
37                    gallery.images_list,
38                    function(image) {
39                        self.appendChild(ngg_mosaic_methods.create_image(
40                            gallery,
41                            image,
42                            undefined,
43                            '1' === self.parentElement.dataset['firstloadEnabled']
44                        ));
45                    }
46                );
47            }
48
49            // Add support for the Image Animations feature; first load and pagination.
50            if ('1' === container.dataset[`${styleName}Enabled`] ) {
51                const style              = container.dataset[`${styleName}Style`];
52                const duration = parseInt(container.dataset[`${styleName}Duration`]);
53                const delay    = parseInt(container.dataset[`${styleName}Delay`]);
54                const items = self.querySelectorAll('.ngg-pro-mosaic-item');
55                items.forEach(
56                    function(image, index) {
57                        image.style.setProperty('--animate-duration', `${duration}ms`);
58                        if (index === (items.length - 1)) { //} && '1' === container.dataset['paginationEnabled']) {
59                            setTimeout(() => {
60                                animateNextGENImage(image, style).then((message) => {
61                                    // Images in the template are deferred from loading until here
62                                    if (ngg_mosaic_methods.get_setting(gallery_id, 'lazy_load_enable', false, 'bool')) {
63                                        jQuery(window).on('scroll', function() {
64                                            window.ngg_mosaic_methods_two.scroll_action(gallery.ID, self);
65                                        });
66                                        jQuery(window).trigger('scroll');
67                                    }
68                                    return "Message received";
69                                });
70                            }, (0 === index ? 0 : index * delay));
71                        } else {
72                            setTimeout(() => {
73                                animateNextGENImage(image, style);
74                            }, (0 === index ? 0 : index * delay));
75                        }
76                    }
77                );
78            } else {
79                if ('1' === container.dataset['paginationEnabled']) {
80                    // Images in the template are deferred from loading until here
81                    if (ngg_mosaic_methods.get_setting(gallery_id, 'lazy_load_enable', false, 'bool')) {
82                        jQuery(window).on('scroll', function() {
83                            window.ngg_mosaic_methods_two.scroll_action(gallery.ID, self);
84                        });
85                        jQuery(window).trigger('scroll');
86                    }
87                }
88            }
89        });
90    },
91
92    getDPIRatio: function() {
93        var ratio = 1;
94
95        // To account for zoom, change to use deviceXDPI instead of systemXDPI
96        if (window.screen.systemXDPI !== undefined
97            &&  window.screen.logicalXDPI !== undefined
98            &&  window.screen.systemXDPI > window.screen.logicalXDPI) {
99            // Only allow for values > 1
100            ratio = window.screen.systemXDPI / window.screen.logicalXDPI;
101        } else if (window.devicePixelRatio !== undefined) {
102            ratio = window.devicePixelRatio;
103        }
104
105        return ratio;
106    },
107
108    get_gallery: function (gallery_id) {
109        var result = null;
110
111        if ('undefined' == typeof window.galleries) {
112            return result;
113        }
114
115        return _.find(galleries, function(gallery) {
116            return (gallery.ID == gallery_id);
117        });
118    },
119
120    get_setting: function(gallery_id, name, def, type) {
121        type = type || 'bool';
122        var gallery = this.get_gallery(gallery_id);
123
124        if (gallery && typeof gallery.display_settings[name] != 'undefined')
125            def = gallery.display_settings[name];
126
127        if (type == 'bool') {
128            if (def == 1 || def == '1')
129                def = true;
130            if (def == 0 || def == '0')
131                def = false;
132        } else if (type == 'int') {
133            def = parseInt(def);
134        } else if (type == 'string') {
135            // don't need to do anything, for now
136        }
137
138        return def;
139    },
140
141    create_image: function(gallery, image, onload, addAnimationClass) {
142        var self = this;
143
144        var div = document.createElement('div');
145        div.setAttribute('class', 'ngg-pro-mosaic-item');
146
147        if (addAnimationClass) {
148            div.classList.add('nextgen-pro-animate-images-loading');
149        }
150
151        var img = document.createElement('img');
152        var url = image.image;
153        if (self.high_dpi && image.use_hdpi) {
154            url = image.srcsets.hdpi;
155        }
156
157        img.setAttribute('title', sanitizeToPlainText(image.title));
158        img.setAttribute('alt',   sanitizeToPlainText(image.title));
159        img.setAttribute('src',   url);
160        img.setAttribute('width', image.width);
161        img.setAttribute('height', image.height);
162
163        // Yes, it's messy, but it's a decently clean way to inject our effect code text into the element
164        var anchor = document.createElement('a');
165        var clauses = gallery.mosaic_effect_code.match(/(\S+)=["']?((?:.(?!["']?\s+(?:\S+)=|[>"']))+.)["']?/ig);
166        if (clauses) {
167            for (var i = 0; i < clauses.length; i++) {
168                var claus = clauses[i].match(/(\S+)=["']?((?:.(?!["']?\s+(?:\S+)=|[>"']))+.)["']?/i);
169                anchor.setAttribute(claus[1], claus[2]);
170            }
171        }
172
173        anchor.setAttribute('href',             image.full_image);
174        anchor.setAttribute('title',            image.description);
175        anchor.setAttribute('data-image-id',    image.image_id);
176        anchor.setAttribute('data-src',         image.image);
177        anchor.setAttribute('data-thumbnail',   image.thumb);
178        anchor.setAttribute('data-title',       image.title);
179        anchor.setAttribute('data-description', image.description);
180        anchor.setAttribute('data-image-name',  image.full_image ? image.full_image.split('/').pop().split('?')[0] : (image.title || ''));
181        anchor.setAttribute('data-ngg-captions-nostylecopy', '1');
182
183        if (image.tiktok_play_url) {
184            anchor.setAttribute('data-tiktok-play-url', image.tiktok_play_url);
185        }
186        if (image.tiktok_share_url) {
187            anchor.setAttribute('data-tiktok-share-url', image.tiktok_share_url);
188        }
189        if (image.tiktok_embed_url || image.tiktok_embed_link) {
190            anchor.setAttribute('data-tiktok-embed-url', image.tiktok_embed_url || image.tiktok_embed_link);
191        }
192        if (image.video_link) {
193            anchor.setAttribute('data-video-url', image.video_link);
194        }
195
196        // Add Dribbble link data attributes if this is a Dribbble image with external link.
197        if (image.is_dribbble === 1 || image.is_dribbble === '1' || image.is_dribbble === true) {
198            anchor.setAttribute('data-ngg-dribbble', '1');
199            anchor.setAttribute('data-dribbble-link', image.dribbble_link);
200            if (image.dribbble_target && image.dribbble_target === '_blank') {
201                anchor.setAttribute('data-dribbble-target', '_blank');
202            }
203        }
204
205        if (typeof onload != 'undefined') {
206            anchor.setAttribute('onload', onload);
207        }
208
209        anchor.appendChild(img);
210
211        if ((image.is_tiktok == 1 || image.is_tiktok == '1' || image.is_tiktok === true)
212            && (image.show_play_button == 1 || image.show_play_button == '1' || image.show_play_button === true)) {
213            var overlay = document.createElement('span');
214            overlay.setAttribute('class', 'ngg-video-play-overlay');
215            overlay.setAttribute('aria-hidden', 'true');
216            anchor.appendChild(overlay);
217        } else if ((image.is_video_link == 1 || image.is_video_link == '1' || image.is_video_link === true)
218                   && image.video_link && image.video_link.length > 0) {
219            // Generic video: add play overlay
220            var overlay = document.createElement('span');
221            overlay.setAttribute('class', 'ngg-video-play-overlay');
222            overlay.setAttribute('aria-hidden', 'true');
223            anchor.appendChild(overlay);
224        }
225        div.appendChild(anchor);
226
227        return div;
228    }
229};
230
231function sanitizeToPlainText(value) {
232	// Create a temporary element to decode HTML entities and remove HTML tags.
233	const tempDiv = jQuery("<div>").html(value);
234	let plainText = tempDiv.text(); // Get plain text (decodes entities and removes tags).
235	tempDiv.remove(); // Clean up the temporary element.
236
237	// Remove special characters, including quotes and backticks.
238	plainText = plainText.replace(/['"`~!@#$%^&*()_+=\[\]{}|;:,.<>?/\\-]/g, "");
239
240	// Trim any extra spaces.
241	return plainText.trim();
242}
243
244(function($) {
245    "use strict";
246
247    var mosaic_methods = {
248        // This image has loaded: remove it from the pending queue
249        image_loaded: function(image_id) {
250            this.scroll_pending = _.without(this.scroll_pending, image_id);
251        },
252
253        // Prevent the listener action from running concurrently
254        scroll_action_running: null,
255
256        // Once scroll_action() fires we don't want to run again for 300ms
257        scroll_timer: null,
258
259        // how many more images to fetch
260        scroll_step: 5,
261
262        // a queue of pending/downloading images
263        scroll_pending: [],
264
265        scroll_more_to_find: true,
266
267        scroll_action: function(gallery_id, myself) {
268            // Just bail now
269            if (this.scroll_action_running == true
270            ||  this.scroll_timer
271            ||  !this.scroll_more_to_find
272            ||  (this.scroll_pending.length >= 1)) {
273                return;
274            }
275
276            this.scroll_action_running = true;
277            var self = this;
278
279            this.scroll_timer = setTimeout(function() {
280                clearTimeout(self.scroll_timer);
281                self.scroll_timer = false;
282            }, 500);
283
284            setTimeout(function() {
285                var $self            = $(myself);
286                var window_height    = $(window).height();
287                var window_position  = $(window).scrollTop();
288                var window_bottom    = window_height + window_position;
289                var container_bottom = $self.height() + $self.offset().top;
290                var row_height       = $self.find('.ngg-pro-mosaic-item.entry-visible').first().height();
291                var last_height      = $self.find('.ngg-pro-mosaic-item.entry-visible').last().height();
292
293                if (window_bottom <= (container_bottom - last_height - (row_height * 2))) {
294                    self.scroll_action_running = false;
295                    return;
296                }
297
298                var gallery = ngg_mosaic_methods.get_gallery(gallery_id);
299
300                var scroll_step = ngg_mosaic_methods.get_setting(gallery_id, 'lazy_load_batch', this.scroll_step, 'int');
301
302                // If there's no more images to find: stop checking in the future
303                if ((gallery.images_list.length - gallery.mosaic_loaded.length) < scroll_step) {
304                    scroll_step = gallery.images_list.length - gallery.mosaic_loaded.length;
305                    self.scroll_more_to_find = false;
306                }
307
308                let newImages = [];
309                const container = myself.parentElement;
310                const styleName = 'pagination';
311
312                // Find X images not already added and append them
313                for (var i = 0; i < scroll_step; i++) {
314                    var image = _.find(gallery.images_list, function(image) {
315                        return (_.indexOf(gallery.mosaic_loaded, image.image_id) == -1)
316                    });
317
318                    gallery.mosaic_loaded.push(image.image_id);
319                    let newImage = ngg_mosaic_methods.create_image(
320                        gallery,
321                        image,
322                        self.image_loaded(image.image_id),
323                        '1' === container.dataset[`${styleName}Enabled`]
324                    );
325                    newImages.push(newImage);
326                    $self.append(newImage);
327                }
328
329                // Have JustifiedGallery update *new* images only
330                $self.justifiedGallery('norewind');
331
332                // Add support for the 'pagination' Image Animations feature.
333                if ('1' === container.dataset[`${styleName}Enabled`] ) {
334                    const style              = container.dataset[`${styleName}Style`];
335                    const duration = parseInt(container.dataset[`${styleName}Duration`]);
336                    const delay    = parseInt(container.dataset[`${styleName}Delay`]);
337
338                    newImages.forEach(
339                        function(image, index) {
340                            image.style.setProperty('--animate-duration', `${duration}ms`);
341                            setTimeout(() => {
342                                animateNextGENImage(image, style);
343                            }, (0 === index ? 0 : index * delay));
344                        }
345                    );
346                }
347
348                // Allow the scroll method to be caught again
349                self.scroll_action_running = false;
350            }, 60);
351        }
352    };
353
354    window.ngg_mosaic_methods_two = mosaic_methods;
355
356    ngg_mosaic_methods.init();
357
358    _.each($('.ngg-pro-mosaic-container'), function(self) {
359
360        var $self = $(self);
361        var gallery_id = $self.data('ngg-pro-mosaic-id');
362
363        var jgoptions = {
364            captions: false,
365            cssAnimation: true,
366            waitThumbnailsLoad: false,
367            justifyThreshold: 0.9,
368            rowHeight: ngg_mosaic_methods.get_setting(gallery_id, 'row_height', 200, 'int'),
369            margins:   ngg_mosaic_methods.get_setting(gallery_id, 'margins',    15,  'int'),
370            lastRow:   ngg_mosaic_methods.get_setting(gallery_id, 'last_row',   'justify', 'string')
371        };
372
373        var gallery = ngg_mosaic_methods.get_gallery(gallery_id);
374
375        // Guarantee the container has a base size
376        $self.css({
377            'min-height': ngg_mosaic_methods.get_setting(gallery_id, 'row_height', 200, 'int') + 'px'
378        });
379
380        if ('undefined' === typeof self.parentElement.dataset['paginationEnabled']
381        ||  '0' === self.parentElement.dataset['paginationEnabled']) {
382            // Images in the template are deferred from loading until here
383            if (ngg_mosaic_methods.get_setting(gallery_id, 'lazy_load_enable', false, 'bool')) {
384                $(window).on('scroll', function() {
385                    mosaic_methods.scroll_action(gallery.ID, self);
386                });
387            }
388        }
389
390        // wait until JG has processed images before trying to update lightboxes
391        $self.on('jg.complete', function() {
392            $(window).trigger('ngg.mosaic.complete', [$self]);
393            $(window).trigger('resize', [$self]);
394
395            // Our captions can't process correctly if the images haven't loaded yet
396            $self.waitForImages(function() {
397                $(window).trigger('refreshed');
398            });
399        });
400
401        $self.justifiedGallery(jgoptions);
402
403        // The below disableRefresh / enableRefresh commands have been altered by Imagely and are not part of
404        // the standard Justified-Gallery distribution. The following prevents JG from recalculating gallery sizes
405        // and thus changing the scroll position when our Pro Lightbox is active.
406        $(window).on('npl_initialization_complete', function() {
407            $('#npl_content').on('npl_opening', function() {
408                $self.justifiedGallery('disableRefresh');
409            });
410            $('#npl_content').on('npl_closing', function() {
411                $self.justifiedGallery('enableRefresh');
412            });
413        });
414
415    });
416
417})(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.