PluginProbe ʕ •ᴥ•ʔ
Responsive Lightbox & Gallery / 2.6.0
Responsive Lightbox & Gallery v2.6.0
2.7.8 trunk 1.0.0 1.0.1 1.0.1.1 1.0.2 1.0.3 1.0.4 1.1.0 1.1.1 1.1.2 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.4.0 1.4.0.1 1.4.1 1.4.11 1.4.12 1.4.13 1.4.14 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.6.0 1.6.1 1.6.10 1.6.11 1.6.12 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 2.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1 2.2.0 2.2.1 2.2.2 2.2.3 2.2.3.1 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.3.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.4.8 2.4.9 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7
responsive-lightbox / assets / prettyphoto / jquery.prettyPhoto.js
responsive-lightbox / assets / prettyphoto Last commit date
images 13 years ago LICENSE 4 years ago README.md 4 years ago jquery.prettyPhoto.js 8 months ago jquery.prettyPhoto.min.js 8 months ago prettyPhoto.css 6 years ago prettyPhoto.min.css 6 years ago
jquery.prettyPhoto.js
1410 lines
1 /* ------------------------------------------------------------------------
2 Class: prettyPhoto
3 Use: Lightbox clone for jQuery
4 Author: Stephane Caron (http://www.no-margin-for-errors.com)
5 Version: 3.1.6-patched
6 ------------------------------------------------------------------------- */
7 (function ($) {
8 $.prettyPhoto = { version: '3.1.6' };
9
10 $.fn.prettyPhoto = function (pp_settings) {
11 pp_settings = jQuery.extend(
12 {
13 hook: 'rel' /* the attribute tag to use for prettyPhoto hooks. default: 'rel'. For HTML5, use "data-rel" or similar. */,
14 animation_speed: 'fast' /* fast/slow/normal */,
15 ajaxcallback: function () {},
16 slideshow: 5000 /* false OR interval time in ms */,
17 autoplay_slideshow: false /* true/false */,
18 opacity: 0.8 /* Value between 0 and 1 */,
19 show_title: true /* true/false */,
20 allow_resize: true /* Resize the photos bigger than viewport. true/false */,
21 allow_expand: true /* Allow the user to expand a resized image. true/false */,
22 default_width: 500,
23 default_height: 344,
24 counter_separator_label: '/' /* The separator for the gallery counter 1 "of" 2 */,
25 theme: 'pp_default' /* light_rounded / dark_rounded / light_square / dark_square / facebook */,
26 horizontal_padding: 20 /* The padding on each side of the picture */,
27 hideflash: false /* Hides all the flash object on a page, set to TRUE if flash appears over prettyPhoto */,
28 wmode: 'opaque' /* Set the flash wmode attribute */,
29 autoplay: true /* Automatically start videos: True/False */,
30 modal: false /* If set to true, only the close button will close the window */,
31 deeplinking: true /* Allow prettyPhoto to update the url to enable deeplinking. */,
32 overlay_gallery: true /* If set to true, a gallery will overlay the fullscreen image on mouse over */,
33 overlay_gallery_max: 30 /* Maximum number of pictures in the overlay gallery */,
34 keyboard_shortcuts: true /* Set to false if you open forms inside prettyPhoto */,
35 changepicturecallback:
36 function () {} /* Called everytime an item is shown/changed */,
37 callback: function () {} /* Called when prettyPhoto is closed */,
38 ie6_fallback: true,
39 markup: '<div class="pp_pic_holder"> \
40 <div class="ppt">&nbsp;</div> \
41 <div class="pp_top"> \
42 <div class="pp_left"></div> \
43 <div class="pp_middle"></div> \
44 <div class="pp_right"></div> \
45 </div> \
46 <div class="pp_content_container"> \
47 <div class="pp_left"> \
48 <div class="pp_right"> \
49 <div class="pp_content"> \
50 <div class="pp_loaderIcon"></div> \
51 <div class="pp_fade"> \
52 <a href="#" class="pp_expand" title="Expand the image">Expand</a> \
53 <div class="pp_hoverContainer"> \
54 <a class="pp_next" href="#">next</a> \
55 <a class="pp_previous" href="#">previous</a> \
56 </div> \
57 <div id="pp_full_res"></div> \
58 <div class="pp_details"> \
59 <div class="pp_nav"> \
60 <a href="#" class="pp_arrow_previous">Previous</a> \
61 <p class="currentTextHolder">0/0</p> \
62 <a href="#" class="pp_arrow_next">Next</a> \
63 </div> \
64 <p class="pp_description"></p> \
65 <div class="pp_social">{pp_social}</div> \
66 <a class="pp_close" href="#">Close</a> \
67 </div> \
68 </div> \
69 </div> \
70 </div> \
71 </div> \
72 </div> \
73 <div class="pp_bottom"> \
74 <div class="pp_left"></div> \
75 <div class="pp_middle"></div> \
76 <div class="pp_right"></div> \
77 </div> \
78 </div> \
79 <div class="pp_overlay"></div>',
80 gallery_markup:
81 '<div class="pp_gallery"> \
82 <a href="#" class="pp_arrow_previous">Previous</a> \
83 <div> \
84 <ul> \
85 {gallery} \
86 </ul> \
87 </div> \
88 <a href="#" class="pp_arrow_next">Next</a> \
89 </div>',
90 image_markup: '<img id="fullResImage" src="{path}" />',
91 flash_markup:
92 '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="{width}" height="{height}"><param name="wmode" value="{wmode}" /><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="{path}" /><embed src="{path}" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="{width}" height="{height}" wmode="{wmode}"></embed></object>',
93 quicktime_markup:
94 '<object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="//www.apple.com/qtactivex/qtplugin.cab" height="{height}" width="{width}"><param name="src" value="{path}"><param name="autoplay" value="{autoplay}"><param name="type" value="video/quicktime"><embed src="{path}" height="{height}" width="{width}" autoplay="{autoplay}" type="video/quicktime" pluginspage="//www.apple.com/quicktime/download/"></embed></object>',
95 iframe_markup:
96 '<iframe src ="{path}" width="{width}" height="{height}" frameborder="no"></iframe>',
97 inline_markup: '<div class="pp_inline">{content}</div>',
98 custom_markup: '',
99 social_tools:
100 '<div class="twitter"><a href="//twitter.com/share" class="twitter-share-button" data-count="none">Tweet</a><script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?"http":"https";if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document, "script", "twitter-wjs");</script></div><div class="facebook"><iframe src="//www.facebook.com/plugins/like.php?locale=en_US&href={location_href}&amp;layout=button_count&amp;show_faces=true&amp;width=500&amp;action=like&amp;font&amp;colorscheme=light&amp;height=23" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:500px; height:23px;" allowTransparency="true"></iframe></div>' /* html or false to disable */,
101 },
102 pp_settings
103 );
104
105 var isMobile = {
106 Android: function () {
107 return navigator.userAgent.match(/Android/i);
108 },
109 BlackBerry: function () {
110 return navigator.userAgent.match(/BlackBerry/i);
111 },
112 iOS: function () {
113 return navigator.userAgent.match(/iPhone|iPad|iPod/i);
114 },
115 Opera: function () {
116 return navigator.userAgent.match(/Opera Mini/i);
117 },
118 Windows: function () {
119 return navigator.userAgent.match(/IEMobile/i);
120 },
121 any: function () {
122 return (
123 isMobile.Android() ||
124 isMobile.BlackBerry() ||
125 isMobile.iOS() ||
126 isMobile.Opera() ||
127 isMobile.Windows()
128 );
129 },
130 };
131
132 // --- Security helpers ---
133 function sanitizeHtml(html, cfg) {
134 if (window.RLG && typeof window.RLG.sanitizeHtml === 'function') {
135 try {
136 return window.RLG.sanitizeHtml(html, cfg || {});
137 } catch (e) {}
138 }
139
140 // Fallback: escape via text node
141 var div = document.createElement('div');
142 div.appendChild(document.createTextNode(html));
143 return div.innerHTML;
144 }
145
146 function isAllowedEmbedUrl(url) {
147 try {
148 if (!url) return false;
149 // Basic protocol checks
150 var u = new URL(url, location.href);
151 var scheme = (u.protocol || '').replace(':', '').toLowerCase();
152
153 if (scheme === 'javascript' || scheme === 'vbscript') return false;
154 if (scheme === 'data') {
155 // allow only certain data image types
156 return /^data:image\/(png|jpeg|jpg|gif)/i.test(url);
157 }
158
159 if (window.RLG && typeof window.RLG.isAllowedEmbedUrl === 'function') {
160 return window.RLG.isAllowedEmbedUrl(url);
161 }
162
163 // default allow only http(s) and same-origin
164 return scheme === 'http' || scheme === 'https' || u.hostname === location.hostname;
165 } catch (e) {
166 return false;
167 }
168 }
169
170 function sanitizeUrlForImage(url) {
171 // For images allow data:image, http(s) and same-origin relative paths
172 try {
173 if (!url) return '';
174 if (/^data:image\//i.test(url)) return url;
175 var u = new URL(url, location.href);
176 var scheme = (u.protocol || '').replace(':', '').toLowerCase();
177 if (scheme === 'http' || scheme === 'https' || u.hostname === location.hostname)
178 return url;
179 return '';
180 } catch (e) {
181 return '';
182 }
183 }
184
185 function fitToMobileViewport(newWindowWidth, newWindowHeight, imgWidth, imgHeight) {
186 var newHeight = 0,
187 newWidth = 0;
188
189 if (imgWidth > imgHeight) {
190 newWidth = newWindowWidth;
191 newHeight = Math.round((imgHeight * newWindowWidth) / imgWidth);
192 } else {
193 newWidth = Math.round((imgWidth * newWindowHeight) / imgHeight);
194 newHeight = newWindowHeight;
195 }
196
197 return _fitToViewport(newWidth, newHeight);
198 }
199
200 // Global variables accessible only by prettyPhoto
201 var matchedObjects = this,
202 percentBased = false,
203 pp_dimensions,
204 pp_open,
205 // prettyPhoto container specific
206 pp_contentHeight,
207 pp_contentWidth,
208 pp_containerHeight,
209 pp_containerWidth,
210 // Window size
211 windowHeight = $(window).height(),
212 windowWidth = $(window).width(),
213 // Global elements
214 pp_slideshow;
215
216 ((doresize = true), (scroll_pos = _get_scroll()));
217
218 // Window/Keyboard events
219 $(window)
220 .off('resize.prettyphoto')
221 .on('resize.prettyphoto', function () {
222 _center_overlay();
223 _resize_overlay();
224 });
225
226 if (pp_settings.keyboard_shortcuts) {
227 $(document)
228 .off('keydown.prettyphoto')
229 .on('keydown.prettyphoto', function (e) {
230 if (typeof $pp_pic_holder != 'undefined') {
231 if ($pp_pic_holder.is(':visible')) {
232 switch (e.keyCode) {
233 case 37:
234 $.prettyPhoto.changePage('previous');
235 e.preventDefault();
236 break;
237 case 39:
238 $.prettyPhoto.changePage('next');
239 e.preventDefault();
240 break;
241 case 27:
242 if (!settings.modal) $.prettyPhoto.close();
243 e.preventDefault();
244 break;
245 }
246 // return false;
247 }
248 }
249 });
250 }
251
252 /**
253 * Initialize prettyPhoto.
254 */
255 $.prettyPhoto.initialize = function () {
256 settings = pp_settings;
257
258 if (settings.theme == 'pp_default') settings.horizontal_padding = 16;
259
260 // Find out if the picture is part of a set
261 theRel = $(this).attr(settings.hook);
262 galleryRegExp = /\-(?:.*)/;
263 isSet = galleryRegExp.exec(theRel) ? true : false;
264
265 // Put the SRCs, TITLEs, ALTs into an array.
266 pp_images = isSet
267 ? jQuery.map(matchedObjects, function (n, i) {
268 if ($(n).attr(settings.hook).indexOf(theRel) != -1)
269 return $(n).attr('href');
270 })
271 : $.makeArray($(this).attr('href'));
272 pp_titles = isSet
273 ? jQuery.map(matchedObjects, function (n, i) {
274 if ($(n).attr(settings.hook).indexOf(theRel) != -1)
275 return $(n).find('img').attr('alt') ? $(n).find('img').attr('alt') : '';
276 })
277 : $.makeArray($(this).find('img').attr('alt'));
278 pp_descriptions = isSet
279 ? jQuery.map(matchedObjects, function (n, i) {
280 if ($(n).attr(settings.hook).indexOf(theRel) != -1)
281 return $(n).attr('title') ? $(n).attr('title') : '';
282 })
283 : $.makeArray($(this).attr('title'));
284
285 if (pp_images.length > settings.overlay_gallery_max) settings.overlay_gallery = false;
286
287 set_position = jQuery.inArray($(this).attr('href'), pp_images); // Define where in the array the clicked item is positionned
288 rel_index = isSet
289 ? set_position
290 : $('a[' + settings.hook + "^='" + theRel + "']").index($(this));
291
292 _build_overlay(this); // Build the overlay {this} being the caller
293
294 if (settings.allow_resize)
295 $(window).on('scroll.prettyphoto', function () {
296 _center_overlay();
297 });
298
299 $.prettyPhoto.open();
300
301 return false;
302 };
303
304 /**
305 * Opens the prettyPhoto modal box.
306 * @param image {String,Array} Full path to the image to be open, can also be an array containing full images paths.
307 * @param title {String,Array} The title to be displayed with the picture, can also be an array containing all the titles.
308 * @param description {String,Array} The description to be displayed with the picture, can also be an array containing all the descriptions.
309 */
310 $.prettyPhoto.open = function (event) {
311 if (typeof settings == 'undefined') {
312 // Means it's an API call, need to manually get the settings and set the variables
313 settings = pp_settings;
314 pp_images = $.makeArray(arguments[0]);
315 pp_titles = arguments[1] ? $.makeArray(arguments[1]) : $.makeArray('');
316 pp_descriptions = arguments[2] ? $.makeArray(arguments[2]) : $.makeArray('');
317 isSet = pp_images.length > 1 ? true : false;
318 set_position = arguments[3] ? arguments[3] : 0;
319 _build_overlay(event.target); // Build the overlay {this} being the caller
320 }
321
322 if (settings.hideflash)
323 $('object,embed,iframe[src*=youtube],iframe[src*=vimeo]').css(
324 'visibility',
325 'hidden'
326 ); // Hide the flash
327
328 _checkPosition($(pp_images).length); // Hide the next/previous links if on first or last images.
329
330 $('.pp_loaderIcon').show();
331
332 if (settings.deeplinking) setHashtag();
333
334 // Rebuild Facebook Like Button with updated href
335 if (settings.social_tools) {
336 facebook_like_link = settings.social_tools.replace(
337 '{location_href}',
338 encodeURIComponent(location.href)
339 );
340 $pp_pic_holder.find('.pp_social').html(facebook_like_link);
341 }
342
343 // Fade the content in
344 if ($ppt.is(':hidden')) $ppt.css('opacity', 0).show();
345 $pp_overlay.show().fadeTo(settings.animation_speed, settings.opacity);
346
347 // Display the current position
348 $pp_pic_holder
349 .find('.currentTextHolder')
350 .text(set_position + 1 + settings.counter_separator_label + $(pp_images).length);
351
352 // Set the description
353 if (
354 typeof pp_descriptions[set_position] != 'undefined' &&
355 pp_descriptions[set_position] != ''
356 ) {
357 var desc = unescape(pp_descriptions[set_position]);
358 var safeDesc =
359 window.RLG && typeof window.RLG.sanitizeHtml === 'function'
360 ? sanitizeHtml(desc)
361 : $('<div/>').text(desc).html();
362 $pp_pic_holder.find('.pp_description').show().html(safeDesc);
363 } else {
364 $pp_pic_holder.find('.pp_description').hide();
365 }
366
367 // Get the dimensions
368 movie_width = parseFloat(getParam('width', pp_images[set_position]))
369 ? getParam('width', pp_images[set_position])
370 : settings.default_width.toString();
371 movie_height = parseFloat(getParam('height', pp_images[set_position]))
372 ? getParam('height', pp_images[set_position])
373 : settings.default_height.toString();
374
375 // If the size is % based, calculate according to window dimensions
376 percentBased = false;
377 if (movie_height.indexOf('%') != -1) {
378 movie_height = parseFloat(
379 ($(window).height() * parseFloat(movie_height)) / 100 - 150
380 );
381 percentBased = true;
382 }
383 if (movie_width.indexOf('%') != -1) {
384 movie_width = parseFloat(($(window).width() * parseFloat(movie_width)) / 100 - 150);
385 percentBased = true;
386 }
387
388 // Fade the holder
389 $pp_pic_holder.fadeIn(function () {
390 // Set the title
391 if (
392 settings.show_title &&
393 pp_titles[set_position] != '' &&
394 typeof pp_titles[set_position] != 'undefined'
395 ) {
396 var title = unescape(pp_titles[set_position]);
397 var safeTitle =
398 window.RLG && typeof window.RLG.sanitizeHtml === 'function'
399 ? sanitizeHtml(title, {
400 ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'small'],
401 })
402 : $('<div/>').text(title).html();
403 $ppt.html(safeTitle);
404 } else {
405 $ppt.html('&nbsp;');
406 }
407
408 imgPreloader = '';
409 skipInjection = false;
410
411 // Inject the proper content
412 switch (_getFileType(pp_images[set_position])) {
413 case 'image':
414 imgPreloader = new Image();
415
416 // Preload the neighbour images
417 nextImage = new Image();
418 if (isSet && set_position < $(pp_images).length - 1)
419 nextImage.src = pp_images[set_position + 1];
420 prevImage = new Image();
421 if (isSet && pp_images[set_position - 1])
422 prevImage.src = pp_images[set_position - 1];
423
424 // Sanitize URL and inject image via DOM (avoid innerHTML with untrusted URLs)
425 var safeSrc = sanitizeUrlForImage(pp_images[set_position]);
426 if (!safeSrc) {
427 $pp_pic_holder
428 .find('#pp_full_res')
429 .empty()
430 .append(
431 $('<div/>').text(
432 'Image cannot be loaded. Make sure the path is correct and image exist.'
433 )
434 );
435 if (typeof imgPreloader.onerror === 'function') imgPreloader.onerror();
436 } else {
437 $pp_pic_holder
438 .find('#pp_full_res')
439 .empty()
440 .append($('<img id="fullResImage" />'));
441
442 imgPreloader.onload = function () {
443 // Fit item to viewport
444 if (isMobile.any())
445 pp_dimensions = fitToMobileViewport(
446 Math.round(windowWidth * 0.9),
447 Math.round(windowHeight * 0.9),
448 imgPreloader.width,
449 imgPreloader.height
450 );
451 else
452 pp_dimensions = _fitToViewport(
453 imgPreloader.width,
454 imgPreloader.height
455 );
456
457 // set real image src now that preloader succeeded
458 $pp_pic_holder.find('#fullResImage').attr('src', safeSrc);
459 _showContent();
460 };
461
462 imgPreloader.onerror = function () {
463 alert(
464 'Image cannot be loaded. Make sure the path is correct and image exist.'
465 );
466 $.prettyPhoto.close();
467 };
468
469 imgPreloader.src = safeSrc;
470 }
471 break;
472
473 case 'youtube':
474 // Fit item to viewport
475 if (isMobile.any())
476 pp_dimensions = fitToMobileViewport(
477 Math.round(windowWidth * 0.9),
478 Math.round(windowHeight * 0.9),
479 movie_width,
480 movie_height
481 );
482 else pp_dimensions = _fitToViewport(movie_width, movie_height);
483
484 // Regular youtube link
485 movie_id = getParam('v', pp_images[set_position]);
486
487 // youtu.be link
488 if (movie_id == '') {
489 movie_id = pp_images[set_position].split('youtu.be/');
490 movie_id = movie_id[1];
491 if (movie_id.indexOf('?') > 0)
492 movie_id = movie_id.substr(0, movie_id.indexOf('?')); // Strip anything after the ?
493
494 if (movie_id.indexOf('&') > 0)
495 movie_id = movie_id.substr(0, movie_id.indexOf('&')); // Strip anything after the &
496 }
497
498 movie = '//www.youtube.com/embed/' + movie_id;
499 getParam('rel', pp_images[set_position])
500 ? (movie += '?rel=' + getParam('rel', pp_images[set_position]))
501 : (movie += '?rel=1');
502 if (settings.autoplay) movie += '&autoplay=1';
503
504 // Inject iframe via DOM if the URL is allowed
505 if (isAllowedEmbedUrl(movie)) {
506 $pp_pic_holder
507 .find('#pp_full_res')
508 .empty()
509 .append(
510 $('<iframe/>').attr({
511 src: movie,
512 width: pp_dimensions['width'],
513 height: pp_dimensions['height'],
514 frameborder: 0,
515 allow: 'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture',
516 allowfullscreen: 'allowfullscreen',
517 })
518 );
519 } else {
520 $pp_pic_holder
521 .find('#pp_full_res')
522 .empty()
523 .append($('<div/>').text('The requested embed is not allowed.'));
524 }
525 skipInjection = true;
526 _showContent();
527 break;
528
529 case 'vimeo':
530 // Fit item to viewport
531 if (isMobile.any())
532 pp_dimensions = fitToMobileViewport(
533 Math.round(windowWidth * 0.9),
534 Math.round(windowHeight * 0.9),
535 movie_width,
536 movie_height
537 );
538 else pp_dimensions = _fitToViewport(movie_width, movie_height);
539
540 movie_id = pp_images[set_position];
541 var regExp = /http(s?):\/\/(www\.)?vimeo.com\/(\d+)/;
542 var match = movie_id.match(regExp);
543
544 movie =
545 '//player.vimeo.com/video/' +
546 match[3] +
547 '?title=0&amp;byline=0&amp;portrait=0';
548 if (settings.autoplay) movie += '&autoplay=1;';
549
550 vimeo_width =
551 pp_dimensions['width'] + '/embed/?moog_width=' + pp_dimensions['width'];
552
553 // Inject iframe via DOM if the URL is allowed
554 if (isAllowedEmbedUrl(movie)) {
555 $pp_pic_holder
556 .find('#pp_full_res')
557 .empty()
558 .append(
559 $('<iframe/>').attr({
560 src: movie,
561 width: vimeo_width,
562 height: pp_dimensions['height'],
563 frameborder: 0,
564 allow: 'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture',
565 allowfullscreen: 'allowfullscreen',
566 })
567 );
568 } else {
569 $pp_pic_holder
570 .find('#pp_full_res')
571 .empty()
572 .append($('<div/>').text('The requested embed is not allowed.'));
573 }
574 skipInjection = true;
575 _showContent();
576 break;
577
578 case 'quicktime':
579 pp_dimensions = _fitToViewport(movie_width, movie_height); // Fit item to viewport
580 pp_dimensions['height'] += 15;
581 pp_dimensions['contentHeight'] += 15;
582 pp_dimensions['containerHeight'] += 15; // Add space for the control bar
583 // QuickTime/legacy media are disabled by default for security reasons
584 $pp_pic_holder
585 .find('#pp_full_res')
586 .empty()
587 .append(
588 $('<div/>').text(
589 'This media format (QuickTime) is not supported due to security reasons.'
590 )
591 );
592 skipInjection = true;
593 _showContent();
594 break;
595
596 case 'flash':
597 // Flash is deprecated/unsafe — do not inject object/embed
598 pp_dimensions = _fitToViewport(movie_width, movie_height);
599 $pp_pic_holder
600 .find('#pp_full_res')
601 .empty()
602 .append($('<div/>').text('Flash content is not supported.'));
603 skipInjection = true;
604 _showContent();
605 break;
606
607 case 'iframe':
608 // Fit item to viewport
609 if (isMobile.any())
610 pp_dimensions = fitToMobileViewport(
611 Math.round(windowWidth * 0.9),
612 Math.round(windowHeight * 0.9),
613 movie_width,
614 movie_height
615 );
616 else pp_dimensions = _fitToViewport(movie_width, movie_height);
617
618 frame_url = pp_images[set_position];
619 frame_url = frame_url.substr(0, frame_url.indexOf('iframe') - 1);
620
621 if (isAllowedEmbedUrl(frame_url)) {
622 $pp_pic_holder
623 .find('#pp_full_res')
624 .empty()
625 .append(
626 $('<iframe/>').attr({
627 src: frame_url,
628 width: pp_dimensions['width'],
629 height: pp_dimensions['height'],
630 frameborder: 0,
631 })
632 );
633 } else {
634 $pp_pic_holder
635 .find('#pp_full_res')
636 .empty()
637 .append($('<div/>').text('The requested embed is not allowed.'));
638 }
639 skipInjection = true;
640 _showContent();
641 doresize = false; // Make sure the dimensions are not resized.
642
643 // Fit item to viewport
644 if (isMobile.any())
645 pp_dimensions = fitToMobileViewport(
646 Math.round(windowWidth * 0.9),
647 Math.round(windowHeight * 0.9),
648 movie_width,
649 movie_height
650 );
651 else pp_dimensions = _fitToViewport(movie_width, movie_height);
652
653 doresize = true; // Reset the dimensions
654
655 break;
656
657 case 'ajax':
658 // Fit item to viewport
659 if (isMobile.any())
660 pp_dimensions = fitToMobileViewport(
661 Math.round(windowWidth * 0.9),
662 Math.round(windowHeight * 0.9),
663 movie_width,
664 movie_height
665 );
666 else pp_dimensions = _fitToViewport(movie_width, movie_height);
667
668 try {
669 var ajaxUrl = new URL(pp_images[set_position], location.href);
670 if (ajaxUrl.origin !== location.origin) {
671 $pp_pic_holder
672 .find('#pp_full_res')
673 .empty()
674 .append(
675 $('<div/>').text(
676 'The requested AJAX content is not allowed.'
677 )
678 );
679 _showContent();
680 } else {
681 $.get(pp_images[set_position], function (responseHTML) {
682 var clean =
683 window.RLG && typeof window.RLG.sanitizeHtml === 'function'
684 ? sanitizeHtml(responseHTML)
685 : $('<div/>').text(responseHTML).html();
686 $pp_pic_holder
687 .find('#pp_full_res')
688 .html(settings.inline_markup.replace(/{content}/g, clean));
689 _showContent();
690 }).fail(function () {
691 $pp_pic_holder
692 .find('#pp_full_res')
693 .empty()
694 .append($('<div/>').text('Content could not be loaded.'));
695 _showContent();
696 });
697 }
698 } catch (e) {
699 $pp_pic_holder
700 .find('#pp_full_res')
701 .empty()
702 .append($('<div/>').text('Content could not be loaded.'));
703 _showContent();
704 }
705 break;
706
707 case 'custom':
708 // Fit item to viewport
709 if (isMobile.any())
710 pp_dimensions = fitToMobileViewport(
711 Math.round(windowWidth * 0.9),
712 Math.round(windowHeight * 0.9),
713 movie_width,
714 movie_height
715 );
716 else pp_dimensions = _fitToViewport(movie_width, movie_height);
717
718 toInject = settings.custom_markup;
719 break;
720
721 case 'inline':
722 // to get the item height clone it, apply default width, wrap it in the prettyPhoto containers , then delete
723 myClone = $(pp_images[set_position])
724 .clone()
725 .append('<br clear="all" />')
726 .css({ width: settings.default_width })
727 .wrapInner('<div id="pp_full_res"><div class="pp_inline"></div></div>')
728 .appendTo($('body'))
729 .show();
730 doresize = false; // Make sure the dimensions are not resized.
731
732 // Fit item to viewport
733 if (isMobile.any())
734 pp_dimensions = fitToMobileViewport(
735 Math.round(windowWidth * 0.9),
736 Math.round(windowHeight * 0.9),
737 $(myClone).width(),
738 $(myClone).height()
739 );
740 else
741 pp_dimensions = _fitToViewport($(myClone).width(), $(myClone).height());
742
743 doresize = true; // Reset the dimensions
744 $(myClone).remove();
745 toInject = settings.inline_markup.replace(
746 /{content}/g,
747 $(pp_images[set_position]).html()
748 );
749 break;
750 }
751
752 if (!imgPreloader && !skipInjection) {
753 var safeInject = toInject;
754 if (window.RLG && typeof window.RLG.sanitizeHtml === 'function') {
755 safeInject = sanitizeHtml(toInject);
756 } else {
757 // fallback: escape to avoid raw HTML injection
758 safeInject = $('<div/>').text(toInject).html();
759 }
760
761 $pp_pic_holder.find('#pp_full_res')[0].innerHTML = safeInject;
762
763 // Show content
764 _showContent();
765 }
766 });
767
768 return false;
769 };
770
771 /**
772 * Change page in the prettyPhoto modal box
773 * @param direction {String} Direction of the paging, previous or next.
774 */
775 $.prettyPhoto.changePage = function (direction) {
776 currentGalleryPage = 0;
777
778 if (direction == 'previous') {
779 set_position--;
780 if (set_position < 0) set_position = $(pp_images).length - 1;
781 } else if (direction == 'next') {
782 set_position++;
783 if (set_position > $(pp_images).length - 1) set_position = 0;
784 } else {
785 set_position = direction;
786 }
787
788 rel_index = set_position;
789
790 if (!doresize) doresize = true; // Allow the resizing of the images
791 if (settings.allow_expand) {
792 $('.pp_contract').removeClass('pp_contract').addClass('pp_expand');
793 }
794
795 _hideContent(function () {
796 $.prettyPhoto.open();
797 });
798 };
799
800 /**
801 * Change gallery page in the prettyPhoto modal box
802 * @param direction {String} Direction of the paging, previous or next.
803 */
804 $.prettyPhoto.changeGalleryPage = function (direction) {
805 if (direction == 'next') {
806 currentGalleryPage++;
807
808 if (currentGalleryPage > totalPage) currentGalleryPage = 0;
809 } else if (direction == 'previous') {
810 currentGalleryPage--;
811
812 if (currentGalleryPage < 0) currentGalleryPage = totalPage;
813 } else {
814 currentGalleryPage = direction;
815 }
816
817 slide_speed =
818 direction == 'next' || direction == 'previous' ? settings.animation_speed : 0;
819
820 slide_to = currentGalleryPage * (itemsPerPage * itemWidth);
821
822 $pp_gallery.find('ul').animate({ left: -slide_to }, slide_speed);
823 };
824
825 /**
826 * Start the slideshow...
827 */
828 $.prettyPhoto.startSlideshow = function () {
829 if (typeof pp_slideshow == 'undefined') {
830 $pp_pic_holder
831 .find('.pp_play')
832 .off('click')
833 .removeClass('pp_play')
834 .addClass('pp_pause')
835 .on('click', function () {
836 $.prettyPhoto.stopSlideshow();
837 return false;
838 });
839 pp_slideshow = setInterval($.prettyPhoto.startSlideshow, settings.slideshow);
840 } else {
841 $.prettyPhoto.changePage('next');
842 }
843 };
844
845 /**
846 * Stop the slideshow...
847 */
848 $.prettyPhoto.stopSlideshow = function () {
849 $pp_pic_holder
850 .find('.pp_pause')
851 .off('click')
852 .removeClass('pp_pause')
853 .addClass('pp_play')
854 .on('click', function () {
855 $.prettyPhoto.startSlideshow();
856 return false;
857 });
858 clearInterval(pp_slideshow);
859 pp_slideshow = undefined;
860 };
861
862 /**
863 * Closes prettyPhoto.
864 */
865 $.prettyPhoto.close = function () {
866 if ($pp_overlay.is(':animated')) return;
867
868 $.prettyPhoto.stopSlideshow();
869
870 $pp_pic_holder.stop().find('object,embed').css('visibility', 'hidden');
871
872 $('div.pp_pic_holder,div.ppt,.pp_fade').fadeOut(settings.animation_speed, function () {
873 $(this).remove();
874 });
875
876 $pp_overlay.fadeOut(settings.animation_speed, function () {
877 if (settings.hideflash)
878 $('object,embed,iframe[src*=youtube],iframe[src*=vimeo]').css(
879 'visibility',
880 'visible'
881 ); // Show the flash
882
883 $(this).remove(); // No more need for the prettyPhoto markup
884
885 $(window).off('scroll.prettyphoto');
886
887 clearHashtag();
888
889 settings.callback();
890
891 doresize = true;
892
893 pp_open = false;
894
895 // avoid delete of identifier (strict mode); clear the settings reference instead
896 settings = null;
897 });
898 };
899
900 /**
901 * Set the proper sizes on the containers and animate the content in.
902 */
903 function _showContent() {
904 $('.pp_loaderIcon').hide();
905
906 // Calculate the opened top position of the pic holder
907 projectedTop =
908 scroll_pos['scrollTop'] + (windowHeight / 2 - pp_dimensions['containerHeight'] / 2);
909 if (projectedTop < 0) projectedTop = 0;
910
911 $ppt.fadeTo(settings.animation_speed, 1);
912
913 // Resize the content holder
914 $pp_pic_holder.find('.pp_content').animate(
915 {
916 height: pp_dimensions['contentHeight'],
917 width: pp_dimensions['contentWidth'],
918 },
919 settings.animation_speed
920 );
921
922 // Resize picture the holder
923 $pp_pic_holder.animate(
924 {
925 top: projectedTop,
926 left:
927 windowWidth / 2 - pp_dimensions['containerWidth'] / 2 < 0
928 ? 0
929 : windowWidth / 2 - pp_dimensions['containerWidth'] / 2,
930 width: pp_dimensions['containerWidth'],
931 },
932 settings.animation_speed,
933 function () {
934 $pp_pic_holder
935 .find('.pp_hoverContainer,#fullResImage')
936 .height(pp_dimensions['height'])
937 .width(pp_dimensions['width']);
938
939 $pp_pic_holder.find('.pp_fade').fadeIn(settings.animation_speed); // Fade the new content
940
941 // Show the nav
942 if (isSet && _getFileType(pp_images[set_position]) == 'image') {
943 $pp_pic_holder.find('.pp_hoverContainer').show();
944 } else {
945 $pp_pic_holder.find('.pp_hoverContainer').hide();
946 }
947
948 if (settings.allow_expand) {
949 if (pp_dimensions['resized']) {
950 // Fade the resizing link if the image is resized
951 $('a.pp_expand,a.pp_contract').show();
952 } else {
953 $('a.pp_expand').hide();
954 }
955 }
956
957 if (settings.autoplay_slideshow && !pp_slideshow && !pp_open)
958 $.prettyPhoto.startSlideshow();
959
960 settings.changepicturecallback(); // Callback!
961
962 pp_open = true;
963 }
964 );
965
966 _insert_gallery();
967 pp_settings.ajaxcallback();
968 }
969
970 /**
971 * Hide the content...DUH!
972 */
973 function _hideContent(callback) {
974 // Fade out the current picture
975 $pp_pic_holder
976 .find('#pp_full_res object,#pp_full_res embed')
977 .css('visibility', 'hidden');
978 $pp_pic_holder.find('.pp_fade').fadeOut(settings.animation_speed, function () {
979 $('.pp_loaderIcon').show();
980
981 callback();
982 });
983 }
984
985 /**
986 * Check the item position in the gallery array, hide or show the navigation links
987 * @param setCount {integer} The total number of items in the set
988 */
989 function _checkPosition(setCount) {
990 setCount > 1 ? $('.pp_nav').show() : $('.pp_nav').hide(); // Hide the bottom nav if it's not a set.
991 }
992
993 /**
994 * Resize the item dimensions if it's bigger than the viewport
995 * @param width {integer} Width of the item to be opened
996 * @param height {integer} Height of the item to be opened
997 * @return An array containin the "fitted" dimensions
998 */
999 function _fitToViewport(width, height) {
1000 resized = false;
1001
1002 _getDimensions(width, height);
1003
1004 // Define them in case there's no resize needed
1005 ((imageWidth = width), (imageHeight = height));
1006
1007 if (
1008 (pp_containerWidth > windowWidth || pp_containerHeight > windowHeight) &&
1009 doresize &&
1010 settings.allow_resize &&
1011 !percentBased
1012 ) {
1013 ((resized = true), (fitting = false));
1014
1015 while (!fitting) {
1016 if (pp_containerWidth > windowWidth) {
1017 imageWidth = windowWidth - 200;
1018 imageHeight = (height / width) * imageWidth;
1019 } else if (pp_containerHeight > windowHeight) {
1020 imageHeight = windowHeight - 200;
1021 imageWidth = (width / height) * imageHeight;
1022 } else {
1023 fitting = true;
1024 }
1025
1026 ((pp_containerHeight = imageHeight), (pp_containerWidth = imageWidth));
1027 }
1028
1029 if (pp_containerWidth > windowWidth || pp_containerHeight > windowHeight) {
1030 _fitToViewport(pp_containerWidth, pp_containerHeight);
1031 }
1032
1033 _getDimensions(imageWidth, imageHeight);
1034 }
1035
1036 return {
1037 width: Math.floor(imageWidth),
1038 height: Math.floor(imageHeight),
1039 containerHeight: Math.floor(pp_containerHeight),
1040 containerWidth: Math.floor(pp_containerWidth) + settings.horizontal_padding * 2,
1041 contentHeight: Math.floor(pp_contentHeight),
1042 contentWidth: Math.floor(pp_contentWidth),
1043 resized: resized,
1044 };
1045 }
1046
1047 /**
1048 * Get the containers dimensions according to the item size
1049 * @param width {integer} Width of the item to be opened
1050 * @param height {integer} Height of the item to be opened
1051 */
1052 function _getDimensions(width, height) {
1053 width = parseFloat(width);
1054 height = parseFloat(height);
1055
1056 // Get the details height, to do so, I need to clone it since it's invisible
1057 $pp_details = $pp_pic_holder.find('.pp_details');
1058 $pp_details.width(width);
1059 detailsHeight =
1060 parseFloat($pp_details.css('marginTop')) +
1061 parseFloat($pp_details.css('marginBottom'));
1062
1063 $pp_details = $pp_details
1064 .clone()
1065 .addClass(settings.theme)
1066 .width(width)
1067 .appendTo($('body'))
1068 .css({
1069 position: 'absolute',
1070 top: -10000,
1071 });
1072 detailsHeight += $pp_details.height();
1073 detailsHeight = detailsHeight <= 34 ? 36 : detailsHeight; // Min-height for the details
1074 $pp_details.remove();
1075
1076 // Get the titles height, to do so, I need to clone it since it's invisible
1077 $pp_title = $pp_pic_holder.find('.ppt');
1078 $pp_title.width(width);
1079 titleHeight =
1080 parseFloat($pp_title.css('marginTop')) + parseFloat($pp_title.css('marginBottom'));
1081 $pp_title = $pp_title.clone().appendTo($('body')).css({
1082 position: 'absolute',
1083 top: -10000,
1084 });
1085 titleHeight += $pp_title.height();
1086 $pp_title.remove();
1087
1088 // Get the container size, to resize the holder to the right dimensions
1089 pp_contentHeight = height + detailsHeight;
1090 pp_contentWidth = width;
1091 pp_containerHeight =
1092 pp_contentHeight +
1093 titleHeight +
1094 $pp_pic_holder.find('.pp_top').height() +
1095 $pp_pic_holder.find('.pp_bottom').height();
1096 pp_containerWidth = width;
1097 }
1098
1099 function _getFileType(itemSrc) {
1100 if (itemSrc.match(/youtube\.com\/watch/i) || itemSrc.match(/youtu\.be/i)) {
1101 return 'youtube';
1102 } else if (itemSrc.match(/vimeo\.com/i)) {
1103 return 'vimeo';
1104 } else if (itemSrc.match(/\b.mov\b/i)) {
1105 return 'quicktime';
1106 } else if (itemSrc.match(/\b.swf\b/i)) {
1107 return 'flash';
1108 } else if (itemSrc.match(/\biframe=true\b/i)) {
1109 return 'iframe';
1110 } else if (itemSrc.match(/\bajax=true\b/i)) {
1111 return 'ajax';
1112 } else if (itemSrc.match(/\bcustom=true\b/i)) {
1113 return 'custom';
1114 } else if (itemSrc.substr(0, 1) == '#') {
1115 return 'inline';
1116 } else {
1117 return 'image';
1118 }
1119 }
1120
1121 function _center_overlay() {
1122 if (doresize && typeof $pp_pic_holder != 'undefined') {
1123 scroll_pos = _get_scroll();
1124 ((contentHeight = $pp_pic_holder.height()),
1125 (contentwidth = $pp_pic_holder.width()));
1126
1127 projectedTop = windowHeight / 2 + scroll_pos['scrollTop'] - contentHeight / 2;
1128 if (projectedTop < 0) projectedTop = 0;
1129
1130 if (contentHeight > windowHeight) return;
1131
1132 $pp_pic_holder.css({
1133 top: projectedTop,
1134 left: windowWidth / 2 + scroll_pos['scrollLeft'] - contentwidth / 2,
1135 });
1136 }
1137 }
1138
1139 function _get_scroll() {
1140 if (self.pageYOffset) {
1141 return { scrollTop: self.pageYOffset, scrollLeft: self.pageXOffset };
1142 } else if (document.documentElement && document.documentElement.scrollTop) {
1143 // Explorer 6 Strict
1144 return {
1145 scrollTop: document.documentElement.scrollTop,
1146 scrollLeft: document.documentElement.scrollLeft,
1147 };
1148 } else if (document.body) {
1149 // all other Explorers
1150 return {
1151 scrollTop: document.body.scrollTop,
1152 scrollLeft: document.body.scrollLeft,
1153 };
1154 }
1155 }
1156
1157 function _resize_overlay() {
1158 ((windowHeight = $(window).height()), (windowWidth = $(window).width()));
1159
1160 if (typeof $pp_overlay != 'undefined')
1161 $pp_overlay.height($(document).height()).width(windowWidth);
1162 }
1163
1164 function _insert_gallery() {
1165 if (
1166 isSet &&
1167 settings.overlay_gallery &&
1168 _getFileType(pp_images[set_position]) == 'image'
1169 ) {
1170 itemWidth = 52 + 5; // 52 beign the thumb width, 5 being the right margin.
1171 navWidth = settings.theme == 'facebook' || settings.theme == 'pp_default' ? 50 : 30; // Define the arrow width depending on the theme
1172
1173 itemsPerPage = Math.floor(
1174 (pp_dimensions['containerWidth'] - 100 - navWidth) / itemWidth
1175 );
1176 itemsPerPage = itemsPerPage < pp_images.length ? itemsPerPage : pp_images.length;
1177 totalPage = Math.ceil(pp_images.length / itemsPerPage) - 1;
1178
1179 // Hide the nav in the case there's no need for links
1180 if (totalPage == 0) {
1181 navWidth = 0; // No nav means no width!
1182 $pp_gallery.find('.pp_arrow_next,.pp_arrow_previous').hide();
1183 } else {
1184 $pp_gallery.find('.pp_arrow_next,.pp_arrow_previous').show();
1185 }
1186
1187 galleryWidth = itemsPerPage * itemWidth;
1188 fullGalleryWidth = pp_images.length * itemWidth;
1189
1190 // Set the proper width to the gallery items
1191 $pp_gallery
1192 .css('margin-left', -(galleryWidth / 2 + navWidth / 2))
1193 .find('div:first')
1194 .width(galleryWidth + 5)
1195 .find('ul')
1196 .width(fullGalleryWidth)
1197 .find('li.selected')
1198 .removeClass('selected');
1199
1200 goToPage =
1201 Math.floor(set_position / itemsPerPage) < totalPage
1202 ? Math.floor(set_position / itemsPerPage)
1203 : totalPage;
1204
1205 $.prettyPhoto.changeGalleryPage(goToPage);
1206
1207 $pp_gallery_li.filter(':eq(' + set_position + ')').addClass('selected');
1208 } else {
1209 $pp_pic_holder.find('.pp_content').off('mouseenter mouseleave');
1210 // $pp_gallery.hide();
1211 }
1212 }
1213
1214 function _build_overlay(caller) {
1215 // Inject Social Tool markup into General markup
1216 if (settings.social_tools)
1217 facebook_like_link = settings.social_tools.replace(
1218 '{location_href}',
1219 encodeURIComponent(location.href)
1220 );
1221
1222 settings.markup = settings.markup.replace('{pp_social}', '');
1223
1224 $('body').append(settings.markup); // Inject the markup
1225
1226 (($pp_pic_holder = $('.pp_pic_holder')),
1227 ($ppt = $('.ppt')),
1228 ($pp_overlay = $('div.pp_overlay'))); // Set my global selectors
1229
1230 // Inject the inline gallery!
1231 if (isSet && settings.overlay_gallery) {
1232 currentGalleryPage = 0;
1233 toInject = '';
1234 for (var i = 0; i < pp_images.length; i++) {
1235 if (!pp_images[i].match(/\b(jpg|jpeg|png|gif|webp|avif|svg)\b/gi)) {
1236 classname = 'default';
1237 img_src = '';
1238 } else {
1239 classname = '';
1240 img_src = sanitizeUrlForImage(pp_images[i]);
1241 if (!img_src) {
1242 classname = 'default';
1243 }
1244 }
1245 toInject +=
1246 "<li class='" +
1247 classname +
1248 "'><a href='#'><img src='" +
1249 img_src +
1250 "' width='50' alt='' /></a></li>";
1251 }
1252
1253 toInject = settings.gallery_markup.replace(/{gallery}/g, toInject);
1254
1255 $pp_pic_holder.find('#pp_full_res').after(toInject);
1256
1257 (($pp_gallery = $('.pp_pic_holder .pp_gallery')),
1258 ($pp_gallery_li = $pp_gallery.find('li'))); // Set the gallery selectors
1259
1260 $pp_gallery.find('.pp_arrow_next').on('click', function () {
1261 $.prettyPhoto.changeGalleryPage('next');
1262 $.prettyPhoto.stopSlideshow();
1263 return false;
1264 });
1265
1266 $pp_gallery.find('.pp_arrow_previous').on('click', function () {
1267 $.prettyPhoto.changeGalleryPage('previous');
1268 $.prettyPhoto.stopSlideshow();
1269 return false;
1270 });
1271
1272 $pp_pic_holder
1273 .find('.pp_content')
1274 .on('mouseenter', function () {
1275 $pp_pic_holder.find('.pp_gallery:not(.disabled)').fadeIn();
1276 })
1277 .on('mouseleave', function () {
1278 $pp_pic_holder.find('.pp_gallery:not(.disabled)').fadeOut();
1279 });
1280
1281 itemWidth = 52 + 5; // 52 beign the thumb width, 5 being the right margin.
1282 $pp_gallery_li.each(function (i) {
1283 $(this)
1284 .find('a')
1285 .on('click', function () {
1286 $.prettyPhoto.changePage(i);
1287 $.prettyPhoto.stopSlideshow();
1288 return false;
1289 });
1290 });
1291 }
1292
1293 // Inject the play/pause if it's a slideshow
1294 if (settings.slideshow) {
1295 $pp_pic_holder.find('.pp_nav').prepend('<a href="#" class="pp_play">Play</a>');
1296 $pp_pic_holder.find('.pp_nav .pp_play').on('click', function () {
1297 $.prettyPhoto.startSlideshow();
1298 return false;
1299 });
1300 }
1301
1302 $pp_pic_holder.attr('class', 'pp_pic_holder ' + settings.theme); // Set the proper theme
1303
1304 $pp_overlay
1305 .css({
1306 opacity: 0,
1307 height: $(document).height(),
1308 width: $(window).width(),
1309 })
1310 .on('click', function () {
1311 if (!settings.modal) $.prettyPhoto.close();
1312 });
1313
1314 $('a.pp_close').on('click', function () {
1315 $.prettyPhoto.close();
1316 return false;
1317 });
1318
1319 if (settings.allow_expand) {
1320 $('a.pp_expand').on('click', function (e) {
1321 // Expand the image
1322 if ($(this).hasClass('pp_expand')) {
1323 $(this).removeClass('pp_expand').addClass('pp_contract');
1324 doresize = false;
1325 } else {
1326 $(this).removeClass('pp_contract').addClass('pp_expand');
1327 doresize = true;
1328 }
1329
1330 _hideContent(function () {
1331 $.prettyPhoto.open();
1332 });
1333
1334 return false;
1335 });
1336 }
1337
1338 $pp_pic_holder
1339 .find('.pp_previous, .pp_nav .pp_arrow_previous')
1340 .on('click', function () {
1341 $.prettyPhoto.changePage('previous');
1342 $.prettyPhoto.stopSlideshow();
1343 return false;
1344 });
1345
1346 $pp_pic_holder.find('.pp_next, .pp_nav .pp_arrow_next').on('click', function () {
1347 $.prettyPhoto.changePage('next');
1348 $.prettyPhoto.stopSlideshow();
1349 return false;
1350 });
1351
1352 _center_overlay(); // Center it
1353 }
1354
1355 if (!pp_alreadyInitialized && getHashtag()) {
1356 pp_alreadyInitialized = true;
1357
1358 // Grab the rel index to trigger the click on the correct element
1359 hashIndex = getHashtag();
1360 hashRel = hashIndex;
1361 hashIndex = hashIndex.substring(hashIndex.indexOf('/') + 1, hashIndex.length - 1);
1362 hashRel = hashRel.substring(0, hashRel.indexOf('/'));
1363
1364 // Little timeout to make sure all the prettyPhoto initialize scripts has been run.
1365 // Useful in the event the page contain several init scripts.
1366 setTimeout(function () {
1367 $('a[' + pp_settings.hook + "^='" + hashRel + "']:eq(" + hashIndex + ')').trigger(
1368 'click'
1369 );
1370 }, 50);
1371 }
1372
1373 return this.off('click.prettyphoto').on('click.prettyphoto', $.prettyPhoto.initialize); // Return the jQuery object for chaining. The unbind method is used to avoid click conflict when the plugin is called more than once
1374 };
1375
1376 function getHashtag() {
1377 var url = location.href;
1378 hashtag =
1379 url.indexOf('#prettyPhoto') !== -1
1380 ? decodeURI(url.substring(url.indexOf('#prettyPhoto') + 1, url.length))
1381 : false;
1382 if (hashtag) {
1383 hashtag = hashtag.replace(/<|>/g, '');
1384 // Validate expected format: prettyPhoto/<rel>/<index>/ (index is integer)
1385 var valid = /^prettyPhoto\/[A-Za-z0-9\-_]+\/[0-9]+\/?$/.test(hashtag);
1386 if (!valid) return false;
1387 }
1388 return hashtag;
1389 }
1390
1391 function setHashtag() {
1392 if (typeof theRel == 'undefined') return; // theRel is set on normal calls, it's impossible to deeplink using the API
1393 location.hash = theRel + '/' + rel_index + '/';
1394 }
1395
1396 function clearHashtag() {
1397 if (location.href.indexOf('#prettyPhoto') !== -1) location.hash = 'prettyPhoto';
1398 }
1399
1400 function getParam(name, url) {
1401 name = name.replace(/[\[]/, '\\\[').replace(/[\]]/, '\\\]');
1402 var regexS = '[\\?&]' + name + '=([^&#]*)';
1403 var regex = new RegExp(regexS);
1404 var results = regex.exec(url);
1405 return results == null ? '' : results[1];
1406 }
1407 })(jQuery);
1408
1409 var pp_alreadyInitialized = false; // Used for the deep linking to make sure not to call the same function several times.
1410