PageSourceSearch

http://0iqy8.cn/assets/js/baguetteBox.js

js 0iqy8.cn collected 2026-10-09 04:34:40 UTC 15,378 bytes, 406 lines download raw bytes

1/*!
2 * baguetteBox.js
3 * @author  feimosi
4 * @version 0.7.0
5 * @url https://github.com/feimosi/baguetteBox.js
6 */
7
8var baguetteBox = (function() {
9    // SVG shapes used in buttons
10    var leftArrow = '<svg width="40" height="60" xmlns="http://www.w3.org/2000/svg" version="1.1">' +
11            '<polyline points="30 10 10 30 30 50" stroke="rgba(255,255,255,0.5)" stroke-width="4"' +
12              'stroke-linecap="butt" fill="none" stroke-linejoin="round">&lt;</polyline>' +
13            '</svg>',
14        rightArrow = '<svg width="40" height="60" xmlns="http://www.w3.org/2000/svg" version="1.1">' +
15            '<polyline points="10 10 30 30 10 50" stroke="rgba(255,255,255,0.5)" stroke-width="4"' +
16              'stroke-linecap="butt" fill="none" stroke-linejoin="round">&gt;</polyline>' +
17            '</svg>',
18        closeX = '<svg width="30" height="30" xmlns="http://www.w3.org/2000/svg" version="1.1">' +
19            '<g stroke="rgb(160, 160, 160)" stroke-width="4">' +
20            '<line x1="5" y1="5" x2="25" y2="25"/>' +
21            '<line x1="5" y1="25" x2="25" y2="5"/>' +
22            'X</g></svg>';
23    // Main ID names
24    var overlayID = 'baguetteBox-overlay';
25    var sliderID = 'baguetteBox-slider';
26    // Global options and their defaults
27    var options = {}, defaults = {
28        captions: true,
29        buttons: 'auto',
30        async: false,
31        preload: 2,
32        animation: 'slideIn'
33    };
34    // DOM Elements references
35    var overlay, slider, previousButton, nextButton, closeButton;
36    // Current image index inside the slider and displayed gallery index
37    var currentIndex = 0, currentGallery = -1;
38    // Touch event start position (for slide gesture)
39    var touchStartX;
40    // If set to true ignore touch events because animation was already fired
41    var touchFlag = false;
42    // Array of all used galleries (DOM elements)
43    var galleries = [];
44    // 2D array of galleries and images inside them
45    var imagesMap = [];
46    // Array containing temporary images DOM elements
47    var imagesArray = [];
48
49    // forEach polyfill for IE8
50    if(!Array.prototype.forEach) {
51        Array.prototype.forEach = function(callback, thisArg) {
52            var len = this.length;
53            for(var i = 0; i < len; i++) {
54                callback.call(thisArg, this[i], i, this);
55            }
56        };
57    }
58
59    // Script entry point
60    function run(selector, userOptions) {
61        buildOverlay();
62        // For each gallery bind a click event to every image inside it
63        galleries = document.querySelectorAll(selector);
64        [].forEach.call(
65            galleries,
66            function (galleryElement, galleryIndex) {
67                var galleryID = imagesMap.length;
68                imagesMap.push(galleryElement.getElementsByTagName('a'));
69                imagesMap[galleryID].options = userOptions;
70                [].forEach.call(
71                    imagesMap[galleryID],
72                    function (imageElement, imageIndex) {
73                        bind(imageElement, 'click', function(event) {
74                            /*jshint -W030 */
75                            event.preventDefault ? event.preventDefault() : event.returnValue = false;
76                            prepareOverlay(galleryID);
77                            showOverlay(imageIndex);
78                        });
79                    }
80                );
81            }
82        );
83        defaults.transforms = testTransformsSupport();
84    }
85
86    function buildOverlay() {
87        overlay = document.getElementById(overlayID);
88        // Check if the overlay already exists
89        if(overlay) {
90            slider = document.getElementById(sliderID);
91            previousButton = document.getElementById('previous-button');
92            nextButton = document.getElementById('next-button');
93            closeButton = document.getElementById('close-button');
94            return;
95        }
96        // Create overlay element
97        overlay = document.createElement('div');
98        overlay.id = overlayID;
99        document.getElementsByTagName('body')[0].appendChild(overlay);
100        // Create gallery slider element
101        slider = document.createElement('div');
102        slider.id = sliderID;
103        overlay.appendChild(slider);
104        // Create all necessary buttons
105        previousButton = document.createElement('button');
106        previousButton.id = 'previous-button';
107        previousButton.innerHTML = leftArrow;
108        overlay.appendChild(previousButton);
109
110        nextButton = document.createElement('button');
111        nextButton.id = 'next-button';
112        nextButton.innerHTML = rightArrow;
113        overlay.appendChild(nextButton);
114
115        closeButton = document.createElement('button');
116        closeButton.id = 'close-button';
117        closeButton.innerHTML = closeX;
118        overlay.appendChild(closeButton);
119
120        previousButton.className = nextButton.className = closeButton.className = 'baguetteBox-button';
121
122        bindEvents();
123    }
124
125    function bindEvents() {
126        // When clicked on the overlay (outside displayed image) close it
127        bind(overlay, 'click', function(event) {
128            if(event.target && event.target.nodeName !== "IMG")
129                hideOverlay();
130        });
131        // Add event listeners for buttons
132        bind(document.getElementById('previous-button'), 'click', function(event) {
133            /*jshint -W030 */
134            event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true;
135            showPreviousImage();
136        });
137        bind(document.getElementById('next-button'), 'click', function(event) {
138            /*jshint -W030 */
139            event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true;
140            showNextImage();
141        });
142        bind(document.getElementById('close-button'), 'click', function(event) {
143            /*jshint -W030 */
144            event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true;
145            hideOverlay();
146        });
147        // Add touch events
148        bind(overlay, 'touchstart', function(event) {
149            // Save x axis position
150            touchStartX = event.changedTouches[0].pageX;
151        });
152        bind(overlay, 'touchmove', function(event) {
153            if(touchFlag)
154                return;
155            /*jshint -W030 */
156            event.preventDefault ? event.preventDefault() : event.returnValue = false;
157            touch = event.touches[0] || event.changedTouches[0];
158            if(touch.pageX - touchStartX > 40) {
159                touchFlag = true;
160                showPreviousImage();
161            } else if (touch.pageX - touchStartX < -40) {
162                touchFlag = true;
163                showNextImage();
164            }
165        });
166        bind(overlay, 'touchend', function(event) {
167            touchFlag = false;
168        });
169        // Activate keyboard shortcuts
170        bind(document, 'keydown', function(event) {
171            switch(event.keyCode) {
172                case 37: // Left arrow
173                    showPreviousImage();
174                    break;
175                case 39: // Right arrow
176                    showNextImage();
177                    break;
178                case 27: // Esc
179                    hideOverlay();
180                    break;
181            }
182        });
183    }
184
185    function prepareOverlay(galleryIndex) {
186        // If the same gallery is being opened prevent from loading it once again
187        if(currentGallery === galleryIndex)
188            return;
189        currentGallery = galleryIndex;
190        // Update gallery specific options
191        setOptions(imagesMap[galleryIndex].options);
192        // Empty slider of previous contents (more effective than .innerHTML = "")
193        while(slider.firstChild)
194            slider.removeChild(slider.firstChild);
195        imagesArray.length = 0;
196        // Prepare and append images containers
197        for(var i = 0; i < imagesMap[galleryIndex].length; i++) {
198            imagesArray.push(returnImageContainer());
199            slider.appendChild(imagesArray[i]);
200        }
201    }
202
203    function setOptions(newOptions) {
204        if(!newOptions)
205            newOptions = {};
206        for(var item in defaults) {
207            options[item] = defaults[item];
208            if(typeof newOptions[item] !== 'undefined')
209                options[item] = newOptions[item];
210        }
211        /* Apply new options */
212        // Change transition for proper animation
213        slider.style.transition = slider.style.webkitTransition = options.animation === 'fadeIn' ? 'opacity .4s ease' : '';
214        // Hide buttons if necessary
215        if(options.buttons === 'auto' && ('ontouchstart' in window || imagesMap[currentGallery].length === 1))
216            options.buttons = false;
217        // Set buttons style to hide or display them
218        previousButton.style.display = nextButton.style.display = options.buttons ? '' : 'none';
219    }
220
221    // Return DOM element for image container <div class="full-image">...</div>
222    function returnImageContainer() {
223        var fullImage = document.createElement('div');
224        fullImage.className = 'full-image';
225        return fullImage;
226    }
227
228    function showOverlay(index) {
229        // Return if overlay is already visible
230        if(overlay.style.display === 'block')
231            return;
232        // Set current index to a new value and show proper image
233        currentIndex = index;
234        loadImage(currentIndex, function() {
235            preloadNext(currentIndex);
236            preloadPrev(currentIndex);
237        });
238        updateOffset();
239        overlay.style.display = 'block';
240        // Fade in overlay
241        setTimeout(function() {
242            overlay.className = 'visible';
243        }, 50);
244    }
245
246    function hideOverlay() {
247        // Return if overlay is already hidden
248        if(overlay.style.display === 'none')
249            return;
250        // Fade out and hide the overlay
251        overlay.className = '';
252        setTimeout(function() {
253            overlay.style.display = 'none';
254        }, 500);
255    }
256
257    function loadImage(index, callback) {
258        var imageContainer = imagesArray[index];
259        // If index is invalid return
260        if(typeof imageContainer === 'undefined')
261            return;
262        // If image is already loaded run callback and return
263        if(imageContainer.getElementsByTagName('img')[0]) {
264            if(callback)
265                callback();
266            return;
267        }
268        // Get element reference, optional caption and source path
269        imageElement = imagesMap[currentGallery][index];
270        imageCaption = imageElement.getAttribute('data-caption') || imageElement.title;
271        imageSrc = getImageSrc(imageElement);
272        // Prepare image container elements
273        var figure = document.createElement('figure');
274        var image = document.createElement('img');
275        var figcaption = document.createElement('figcaption');
276        imageContainer.appendChild(figure);
277        // Add loader element
278        figure.innerHTML = '<div class="spinner">' +
279            '<div class="double-bounce1"></div>' +
280            '<div class="double-bounce2"></div>' +
281            '</div>';
282        // Set callback function when image loads
283        image.onload = function() {
284            // Remove loader element
285            var spinner = this.parentNode.querySelector('.spinner');
286            this.parentNode.removeChild(spinner);
287            if(!options.async && callback)
288                callback();
289        };
290        image.setAttribute('src', imageSrc);
291        figure.appendChild(image);
292        // Insert caption if available
293        if(options.captions && imageCaption) {
294            figcaption.innerHTML = imageCaption;
295            figure.appendChild(figcaption);
296        }
297        // Run callback
298        if(options.async && callback)
299            callback();
300    }
301
302    function getImageSrc(image) {
303        // Set dafult image path from href
304        var result = imageElement.getAttribute('href');
305        // If dataset is supported find the most suitable image
306        if(image.dataset) {
307            var srcs = [];
308            // Get all possible image versions depending on the resolution 
309            for(var item in image.dataset) {
310                if(item.substring(0, 3) === 'at-' && !isNaN(item.substring(3)))
311                    srcs[item.replace('at-', '')] = image.dataset[item];
312            }
313            // Sort resolutions ascending
314            keys = Object.keys(srcs).sort(function(a, b) {
315                return parseInt(a) < parseInt(b) ? -1 : 1;
316            });
317            // Get real screen resolution 
318            var width = window.innerWidth * window.devicePixelRatio;
319            // Find first image bigger than or equal to the current width
320            for(var i = 0; i < keys.length; i++) {
321                if(keys[i] >= width) {
322                    result = srcs[keys[i]];    
323                    break;
324                }
325                result = srcs[keys[i]];
326            }
327        }
328        return result;
329    }
330
331    function showNextImage() {
332        if(currentIndex <= imagesArray.length - 2) {
333            currentIndex++;
334            updateOffset();
335            preloadNext(currentIndex);
336        } else {
337            slider.className = 'bounce-from-right';
338            setTimeout(function() {
339                slider.className = '';
340            }, 400);
341        }
342    }
343
344    function showPreviousImage() {
345        if(currentIndex >= 1) {
346            currentIndex--;
347            updateOffset();
348            preloadPrev(currentIndex);
349        } else {
350            slider.className = 'bounce-from-left';
351            setTimeout(function() {
352                slider.className = '';
353            }, 400);
354        }
355    }
356
357    function updateOffset() {
358        var offset = -currentIndex * 100 + '%';
359        if(options.animation === 'fadeIn') {
360            slider.style.opacity = 0;
361            setTimeout(function() {
362                /*jshint -W030 */
363                options.transforms ?
364                    slider.style.transform = slider.style.webkitTransform = 'translate3d(' + offset + ',0,0)'
365                    : slider.style.left = offset;
366                slider.style.opacity = 1;
367            }, 400);
368        } else {
369            /*jshint -W030 */
370            options.transforms ?
371                slider.style.transform = slider.style.webkitTransform = 'translate3d(' + offset + ',0,0)'
372                : slider.style.left = offset;
373        }
374    }
375
376    function testTransformsSupport() {
377        var div = document.createElement('div'),
378            support = false;
379        support = typeof div.style.perspective !== 'undefined' || typeof div.style.webkitPerspective !== 'undefined';
380        return support;
381    }
382
383    function preloadNext(index) {
384        if(index - currentIndex >= options.preload)
385            return;
386        loadImage(index + 1, function() { preloadNext(index + 1); });
387    }
388
389    function preloadPrev(index) {
390        if(currentIndex - index >= options.preload)
391            return;
392        loadImage(index - 1, function() { preloadPrev(index - 1); });
393    }
394
395    function bind(element, event, callback) {
396        if(element.addEventListener)
397            element.addEventListener(event, callback, false);
398        else
399            element.attachEvent('on' + event, callback);
400    }
401
402    return {
403        run: run
404    };
405
406})();

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.