Bootstrap-Image-Gallery-rails 1.0.0.3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,215 @@
1
+ /*
2
+ * blueimp Gallery Vimeo Video Factory JS 1.2.0
3
+ * https://github.com/blueimp/Gallery
4
+ *
5
+ * Copyright 2013, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ */
11
+
12
+ /* global define, window, document, location, $f */
13
+
14
+ (function (factory) {
15
+ 'use strict';
16
+ if (typeof define === 'function' && define.amd) {
17
+ // Register as an anonymous AMD module:
18
+ define([
19
+ './blueimp-helper',
20
+ './blueimp-gallery-video'
21
+ ], factory);
22
+ } else {
23
+ // Browser globals:
24
+ factory(
25
+ window.blueimp.helper || window.jQuery,
26
+ window.blueimp.Gallery
27
+ );
28
+ }
29
+ }(function ($, Gallery) {
30
+ 'use strict';
31
+
32
+ if (!window.postMessage) {
33
+ return Gallery;
34
+ }
35
+
36
+ $.extend(Gallery.prototype.options, {
37
+ // The list object property (or data attribute) with the Vimeo video id:
38
+ vimeoVideoIdProperty: 'vimeo',
39
+ // The URL for the Vimeo video player, can be extended with custom parameters:
40
+ // https://developer.vimeo.com/player/embedding
41
+ vimeoPlayerUrl: '//player.vimeo.com/video/VIDEO_ID?api=1&player_id=PLAYER_ID',
42
+ // The prefix for the Vimeo video player ID:
43
+ vimeoPlayerIdPrefix: 'vimeo-player-',
44
+ // Require a click on the native Vimeo player for the initial playback:
45
+ vimeoClickToPlay: true
46
+ });
47
+
48
+ var textFactory = Gallery.prototype.textFactory || Gallery.prototype.imageFactory,
49
+ VimeoPlayer = function (url, videoId, playerId, clickToPlay) {
50
+ this.url = url;
51
+ this.videoId = videoId;
52
+ this.playerId = playerId;
53
+ this.clickToPlay = clickToPlay;
54
+ this.element = document.createElement('div');
55
+ this.listeners = {};
56
+ },
57
+ counter = 0;
58
+
59
+ $.extend(VimeoPlayer.prototype, {
60
+
61
+ canPlayType: function () {
62
+ return true;
63
+ },
64
+
65
+ on: function (type, func) {
66
+ this.listeners[type] = func;
67
+ return this;
68
+ },
69
+
70
+ loadAPI: function () {
71
+ var that = this,
72
+ apiUrl = '//' + (location.protocol === 'https' ? 'secure-' : '') +
73
+ 'a.vimeocdn.com/js/froogaloop2.min.js',
74
+ scriptTags = document.getElementsByTagName('script'),
75
+ i = scriptTags.length,
76
+ scriptTag,
77
+ called,
78
+ callback = function () {
79
+ if (!called && that.playOnReady) {
80
+ that.play();
81
+ }
82
+ called = true;
83
+ };
84
+ while (i) {
85
+ i -= 1;
86
+ if (scriptTags[i].src === apiUrl) {
87
+ scriptTag = scriptTags[i];
88
+ break;
89
+ }
90
+ }
91
+ if (!scriptTag) {
92
+ scriptTag = document.createElement('script');
93
+ scriptTag.src = apiUrl;
94
+ }
95
+ $(scriptTag).on('load', callback);
96
+ scriptTags[0].parentNode.insertBefore(scriptTag, scriptTags[0]);
97
+ // Fix for cached scripts on IE 8:
98
+ if (/loaded|complete/.test(scriptTag.readyState)) {
99
+ callback();
100
+ }
101
+ },
102
+
103
+ onReady: function () {
104
+ var that = this;
105
+ this.ready = true;
106
+ this.player.addEvent('play', function () {
107
+ that.hasPlayed = true;
108
+ that.onPlaying();
109
+ });
110
+ this.player.addEvent('pause', function () {
111
+ that.onPause();
112
+ });
113
+ this.player.addEvent('finish', function () {
114
+ that.onPause();
115
+ });
116
+ if (this.playOnReady) {
117
+ this.play();
118
+ }
119
+ },
120
+
121
+ onPlaying: function () {
122
+ if (this.playStatus < 2) {
123
+ this.listeners.playing();
124
+ this.playStatus = 2;
125
+ }
126
+ },
127
+
128
+ onPause: function () {
129
+ this.listeners.pause();
130
+ delete this.playStatus;
131
+ },
132
+
133
+ insertIframe: function () {
134
+ var iframe = document.createElement('iframe');
135
+ iframe.src = this.url
136
+ .replace('VIDEO_ID', this.videoId)
137
+ .replace('PLAYER_ID', this.playerId);
138
+ iframe.id = this.playerId;
139
+ this.element.parentNode.replaceChild(iframe, this.element);
140
+ this.element = iframe;
141
+ },
142
+
143
+ play: function () {
144
+ var that = this;
145
+ if (!this.playStatus) {
146
+ this.listeners.play();
147
+ this.playStatus = 1;
148
+ }
149
+ if (this.ready) {
150
+ if (!this.hasPlayed && (this.clickToPlay || (window.navigator &&
151
+ /iP(hone|od|ad)/.test(window.navigator.platform)))) {
152
+ // Manually trigger the playing callback if clickToPlay
153
+ // is enabled and to workaround a limitation in iOS,
154
+ // which requires synchronous user interaction to start
155
+ // the video playback:
156
+ this.onPlaying();
157
+ } else {
158
+ this.player.api('play');
159
+ }
160
+ } else {
161
+ this.playOnReady = true;
162
+ if (!window.$f) {
163
+ this.loadAPI();
164
+ } else if (!this.player) {
165
+ this.insertIframe();
166
+ this.player = $f(this.element);
167
+ this.player.addEvent('ready', function () {
168
+ that.onReady();
169
+ });
170
+ }
171
+ }
172
+ },
173
+
174
+ pause: function () {
175
+ if (this.ready) {
176
+ this.player.api('pause');
177
+ } else if (this.playStatus) {
178
+ delete this.playOnReady;
179
+ this.listeners.pause();
180
+ delete this.playStatus;
181
+ }
182
+ }
183
+
184
+ });
185
+
186
+ $.extend(Gallery.prototype, {
187
+
188
+ VimeoPlayer: VimeoPlayer,
189
+
190
+ textFactory: function (obj, callback) {
191
+ var options = this.options,
192
+ videoId = this.getItemProperty(obj, options.vimeoVideoIdProperty);
193
+ if (videoId) {
194
+ if (this.getItemProperty(obj, options.urlProperty) === undefined) {
195
+ obj[options.urlProperty] = '//vimeo.com/' + videoId;
196
+ }
197
+ counter += 1;
198
+ return this.videoFactory(
199
+ obj,
200
+ callback,
201
+ new VimeoPlayer(
202
+ options.vimeoPlayerUrl,
203
+ videoId,
204
+ options.vimeoPlayerIdPrefix + counter,
205
+ options.vimeoClickToPlay
206
+ )
207
+ );
208
+ }
209
+ return textFactory.call(this, obj, callback);
210
+ }
211
+
212
+ });
213
+
214
+ return Gallery;
215
+ }));
@@ -0,0 +1,229 @@
1
+ /*
2
+ * blueimp Gallery YouTube Video Factory JS 1.2.0
3
+ * https://github.com/blueimp/Gallery
4
+ *
5
+ * Copyright 2013, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ */
11
+
12
+ /* global define, window, document, YT */
13
+
14
+ (function (factory) {
15
+ 'use strict';
16
+ if (typeof define === 'function' && define.amd) {
17
+ // Register as an anonymous AMD module:
18
+ define([
19
+ './blueimp-helper',
20
+ './blueimp-gallery-video'
21
+ ], factory);
22
+ } else {
23
+ // Browser globals:
24
+ factory(
25
+ window.blueimp.helper || window.jQuery,
26
+ window.blueimp.Gallery
27
+ );
28
+ }
29
+ }(function ($, Gallery) {
30
+ 'use strict';
31
+
32
+ if (!window.postMessage) {
33
+ return Gallery;
34
+ }
35
+
36
+ $.extend(Gallery.prototype.options, {
37
+ // The list object property (or data attribute) with the YouTube video id:
38
+ youTubeVideoIdProperty: 'youtube',
39
+ // Optional object with parameters passed to the YouTube video player:
40
+ // https://developers.google.com/youtube/player_parameters
41
+ youTubePlayerVars: {
42
+ wmode: 'transparent'
43
+ },
44
+ // Require a click on the native YouTube player for the initial playback:
45
+ youTubeClickToPlay: true
46
+ });
47
+
48
+ var textFactory = Gallery.prototype.textFactory || Gallery.prototype.imageFactory,
49
+ YouTubePlayer = function (videoId, playerVars, clickToPlay) {
50
+ this.videoId = videoId;
51
+ this.playerVars = playerVars;
52
+ this.clickToPlay = clickToPlay;
53
+ this.element = document.createElement('div');
54
+ this.listeners = {};
55
+ };
56
+
57
+ $.extend(YouTubePlayer.prototype, {
58
+
59
+ canPlayType: function () {
60
+ return true;
61
+ },
62
+
63
+ on: function (type, func) {
64
+ this.listeners[type] = func;
65
+ return this;
66
+ },
67
+
68
+ loadAPI: function () {
69
+ var that = this,
70
+ onYouTubeIframeAPIReady = window.onYouTubeIframeAPIReady,
71
+ apiUrl = '//www.youtube.com/iframe_api',
72
+ scriptTags = document.getElementsByTagName('script'),
73
+ i = scriptTags.length,
74
+ scriptTag;
75
+ window.onYouTubeIframeAPIReady = function () {
76
+ if (onYouTubeIframeAPIReady) {
77
+ onYouTubeIframeAPIReady.apply(this);
78
+ }
79
+ if (that.playOnReady) {
80
+ that.play();
81
+ }
82
+ };
83
+ while (i) {
84
+ i -= 1;
85
+ if (scriptTags[i].src === apiUrl) {
86
+ return;
87
+ }
88
+ }
89
+ scriptTag = document.createElement('script');
90
+ scriptTag.src = apiUrl;
91
+ scriptTags[0].parentNode.insertBefore(scriptTag, scriptTags[0]);
92
+ },
93
+
94
+ onReady: function () {
95
+ this.ready = true;
96
+ if (this.playOnReady) {
97
+ this.play();
98
+ }
99
+ },
100
+
101
+ onPlaying: function () {
102
+ if (this.playStatus < 2) {
103
+ this.listeners.playing();
104
+ this.playStatus = 2;
105
+ }
106
+ },
107
+
108
+ onPause: function () {
109
+ Gallery.prototype.setTimeout.call(
110
+ this,
111
+ this.checkSeek,
112
+ null,
113
+ 2000
114
+ );
115
+ },
116
+
117
+ checkSeek: function () {
118
+ if (this.stateChange === YT.PlayerState.PAUSED ||
119
+ this.stateChange === YT.PlayerState.ENDED) {
120
+ // check if current state change is actually paused
121
+ this.listeners.pause();
122
+ delete this.playStatus;
123
+ }
124
+ },
125
+
126
+ onStateChange: function (event) {
127
+ switch (event.data) {
128
+ case YT.PlayerState.PLAYING:
129
+ this.hasPlayed = true;
130
+ this.onPlaying();
131
+ break;
132
+ case YT.PlayerState.PAUSED:
133
+ case YT.PlayerState.ENDED:
134
+ this.onPause();
135
+ break;
136
+ }
137
+ // Save most recent state change to this.stateChange
138
+ this.stateChange = event.data;
139
+ },
140
+
141
+ onError: function (event) {
142
+ this.listeners.error(event);
143
+ },
144
+
145
+ play: function () {
146
+ var that = this;
147
+ if (!this.playStatus) {
148
+ this.listeners.play();
149
+ this.playStatus = 1;
150
+ }
151
+ if (this.ready) {
152
+ if (!this.hasPlayed && (this.clickToPlay || (window.navigator &&
153
+ /iP(hone|od|ad)/.test(window.navigator.platform)))) {
154
+ // Manually trigger the playing callback if clickToPlay
155
+ // is enabled and to workaround a limitation in iOS,
156
+ // which requires synchronous user interaction to start
157
+ // the video playback:
158
+ this.onPlaying();
159
+ } else {
160
+ this.player.playVideo();
161
+ }
162
+ } else {
163
+ this.playOnReady = true;
164
+ if (!(window.YT && YT.Player)) {
165
+ this.loadAPI();
166
+ } else if (!this.player) {
167
+ this.player = new YT.Player(this.element, {
168
+ videoId: this.videoId,
169
+ playerVars: this.playerVars,
170
+ events: {
171
+ onReady: function () {
172
+ that.onReady();
173
+ },
174
+ onStateChange: function (event) {
175
+ that.onStateChange(event);
176
+ },
177
+ onError: function (event) {
178
+ that.onError(event);
179
+ }
180
+ }
181
+ });
182
+ }
183
+ }
184
+ },
185
+
186
+ pause: function () {
187
+ if (this.ready) {
188
+ this.player.pauseVideo();
189
+ } else if (this.playStatus) {
190
+ delete this.playOnReady;
191
+ this.listeners.pause();
192
+ delete this.playStatus;
193
+ }
194
+ }
195
+
196
+ });
197
+
198
+ $.extend(Gallery.prototype, {
199
+
200
+ YouTubePlayer: YouTubePlayer,
201
+
202
+ textFactory: function (obj, callback) {
203
+ var options = this.options,
204
+ videoId = this.getItemProperty(obj, options.youTubeVideoIdProperty);
205
+ if (videoId) {
206
+ if (this.getItemProperty(obj, options.urlProperty) === undefined) {
207
+ obj[options.urlProperty] = '//www.youtube.com/watch?v=' + videoId;
208
+ }
209
+ if (this.getItemProperty(obj, options.videoPosterProperty) === undefined) {
210
+ obj[options.videoPosterProperty] = '//img.youtube.com/vi/' + videoId +
211
+ '/maxresdefault.jpg';
212
+ }
213
+ return this.videoFactory(
214
+ obj,
215
+ callback,
216
+ new YouTubePlayer(
217
+ videoId,
218
+ options.youTubePlayerVars,
219
+ options.youTubeClickToPlay
220
+ )
221
+ );
222
+ }
223
+ return textFactory.call(this, obj, callback);
224
+ }
225
+
226
+ });
227
+
228
+ return Gallery;
229
+ }));
@@ -0,0 +1,1341 @@
1
+ /*
2
+ * blueimp Gallery JS 2.14.0
3
+ * https://github.com/blueimp/Gallery
4
+ *
5
+ * Copyright 2013, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Swipe implementation based on
9
+ * https://github.com/bradbirdsall/Swipe
10
+ *
11
+ * Licensed under the MIT license:
12
+ * http://www.opensource.org/licenses/MIT
13
+ */
14
+
15
+ /* global define, window, document, DocumentTouch */
16
+
17
+ (function (factory) {
18
+ 'use strict';
19
+ if (typeof define === 'function' && define.amd) {
20
+ // Register as an anonymous AMD module:
21
+ define(['./blueimp-helper'], factory);
22
+ } else {
23
+ // Browser globals:
24
+ window.blueimp = window.blueimp || {};
25
+ window.blueimp.Gallery = factory(
26
+ window.blueimp.helper || window.jQuery
27
+ );
28
+ }
29
+ }(function ($) {
30
+ 'use strict';
31
+
32
+ function Gallery(list, options) {
33
+ if (document.body.style.maxHeight === undefined) {
34
+ // document.body.style.maxHeight is undefined on IE6 and lower
35
+ return null;
36
+ }
37
+ if (!this || this.options !== Gallery.prototype.options) {
38
+ // Called as function instead of as constructor,
39
+ // so we simply return a new instance:
40
+ return new Gallery(list, options);
41
+ }
42
+ if (!list || !list.length) {
43
+ this.console.log(
44
+ 'blueimp Gallery: No or empty list provided as first argument.',
45
+ list
46
+ );
47
+ return;
48
+ }
49
+ this.list = list;
50
+ this.num = list.length;
51
+ this.initOptions(options);
52
+ this.initialize();
53
+ }
54
+
55
+ $.extend(Gallery.prototype, {
56
+
57
+ options: {
58
+ // The Id, element or querySelector of the gallery widget:
59
+ container: '#blueimp-gallery',
60
+ // The tag name, Id, element or querySelector of the slides container:
61
+ slidesContainer: 'div',
62
+ // The tag name, Id, element or querySelector of the title element:
63
+ titleElement: 'h3',
64
+ // The class to add when the gallery is visible:
65
+ displayClass: 'blueimp-gallery-display',
66
+ // The class to add when the gallery controls are visible:
67
+ controlsClass: 'blueimp-gallery-controls',
68
+ // The class to add when the gallery only displays one element:
69
+ singleClass: 'blueimp-gallery-single',
70
+ // The class to add when the left edge has been reached:
71
+ leftEdgeClass: 'blueimp-gallery-left',
72
+ // The class to add when the right edge has been reached:
73
+ rightEdgeClass: 'blueimp-gallery-right',
74
+ // The class to add when the automatic slideshow is active:
75
+ playingClass: 'blueimp-gallery-playing',
76
+ // The class for all slides:
77
+ slideClass: 'slide',
78
+ // The slide class for loading elements:
79
+ slideLoadingClass: 'slide-loading',
80
+ // The slide class for elements that failed to load:
81
+ slideErrorClass: 'slide-error',
82
+ // The class for the content element loaded into each slide:
83
+ slideContentClass: 'slide-content',
84
+ // The class for the "toggle" control:
85
+ toggleClass: 'toggle',
86
+ // The class for the "prev" control:
87
+ prevClass: 'prev',
88
+ // The class for the "next" control:
89
+ nextClass: 'next',
90
+ // The class for the "close" control:
91
+ closeClass: 'close',
92
+ // The class for the "play-pause" toggle control:
93
+ playPauseClass: 'play-pause',
94
+ // The list object property (or data attribute) with the object type:
95
+ typeProperty: 'type',
96
+ // The list object property (or data attribute) with the object title:
97
+ titleProperty: 'title',
98
+ // The list object property (or data attribute) with the object URL:
99
+ urlProperty: 'href',
100
+ // The gallery listens for transitionend events before triggering the
101
+ // opened and closed events, unless the following option is set to false:
102
+ displayTransition: true,
103
+ // Defines if the gallery slides are cleared from the gallery modal,
104
+ // or reused for the next gallery initialization:
105
+ clearSlides: true,
106
+ // Defines if images should be stretched to fill the available space,
107
+ // while maintaining their aspect ratio (will only be enabled for browsers
108
+ // supporting background-size="contain", which excludes IE < 9).
109
+ // Set to "cover", to make images cover all available space (requires
110
+ // support for background-size="cover", which excludes IE < 9):
111
+ stretchImages: false,
112
+ // Toggle the controls on pressing the Return key:
113
+ toggleControlsOnReturn: true,
114
+ // Toggle the automatic slideshow interval on pressing the Space key:
115
+ toggleSlideshowOnSpace: true,
116
+ // Navigate the gallery by pressing left and right on the keyboard:
117
+ enableKeyboardNavigation: true,
118
+ // Close the gallery on pressing the Esc key:
119
+ closeOnEscape: true,
120
+ // Close the gallery when clicking on an empty slide area:
121
+ closeOnSlideClick: true,
122
+ // Close the gallery by swiping up or down:
123
+ closeOnSwipeUpOrDown: true,
124
+ // Emulate touch events on mouse-pointer devices such as desktop browsers:
125
+ emulateTouchEvents: true,
126
+ // Stop touch events from bubbling up to ancestor elements of the Gallery:
127
+ stopTouchEventsPropagation: false,
128
+ // Hide the page scrollbars:
129
+ hidePageScrollbars: true,
130
+ // Stops any touches on the container from scrolling the page:
131
+ disableScroll: true,
132
+ // Carousel mode (shortcut for carousel specific options):
133
+ carousel: false,
134
+ // Allow continuous navigation, moving from last to first
135
+ // and from first to last slide:
136
+ continuous: true,
137
+ // Remove elements outside of the preload range from the DOM:
138
+ unloadElements: true,
139
+ // Start with the automatic slideshow:
140
+ startSlideshow: false,
141
+ // Delay in milliseconds between slides for the automatic slideshow:
142
+ slideshowInterval: 5000,
143
+ // The starting index as integer.
144
+ // Can also be an object of the given list,
145
+ // or an equal object with the same url property:
146
+ index: 0,
147
+ // The number of elements to load around the current index:
148
+ preloadRange: 2,
149
+ // The transition speed between slide changes in milliseconds:
150
+ transitionSpeed: 400,
151
+ // The transition speed for automatic slide changes, set to an integer
152
+ // greater 0 to override the default transition speed:
153
+ slideshowTransitionSpeed: undefined,
154
+ // The event object for which the default action will be canceled
155
+ // on Gallery initialization (e.g. the click event to open the Gallery):
156
+ event: undefined,
157
+ // Callback function executed when the Gallery is initialized.
158
+ // Is called with the gallery instance as "this" object:
159
+ onopen: undefined,
160
+ // Callback function executed when the Gallery has been initialized
161
+ // and the initialization transition has been completed.
162
+ // Is called with the gallery instance as "this" object:
163
+ onopened: undefined,
164
+ // Callback function executed on slide change.
165
+ // Is called with the gallery instance as "this" object and the
166
+ // current index and slide as arguments:
167
+ onslide: undefined,
168
+ // Callback function executed after the slide change transition.
169
+ // Is called with the gallery instance as "this" object and the
170
+ // current index and slide as arguments:
171
+ onslideend: undefined,
172
+ // Callback function executed on slide content load.
173
+ // Is called with the gallery instance as "this" object and the
174
+ // slide index and slide element as arguments:
175
+ onslidecomplete: undefined,
176
+ // Callback function executed when the Gallery is about to be closed.
177
+ // Is called with the gallery instance as "this" object:
178
+ onclose: undefined,
179
+ // Callback function executed when the Gallery has been closed
180
+ // and the closing transition has been completed.
181
+ // Is called with the gallery instance as "this" object:
182
+ onclosed: undefined
183
+ },
184
+
185
+ carouselOptions: {
186
+ hidePageScrollbars: false,
187
+ toggleControlsOnReturn: false,
188
+ toggleSlideshowOnSpace: false,
189
+ enableKeyboardNavigation: false,
190
+ closeOnEscape: false,
191
+ closeOnSlideClick: false,
192
+ closeOnSwipeUpOrDown: false,
193
+ disableScroll: false,
194
+ startSlideshow: true
195
+ },
196
+
197
+ console: window.console && typeof window.console.log === 'function' ?
198
+ window.console :
199
+ {log: function () {}},
200
+
201
+ // Detect touch, transition, transform and background-size support:
202
+ support: (function (element) {
203
+ var support = {
204
+ touch: window.ontouchstart !== undefined ||
205
+ (window.DocumentTouch && document instanceof DocumentTouch)
206
+ },
207
+ transitions = {
208
+ webkitTransition: {
209
+ end: 'webkitTransitionEnd',
210
+ prefix: '-webkit-'
211
+ },
212
+ MozTransition: {
213
+ end: 'transitionend',
214
+ prefix: '-moz-'
215
+ },
216
+ OTransition: {
217
+ end: 'otransitionend',
218
+ prefix: '-o-'
219
+ },
220
+ transition: {
221
+ end: 'transitionend',
222
+ prefix: ''
223
+ }
224
+ },
225
+ elementTests = function () {
226
+ var transition = support.transition,
227
+ prop,
228
+ translateZ;
229
+ document.body.appendChild(element);
230
+ if (transition) {
231
+ prop = transition.name.slice(0, -9) + 'ransform';
232
+ if (element.style[prop] !== undefined) {
233
+ element.style[prop] = 'translateZ(0)';
234
+ translateZ = window.getComputedStyle(element)
235
+ .getPropertyValue(transition.prefix + 'transform');
236
+ support.transform = {
237
+ prefix: transition.prefix,
238
+ name: prop,
239
+ translate: true,
240
+ translateZ: !!translateZ && translateZ !== 'none'
241
+ };
242
+ }
243
+ }
244
+ if (element.style.backgroundSize !== undefined) {
245
+ support.backgroundSize = {};
246
+ element.style.backgroundSize = 'contain';
247
+ support.backgroundSize.contain = window
248
+ .getComputedStyle(element)
249
+ .getPropertyValue('background-size') === 'contain';
250
+ element.style.backgroundSize = 'cover';
251
+ support.backgroundSize.cover = window
252
+ .getComputedStyle(element)
253
+ .getPropertyValue('background-size') === 'cover';
254
+ }
255
+ document.body.removeChild(element);
256
+ };
257
+ (function (support, transitions) {
258
+ var prop;
259
+ for (prop in transitions) {
260
+ if (transitions.hasOwnProperty(prop) &&
261
+ element.style[prop] !== undefined) {
262
+ support.transition = transitions[prop];
263
+ support.transition.name = prop;
264
+ break;
265
+ }
266
+ }
267
+ }(support, transitions));
268
+ if (document.body) {
269
+ elementTests();
270
+ } else {
271
+ $(document).on('DOMContentLoaded', elementTests);
272
+ }
273
+ return support;
274
+ // Test element, has to be standard HTML and must not be hidden
275
+ // for the CSS3 tests using window.getComputedStyle to be applicable:
276
+ }(document.createElement('div'))),
277
+
278
+ requestAnimationFrame: window.requestAnimationFrame ||
279
+ window.webkitRequestAnimationFrame ||
280
+ window.mozRequestAnimationFrame,
281
+
282
+ initialize: function () {
283
+ this.initStartIndex();
284
+ if (this.initWidget() === false) {
285
+ return false;
286
+ }
287
+ this.initEventListeners();
288
+ // Load the slide at the given index:
289
+ this.onslide(this.index);
290
+ // Manually trigger the slideend event for the initial slide:
291
+ this.ontransitionend();
292
+ // Start the automatic slideshow if applicable:
293
+ if (this.options.startSlideshow) {
294
+ this.play();
295
+ }
296
+ },
297
+
298
+ slide: function (to, speed) {
299
+ window.clearTimeout(this.timeout);
300
+ var index = this.index,
301
+ direction,
302
+ naturalDirection,
303
+ diff;
304
+ if (index === to || this.num === 1) {
305
+ return;
306
+ }
307
+ if (!speed) {
308
+ speed = this.options.transitionSpeed;
309
+ }
310
+ if (this.support.transition) {
311
+ if (!this.options.continuous) {
312
+ to = this.circle(to);
313
+ }
314
+ // 1: backward, -1: forward:
315
+ direction = Math.abs(index - to) / (index - to);
316
+ // Get the actual position of the slide:
317
+ if (this.options.continuous) {
318
+ naturalDirection = direction;
319
+ direction = -this.positions[this.circle(to)] / this.slideWidth;
320
+ // If going forward but to < index, use to = slides.length + to
321
+ // If going backward but to > index, use to = -slides.length + to
322
+ if (direction !== naturalDirection) {
323
+ to = -direction * this.num + to;
324
+ }
325
+ }
326
+ diff = Math.abs(index - to) - 1;
327
+ // Move all the slides between index and to in the right direction:
328
+ while (diff) {
329
+ diff -= 1;
330
+ this.move(
331
+ this.circle((to > index ? to : index) - diff - 1),
332
+ this.slideWidth * direction,
333
+ 0
334
+ );
335
+ }
336
+ to = this.circle(to);
337
+ this.move(index, this.slideWidth * direction, speed);
338
+ this.move(to, 0, speed);
339
+ if (this.options.continuous) {
340
+ this.move(
341
+ this.circle(to - direction),
342
+ -(this.slideWidth * direction),
343
+ 0
344
+ );
345
+ }
346
+ } else {
347
+ to = this.circle(to);
348
+ this.animate(index * -this.slideWidth, to * -this.slideWidth, speed);
349
+ }
350
+ this.onslide(to);
351
+ },
352
+
353
+ getIndex: function () {
354
+ return this.index;
355
+ },
356
+
357
+ getNumber: function () {
358
+ return this.num;
359
+ },
360
+
361
+ prev: function () {
362
+ if (this.options.continuous || this.index) {
363
+ this.slide(this.index - 1);
364
+ }
365
+ },
366
+
367
+ next: function () {
368
+ if (this.options.continuous || this.index < this.num - 1) {
369
+ this.slide(this.index + 1);
370
+ }
371
+ },
372
+
373
+ play: function (time) {
374
+ var that = this;
375
+ window.clearTimeout(this.timeout);
376
+ this.interval = time || this.options.slideshowInterval;
377
+ if (this.elements[this.index] > 1) {
378
+ this.timeout = this.setTimeout(
379
+ (!this.requestAnimationFrame && this.slide) || function (to, speed) {
380
+ that.animationFrameId = that.requestAnimationFrame.call(
381
+ window,
382
+ function () {
383
+ that.slide(to, speed);
384
+ }
385
+ );
386
+ },
387
+ [this.index + 1, this.options.slideshowTransitionSpeed],
388
+ this.interval
389
+ );
390
+ }
391
+ this.container.addClass(this.options.playingClass);
392
+ },
393
+
394
+ pause: function () {
395
+ window.clearTimeout(this.timeout);
396
+ this.interval = null;
397
+ this.container.removeClass(this.options.playingClass);
398
+ },
399
+
400
+ add: function (list) {
401
+ var i;
402
+ if (!list.concat) {
403
+ // Make a real array out of the list to add:
404
+ list = Array.prototype.slice.call(list);
405
+ }
406
+ if (!this.list.concat) {
407
+ // Make a real array out of the Gallery list:
408
+ this.list = Array.prototype.slice.call(this.list);
409
+ }
410
+ this.list = this.list.concat(list);
411
+ this.num = this.list.length;
412
+ if (this.num > 2 && this.options.continuous === null) {
413
+ this.options.continuous = true;
414
+ this.container.removeClass(this.options.leftEdgeClass);
415
+ }
416
+ this.container
417
+ .removeClass(this.options.rightEdgeClass)
418
+ .removeClass(this.options.singleClass);
419
+ for (i = this.num - list.length; i < this.num; i += 1) {
420
+ this.addSlide(i);
421
+ this.positionSlide(i);
422
+ }
423
+ this.positions.length = this.num;
424
+ this.initSlides(true);
425
+ },
426
+
427
+ resetSlides: function () {
428
+ this.slidesContainer.empty();
429
+ this.slides = [];
430
+ },
431
+
432
+ handleClose: function () {
433
+ var options = this.options;
434
+ this.destroyEventListeners();
435
+ // Cancel the slideshow:
436
+ this.pause();
437
+ this.container[0].style.display = 'none';
438
+ this.container
439
+ .removeClass(options.displayClass)
440
+ .removeClass(options.singleClass)
441
+ .removeClass(options.leftEdgeClass)
442
+ .removeClass(options.rightEdgeClass);
443
+ if (options.hidePageScrollbars) {
444
+ document.body.style.overflow = this.bodyOverflowStyle;
445
+ }
446
+ if (this.options.clearSlides) {
447
+ this.resetSlides();
448
+ }
449
+ if (this.options.onclosed) {
450
+ this.options.onclosed.call(this);
451
+ }
452
+ },
453
+
454
+ close: function () {
455
+ var that = this,
456
+ closeHandler = function (event) {
457
+ if (event.target === that.container[0]) {
458
+ that.container.off(
459
+ that.support.transition.end,
460
+ closeHandler
461
+ );
462
+ that.handleClose();
463
+ }
464
+ };
465
+ if (this.options.onclose) {
466
+ this.options.onclose.call(this);
467
+ }
468
+ if (this.support.transition && this.options.displayTransition) {
469
+ this.container.on(
470
+ this.support.transition.end,
471
+ closeHandler
472
+ );
473
+ this.container.removeClass(this.options.displayClass);
474
+ } else {
475
+ this.handleClose();
476
+ }
477
+ },
478
+
479
+ circle: function (index) {
480
+ // Always return a number inside of the slides index range:
481
+ return (this.num + (index % this.num)) % this.num;
482
+ },
483
+
484
+ move: function (index, dist, speed) {
485
+ this.translateX(index, dist, speed);
486
+ this.positions[index] = dist;
487
+ },
488
+
489
+ translate: function (index, x, y, speed) {
490
+ var style = this.slides[index].style,
491
+ transition = this.support.transition,
492
+ transform = this.support.transform;
493
+ style[transition.name + 'Duration'] = speed + 'ms';
494
+ style[transform.name] = 'translate(' + x + 'px, ' + y + 'px)' +
495
+ (transform.translateZ ? ' translateZ(0)' : '');
496
+ },
497
+
498
+ translateX: function (index, x, speed) {
499
+ this.translate(index, x, 0, speed);
500
+ },
501
+
502
+ translateY: function (index, y, speed) {
503
+ this.translate(index, 0, y, speed);
504
+ },
505
+
506
+ animate: function (from, to, speed) {
507
+ if (!speed) {
508
+ this.slidesContainer[0].style.left = to + 'px';
509
+ return;
510
+ }
511
+ var that = this,
512
+ start = new Date().getTime(),
513
+ timer = window.setInterval(function () {
514
+ var timeElap = new Date().getTime() - start;
515
+ if (timeElap > speed) {
516
+ that.slidesContainer[0].style.left = to + 'px';
517
+ that.ontransitionend();
518
+ window.clearInterval(timer);
519
+ return;
520
+ }
521
+ that.slidesContainer[0].style.left = (((to - from) *
522
+ (Math.floor((timeElap / speed) * 100) / 100)) +
523
+ from) + 'px';
524
+ }, 4);
525
+ },
526
+
527
+ preventDefault: function (event) {
528
+ if (event.preventDefault) {
529
+ event.preventDefault();
530
+ } else {
531
+ event.returnValue = false;
532
+ }
533
+ },
534
+
535
+ stopPropagation: function (event) {
536
+ if (event.stopPropagation) {
537
+ event.stopPropagation();
538
+ } else {
539
+ event.cancelBubble = true;
540
+ }
541
+ },
542
+
543
+ onresize: function () {
544
+ this.initSlides(true);
545
+ },
546
+
547
+ onmousedown: function (event) {
548
+ // Trigger on clicks of the left mouse button only
549
+ // and exclude video elements:
550
+ if (event.which && event.which === 1 &&
551
+ event.target.nodeName !== 'VIDEO') {
552
+ // Preventing the default mousedown action is required
553
+ // to make touch emulation work with Firefox:
554
+ event.preventDefault();
555
+ (event.originalEvent || event).touches = [{
556
+ pageX: event.pageX,
557
+ pageY: event.pageY
558
+ }];
559
+ this.ontouchstart(event);
560
+ }
561
+ },
562
+
563
+ onmousemove: function (event) {
564
+ if (this.touchStart) {
565
+ (event.originalEvent || event).touches = [{
566
+ pageX: event.pageX,
567
+ pageY: event.pageY
568
+ }];
569
+ this.ontouchmove(event);
570
+ }
571
+ },
572
+
573
+ onmouseup: function (event) {
574
+ if (this.touchStart) {
575
+ this.ontouchend(event);
576
+ delete this.touchStart;
577
+ }
578
+ },
579
+
580
+ onmouseout: function (event) {
581
+ if (this.touchStart) {
582
+ var target = event.target,
583
+ related = event.relatedTarget;
584
+ if (!related || (related !== target &&
585
+ !$.contains(target, related))) {
586
+ this.onmouseup(event);
587
+ }
588
+ }
589
+ },
590
+
591
+ ontouchstart: function (event) {
592
+ if (this.options.stopTouchEventsPropagation) {
593
+ this.stopPropagation(event);
594
+ }
595
+ // jQuery doesn't copy touch event properties by default,
596
+ // so we have to access the originalEvent object:
597
+ var touches = (event.originalEvent || event).touches[0];
598
+ this.touchStart = {
599
+ // Remember the initial touch coordinates:
600
+ x: touches.pageX,
601
+ y: touches.pageY,
602
+ // Store the time to determine touch duration:
603
+ time: Date.now()
604
+ };
605
+ // Helper variable to detect scroll movement:
606
+ this.isScrolling = undefined;
607
+ // Reset delta values:
608
+ this.touchDelta = {};
609
+ },
610
+
611
+ ontouchmove: function (event) {
612
+ if (this.options.stopTouchEventsPropagation) {
613
+ this.stopPropagation(event);
614
+ }
615
+ // jQuery doesn't copy touch event properties by default,
616
+ // so we have to access the originalEvent object:
617
+ var touches = (event.originalEvent || event).touches[0],
618
+ scale = (event.originalEvent || event).scale,
619
+ index = this.index,
620
+ touchDeltaX,
621
+ indices;
622
+ // Ensure this is a one touch swipe and not, e.g. a pinch:
623
+ if (touches.length > 1 || (scale && scale !== 1)) {
624
+ return;
625
+ }
626
+ if (this.options.disableScroll) {
627
+ event.preventDefault();
628
+ }
629
+ // Measure change in x and y coordinates:
630
+ this.touchDelta = {
631
+ x: touches.pageX - this.touchStart.x,
632
+ y: touches.pageY - this.touchStart.y
633
+ };
634
+ touchDeltaX = this.touchDelta.x;
635
+ // Detect if this is a vertical scroll movement (run only once per touch):
636
+ if (this.isScrolling === undefined) {
637
+ this.isScrolling = this.isScrolling ||
638
+ Math.abs(touchDeltaX) < Math.abs(this.touchDelta.y);
639
+ }
640
+ if (!this.isScrolling) {
641
+ // Always prevent horizontal scroll:
642
+ event.preventDefault();
643
+ // Stop the slideshow:
644
+ window.clearTimeout(this.timeout);
645
+ if (this.options.continuous) {
646
+ indices = [
647
+ this.circle(index + 1),
648
+ index,
649
+ this.circle(index - 1)
650
+ ];
651
+ } else {
652
+ // Increase resistance if first slide and sliding left
653
+ // or last slide and sliding right:
654
+ this.touchDelta.x = touchDeltaX =
655
+ touchDeltaX /
656
+ (((!index && touchDeltaX > 0) ||
657
+ (index === this.num - 1 && touchDeltaX < 0)) ?
658
+ (Math.abs(touchDeltaX) / this.slideWidth + 1) : 1);
659
+ indices = [index];
660
+ if (index) {
661
+ indices.push(index - 1);
662
+ }
663
+ if (index < this.num - 1) {
664
+ indices.unshift(index + 1);
665
+ }
666
+ }
667
+ while (indices.length) {
668
+ index = indices.pop();
669
+ this.translateX(index, touchDeltaX + this.positions[index], 0);
670
+ }
671
+ } else if (this.options.closeOnSwipeUpOrDown) {
672
+ this.translateY(index, this.touchDelta.y + this.positions[index], 0);
673
+ }
674
+ },
675
+
676
+ ontouchend: function (event) {
677
+ if (this.options.stopTouchEventsPropagation) {
678
+ this.stopPropagation(event);
679
+ }
680
+ var index = this.index,
681
+ speed = this.options.transitionSpeed,
682
+ slideWidth = this.slideWidth,
683
+ isShortDuration = Number(Date.now() - this.touchStart.time) < 250,
684
+ // Determine if slide attempt triggers next/prev slide:
685
+ isValidSlide = (isShortDuration && Math.abs(this.touchDelta.x) > 20) ||
686
+ Math.abs(this.touchDelta.x) > slideWidth / 2,
687
+ // Determine if slide attempt is past start or end:
688
+ isPastBounds = (!index && this.touchDelta.x > 0) ||
689
+ (index === this.num - 1 && this.touchDelta.x < 0),
690
+ isValidClose = !isValidSlide && this.options.closeOnSwipeUpOrDown &&
691
+ ((isShortDuration && Math.abs(this.touchDelta.y) > 20) ||
692
+ Math.abs(this.touchDelta.y) > this.slideHeight / 2),
693
+ direction,
694
+ indexForward,
695
+ indexBackward,
696
+ distanceForward,
697
+ distanceBackward;
698
+ if (this.options.continuous) {
699
+ isPastBounds = false;
700
+ }
701
+ // Determine direction of swipe (true: right, false: left):
702
+ direction = this.touchDelta.x < 0 ? -1 : 1;
703
+ if (!this.isScrolling) {
704
+ if (isValidSlide && !isPastBounds) {
705
+ indexForward = index + direction;
706
+ indexBackward = index - direction;
707
+ distanceForward = slideWidth * direction;
708
+ distanceBackward = -slideWidth * direction;
709
+ if (this.options.continuous) {
710
+ this.move(this.circle(indexForward), distanceForward, 0);
711
+ this.move(this.circle(index - 2 * direction), distanceBackward, 0);
712
+ } else if (indexForward >= 0 &&
713
+ indexForward < this.num) {
714
+ this.move(indexForward, distanceForward, 0);
715
+ }
716
+ this.move(index, this.positions[index] + distanceForward, speed);
717
+ this.move(
718
+ this.circle(indexBackward),
719
+ this.positions[this.circle(indexBackward)] + distanceForward,
720
+ speed
721
+ );
722
+ index = this.circle(indexBackward);
723
+ this.onslide(index);
724
+ } else {
725
+ // Move back into position
726
+ if (this.options.continuous) {
727
+ this.move(this.circle(index - 1), -slideWidth, speed);
728
+ this.move(index, 0, speed);
729
+ this.move(this.circle(index + 1), slideWidth, speed);
730
+ } else {
731
+ if (index) {
732
+ this.move(index - 1, -slideWidth, speed);
733
+ }
734
+ this.move(index, 0, speed);
735
+ if (index < this.num - 1) {
736
+ this.move(index + 1, slideWidth, speed);
737
+ }
738
+ }
739
+ }
740
+ } else {
741
+ if (isValidClose) {
742
+ this.close();
743
+ } else {
744
+ // Move back into position
745
+ this.translateY(index, 0, speed);
746
+ }
747
+ }
748
+ },
749
+
750
+ ontouchcancel: function (event) {
751
+ if (this.touchStart) {
752
+ this.ontouchend(event);
753
+ delete this.touchStart;
754
+ }
755
+ },
756
+
757
+ ontransitionend: function (event) {
758
+ var slide = this.slides[this.index];
759
+ if (!event || slide === event.target) {
760
+ if (this.interval) {
761
+ this.play();
762
+ }
763
+ this.setTimeout(
764
+ this.options.onslideend,
765
+ [this.index, slide]
766
+ );
767
+ }
768
+ },
769
+
770
+ oncomplete: function (event) {
771
+ var target = event.target || event.srcElement,
772
+ parent = target && target.parentNode,
773
+ index;
774
+ if (!target || !parent) {
775
+ return;
776
+ }
777
+ index = this.getNodeIndex(parent);
778
+ $(parent).removeClass(this.options.slideLoadingClass);
779
+ if (event.type === 'error') {
780
+ $(parent).addClass(this.options.slideErrorClass);
781
+ this.elements[index] = 3; // Fail
782
+ } else {
783
+ this.elements[index] = 2; // Done
784
+ }
785
+ // Fix for IE7's lack of support for percentage max-height:
786
+ if (target.clientHeight > this.container[0].clientHeight) {
787
+ target.style.maxHeight = this.container[0].clientHeight;
788
+ }
789
+ if (this.interval && this.slides[this.index] === parent) {
790
+ this.play();
791
+ }
792
+ this.setTimeout(
793
+ this.options.onslidecomplete,
794
+ [index, parent]
795
+ );
796
+ },
797
+
798
+ onload: function (event) {
799
+ this.oncomplete(event);
800
+ },
801
+
802
+ onerror: function (event) {
803
+ this.oncomplete(event);
804
+ },
805
+
806
+ onkeydown: function (event) {
807
+ switch (event.which || event.keyCode) {
808
+ case 13: // Return
809
+ if (this.options.toggleControlsOnReturn) {
810
+ this.preventDefault(event);
811
+ this.toggleControls();
812
+ }
813
+ break;
814
+ case 27: // Esc
815
+ if (this.options.closeOnEscape) {
816
+ this.close();
817
+ }
818
+ break;
819
+ case 32: // Space
820
+ if (this.options.toggleSlideshowOnSpace) {
821
+ this.preventDefault(event);
822
+ this.toggleSlideshow();
823
+ }
824
+ break;
825
+ case 37: // Left
826
+ if (this.options.enableKeyboardNavigation) {
827
+ this.preventDefault(event);
828
+ this.prev();
829
+ }
830
+ break;
831
+ case 39: // Right
832
+ if (this.options.enableKeyboardNavigation) {
833
+ this.preventDefault(event);
834
+ this.next();
835
+ }
836
+ break;
837
+ }
838
+ },
839
+
840
+ handleClick: function (event) {
841
+ var options = this.options,
842
+ target = event.target || event.srcElement,
843
+ parent = target.parentNode,
844
+ isTarget = function (className) {
845
+ return $(target).hasClass(className) ||
846
+ $(parent).hasClass(className);
847
+ };
848
+ if (isTarget(options.toggleClass)) {
849
+ // Click on "toggle" control
850
+ this.preventDefault(event);
851
+ this.toggleControls();
852
+ } else if (isTarget(options.prevClass)) {
853
+ // Click on "prev" control
854
+ this.preventDefault(event);
855
+ this.prev();
856
+ } else if (isTarget(options.nextClass)) {
857
+ // Click on "next" control
858
+ this.preventDefault(event);
859
+ this.next();
860
+ } else if (isTarget(options.closeClass)) {
861
+ // Click on "close" control
862
+ this.preventDefault(event);
863
+ this.close();
864
+ } else if (isTarget(options.playPauseClass)) {
865
+ // Click on "play-pause" control
866
+ this.preventDefault(event);
867
+ this.toggleSlideshow();
868
+ } else if (parent === this.slidesContainer[0]) {
869
+ // Click on slide background
870
+ this.preventDefault(event);
871
+ if (options.closeOnSlideClick) {
872
+ this.close();
873
+ } else {
874
+ this.toggleControls();
875
+ }
876
+ } else if (parent.parentNode &&
877
+ parent.parentNode === this.slidesContainer[0]) {
878
+ // Click on displayed element
879
+ this.preventDefault(event);
880
+ this.toggleControls();
881
+ }
882
+ },
883
+
884
+ onclick: function (event) {
885
+ if (this.options.emulateTouchEvents &&
886
+ this.touchDelta && (Math.abs(this.touchDelta.x) > 20 ||
887
+ Math.abs(this.touchDelta.y) > 20)) {
888
+ delete this.touchDelta;
889
+ return;
890
+ }
891
+ return this.handleClick(event);
892
+ },
893
+
894
+ updateEdgeClasses: function (index) {
895
+ if (!index) {
896
+ this.container.addClass(this.options.leftEdgeClass);
897
+ } else {
898
+ this.container.removeClass(this.options.leftEdgeClass);
899
+ }
900
+ if (index === this.num - 1) {
901
+ this.container.addClass(this.options.rightEdgeClass);
902
+ } else {
903
+ this.container.removeClass(this.options.rightEdgeClass);
904
+ }
905
+ },
906
+
907
+ handleSlide: function (index) {
908
+ if (!this.options.continuous) {
909
+ this.updateEdgeClasses(index);
910
+ }
911
+ this.loadElements(index);
912
+ if (this.options.unloadElements) {
913
+ this.unloadElements(index);
914
+ }
915
+ this.setTitle(index);
916
+ },
917
+
918
+ onslide: function (index) {
919
+ this.index = index;
920
+ this.handleSlide(index);
921
+ this.setTimeout(this.options.onslide, [index, this.slides[index]]);
922
+ },
923
+
924
+ setTitle: function (index) {
925
+ var text = this.slides[index].firstChild.title,
926
+ titleElement = this.titleElement;
927
+ if (titleElement.length) {
928
+ this.titleElement.empty();
929
+ if (text) {
930
+ titleElement[0].appendChild(document.createTextNode(text));
931
+ }
932
+ }
933
+ },
934
+
935
+ setTimeout: function (func, args, wait) {
936
+ var that = this;
937
+ return func && window.setTimeout(function () {
938
+ func.apply(that, args || []);
939
+ }, wait || 0);
940
+ },
941
+
942
+ imageFactory: function (obj, callback) {
943
+ var that = this,
944
+ img = this.imagePrototype.cloneNode(false),
945
+ url = obj,
946
+ backgroundSize = this.options.stretchImages,
947
+ called,
948
+ element,
949
+ callbackWrapper = function (event) {
950
+ if (!called) {
951
+ event = {
952
+ type: event.type,
953
+ target: element
954
+ };
955
+ if (!element.parentNode) {
956
+ // Fix for IE7 firing the load event for
957
+ // cached images before the element could
958
+ // be added to the DOM:
959
+ return that.setTimeout(callbackWrapper, [event]);
960
+ }
961
+ called = true;
962
+ $(img).off('load error', callbackWrapper);
963
+ if (backgroundSize) {
964
+ if (event.type === 'load') {
965
+ element.style.background = 'url("' + url +
966
+ '") center no-repeat';
967
+ element.style.backgroundSize = backgroundSize;
968
+ }
969
+ }
970
+ callback(event);
971
+ }
972
+ },
973
+ title;
974
+ if (typeof url !== 'string') {
975
+ url = this.getItemProperty(obj, this.options.urlProperty);
976
+ title = this.getItemProperty(obj, this.options.titleProperty);
977
+ }
978
+ if (backgroundSize === true) {
979
+ backgroundSize = 'contain';
980
+ }
981
+ backgroundSize = this.support.backgroundSize &&
982
+ this.support.backgroundSize[backgroundSize] && backgroundSize;
983
+ if (backgroundSize) {
984
+ element = this.elementPrototype.cloneNode(false);
985
+ } else {
986
+ element = img;
987
+ img.draggable = false;
988
+ }
989
+ if (title) {
990
+ element.title = title;
991
+ }
992
+ $(img).on('load error', callbackWrapper);
993
+ img.src = url;
994
+ return element;
995
+ },
996
+
997
+ createElement: function (obj, callback) {
998
+ var type = obj && this.getItemProperty(obj, this.options.typeProperty),
999
+ factory = (type && this[type.split('/')[0] + 'Factory']) ||
1000
+ this.imageFactory,
1001
+ element = obj && factory.call(this, obj, callback);
1002
+ if (!element) {
1003
+ element = this.elementPrototype.cloneNode(false);
1004
+ this.setTimeout(callback, [{
1005
+ type: 'error',
1006
+ target: element
1007
+ }]);
1008
+ }
1009
+ $(element).addClass(this.options.slideContentClass);
1010
+ return element;
1011
+ },
1012
+
1013
+ loadElement: function (index) {
1014
+ if (!this.elements[index]) {
1015
+ if (this.slides[index].firstChild) {
1016
+ this.elements[index] = $(this.slides[index])
1017
+ .hasClass(this.options.slideErrorClass) ? 3 : 2;
1018
+ } else {
1019
+ this.elements[index] = 1; // Loading
1020
+ $(this.slides[index]).addClass(this.options.slideLoadingClass);
1021
+ this.slides[index].appendChild(this.createElement(
1022
+ this.list[index],
1023
+ this.proxyListener
1024
+ ));
1025
+ }
1026
+ }
1027
+ },
1028
+
1029
+ loadElements: function (index) {
1030
+ var limit = Math.min(this.num, this.options.preloadRange * 2 + 1),
1031
+ j = index,
1032
+ i;
1033
+ for (i = 0; i < limit; i += 1) {
1034
+ // First load the current slide element (0),
1035
+ // then the next one (+1),
1036
+ // then the previous one (-2),
1037
+ // then the next after next (+2), etc.:
1038
+ j += i * (i % 2 === 0 ? -1 : 1);
1039
+ // Connect the ends of the list to load slide elements for
1040
+ // continuous navigation:
1041
+ j = this.circle(j);
1042
+ this.loadElement(j);
1043
+ }
1044
+ },
1045
+
1046
+ unloadElements: function (index) {
1047
+ var i,
1048
+ slide,
1049
+ diff;
1050
+ for (i in this.elements) {
1051
+ if (this.elements.hasOwnProperty(i)) {
1052
+ diff = Math.abs(index - i);
1053
+ if (diff > this.options.preloadRange &&
1054
+ diff + this.options.preloadRange < this.num) {
1055
+ slide = this.slides[i];
1056
+ slide.removeChild(slide.firstChild);
1057
+ delete this.elements[i];
1058
+ }
1059
+ }
1060
+ }
1061
+ },
1062
+
1063
+ addSlide: function (index) {
1064
+ var slide = this.slidePrototype.cloneNode(false);
1065
+ slide.setAttribute('data-index', index);
1066
+ this.slidesContainer[0].appendChild(slide);
1067
+ this.slides.push(slide);
1068
+ },
1069
+
1070
+ positionSlide: function (index) {
1071
+ var slide = this.slides[index];
1072
+ slide.style.width = this.slideWidth + 'px';
1073
+ if (this.support.transition) {
1074
+ slide.style.left = (index * -this.slideWidth) + 'px';
1075
+ this.move(index, this.index > index ? -this.slideWidth :
1076
+ (this.index < index ? this.slideWidth : 0), 0);
1077
+ }
1078
+ },
1079
+
1080
+ initSlides: function (reload) {
1081
+ var clearSlides,
1082
+ i;
1083
+ if (!reload) {
1084
+ this.positions = [];
1085
+ this.positions.length = this.num;
1086
+ this.elements = {};
1087
+ this.imagePrototype = document.createElement('img');
1088
+ this.elementPrototype = document.createElement('div');
1089
+ this.slidePrototype = document.createElement('div');
1090
+ $(this.slidePrototype).addClass(this.options.slideClass);
1091
+ this.slides = this.slidesContainer[0].children;
1092
+ clearSlides = this.options.clearSlides ||
1093
+ this.slides.length !== this.num;
1094
+ }
1095
+ this.slideWidth = this.container[0].offsetWidth;
1096
+ this.slideHeight = this.container[0].offsetHeight;
1097
+ this.slidesContainer[0].style.width =
1098
+ (this.num * this.slideWidth) + 'px';
1099
+ if (clearSlides) {
1100
+ this.resetSlides();
1101
+ }
1102
+ for (i = 0; i < this.num; i += 1) {
1103
+ if (clearSlides) {
1104
+ this.addSlide(i);
1105
+ }
1106
+ this.positionSlide(i);
1107
+ }
1108
+ // Reposition the slides before and after the given index:
1109
+ if (this.options.continuous && this.support.transition) {
1110
+ this.move(this.circle(this.index - 1), -this.slideWidth, 0);
1111
+ this.move(this.circle(this.index + 1), this.slideWidth, 0);
1112
+ }
1113
+ if (!this.support.transition) {
1114
+ this.slidesContainer[0].style.left =
1115
+ (this.index * -this.slideWidth) + 'px';
1116
+ }
1117
+ },
1118
+
1119
+ toggleControls: function () {
1120
+ var controlsClass = this.options.controlsClass;
1121
+ if (this.container.hasClass(controlsClass)) {
1122
+ this.container.removeClass(controlsClass);
1123
+ } else {
1124
+ this.container.addClass(controlsClass);
1125
+ }
1126
+ },
1127
+
1128
+ toggleSlideshow: function () {
1129
+ if (!this.interval) {
1130
+ this.play();
1131
+ } else {
1132
+ this.pause();
1133
+ }
1134
+ },
1135
+
1136
+ getNodeIndex: function (element) {
1137
+ return parseInt(element.getAttribute('data-index'), 10);
1138
+ },
1139
+
1140
+ getNestedProperty: function (obj, property) {
1141
+ property.replace(
1142
+ // Matches native JavaScript notation in a String,
1143
+ // e.g. '["doubleQuoteProp"].dotProp[2]'
1144
+ /\[(?:'([^']+)'|"([^"]+)"|(\d+))\]|(?:(?:^|\.)([^\.\[]+))/g,
1145
+ function (str, singleQuoteProp, doubleQuoteProp, arrayIndex, dotProp) {
1146
+ var prop = dotProp || singleQuoteProp || doubleQuoteProp ||
1147
+ (arrayIndex && parseInt(arrayIndex, 10));
1148
+ if (str && obj) {
1149
+ obj = obj[prop];
1150
+ }
1151
+ }
1152
+ );
1153
+ return obj;
1154
+ },
1155
+
1156
+ getDataProperty: function (obj, property) {
1157
+ if (obj.getAttribute) {
1158
+ var prop = obj.getAttribute('data-' +
1159
+ property.replace(/([A-Z])/g, '-$1').toLowerCase());
1160
+ if (typeof prop === 'string') {
1161
+ if (/^(true|false|null|-?\d+(\.\d+)?|\{[\s\S]*\}|\[[\s\S]*\])$/
1162
+ .test(prop)) {
1163
+ try {
1164
+ return $.parseJSON(prop);
1165
+ } catch (ignore) {}
1166
+ }
1167
+ return prop;
1168
+ }
1169
+ }
1170
+ },
1171
+
1172
+ getItemProperty: function (obj, property) {
1173
+ var prop = obj[property];
1174
+ if (prop === undefined) {
1175
+ prop = this.getDataProperty(obj, property);
1176
+ if (prop === undefined) {
1177
+ prop = this.getNestedProperty(obj, property);
1178
+ }
1179
+ }
1180
+ return prop;
1181
+ },
1182
+
1183
+ initStartIndex: function () {
1184
+ var index = this.options.index,
1185
+ urlProperty = this.options.urlProperty,
1186
+ i;
1187
+ // Check if the index is given as a list object:
1188
+ if (index && typeof index !== 'number') {
1189
+ for (i = 0; i < this.num; i += 1) {
1190
+ if (this.list[i] === index ||
1191
+ this.getItemProperty(this.list[i], urlProperty) ===
1192
+ this.getItemProperty(index, urlProperty)) {
1193
+ index = i;
1194
+ break;
1195
+ }
1196
+ }
1197
+ }
1198
+ // Make sure the index is in the list range:
1199
+ this.index = this.circle(parseInt(index, 10) || 0);
1200
+ },
1201
+
1202
+ initEventListeners: function () {
1203
+ var that = this,
1204
+ slidesContainer = this.slidesContainer,
1205
+ proxyListener = function (event) {
1206
+ var type = that.support.transition &&
1207
+ that.support.transition.end === event.type ?
1208
+ 'transitionend' : event.type;
1209
+ that['on' + type](event);
1210
+ };
1211
+ $(window).on('resize', proxyListener);
1212
+ $(document.body).on('keydown', proxyListener);
1213
+ this.container.on('click', proxyListener);
1214
+ if (this.support.touch) {
1215
+ slidesContainer
1216
+ .on('touchstart touchmove touchend touchcancel', proxyListener);
1217
+ } else if (this.options.emulateTouchEvents &&
1218
+ this.support.transition) {
1219
+ slidesContainer
1220
+ .on('mousedown mousemove mouseup mouseout', proxyListener);
1221
+ }
1222
+ if (this.support.transition) {
1223
+ slidesContainer.on(
1224
+ this.support.transition.end,
1225
+ proxyListener
1226
+ );
1227
+ }
1228
+ this.proxyListener = proxyListener;
1229
+ },
1230
+
1231
+ destroyEventListeners: function () {
1232
+ var slidesContainer = this.slidesContainer,
1233
+ proxyListener = this.proxyListener;
1234
+ $(window).off('resize', proxyListener);
1235
+ $(document.body).off('keydown', proxyListener);
1236
+ this.container.off('click', proxyListener);
1237
+ if (this.support.touch) {
1238
+ slidesContainer
1239
+ .off('touchstart touchmove touchend touchcancel', proxyListener);
1240
+ } else if (this.options.emulateTouchEvents &&
1241
+ this.support.transition) {
1242
+ slidesContainer
1243
+ .off('mousedown mousemove mouseup mouseout', proxyListener);
1244
+ }
1245
+ if (this.support.transition) {
1246
+ slidesContainer.off(
1247
+ this.support.transition.end,
1248
+ proxyListener
1249
+ );
1250
+ }
1251
+ },
1252
+
1253
+ handleOpen: function () {
1254
+ if (this.options.onopened) {
1255
+ this.options.onopened.call(this);
1256
+ }
1257
+ },
1258
+
1259
+ initWidget: function () {
1260
+ var that = this,
1261
+ openHandler = function (event) {
1262
+ if (event.target === that.container[0]) {
1263
+ that.container.off(
1264
+ that.support.transition.end,
1265
+ openHandler
1266
+ );
1267
+ that.handleOpen();
1268
+ }
1269
+ };
1270
+ this.container = $(this.options.container);
1271
+ if (!this.container.length) {
1272
+ this.console.log(
1273
+ 'blueimp Gallery: Widget container not found.',
1274
+ this.options.container
1275
+ );
1276
+ return false;
1277
+ }
1278
+ this.slidesContainer = this.container.find(
1279
+ this.options.slidesContainer
1280
+ ).first();
1281
+ if (!this.slidesContainer.length) {
1282
+ this.console.log(
1283
+ 'blueimp Gallery: Slides container not found.',
1284
+ this.options.slidesContainer
1285
+ );
1286
+ return false;
1287
+ }
1288
+ this.titleElement = this.container.find(
1289
+ this.options.titleElement
1290
+ ).first();
1291
+ if (this.num === 1) {
1292
+ this.container.addClass(this.options.singleClass);
1293
+ }
1294
+ if (this.options.onopen) {
1295
+ this.options.onopen.call(this);
1296
+ }
1297
+ if (this.support.transition && this.options.displayTransition) {
1298
+ this.container.on(
1299
+ this.support.transition.end,
1300
+ openHandler
1301
+ );
1302
+ } else {
1303
+ this.handleOpen();
1304
+ }
1305
+ if (this.options.hidePageScrollbars) {
1306
+ // Hide the page scrollbars:
1307
+ this.bodyOverflowStyle = document.body.style.overflow;
1308
+ document.body.style.overflow = 'hidden';
1309
+ }
1310
+ this.container[0].style.display = 'block';
1311
+ this.initSlides();
1312
+ this.container.addClass(this.options.displayClass);
1313
+ },
1314
+
1315
+ initOptions: function (options) {
1316
+ // Create a copy of the prototype options:
1317
+ this.options = $.extend({}, this.options);
1318
+ // Check if carousel mode is enabled:
1319
+ if ((options && options.carousel) ||
1320
+ (this.options.carousel && (!options || options.carousel !== false))) {
1321
+ $.extend(this.options, this.carouselOptions);
1322
+ }
1323
+ // Override any given options:
1324
+ $.extend(this.options, options);
1325
+ if (this.num < 3) {
1326
+ // 1 or 2 slides cannot be displayed continuous,
1327
+ // remember the original option by setting to null instead of false:
1328
+ this.options.continuous = this.options.continuous ? null : false;
1329
+ }
1330
+ if (!this.support.transition) {
1331
+ this.options.emulateTouchEvents = false;
1332
+ }
1333
+ if (this.options.event) {
1334
+ this.preventDefault(this.options.event);
1335
+ }
1336
+ }
1337
+
1338
+ });
1339
+
1340
+ return Gallery;
1341
+ }));