Bootstrap-Image-Gallery-rails 1.0.0.3.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }));